《Unity Shader入门精要》第五章笔记 | 开始shader练习

一个简单的顶点/片元着色器

代码
Shader "Unity Shaders Book/Chapter 5/Simple Shader" {
    Properties {
        // 声明一个Color类型的属性
        _Color ("Color Tint", Color) = (1.0,1.0,1.0,1.0)
    }
    SubShader {
        Pass {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            // 在Cg代码中,我们需要定义一个与属性名称和类型都匹配的变量
            fixed4 _Color;

            // 使用一个结构体来定义顶点着色器的输入
            struct a2v {
                // POSITION语义告诉Unity,用模型空间的顶点坐标填充vertex变量
                float4 vertex : POSITION;
                // NORMAL语义告诉Unity,用模型空间的法线方向填充normal变量
                float3 normal : NORMAL;
                // TEXCOORD0语义告诉Unity,用模型的第一套纹理坐标填充texcoord变量
                float4 texcoord : TEXCOORD0;
            };

            // 使用一个结构体来定义顶点着色器的输出
            struct v2f {
                // SV_POSITION语义告诉Unity,pos里包含了顶点在裁剪空间中的位置信息
                float4 pos : SV_POSITION;
                // COLOR0语义可以用于存储颜色信息
                fixed3 color : COLOR0;
            };

            v2f vert(a2v v) : SV_POSITION {
                v2f o;
                // 使用v.vertex来访问模型空间的顶点坐标
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target {
                fixed3 c = i.color;
                // 使用_Color属性来控制输出颜色
                c *= _Color.rgb;
                return fixed4(c, 1.0);
            }

            ENDCG
        }
    }
}

  • 模型数据从哪里来: a2v结构体定义了顶点着色器的输入
  • 顶点着色器和片元着色器之间如何通信: v2f结构体定义了顶点着色器的输入和片元着色器的输入
  • 如何使用属性: Properties 语义块中,并在其中声明了一个属性_Color。并在Cg代码中定一个变量。
  • 顶点着色器是逐顶点调用的,而片元着色器是逐片元调用的。片元着色器中的输入实际上是把顶点着色器的输出进行插值后得到的结果。

ShaderLab中属性的类型和Cg中变量的类型之间的匹配关系 如下:

……

阅读全文

MAC平台几何着色器不生效

问题

MAC平台几何着色器不生效

解决步骤

  1. unity shaderlab 怎么设置以至于支持几何着色器
  2. 找原因,设置 编译目标级别,#pragma target 4.0, 不管用
  3. 看到一句话,Unity 在 Metal 图形上支持曲面细分着色器,但 Metal 不支持几何着色器
  4. 找到mac和ios平台使用的是Metal标准的图形api
  5. 遂查询是否有其他的图形 API, 发现 mac和ios还支持 OpenGL
  6. 在Unity中编写的Shader最终会根据不同的平台来编绎成不同的着色器语言,官方的建议是用Cg/HLSL来编写,当然也可以使用GLSL,主要是因为Cg/HLSL有更好的跨平台性,更倾向于使用Cg/HLSL来编写Shader程序。
  7. Shader编程语言
  • 基于OpenGL的OpenGL Shading Language,简称GLSL。
  • 基于DirectX的High Level Shading Language,简称HLSL。
  • 还有NVIDIA公司的C for Graphic,简称Cg语言。
  1. URP 通用渲染管线使用HLSL
  2. unity是否可以指定 graphics API
  3. 打开 Player 设置(菜单:Edit > Project Settings,然后选择 Player 类别)。 导航到 Other Settings 并确保选中 Auto Graphics API

参考链接

……

阅读全文

MAC平台几何着色器不生效

问题

MAC平台几何着色器不生效

解决步骤

  1. unity shaderlab 怎么设置以至于支持几何着色器
  2. 找原因,设置 编译目标级别,#pragma target 4.0, 不管用
  3. 看到一句话,Unity 在 Metal 图形上支持曲面细分着色器,但 Metal 不支持几何着色器
  4. 找到mac和ios平台使用的是Metal标准的图形api
  5. 遂查询是否有其他的图形 API, 发现 mac和ios还支持 OpenGL
  6. 在Unity中编写的Shader最终会根据不同的平台来编绎成不同的着色器语言,官方的建议是用Cg/HLSL来编写,当然也可以使用GLSL,主要是因为Cg/HLSL有更好的跨平台性,更倾向于使用Cg/HLSL来编写Shader程序。
  7. Shader编程语言
  • 基于OpenGL的OpenGL Shading Language,简称GLSL。
  • 基于DirectX的High Level Shading Language,简称HLSL。
  • 还有NVIDIA公司的C for Graphic,简称Cg语言。
  1. URP 通用渲染管线使用HLSL
  2. unity是否可以指定 graphics API
  3. 打开 Player 设置(菜单:Edit > Project Settings,然后选择 Player 类别)。 导航到 Other Settings 并确保选中 Auto Graphics API

参考链接

……

阅读全文

ShaderLab常用函数

数学函数

cg/hlsl函数功能描述
dot(A,B)点积, 点积结果为标量,主要用于求向量的夹角或b向量在a向量上的投影
cross(A,B)叉积, 叉积结果为向量,结果与这两个向量组成的平面垂直。主要用于3D图形学
mul(M, N)矩阵M和矩阵N的积
mul(M, v)矩阵M和列向量v的积
mul(v, M)行向量v和矩阵M的积
abs(x)
saturate(x)把x限制到[0,1]之间
clamp(x,a,b)把x限制到[a,b]之间
TRANSFORM_TEXo.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
等价于: o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
_MainTex_ST.xy中是tiling _MainTex_ST.zw中是offset
sqrt(x)求x的平方根,,x必须大于0
rsqrt(x)x的平方根的倒数,x必须大于0
all(x)如果输入参数均不为0,则返回ture; 否则返回flase。&&运算
any(x)输入参数只要有其中一个不为0,则返回true。
lerp(a, b, w)计算(1-w)a + b*w 。即在下限a和上限b之间进行插值,w表示权值。注意,如果a和b是向量,则权值w必须是标量或者等长的向量。
lerp(a, b, w)官方解释: float lerp(float a, float b, float w) { return a + w*(b-a);}
MyExplain: float lerp(float a, float b, float w) { return a(1-w) + b * w; }

一个混合公式,他们俗称插值, 只不过w相当于以第二个参数为源,第一个参数为目标。 直白点,就是把b向a上混合
ceil(x)对x向上取整。
floor(x)对x向下取整。
round(x)返回四舍五入值。
step(a, x)如果x< a,返回0;否则,返回1
sign(x)如果x大于0,返回1;如果小于0,返回-1;否则返回0;
exp(x)计算e^x,e=2.71828
exp2(x)计算2^x
fmod(x,y)返回x/y的余数。如果y为0,结果不可预料。
modf(x, out ip)把x分解成整数和分数两部分,每部分都和x有着相同的符号,整数部分被保存在ip中,分数部分由函数返回
max(a, b)比较两个标量或等长向量元素,返回最大值。
min(a,b)比较两个标量或等长向量元素,返回最小值。
determinant(m)计算矩阵的行列式因子。
transpose(M)矩阵M的转置矩阵
degrees(x)函数将弧度值转换为角度值
radians(x)函数将角度值转换为弧度值
log(x)计算ln(x)的值,x必须大于0
log2(x)计算log2^x的值,x必须大于0
log10(x)计算log10^x的值,x必须大于0
frac(x)返回标量或矢量的小数
frexp(x, out i)将浮点数x分解为尾数和指数,即, 返回m,并将指数存入i中;如果x为0,则尾数和指数都返回0
isfinite(x)判断标量或者向量中的每个数据是否是有限数,如果是返回true;否则返回false;
isinf(x)判断标量或者向量中的每个数据是否是无限,如果是返回true;否则返回false;
isnan(x)判断标量或者向量中的每个数据是否是非数据(not-a-number NaN),如果是返回true;否则返回false;
lit(NdotL, NdotH, m)N表示法向量。L表示入射光向量。H表示半角向量。m表示高光向量。函数计算环境光,散射光,镜面光的贡献,返回四元向量: X表示环境光的贡献,总是1;Y表示散射光的贡献,如果N.L<0,则为0,否则为N.L; Z表示镜面光的贡献,如果N.L<0或者N.H<0,则为0;否则为(N.H)^m;W始终为1
noise(x)根据它的参数类型,这个函数可以是一元、二元或三元噪音函数。返回的值在0和1之间,并且通常与给定的输入值一样
ldexp(x, n)计算x*(2^n)的值
smoothstep(min, max, x)x位于min和max之间,若x=min,返回0;若x=max,返回1;若x在两者之间,按下列公式返回数据:-2*((x-min)/(max-min))^3+3*((x-min)/(max-min))^2
sin(x)返回弧度x的正弦值,返回值范围为[-1,1]
cos(x)返回弧度x的余弦值。返回值范围为[-1,1]
tan(x)计算x正切值
asin(x)反正弦函数,输入参数取值区间为[-1,1],返回角度值范围为[-π/2,π/2]
acos(x)反余切函数,输入参数范围为[-1,1], 返回[0,π]区间的角度值
atan(x)反正切函数
sinh(x)计算x的双曲正弦
cosh(x)计算x的双曲余弦值。
tanh(x)计算x的双曲线切线
sincos(float x, out s, out c)同时计算x的sin值和cos值,其中s=sin(x),c=cos(x)。该函数比分别运算要快很多!

几何函数

cg/hlsl函数功能描述
normalize(v)返回v向量的单位向量
reflect(I, N)根据入射光纤方向I和表面法向量N计算反射向量,仅对三元向量有效
length(v)返回v向量的模,即sqrt(dot(v,v))
distance(pt1, pt2)两点之间的欧几里德距离
faceforward(N,I,Ng)如果dot(I,Ng)<0,返回N;否则返回-N。
refract(I,N,eta)根据入射光线方向I,表面法向量N和折射相对系数eta,计算折射向量。如果对给定的eta,I和N之间的角度太大,返回(0,0,0)。只对三元向量有效

纹理映射函数

cg/hlsl函数功能描述
tex1D(sampler1D tex, float s)一维纹理查询
tex1D(sampler1D tex, float s, float dsdx, float dsdy)使用导数值(derivatives)查询一维纹理
Tex1D(sampler1D tex, float2 sz)一维纹理查询,并进行深度值比较
Tex1D(sampler1D tex, float2 sz, float dsdx,float dsdy)使用导数值查询一维纹理, 并进行深度值比较
Tex1Dproj(sampler1D tex, float2 sq)一维投影纹理查询
Tex1Dproj(sampler1D tex, float3 szq)一维投影纹理查询,并比较深度值
Tex2D(sampler2D tex, float2 s)二维纹理查询
Tex2D(sampler2D tex, float2 s, float2 dsdx, float2 dsdy)使用导数值查询二维纹理
Tex2D(sampler2D tex, float3 sz)二维纹理查询,并进行深度值比较
Tex2D(sampler2D tex, float3 sz, float2 dsdx,float2 dsdy)使用导数值查询二维纹理,并进行深度值比较
Tex2Dproj(sampler2D tex, float3 sq)二维投影纹理查询
Tex2Dproj(sampler2D tex, float4 szq)二维投影纹理查询,并进行深度值比较
texRECT(samplerRECT tex, float2 s)二维非投影矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy)二维非投影使用导数的矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz)二维非投影深度比较矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy)二维非投影深度比较并使用导数的矩形纹理查询(OpenGL独有)
texRECT proj(samplerRECT tex, float3 sq)二维投影矩形纹理查询(OpenGL独有)
texRECT proj(samplerRECT tex, float3 szq)二维投影矩形纹理深度比较查询(OpenGL独有)
Tex3D(sampler3D tex, float s)三维纹理查询
Tex3D(sampler3D tex, float3 s, float3 dsdx, float3 dsdy)结合导数值查询三维纹理
Tex3Dproj(sampler3D tex, float4 szq)查询三维投影纹理,并进行深度值比较
texCUBE(samplerCUBE tex, float3 s)查询立方体纹理
texCUBE (samplerCUBE tex, float3 s, float3 dsdx, float3 dsdy)结合导数值查询立方体纹理
texCUBEproj (samplerCUBE tex, float4 sq)查询投影立方体纹理
……

