Unity的Shader学习笔记(24)[21/01/30_周六][76-78]

写了几天技术方案文档....

----------------------------

目录

课时76:FragmentShader-纹理法线和凹凸贴图4

课时77:FragmentShader-Cube纹理采样

课时78:FragmentShader-实现高效的Reflection shader


课时76:FragmentShader-纹理法线和凹凸贴图4

纹理空间的坐标系,切空间坐标系。

灯光转入该坐标系,得到正确的光照计算。

这节课相当于复习了一下以前的光照算法,在那基础上加上法线贴图。

Shader "Custom/MyDumpedDiffuse"
{
    Properties{
        _BumpTex("NormalMap",2D)=""{}
    }
    SubShader
    {
        tags{"queue"="Geometry"}
        pass
        {
            tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "unitycg.cginc"
            #include "lighting.cginc"
            struct v2f {
                float4 pos:POSITION;
                float2 uv:TEXCOORD0;
                float3 wpos:TEXCOORD1;
                float3 lightDir:TEXCOORD2;
            };
            v2f vert(appdata_tan v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.wpos = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.uv = v.texcoord.xy;//uv偏移缩放这里先不考虑
                //float3 binormal = cross(v.tangent.xyz, v.normal);//T cross N => B
                //float3x3 rotation = float3x3(v.tangent.xyz, binormal, v.normal);//光向量旋转矩阵,切空间
                TANGENT_SPACE_ROTATION;
                o.lightDir = mul(rotation, _WorldSpaceLightPos0.xyz);//从WorldSpace转到切空间?
                return o;
            }
            sampler2D _BumpTex;
            fixed4 frag(v2f IN) :COLOR
            {
                float3 L = normalize(IN.lightDir);//为什么要在这里normalize?
                half4  nTex=tex2D(_BumpTex, IN.uv);//用uv到法线贴图采样
                float3 N = UnpackNormal(nTex);//获取正确的法向量
                N = normalize(N);
                //UnpackNormal()是对法线纹理的采样结果的一个反映射操作,
                //其对应的法线纹理需要设置为Normal map的格式。
                float ndotl = saturate(dot(N, L));//以前的光照角度/强度?
                fixed4 col = _LightColor0 * ndotl;//光照强度?
                col.rgb += Shade4PointLights(unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
                    unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
                    unity_4LightAtten0, IN.wpos, N);//点光源采样
                return col;//这个反而正常
                //return col + UNITY_LIGHTMODEL_AMBIENT;//加上环境光,会过白
            }
            ENDCG
        }
    }
}

结果和教程有点差异:1.加上UNITY_LIGHTMODEL_AMBIENT的话,会偏白

不加才算正常。

2.Shade4PointLights,就算没有平行光,就算把点光源设置为Important,也是有光照数据采集到的。

3.Shade4PointLights采集到的点光源有问题,不是圆形的

再加个ForwardAdd的pass

pass
        {
           tags{"LightMode" = "ForwardAdd"}
           CGPROGRAM
           #pragma vertex vert
           #pragma fragment frag
           #include "unitycg.cginc"
           #include "lighting.cginc"
           struct v2f {
               float4 pos:POSITION;
               float2 uv:TEXCOORD0;
               float3 wpos:TEXCOORD1;
               float3 lightDir:TEXCOORD2;
           };
           v2f vert(appdata_tan v)
           {
               v2f o;
               o.pos = UnityObjectToClipPos(v.vertex);
               o.wpos = mul(unity_ObjectToWorld, v.vertex).xyz;
               o.uv = v.texcoord.xy;//uv偏移缩放这里先不考虑
               //float3 binormal = cross(v.tangent.xyz, v.normal);//T cross N => B
               //float3x3 rotation = float3x3(v.tangent.xyz, binormal, v.normal);//光向量旋转矩阵,切空间
               TANGENT_SPACE_ROTATION;
               o.lightDir = mul(rotation, _WorldSpaceLightPos0.xyz);//从WorldSpace转到切空间?
               //_WorldSpaceLightPos0点光源
               return o;
           }
           sampler2D _BumpTex;
           fixed4 frag(v2f IN) :COLOR
           {
               float3 L = normalize(IN.lightDir);//为什么要在这里normalize?
               half4  nTex = tex2D(_BumpTex, IN.uv);//用uv到法线贴图采样
               float3 N = UnpackNormal(nTex);//获取正确的法向量
               N = normalize(N);
               //UnpackNormal()是对法线纹理的采样结果的一个反映射操作,
               //其对应的法线纹理需要设置为Normal map的格式。
               float ndotl = saturate(dot(N, L));//以前的光照角度/强度?
               float atten = 1;//点光源衰减
               if (_WorldSpaceLightPos0.w != 0)//点光源
               {
                   //atten = 1.0 / length(IN.lightDir);//不明白为什么是这个
                   atten = 1.0/ length(IN.wpos- _WorldSpaceLightPos0.xyz);//改成了这个,正常的。
                   atten*= 0.3;//一个系数
               }
               //return fixed4(atten, atten, atten, atten);
               fixed4 col = _LightColor0 * ndotl * atten;//光照强度?
               return col;//这个反而正常
               //return col + UNITY_LIGHTMODEL_AMBIENT;//加上环境光,会过白
           }
           ENDCG
        }

这里的光源衰减洗漱如果用教程的 1.0/length(IN.lightDir);则结果是都是黑色的

我用基于世界坐标的距离来计算,得到了根据距离衰减的效果。

把两个pass 混合,加个blend one one。

大体上有个效果了。

