目录
[TOC]
一、自定义Unlit Shader
1.创建Unlit Shader
构建合适的文件夹结构,用于存放Shader以及其他文件。
在”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”。
如果遇到持续loading不显示包文件的情形,可以先关闭当前项目,然后离线重新打开当前项目,并打开PackageManager,此时会显示所有包文件,然后再开启网络进行导入安装。
安装完成后,”Project”窗口内的”Packages”文件夹下回多出”Core RP Library”文件夹。
安装成功后,可以正确使用宏和常量缓冲区了:
//引入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