阅读全文

ShaderLab常用函数

数学函数

cg/hlsl函数功能描述
dot(A,B)点积, 点积结果为标量,主要用于求向量的夹角或b向量在a向量上的投影
cross(A,B)叉积, 叉积结果为向量,结果与这两个向量组成的平面垂直。主要用于3D图形学
mul(M, N)矩阵M和矩阵N的积
mul(M, v)矩阵M和列向量v的积
mul(v, M)行向量v和矩阵M的积
abs(x)
saturate(x)把x限制到[0,1]之间
clamp(x,a,b)把x限制到[a,b]之间
TRANSFORM_TEXo.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
等价于: o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
_MainTex_ST.xy中是tiling _MainTex_ST.zw中是offset
sqrt(x)求x的平方根,,x必须大于0
rsqrt(x)x的平方根的倒数,x必须大于0
all(x)如果输入参数均不为0,则返回ture; 否则返回flase。&&运算
any(x)输入参数只要有其中一个不为0,则返回true。
lerp(a, b, w)计算(1-w)a + b*w 。即在下限a和上限b之间进行插值,w表示权值。注意,如果a和b是向量,则权值w必须是标量或者等长的向量。
lerp(a, b, w)官方解释: float lerp(float a, float b, float w) { return a + w*(b-a);}
MyExplain: float lerp(float a, float b, float w) { return a(1-w) + b * w; }

