[UnityShader2]顶点片段着色器实例(三)

原文链接:http://www.cnblogs.com/Esfog/default.html?page=2


1.漫反射

Shader "Esfog/Diffuse" 
{
    Properties 
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }
    SubShader 
    {
        Pass
        {
            Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            uniform sampler2D _MainTex;
            uniform float4    _LightColor0;
            struct VertexOutput 
            {
                float4 pos:SV_POSITION;
                float2 uv_MainTex:TEXCOORD0;
                float3 normal:TEXCOORD1;
            };

            VertexOutput vert(appdata_base input)
            {
                VertexOutput o;
                o.pos = mul(UNITY_MATRIX_MVP,input.vertex);
                o.uv_MainTex = input.texcoord.xy;
                o.normal = normalize(mul(float4(input.normal,0),_World2Object));
                return o;
            }

            float4 frag(VertexOutput input):COLOR
            {
                float3 normalDir = normalize(input.normal);
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                float3 Kd = tex2D(_MainTex,input.uv_MainTex).xyz;
                float3 diffuseReflection = Kd * _LightColor0.rgb * max(0,dot(normalDir,lightDir));
                return float4(diffuseReflection,1);
            }
            ENDCG
        }
    } 
    FallBack "Diffuse"
}

2.镜面反射

Shader "Esfog/SpecularReflection"
{
    Properties 
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _SpecColor("SpecularColor",Color) = (1,1,1,1)
        _Shininess("Shininess",Float) = 10
    }
    SubShader 
    {
        Pass
        {
            Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma target 5.0
            uniform float4 _LightColor0;
            uniform sampler2D _MainTex;
            uniform float _Shininess;
            uniform float4 _SpecColor;
            struct VertexOutput 
            {
                float4 pos:SV_POSITION;
                float4 posWorld:TEXCOORD0;
                float3 normal:TEXCOORD1;
                float2 uv:TEXCOORD2;
            };

            VertexOutput vert(appdata_base input)
            {
                VertexOutput o;
                o.pos = mul(UNITY_MATRIX_MVP,input.vertex);
                o.posWorld = mul(_Object2World,input.vertex);
                o.normal = normalize(mul(float4(input.normal,0.0),_World2Object).xyz);
                o.uv = input.texcoord.xy;
                return o;
            }

            float4 frag(VertexOutput input):COLOR
            {
                float3 normalDir = normalize(input.normal);
                float3 viewDir = normalize(float3(_WorldSpaceCameraPos - input.posWorld));
                float4 Kd = tex2D(_MainTex,input.uv);
                float4 Ks = _SpecColor;
                float4 Ka = Kd;
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                float3 ambientLighting = Ka.rgb * UNITY_LIGHTMODEL_AMBIENT.rgb;
                float3 diffuseReflection = Kd.rgb * _LightColor0.rgb * max(0.0,dot(normalDir,lightDir));
                float facing;
                if(dot(normalDir,lightDir)<=0)
                {
                    facing = 0;
                }
                else
                {
                    facing = 1;
                }
                float3 SpecularReflection = facing * _LightColor0.rgb * _SpecColor.rgb * pow(max(0,dot(reflect(-lightDir,normalDir),viewDir)),_Shininess);
                return float4(ambientLighting + diffuseReflection + SpecularReflection,1);
            }
            ENDCG    
        }
    } 
    FallBack "Diffuse"
}

3.法线贴图(环境光+漫反射光+镜面反射光+法线贴图)

Shader "Esfog/NormalMap" 
{
    Properties 
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _NormalMap("NormalMap",2D) = "Bump"{}
        _SpecColor("SpecularColor",Color) = (1,1,1,1)
        _Shininess("Shininess",Float) = 10
    }
    SubShader 
    {
        
        Pass
        {
            Tags { "LightMode"="ForwardBase" }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            uniform sampler2D _MainTex;
            uniform sampler2D _NormalMap;
            uniform float4 _SpecColor;
            uniform float _Shininess;
            uniform float4 _LightColor0;

            struct VertexOutput 
            {
                float4 pos:SV_POSITION;
                float2 uv:TEXCOORD0;
                float3 lightDir:TEXCOORD1;
                float3 viewDir:TEXCOORD2;
            };

            VertexOutput vert(appdata_tan v)
            {
                VertexOutput o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                o.uv = v.texcoord.xy;

                //float3 normal = v.normal;
                //float3 tangent = v.tangent;
                //float3 binormal= cross(v.normal,v.tangent.xyz) * v.tangent.w;
                //float3x3 Object2TangentMatrix = float3x3(tangent,binormal,normal);
                //o.lightDir = mul(Object2TangentMatrix,ObjSpaceLightDir(v.vertex));
                //o.viewDir = mul(Object2TangentMatrix,ObjSpaceViewDir(v.vertex));
                //上面注释掉的等价于下面的
                //将本地空间的光线方向,观察方向转换为切线空间,方便与切线空间的法线进行计算
                TANGENT_SPACE_ROTATION;
                o.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex));
                o.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex));

                return o;
            }

            float4 frag(VertexOutput input):COLOR
            {
                float3 lightDir = normalize(input.lightDir);
                float3 viewDir = normalize(input.viewDir);

                //float4 encodedNormal = tex2D(_NormalMap,input.uv);
                //float3 normal = float3(2.0*encodedNormal.ag - 1,0.0);
                //normal.z = sqrt(1 - dot(normal,normal));
                //上面注释掉的等价于下面的
                float3 normal = UnpackNormal(tex2D(_NormalMap, input.uv));

                float4 texColor = tex2D(_MainTex,input.uv);
                float3 ambient = texColor.rgb * UNITY_LIGHTMODEL_AMBIENT.rgb;
                float3 diffuseReflection = texColor.rgb * _LightColor0.rgb * max(0,dot(normal,lightDir));
                float facing;
                if(dot(normal,lightDir)<0)
                {
                    facing = 0;
                }
                else
                {
                    facing = 1;
                }
                float3 specularRelection = _SpecColor.rgb * _LightColor0.rgb * facing * pow(max(0,dot(reflect(-lightDir,normal),viewDir)),_Shininess);

                return float4(ambient + diffuseReflection + specularRelection,1);
            }
            ENDCG
        }
        
    } 
    FallBack "Diffuse"
}

