SRP--定制着色器

目录

[TOC]

一、自定义Unlit Shader

1.创建Unlit Shader

构建合适的文件夹结构,用于存放Shader以及其他文件。

picture0

在”Shaders”文件夹中创建Unlit Shader,并重命名为Unlit。

代码:

Shader "My Pipeline/Unlit"
{
    Properties
    {
    }
    SubShader
    {

        Pass
        {
            HLSLPROGRAM
		   //以支持OpenGL ES 2编译
		   #pragma target 3.5

		   #pragma vertex UnlitPassVertex
		   #pragma fragment UnlitPassFragment

		   #include "../ShaderLibrary/Unlit.hlsl"

		   ENDHLSL
        }
    }
}

2.创建”Unlit.hlsl”库文件

为了复用代码,可以创建hlsl库文件,以后要使用Unlit Shader代码时引用库文件即可。在”ShaderLibrary”文件夹下创建”Unlit.hlsl”文件。

(1)常规结构体和顶点片元函数:

/*
自定义RP的Unlit库文件(.hlsl)
 */

struct VertexInput{
	float4 pos : POSITION;
};

struct VertexOutput{
	float4 clipPos : SV_POSITION;
};

VertexOutput UnlitPassVertex (VertexInput input) {
	VertexOutput output;
	return output;
}

float4 UnlitPassFragment (VertexOutput input) : SV_TARGET {
	return 1;
}

(2)防止重复包含库文件

#ifndef MYRP_UNLIT_INCLUDED
#define MYRP_UNLIT_INCLUDED
......
//MYRP_UNLIT_INCLUDED
#endif

(3)常量缓冲器

Unity不提供MVP矩阵(模型-视图-投影矩阵)的原因在于要避免M矩阵与VP矩阵的矩阵乘法。VP矩阵可以用于每帧中同意摄像机所绘制的所有内容。VP矩阵通常放于”per-frame buffer”中;M矩阵通常放于”per-draw buffer”中。

常量缓冲器并不适用于所有平台,所以应该只在受支持的平台中使用,Unity使用宏CBUFFER_START(name参数)CBUFFER_END处理了平台之间的差异。要使用这两个宏需要引入Render-Pipelines.core V4.6.0预览版。可以通过包管理器”Package Manager”来导入、安装此文件。

使用”Package Manager”安装”Render-Pipelines.core V4.6.0”

打开”Advanced”下拉菜单并勾选”Show Preview Packages”。

picture1

如果遇到持续loading不显示包文件的情形,可以先关闭当前项目,然后离线重新打开当前项目,并打开PackageManager,此时会显示所有包文件,然后再开启网络进行导入安装。

安装完成后,”Project”窗口内的”Packages”文件夹下回多出”Core RP Library”文件夹。

picture2

安装成功后,可以正确使用宏和常量缓冲区了:

//引入CoreRPLibrary V4.6.0
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"

CBUFFER_START(UnityPerFrame)
float4x4 unity_ObjectToWorld;//M矩阵(模型空间到世界空间的转换矩阵)
CBUFFER_END

CBUFFER_START(UnityPerDraw)
float4x4 unity_MatrixVP;//VP矩阵
CBUFFER_END

然后在顶点函数中对顶点进行坐标空间转换。转换到世界空间的时候存在一个优化:由于矩阵乘法使用的是齐次坐标,顶点的齐次坐标的第四个分量总是1,所以显示第四个分量可以使编译器优化计算。

未优化:

	float4 worldPos = mul(unity_ObjectToWorld , input.pos);
	output.clipPos = mul(unity_MatrixVP , worldPos);

优化后:

	float4 worldPos = mul(unity_ObjectToWorld , float4(input.pos.xyz , 1.0));
	output.clipPos = mul(unity_MatrixVP , worldPos);

查看编译为D3D11的代码可以看到这个优化:

未优化:

   0: mul r0.xyzw, v0.yyyy, cb0[1].xyzw
   1: mad r0.xyzw, cb0[0].xyzw, v0.xxxx, r0.xyzw
   2: mad r0.xyzw, cb0[2].xyzw, v0.zzzz, r0.xyzw
   3: mad r0.xyzw, cb0[3].xyzw, v0.wwww, r0.xyzw
   4: mul r1.xyzw, r0.yyyy, cb1[1].xyzw
   5: mad r1.xyzw, cb1[0].xyzw, r0.xxxx, r1.xyzw
   6: mad r1.xyzw, cb1[2].xyzw, r0.zzzz, r1.xyzw
   7: mad o0.xyzw, cb1[3].xyzw, r0.wwww, r1.xyzw

优化后:

   0: mul r0.xyzw, v0.yyyy, cb0[1].xyzw
   1: mad r0.xyzw, cb0[0].xyzw, v0.xxxx, r0.xyzw
   2: mad r0.xyzw, cb0[2].xyzw, v0.zzzz, r0.xyzw
   3: add r0.xyzw, r0.xyzw, cb0[3].xyzw
   4: mul r1.xyzw, r0.yyyy, cb1[1].xyzw
   5: mad r1.xyzw, cb1[0].xyzw, r0.xxxx, r1.xyzw
   6: mad r1.xyzw, cb1[2].xyzw, r0.zzzz, r1.xyzw
   7: mad o0.xyzw, cb1[3].xyzw, r0.wwww, r1.xyzw

(4)当前”Unlit.hlsl”库文件的完整代码

完整代码:

/*
自定义RP的Unlit库文件(.hlsl)
 */

//防止重复包含库文件
#ifndef MYRP_UNLIT_INCLUDED
#define MYRP_UNLIT_INCLUDED
//引入CoreRPLibrary V4.6.0
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"

CBUFFER_START(UnityPerFrame)
float4x4 unity_ObjectToWorld;//M矩阵(模型空间到世界空间的转换矩阵)
CBUFFER_END

CBUFFER_START(UnityPerDraw)
float4x4 unity_MatrixVP;//VP矩阵
CBUFFER_END

struct VertexInput{
	float4 pos : POSITION;
};

struct VertexOutput{
	float4 clipPos : SV_POSITION;
};

VertexOutput UnlitPassVertex (VertexInput input) {
	VertexOutput output;
	//float4 worldPos = mul(unity_ObjectToWorld , input.pos);
	//上式的优化:
	float4 worldPos = mul(unity_ObjectToWorld , float4(input.pos.xyz , 1.0));
	output.clipPos = mul(unity_MatrixVP , worldPos);
	return output;
}

float4 UnlitPassFragment (VertexOutput input) : SV_TARGET {
	return 1;
}

//MYRP_UNLIT_INCLUDED
#endif