一个混合公式,他们俗称插值, 只不过w相当于以第二个参数为源,第一个参数为目标。 直白点,就是把b向a上混合
ceil(x)对x向上取整。
floor(x)对x向下取整。
round(x)返回四舍五入值。
step(a, x)如果x< a,返回0;否则,返回1
sign(x)如果x大于0,返回1;如果小于0,返回-1;否则返回0;
exp(x)计算e^x,e=2.71828
exp2(x)计算2^x
fmod(x,y)返回x/y的余数。如果y为0,结果不可预料。
modf(x, out ip)把x分解成整数和分数两部分,每部分都和x有着相同的符号,整数部分被保存在ip中,分数部分由函数返回
max(a, b)比较两个标量或等长向量元素,返回最大值。
min(a,b)比较两个标量或等长向量元素,返回最小值。
determinant(m)计算矩阵的行列式因子。
transpose(M)矩阵M的转置矩阵
degrees(x)函数将弧度值转换为角度值
radians(x)函数将角度值转换为弧度值
log(x)计算ln(x)的值,x必须大于0
log2(x)计算log2^x的值,x必须大于0
log10(x)计算log10^x的值,x必须大于0
frac(x)返回标量或矢量的小数
frexp(x, out i)将浮点数x分解为尾数和指数,即, 返回m,并将指数存入i中;如果x为0,则尾数和指数都返回0
isfinite(x)判断标量或者向量中的每个数据是否是有限数,如果是返回true;否则返回false;
isinf(x)判断标量或者向量中的每个数据是否是无限,如果是返回true;否则返回false;
isnan(x)判断标量或者向量中的每个数据是否是非数据(not-a-number NaN),如果是返回true;否则返回false;
lit(NdotL, NdotH, m)N表示法向量。L表示入射光向量。H表示半角向量。m表示高光向量。函数计算环境光,散射光,镜面光的贡献,返回四元向量: X表示环境光的贡献,总是1;Y表示散射光的贡献,如果N.L<0,则为0,否则为N.L; Z表示镜面光的贡献,如果N.L<0或者N.H<0,则为0;否则为(N.H)^m;W始终为1
noise(x)根据它的参数类型,这个函数可以是一元、二元或三元噪音函数。返回的值在0和1之间,并且通常与给定的输入值一样
ldexp(x, n)计算x*(2^n)的值
smoothstep(min, max, x)x位于min和max之间,若x=min,返回0;若x=max,返回1;若x在两者之间,按下列公式返回数据:-2*((x-min)/(max-min))^3+3*((x-min)/(max-min))^2
sin(x)返回弧度x的正弦值,返回值范围为[-1,1]
cos(x)返回弧度x的余弦值。返回值范围为[-1,1]
tan(x)计算x正切值
asin(x)反正弦函数,输入参数取值区间为[-1,1],返回角度值范围为[-π/2,π/2]
acos(x)反余切函数,输入参数范围为[-1,1], 返回[0,π]区间的角度值
atan(x)反正切函数
sinh(x)计算x的双曲正弦
cosh(x)计算x的双曲余弦值。
tanh(x)计算x的双曲线切线
sincos(float x, out s, out c)同时计算x的sin值和cos值,其中s=sin(x),c=cos(x)。该函数比分别运算要快很多!