这节课的核心是

               half4  nTex = tex2D(_BumpTex, IN.uv);//用uv到法线贴图采样
               float3 N = UnpackNormal(nTex);//获取正确的法向量
               N = normalize(N);

从法线贴图获取法向量,而不是以前的获取顶点的法向量。

课时77:FragmentShader-Cube纹理采样

立方体纹理采样,6个面。

环境映射,依靠立方体纹理采样。

反射周围环境的效果。

基于立方体的三维的反射向量,和立方体相交的点。

眼睛看到的模型的点的颜色,是该点的反射向量和包围的立方体的相交的点的颜色。

UnityWorldSpaceViewDir

WorldSpaceViewDir

ObjSpaceViewDir

Shader "Custom/Cubemap"
{
    Properties{
        _Cube("Cubemap",cube)=""{}
    }
    SubShader
    {
        pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "unitycg.cginc"
            samplerCUBE _Cube;
            struct v2f {
                float4 pos:POSITION;
                float3 R:TEXCOORD0;//反射向量
            };
            v2f vert(appdata_tan v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                float3 V = -WorldSpaceViewDir(v.vertex);//世界空间
                float3 N = mul(v.normal, (float3x3)unity_WorldToObject);
                N = normalize(N);
                o.R = reflect(V, N);//反射向量
                return o;
            }
            fixed4 frag(v2f IN) :COLOR
            {
                fixed4 color = texCUBE(_Cube,IN.R);
                return color;
            }
            ENDCG
        }
    }
}

找一个Cubemap

Camera.RenderToCubemap

动态反射贴图

https://docs.unity3d.com/cn/2018.4/ScriptReference/Camera.RenderToCubemap.html

1.RenderToCubemap

2.反射探头Reflection Probe

课时78:FragmentShader-实现高效的Reflection shader

Surface Shader input structure
The input structure Input generally has any texture coordinates needed by the shader. Texture coordinates must be named "uv" followed by texture name (or start it with "uv2" to use second texture coordinate set).

Additional values that can be put into Input structure:

float3 viewDir - will contain view direction, for computing Parallax effects, rim lighting etc.
float4 with COLOR semantic - will contain interpolated per-vertex color.
float4 screenPos - will contain screen space position for reflection effects. Used by WetStreet shader in Dark Unity for example.
float3 worldPos - will contain world space position.
float3 worldRefl - will contain world reflection vector if surface shader does not write to o.Normal. See Reflect-Diffuse shader for example.
float3 worldNormal - will contain world normal vector if surface shader does not write to o.Normal.
float3 worldRefl; INTERNAL_DATA - will contain world reflection vector if surface shader writes to o.Normal. To get the reflection vector based on per-pixel normal map, use WorldReflectionVector (IN, o.Normal). See Reflect-Bumped shader for example.
float3 worldNormal; INTERNAL_DATA - will contain world normal vector if surface shader writes to o.Normal. To get the normal vector based on per-pixel normal map, use WorldNormalVector (IN, o.Normal).

worldRefl,不用计算,这个变量就保存了视角的反射向量,拿来用就行。

在前面的车子变色的shader的技术上修改

Shader "Custom/CartPaint_surface2"
{
    Properties
    {
        //_MainColor("MainColor",color) = (1,1,1,1)
        _SecondColor("SecondColor",color) = (1,1,1,1)
        _CenterY("CenterY",range(-3,3)) = 0
        [Enum(X,1,Y,2,Z,3)] _Dir("Dir", Int) = 1
        _R("R",range(0,1)) = 0.1
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _Intensity("Intensity",range(0,5))=1
        _Cube("Cubemap",cube)=""{}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        //LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows vertex:vert
        //#pragma surface surf Standard vertex:vert

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        //fixed4 _MainColor;
        fixed4 _SecondColor;
        float _CenterY;
        float _R;
        float _Intensity;
        int _Dir;

        sampler2D _MainTex;

        samplerCUBE _Cube;

        struct Input
        {
            //float2 uv_MainTex;
            float3 R;
            float y;

        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

    void vert (inout appdata_full v, out Input o) {
        //o.uv_MainTex=v.texcoord.xy;
        o.y=v.vertex.x;
        float3 p = v.vertex;
        //float3 p = o.pos;
        if (_Dir == 1) {
            o.y = p.x;
        }
        if (_Dir == 2) {
            o.y = p.y;
        }
        if (_Dir == 3) {
            o.y = p.z;
        }
        float3 V = -WorldSpaceViewDir(v.vertex);//世界空间
        float3 N = mul(v.normal, (float3x3)unity_WorldToObject);
        N = normalize(N);
        o.R = reflect(V, N);//反射向量
        //return o;
      }
        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            //fixed4 c = tex2D (_MainTex, IN.uv_MainTex) ;
            fixed4 c = texCUBE(_Cube, IN.R);
            //o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
            float d = IN.y - _CenterY;//到分界线的距离,(-0.5,0.5)
            float s = abs(d);//距离的绝对值
            float u = d / s;//1:在上方,-1:在下方
            float f = s / _R;//距离相对于过渡区域的比例,在过渡区域内(0,1),在过渡区域外(1,...)
            f = saturate(f);//限制在(0,1)范围,大于1的也是1,在过渡区域外则是 两种颜色之一,不融合。
            float g = u * f;//给系数一个正负
            //float l = g;
            float l = g / 2 + 0.5;//从-1到1变成0,1
            //在分界线上时,f=0,g=0,l=0.5,融合。
            //在红色那边是,f=1,g=1,l=1;
            //黄色那边,f=-1,g=-1,l=0;
            o.Albedo= lerp(_SecondColor, c, l)* _Intensity;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

加个点光源

教程效果:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值