zoukankan      html  css  js  c++  java
  • unity shader 入门

    1.一个简单的顶点/片元着色器基本结构

    Shader "Unity Shaders Book/Chapter 5/Simple Shader" {
        }
        SubShader {
            Pass {
                CGPROGRAM
                //告诉unity哪个函数包含了顶点着色器的代码
                #pragma vertex vert
                //告诉unity哪个函数包含了片元着色器的代码
                #pragma fragment frag
                //POSITION:告诉unity把模型的顶点坐标填充到v中;SV_POSITION:告诉unity顶点着色器输出的裁剪空间中的顶点坐标
               float4 vert(float4 v:POSITION) : SV_POSITION{
                    return mul(UNITY_MATRIX_MVP,V);
                }
                //SV_Target:把用户的输出颜色存储到一个渲染目标中
                fixed4 frag() : SV_Target {
                    return fixed4(1.0,1.0,1.0,1.0);
                }
                ENDCG
            }
        }
    }

    2.为顶点着色器定义一个新的传入参数,使用结构体

    Shader "Unity Shaders Book/Chapter 5/Simple Shader" {
        }
        SubShader {
            Pass {
                CGPROGRAM
                //告诉unity哪个函数包含了顶点着色器的代码
                #pragma vertex vert
                //告诉unity哪个函数包含了片元着色器的代码
                #pragma fragment frag
            //a:应用;v:顶点着色器;a2v:把数据从应用阶段传递到顶点着色器
                struct a2v {
                    //    POSITION:告诉unity使用模型空间的顶点坐标填充vertex变量
                    float4 vertex : POSITION;
                    //    NORMAL:告诉unity使用模型空间的法线方向填充normal
                    float3 normal : NORMAL;
                    //    TEXCOORD:告诉unity使用模型的第一套纹理坐标填充texcoord变量
                    float texcoord : TEXCOORD;
                }
    
                //POSITION:告诉unity把模型的顶点坐标填充到v中;SV_POSITION:告诉unity顶点着色器输出的裁剪空间中的顶点坐标
               float4 vert(a2v v) : SV_POSITION{
                    return mul(UNITY_MATRIX_MVP,V.tertex);
                }
                //SV_Target:把用户的输出颜色存储到一个渲染目标中
                fixed4 frag() : SV_Target {
                    return fixed4(1.0,1.0,1.0,1.0);
                }
                ENDCG
            }
        }
    }

    POSITION,NORMAL,TEXCOORD中的数据由使用该shader的材质的MeshRender组件提供。在每帧调用Draw Call时,Mesh Render组建会把它负责渲染的模型书记发送给shader。

    3。为片元着色器定义一个新的传入参数,使用结构体

    Shader "Unity Shaders Book/Chapter 5/Simple Shader" {
        }
        SubShader {
            Pass {
                CGPROGRAM
                //告诉unity哪个函数包含了顶点着色器的代码
                #pragma vertex vert
                //告诉unity哪个函数包含了片元着色器的代码
                #pragma fragment frag
    
                struct a2v {
                    //    POSITION:告诉unity使用模型空间的顶点坐标填充vertex变量
                    float4 vertex : POSITION;
                    //    NORMAL:告诉unity使用模型空间的发现方向填充normal
                    float3 normal : NORMAL;
                    //    TEXCOORD:告诉unity使用模型的第一套纹理坐标填充texcoord变量
                    float texcoord : TEXCOORD;
                }
                struct v2f {
                    //    SV_POSITION:告诉unity ,pos里包含了顶点在裁剪空间中的位置信息
                    float4 pos : SV_POSITION;
                    //    COLOR:存储颜色信息
                    fixed3 color : COLOR0;
                }
                
                //POSITION:告诉unity把模型的顶点坐标填充到v中;SV_POSITION:告诉unity顶点着色器输出的裁剪空间中的顶点坐标
               v2f vert(a2v v) : SV_POSITION{
                    //声明输出结果
                    v2f o;
                    o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                    //v.normal包含了顶点的法线方向,其分量范围在[-1.0,1.0]
                    //下麦呢的代码把分量范围映射到了[0.0,1.0]
                    //存储到o.color中传递给片元着色器
                    o.color = v.normal*0.5 + fixed3(0.5, 0.5, 0.5);
                    return o;
                }
                //SV_Target:把用户的输出颜色存储到一个渲染目标中
                fixed4 frag(v2f i) : SV_Target {
                    //将插值后的i.color显示到屏幕上
                    return fixed4(i.color,1.0);
                }
                ENDCG
            }
        }
    }

    v2f用于顶点着色器和片元着色器之间传递信息。

    4。添加属性,方便在面板上直接控制模型在屏幕上显示的颜色

    Shader "Unity Shaders Book/Chapter 5/Simple Shader" {
        Properties{
            //声明一个Color类型的属性
            _Color("Color",Color) = (1.0,1.0,1.0,1.0)
        }
            SubShader{
                Pass {
                    CGPROGRAM
    
                    #pragma vertex vert
                    #pragma fragment frag
    
                    //在CG代码中,需要定义一个与属性名称和类型都匹配的变量
                    fixed4 _Color;
    
                    struct a2v {
                        float4 vertex : POSITION;
                        float3 normal : NORMAL;
                        float texcoord : TEXCOORD;
                    }
                    struct v2f {
                        float4 pos : SV_POSITION;
                        fixed3 color : COLOR0;
                    }
                
                   v2f vert(a2v v) : SV_POSITION{
                        v2f o;
                        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
            }
        }
    }

    SV代表系统数值,对于有特殊含义的变量最好以SV开头的语义进行修饰。

    5.添加内置的包含文件

    6.Unity支持的语义

     

    颜色分量中任何大于1的数值将会被这是为1,而任何小于0的数值都会被设置为0。

    7.shader整洁之道

    (1).数值类型

    (2).避免不必要的计算

    避免在shader'(尤其是片元着色器)中进行大量计算,不然很可能出席拿一下错误:

    (3)慎用分支和循环语句

      尽量把计算向流水线上端移动,例如:把放在片元着色器中的计算放到顶点着色器中,或直接在CPU中进行预计算,再把结果传递给shader。

      当不可避免使用分支语句进行计算时:

    (4)不要除以0

    8.漫反射光照模型

    (1)高光反射:表示物体表面是如何反射光线的。

    (2)漫反射:表示有多少光线会被折射,吸收和散射出表面。

     (3)标准光照模型的4部分:自发光,高光反射,漫反射(兰伯特光照模型),环境光

    注意:在计算法线和光源方向时,应选择同一坐标系

    (4)在片元着色器中计算光照模型-----逐像素光照,又称为Phong着色

        在顶点着色器中计算光照模型-----逐顶点光照,Gouraud Shading

    (5).逐顶点漫反射光照模型

    Shader "MyShader" {
        Properties {
            _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
        }
        SubShader {
            Pass { 
                Tags { "LightMode"="ForwardBase" }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
           #include "Lighting.cginc" fixed4 _Diffuse; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; fixed3 color : COLOR; }; v2f vert(a2v v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP,v.tvertex); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
             //世界空间下的法线
             o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);//方法一
             o.worldNormal = UnityObjectToWorldNormal(v.normal);//方法二

             fixed3 worldNormal
    = normalize(mul(v.normal, (float3x3)unity_WorldToObject)); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); o.color = ambient + diffuse; return o; } fixed4 frag(v2f i) : SV_Target { return fixed4(i.color, 1.0); } ENDCG } } FallBack "Diffuse" }

     (6).逐像素漫反射光照模型

    Shader "MyShader" {
        Properties {
            _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
        }
        SubShader {
            Pass { 
                Tags { "LightMode"="ForwardBase" }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
           #include "Lighting.cginc" fixed4 _Diffuse; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; fixed3 worldNormal : TEXCOORD0; }; v2f vert(a2v v) { v2f o;
              //将顶点坐标从模型空间转换到裁剪空间 o.pos
    = mul(UNITY_MATRIX_MVP,v.tvertex);//方法一
              o.pos = mul(UNITY_MATRIX_MVP,v.tvertex);//方法二 o.worldNormal = mul(v.normal, (float3x3)_World2Object); return o; } fixed4 frag(v2f i) : SV_Target { fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//世界空间下环境光颜色 fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);//世界空间下的光照方向 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));//saturate函数:把参数截取到[0,1]的范围。 fixed3 color = ambient + diffuse; return fixed4(color, 1.0); } ENDCG } } FallBack "Diffuse" }

     半兰伯特光照模型与兰伯特光照模型的区别在于:兰伯特光照模型使用saturate函数把saturate(dot(worldNormal, worldLightDir))截取到[0,1]的范围。半兰伯特使用dot(worldNormal, worldLightDir)*0.5+0.5截取到[-1,1]的范围。

    半兰伯特光照模型(逐像素):

    Shader "Unity Shaders Book/Chapter 6/Half Lambert" {
        Properties {
            _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
        }
        SubShader {
            Pass { 
                Tags { "LightMode"="ForwardBase" }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "Lighting.cginc"
                fixed4 _Diffuse;
                struct a2v {
                    float4 vertex : POSITION;
                    float3 normal : NORMAL;
                };
                struct v2f {
                    float4 pos : SV_POSITION;
                    float3 worldNormal : TEXCOORD0;
                };
                v2f vert(a2v v) {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
                    return o;
                }
                fixed4 frag(v2f i) : SV_Target {
                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                    fixed3 worldNormal = normalize(i.worldNormal);
                    fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                    fixed halfLambert = dot(worldNormal, worldLightDir) * 0.5 + 0.5;
                    fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;
                    fixed3 color = ambient + diffuse;
                    return fixed4(color, 1.0);
                }
                ENDCG
            }
        } 
        FallBack "Diffuse"
    }

    9.高光反射光照模型

    逐顶点:

    Shader "Unity Shaders Book/Chapter 6/Specular Vertex-Level" {
        Properties {
            _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
            _Specular ("Specular", Color) = (1, 1, 1, 1)
            _Gloss ("Gloss", Range(8.0, 256)) = 20
        }
        SubShader {
            Pass { 
                Tags { "LightMode"="ForwardBase" }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "Lighting.cginc"
                fixed4 _Diffuse;
                fixed4 _Specular;
                float _Gloss;
                struct a2v {
                    float4 vertex : POSITION;
                    float3 normal : NORMAL;
                };
                struct v2f {
                    float4 pos : SV_POSITION;
                    fixed3 color : COLOR;
                };
                v2f vert(a2v v) {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                    fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                    fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                    fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
                    // 世界空间下反射光方向
                    fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
                    // 世界空间下视野方向
                    fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);
                    fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);
                    o.color = ambient + diffuse + specular;             
                    return o;
                }
                fixed4 frag(v2f i) : SV_Target {
                    return fixed4(i.color, 1.0);
                }
                ENDCG
            }
        } 
        FallBack "Specular"
    }

    逐像素:

    Shader "Unity Shaders Book/Chapter 6/Specular Pixel-Level" {
        Properties {
            _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
            _Specular ("Specular", Color) = (1, 1, 1, 1)
            _Gloss ("Gloss", Range(8.0, 256)) = 20
        }
        SubShader {
            Pass { 
                Tags { "LightMode"="ForwardBase" }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "Lighting.cginc"
                fixed4 _Diffuse;
                fixed4 _Specular;
                float _Gloss;
                struct a2v {
                    float4 vertex : POSITION;
                    float3 normal : NORMAL;
                };
                struct v2f {
                    float4 pos : SV_POSITION;
                    float3 worldNormal : TEXCOORD0;
                    float3 worldPos : TEXCOORD1;
                };
                v2f vert(a2v v) {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
             // 传统计算光照方向的方法(1) o.worldPos
    = mul(unity_ObjectToWorld, v.vertex).xyz; return o; } fixed4 frag(v2f i) : SV_Target { fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 worldNormal = normalize(i.worldNormal);
              // 使用UnityCG.cginc中的函数计算光照方向的方法(2)
              fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
              
    fixed3 worldLightDir
    = normalize(_WorldSpaceLightPos0.xyz); fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); // 世界空间下反射光方向 fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal)); // 世界空间下视野方向---传统方法(1) fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
             //采用unity内置函数(2)
              fixed3 viewDir=normalize(UnityWorldSpaceViewDir(i.worldPos));
    fixed3 specular
    = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss); return fixed4(ambient + diffuse + specular, 1.0); } ENDCG } } FallBack "Specular" }

     10.Blinn-Phong光照模型

    逐像素:

    // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    
    Shader "Unity Shaders Book/Chapter 6/Blinn-Phong" {
        Properties {
            _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
            _Specular ("Specular", Color) = (1, 1, 1, 1)
            _Gloss ("Gloss", Range(8.0, 256)) = 20
        }
        SubShader {
            Pass { 
                Tags { "LightMode"="ForwardBase" }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "Lighting.cginc"
                fixed4 _Diffuse;
                fixed4 _Specular;
                float _Gloss;
                struct a2v {
                    float4 vertex : POSITION;
                    float3 normal : NORMAL;
                };
                struct v2f {
                    float4 pos : SV_POSITION;
                    float3 worldNormal : TEXCOORD0;
                    float3 worldPos : TEXCOORD1;
                };
                v2f vert(a2v v) {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
                    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                    return o;
                }
                fixed4 frag(v2f i) : SV_Target {
                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                    fixed3 worldNormal = normalize(i.worldNormal);
                    fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                    fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));
                    // Get the view direction in world space
                    fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
                    // Get the half direction in world space
                    fixed3 halfDir = normalize(worldLightDir + viewDir);
                    // Compute specular term
                    fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
                    return fixed4(ambient + diffuse + specular, 1.0);
                }
                ENDCG
            }
        } 
        FallBack "Specular"
    }

    注意:

    1。在实际的渲染中,绝大多数情况选择Blinn-Phong光照模型。

    2。上例中计算光源方向的方法只适用于平行光。

  • 相关阅读:
    C 找到该列最大的前两个数字
    C 寻找和最大的子序列
    C 找出最长的回文子串(不区分大小写)
    C 字符串数组
    C 寻找重复字符并输出他们的位置
    C 寻找0~100的守形数
    C 在外部函数中修改指针变量
    C int转为二进制 再进行与操作
    C 计算阶乘之和
    C 奇偶校验
  • 原文地址:https://www.cnblogs.com/shirln/p/9324146.html
Copyright © 2011-2022 走看看