几何函数

cg/hlsl函数功能描述
normalize(v)返回v向量的单位向量
reflect(I, N)根据入射光纤方向I和表面法向量N计算反射向量,仅对三元向量有效
length(v)返回v向量的模,即sqrt(dot(v,v))
distance(pt1, pt2)两点之间的欧几里德距离
faceforward(N,I,Ng)如果dot(I,Ng)<0,返回N;否则返回-N。
refract(I,N,eta)根据入射光线方向I,表面法向量N和折射相对系数eta,计算折射向量。如果对给定的eta,I和N之间的角度太大,返回(0,0,0)。只对三元向量有效

纹理映射函数

cg/hlsl函数功能描述
tex1D(sampler1D tex, float s)一维纹理查询
tex1D(sampler1D tex, float s, float dsdx, float dsdy)使用导数值(derivatives)查询一维纹理
Tex1D(sampler1D tex, float2 sz)一维纹理查询,并进行深度值比较
Tex1D(sampler1D tex, float2 sz, float dsdx,float dsdy)使用导数值查询一维纹理, 并进行深度值比较
Tex1Dproj(sampler1D tex, float2 sq)一维投影纹理查询
Tex1Dproj(sampler1D tex, float3 szq)一维投影纹理查询,并比较深度值
Tex2D(sampler2D tex, float2 s)二维纹理查询
Tex2D(sampler2D tex, float2 s, float2 dsdx, float2 dsdy)使用导数值查询二维纹理
Tex2D(sampler2D tex, float3 sz)二维纹理查询,并进行深度值比较
Tex2D(sampler2D tex, float3 sz, float2 dsdx,float2 dsdy)使用导数值查询二维纹理,并进行深度值比较
Tex2Dproj(sampler2D tex, float3 sq)二维投影纹理查询
Tex2Dproj(sampler2D tex, float4 szq)二维投影纹理查询,并进行深度值比较
texRECT(samplerRECT tex, float2 s)二维非投影矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy)二维非投影使用导数的矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz)二维非投影深度比较矩形纹理查询(OpenGL独有)
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy)二维非投影深度比较并使用导数的矩形纹理查询(OpenGL独有)
texRECT proj(samplerRECT tex, float3 sq)二维投影矩形纹理查询(OpenGL独有)
texRECT proj(samplerRECT tex, float3 szq)二维投影矩形纹理深度比较查询(OpenGL独有)
Tex3D(sampler3D tex, float s)三维纹理查询
Tex3D(sampler3D tex, float3 s, float3 dsdx, float3 dsdy)结合导数值查询三维纹理
Tex3Dproj(sampler3D tex, float4 szq)查询三维投影纹理,并进行深度值比较
texCUBE(samplerCUBE tex, float3 s)查询立方体纹理
texCUBE (samplerCUBE tex, float3 s, float3 dsdx, float3 dsdy)结合导数值查询立方体纹理
texCUBEproj (samplerCUBE tex, float4 sq)查询投影立方体纹理
……