4.帧动画

Shader "Esfog/SpriteUV" 
{
    Properties 
    {
        _SpriteTex ("SpriteTexture (RGB)", 2D) = "white" {}
        _SpriteRowCount ("RowCounts",float) = 0
        _SpriteColumnCount ("ColumnCounts",float) = 0
        _Speed ("AnimationSpeed",Range(0.01,10)) = 4
    }
    SubShader 
    {
        Pass
        {
            Tags { "RenderType"="Opaque" }
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            uniform sampler2D _SpriteTex;
            uniform float _SpriteRowCount;
            uniform float _SpriteColumnCount;
            uniform float _Speed;
            
            struct VertexOutput
            {
                float4 pos:SV_POSITION;
                float2 uv:TEXCOORD0;
            };

            VertexOutput vert(appdata_base input)
            {
                VertexOutput o;
                o.pos = mul(UNITY_MATRIX_MVP,input.vertex);
                o.uv = input.texcoord.xy;
                return o;
            }
            
            float4 frag(VertexOutput input):COLOR
            {
				float perSecondFrame = 1 / _Speed;//每秒帧数
				int frameNum = _Time.y / perSecondFrame;//当前帧数
                float totalSpriteCount = _SpriteRowCount * _SpriteColumnCount;//总帧数
				frameNum = fmod(frameNum,totalSpriteCount);

				int rowIndex = frameNum / _SpriteColumnCount;//第几行
				int columnIndex = fmod(frameNum,_SpriteColumnCount);//第几列
				rowIndex = _SpriteRowCount - rowIndex - 1;//因为uv跟播放动画的顺序不一致

                float rowAvgPercent = 1 / _SpriteColumnCount;//每行单个sprited的uv比例
                float columnAvgPercent = 1 / _SpriteRowCount;//每列单个sprited的uv比例
				
				float2 spriteUV = input.uv;
				spriteUV.x = (spriteUV.x + columnIndex) * rowAvgPercent;
                spriteUV.y = (spriteUV.y + rowIndex) * columnAvgPercent; 
				 
				float4 col = tex2D(_SpriteTex,spriteUV);
                return col; 
            }           
            ENDCG
        }
    } 
    FallBack "Diffuse"
}


### GPU实例化与着色器优化 在Unity中实现高效的GPU实例化和着色器优化能够显著提升性能,尤其是在处理大量对象时。通过利用硬件加速功能,可以减少CPU负载并提高渲染效率。 #### 使用GPU实例化的原理 GPU实例化允许一次性绘制多个相同网格的对象,而不是逐个发送绘制调用给图形API。这减少了状态切换次数以及批处理开销。为了启用此特性,在编写自定义Shader时需加入`Instancing On`指令[^1]: ```hlsl Shader "Custom/InstancedShader" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 200 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_instancing struct appdata_t { float4 vertex : POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 pos : SV_POSITION; UNITY_VERTEX_OUTPUT_STEREO }; sampler2D _MainTex; v2f vert (appdata_t v) { v2f o; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.pos = UnityObjectToClipPos(v.vertex); return o; } fixed4 frag (v2f i) : SV_Target { return tex2D(_MainTex, i.uv); } ENDCG } } } ``` 上述代码展示了如何创建支持实例化的简单顶点片段着色器,并启用了多编译选项来适应不同平台需求。 #### 实现细节 当使用带有实例化特性的材质时,可通过脚本批量设置变换矩阵和其他属性数据到MaterialPropertyBlock中传递给MeshRenderer组件。这样可以在一次DrawCall内完成大批量物体的更新操作[^2]: ```csharp using UnityEngine; public class InstancerExample : MonoBehaviour { public GameObject prefab; // 被实例化的预制件 private MaterialPropertyBlock mpb; void Start() { int count = 1000; Transform[] transforms = new Transform[count]; for(int i=0;i<count;++i){ var go = Instantiate(prefab); go.transform.SetParent(transform,false); transforms[i]=go.transform; } mpb=new MaterialPropertyBlock(); UpdateInstancesData(transforms); } void LateUpdate(){ UpdateInstancesData(GetComponentsInChildren<Transform>()); } void UpdateInstancesData(Transform[] ts){ Matrix4x4[] matrices = new Matrix4x4[ts.Length]; for(int i=0;i<matrices.Length && i<ts.Length;++i){ matrices[i]=ts[i].localToWorldMatrix; } Graphics.DrawMeshInstanced( ((SkinnedMeshRenderer)prefab.GetComponent(typeof(SkinnedMeshRenderer))).sharedMesh, 0,//submeshIndex ((Renderer)prefab.GetComponent(typeof(Renderer))).material, matrices, matrices.Length, mpb//optional material properties block. ); } } ``` 这段C#代码实现了动态管理场景中的实例化对象集合的功能,包括初始化阶段创建指定数量的副本及其后期位置姿态同步刷新逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值