阅读全文

UnityCG.cginc中常用函数

摄像机方向

  1. WorldSpaceViewDir 输入一个模型空间中的顶点坐标 -> 输出(世界空间)从这个点到摄像机的观察方向;
WorldSpaceViewDir
// 内部实现也是用UnityWorldSpaceViewDir
// Computes world space view direction, from object space position
// *Legacy* Please use UnityWorldSpaceViewDir instead
inline float3 WorldSpaceViewDir( in float4 localPos )
{
    float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz;
    return UnityWorldSpaceViewDir(worldPos);
}

  1. UnityWorldSpaceViewDir 输入一个模型空间中的顶点坐标 -> 输出(世界空间)从这个点到摄像机的观察方向;
UnityWorldSpaceViewDir
// Computes world space view direction, from object space position
inline float3 UnityWorldSpaceViewDir( in float3 worldPos )
{
    return _WorldSpaceCameraPos.xyz - worldPos;
}

  1. ObjSpaceViewDir 模型空间中的顶点坐标 -> 模型空间从这个点到摄像机的观察方向;
ObjSpaceViewDir
// Computes object space view direction
inline float3 ObjSpaceViewDir( in float4 v )
{
    float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
    return objSpaceCameraPos - v.xyz;
}

光源方向

  1. WorldSpaceLightDir 模型空间中的顶点坐标 -> 世界空间中从这个点到光源的方向
WorldSpaceLightDir
// Computes world space light direction, from object space position
// *Legacy* Please use UnityWorldSpaceLightDir instead
inline float3 WorldSpaceLightDir( in float4 localPos )
{
    float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz;
    return UnityWorldSpaceLightDir(worldPos);
}

  1. UnityWorldSpaceLightDir (ForwardBase Only,not normalized)世界空间中的顶点坐标 -> 世界空间中从这个点到光源的方向
WorldSpaceLightDir
// Computes world space light direction, from world space position
inline float3 UnityWorldSpaceLightDir( in float3 worldPos )
{
    #ifndef USING_LIGHT_MULTI_COMPILE
        return _WorldSpaceLightPos0.xyz - worldPos * _WorldSpaceLightPos0.w;
    #else
        #ifndef USING_DIRECTIONAL_LIGHT
        return _WorldSpaceLightPos0.xyz - worldPos;
        #else
        return _WorldSpaceLightPos0.xyz;
        #endif
    #endif
}

……

阅读全文

UnityCG.cginc中常用函数

摄像机方向

  1. WorldSpaceViewDir 输入一个模型空间中的顶点坐标 -> 输出(世界空间)从这个点到摄像机的观察方向;
WorldSpaceViewDir
// 内部实现也是用UnityWorldSpaceViewDir
// Computes world space view direction, from object space position
// *Legacy* Please use UnityWorldSpaceViewDir instead
inline float3 WorldSpaceViewDir( in float4 localPos )
{
    float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz;
    return UnityWorldSpaceViewDir(worldPos);
}

  1. UnityWorldSpaceViewDir 输入一个模型空间中的顶点坐标 -> 输出(世界空间)从这个点到摄像机的观察方向;
UnityWorldSpaceViewDir
// Computes world space view direction, from object space position
inline float3 UnityWorldSpaceViewDir( in float3 worldPos )
{
    return _WorldSpaceCameraPos.xyz - worldPos;
}

  1. ObjSpaceViewDir 模型空间中的顶点坐标 -> 模型空间从这个点到摄像机的观察方向;
ObjSpaceViewDir
// Computes object space view direction
inline float3 ObjSpaceViewDir( in float4 v )
{
    float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
    return objSpaceCameraPos - v.xyz;
}

光源方向

  1. WorldSpaceLightDir 模型空间中的顶点坐标 -> 世界空间中从这个点到光源的方向
WorldSpaceLightDir
// Computes world space light direction, from object space position
// *Legacy* Please use UnityWorldSpaceLightDir instead
inline float3 WorldSpaceLightDir( in float4 localPos )
{
    float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz;
    return UnityWorldSpaceLightDir(worldPos);
}

  1. UnityWorldSpaceLightDir (ForwardBase Only,not normalized)世界空间中的顶点坐标 -> 世界空间中从这个点到光源的方向
WorldSpaceLightDir
// Computes world space light direction, from world space position
inline float3 UnityWorldSpaceLightDir( in float3 worldPos )
{
    #ifndef USING_LIGHT_MULTI_COMPILE
        return _WorldSpaceLightPos0.xyz - worldPos * _WorldSpaceLightPos0.w;
    #else
        #ifndef USING_DIRECTIONAL_LIGHT
        return _WorldSpaceLightPos0.xyz - worldPos;
        #else
        return _WorldSpaceLightPos0.xyz;
        #endif
    #endif
}

……

阅读全文

《Unity Shader入门精要》第四章笔记 | 学习Shader所需的数学基础

概述

在学习Shader的过程中,我们最常使用的就是矢量和矩阵(即数学的分支之一——线性代数)。

笛卡儿坐标系

我们使用数学绝大部分都是为了计算位置、距离和角度等变量。而这些计算大部分都是在笛卡儿坐标系 (Cartesian Coordinate System) 下进行的。这个名字来源于法国伟大的哲学家、物理学家、心理学家、数学家笛卡儿(René Descartes)。

……

阅读全文

《Unity Shader入门精要》第四章笔记 | 学习Shader所需的数学基础

概述

在学习Shader的过程中,我们最常使用的就是矢量和矩阵(即数学的分支之一——线性代数)。

笛卡儿坐标系

我们使用数学绝大部分都是为了计算位置、距离和角度等变量。而这些计算大部分都是在笛卡儿坐标系 (Cartesian Coordinate System) 下进行的。这个名字来源于法国伟大的哲学家、物理学家、心理学家、数学家笛卡儿(René Descartes)。

……

阅读全文

《Unity Shader入门精要》第三章笔记| UnityShader基础

材质

在Unity中我们需要配合使用材质 (Material) 和Unity Shader才能达到需要的效果。一个最常见的流程是

  • 创建一个材质;活着导入一个材质
  • 创建一个Unity Shader,并把它赋给上一步中创建的材质;
  • 把材质赋给要渲染的对象;
  • 在材质面板中调整Unity Shader的属性,以得到满意的效果。

Unity的材质

Unity中的材质需要结合一个GameObject的Mesh或者Particle Systems组件来工作。它决定了我们的游戏对象看起来是什么样子的(这当然也需要Unity Shader的配合)。

……

阅读全文