Unity URP 曲面细分着色器加几何着色器实现草的渲染

曲面细分着色器加几何着色器实现草的渲染
Shader "Unlit/TessellationAndGeometry"
{
    Properties
    {
        _EdgeFactor("Edge Factor", Range(1.0, 20)) = 1.0
        _InsideFactor("Inside Factor", Range(1.0, 20)) = 1.0

        _HeightMap("Height Map", 2D) = "black" {}
        _HeightScale("Height Scale", Range(0,10)) = 1
        _BaseTex("Base Tex",2D) = "white" {}
        _BendRotationRandom("Bend Rotation Random", Range(0, 1)) = 0.2
        _BaseWidth("BaseWidth",Range(0,2)) = 0.5
        _RandomWidth("RandomWidth",Range(0,2)) = 0.5
        _BaseHeight("BaseHeight",Range(0,10)) = 3
        _RandomHeight("RandomHeight",Range(0,2)) = 1
        _WindTex("WinTex",2D) = "white"{}
        _WindStrength("WindStrength",Range(1,10)) = 1
        _WindFrequency("WindFrequency",Range(0,10)) = 1
        _NodeCount("NodeCount",Range(1,10)) = 1//草的节点数
        _NodeOffetStrength("NodeOffetStrength",Range(0,10)) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            cull off
            HLSLPROGRAM
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            #pragma target 4.6

            #pragma shader_feature _ _FACTORTYPE_CUSTOM _FACTORTYPE_VIEW _FACTORTYPE_TEST
            
            //Execute order : vertex shader -> [hull shader + tessllation => domain shader] -> geometry shader -> fragment shader
            #pragma vertex vert
            #pragma hull HullS
            #pragma geometry geo
            #pragma domain DomainS
            #pragma fragment frag

            struct Attribute
            {
                float4 positionOS : POSITION;
                float2 uv : TEXCOORD0;
                float4 tangent: TANGENT;
                float3 normal: NORMAL;
            };
            struct Varings
            {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0;
            };
            struct TrianglePatchTess
            {
                //三角面 边细分因子
                float edgeTess[3] : SV_TessFactor; 
                //三角面 内细分因子
                float insideTess : SV_InsideTessFactor;
            };
            struct HullOutput
            {
                float3 positionOS : TEXCOORD0;
                float2 uv : TEXCOORD1;
                float4 tangent: TEXCOORD2;
                float3 normal: TEXCOORD3;
            };
            struct DomainOutput
            {
                float3 positionOS : TEXCOORD0;
                float2 uv : TEXCOORD1;
                float4 tangent: TEXCOORD2;
                float3 normal: TEXCOORD3;
            };
            struct GeoOutput
            {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0;
                //float3 bary : TEXCOORD1;
            };

            half _EdgeFactor;
            half _InsideFactor;
            float _HeightScale;
            float _BendRotationRandom;
            sampler2D _HeightMap;
            sampler2D _BaseTex;
            float _BaseWidth;
            float _BaseHeight;
            float _RandomWidth;
            float _RandomHeight;
            sampler2D _WindTex;
            float _WindStrength;
            float _WindFrequency;
            float _NodeCount;
            float _NodeOffetStrength;

            /*domain:patch的类型。可选用的参数有tri(三角形面片)、quad(四边形面片)或isoline(等值线)。
            partitioning:曲面细分的模式。
            interger:新顶点的添加或一处仅取决于曲面细分因子的整数部分,向上取整。这样一来,在网格随着曲面细分级别而改变时,会容易发生明显的突跃(popping)情况。
            非整数曲面细分(fractional_even/fractional_odd)。新顶点的添加或移除取决于曲面细分因子的整数部分,但是细微的“渐变”调整就要根据因子的小数部分。具体见后面的图片。
            outputpology:通过细分所创的三角形的绕序
            triangle_cw:顺时针方向的绕序
            triangle_ccw:逆时针方向的绕序
            line:针对线段曲面细分
            outputcontrolpoints:外壳着色器执行的次数,每次执行都输出1个控制点。系统值SV_OutputControlPointID给出的索引标明当前正在工作的外壳着色器所输出的控制点。
            patchconstantfunc:指定常量外壳着色器函数名称的字符串。
            maxtessfactor:告知驱动程序,用户在着色器所用的曲面细分因子的最大值。一般硬件最大值为64。*/


            [domain("tri")] 
            [partitioning("integer")] 
            [outputtopology("triangle_cw")]  
            [outputcontrolpoints(4)] 
            [patchconstantfunc("ComputeTessFactor")] 
            [maxtessfactor(64.0)] 
            HullOutput HullS(InputPatch<Attribute, 3> input, uint controlPointId : SV_OutputControlPointID, uint patchId : SV_PrimitiveID)
            {
                HullOutput output;

                output.positionOS = input[controlPointId].positionOS;
                output.uv = input[controlPointId].uv;
                output.tangent = input[controlPointId].tangent;
                output.normal = input[controlPointId].normal;
                return output;
            }
            TrianglePatchTess ComputeTessFactor(InputPatch<Attribute, 3> patch, uint patchId : SV_PrimitiveID)
            {
                TrianglePatchTess output;
                output.edgeTess[0] = _EdgeFactor;
                output.edgeTess[1] = _EdgeFactor;
                output.edgeTess[2] = _EdgeFactor;

                output.insideTess = _InsideFactor;
                return output;
            }

            [domain("tri")]
            DomainOutput DomainS(TrianglePatchTess patchTess, float3 bary: SV_DomainLocation, const OutputPatch<HullOutput, 3> patch)
            {
                DomainOutput output;

                float3 positionOS = patch[0].positionOS * bary.x + patch[1].positionOS * bary.y + patch[2].positionOS * bary.z; 
                float2 uv = patch[0].uv * bary.x + patch[1].uv * bary.y + patch[2].uv * bary.z; 
                float4 tangent = patch[0].tangent * bary.x + patch[1].tangent * bary.y + patch[2].tangent * bary.z;
                float3 normal = patch[0].normal * bary.x + patch[1].normal * bary.y + patch[2].normal * bary.z;
                
                float height = tex2Dlod(_HeightMap, float4(uv,0,0)).x * _HeightScale;
                positionOS.y += height;

                output.positionOS = positionOS;
                output.uv = uv;
                output.tangent = tangent;
                output.normal = normal;
                return output;
            }

            float3x3 RotateAroundAxis3x3(float3 u, float angle )
			{
				float C = cos( angle );
				float S = sin( angle );
				float t = 1 - C;
				float m00 = t * u.x * u.x + C;
				float m01 = t * u.x * u.y - S * u.z;
				float m02 = t * u.x * u.z + S * u.y;
				float m10 = t * u.x * u.y + S * u.z;
				float m11 = t * u.y * u.y + C;
				float m12 = t * u.y * u.z - S * u.x;
				float m20 = t * u.x * u.z - S * u.y;
				float m21 = t * u.y * u.z + S * u.x;
				float m22 = t * u.z * u.z + C;
				float3x3 finalMatrix = float3x3( m00, m01, m02, m10, m11, m12, m20, m21, m22 );
				return finalMatrix;
			}

            float Rand(float3 posOS)
            {
                float dotResult_Random = dot( posOS , float3( 12.9898,78.233, 53.539) );
				float lerpResult_Random = lerp( 0.0 , 1.0 , frac( ( sin( dotResult_Random ) * 43758.55 ) ));
                return lerpResult_Random;
            }

            float4 TransformToHClip(float3x3 transformMul,float3 posOffset,float3 posOS)
            {
                return TransformObjectToHClip(posOS + mul(transformMul,posOffset));
            }
            
            [maxvertexcount(10)]
            void geo(triangle DomainOutput input[3], inout TriangleStream<GeoOutput> stream) 
            {
                //GeoOutput output[1 +_NodeCount * 2];
                float3 vNormal = input[0].normal;
                float4 vTangent = input[0].tangent;
                float3 vBinormal = cross(vNormal,vTangent)*GetOddNegativeScale();
                float3x3 tangentToObject = float3x3(vTangent.x, vBinormal.x, vNormal.x,vTangent.y, vBinormal.y, vNormal.y,vTangent.z, vBinormal.z, vNormal.z);//CreateTangentToWorld(input[0].normal,input[0].tangent,1);;//float3x3(vTangent,vBinormal,vNormal); //
                //使用模型空间法线得到的就是tangenttoobject,这样的出来的矩阵要右乘
                //float3x3 tangentToObject = CreateTangentToWorld(vNormal,vTangent,1);
               
                float3 rotationAxis = float3(0,1,0);
                float rand = Rand(input[0].positionOS.xyz);
                float randomAngle = rand * PI * _BendRotationRandom;
                float3x3 rotationMul = RotateAroundAxis3x3(rotationAxis,randomAngle);
                
                rand = Rand(input[0].positionOS.zyx);
                float width = _RandomWidth * (rand) + _BaseWidth;
                float height = _RandomHeight * (rand * 2 - 1) + _BaseHeight;

                float2 windCol = (tex2Dlod(_WindTex,float4(input[0].uv * _Time.x * _WindFrequency,0,0)).xy * 2 - 1) * _WindStrength;
                float3 wind = normalize(float3(windCol.x,windCol.y,0));//绕着跟旋转
                float3x3 windMul = RotateAroundAxis3x3(wind,windCol.x * PI);
                float3x3 transformMul = mul(windMul,mul(rotationMul,tangentToObject));

                GeoOutput output;
                //每多一个节就增加两个点
                for (int i = 0;i < _NodeCount;i++)
                {
                    float t = i/(float)_NodeCount;
                    float w = ((1 - t) * width);
                    float h = t * height;

                    output.positionCS = TransformToHClip(transformMul,float3(w, pow(t,_NodeOffetStrength) * rand,h),input[0].positionOS);
                    output.uv = float2(0,t);
                    stream.Append(output);
                    output.positionCS = TransformToHClip(transformMul,float3(-w, pow(t,_NodeOffetStrength) * rand,h),input[0].positionOS);
                    output.uv = float2(1,t);
                    stream.Append(output);
}
                
                //output[0].positionCS = TransformToHClip(transformMul,float3(width,0,0),input[0].positionOS);
                //output[1].positionCS = TransformToHClip(transformMul,float3(-width,0,0),input[0].positionOS);
                output.positionCS = TransformToHClip(transformMul,float3(0,0,height),input[0].positionOS);

                //重新设置uv,后面采样贴图使用。
                //output[0].uv = float2(0,0);
                //output[1].uv = float2(1,0);
                output.uv = float2(0.5,1);

                //output[0].bary = float3(1,0,0);
                //output[1].bary = float3(0,1,0);
                //output[2].bary = float3(0,0,1);

                //stream.Append(output[0]);
                //stream.Append(output[1]);
                stream.Append(output);
            }
            Attribute vert(Attribute input)
            {
                return input;
            }

            half4 frag(GeoOutput input) : SV_Target
            {
                return tex2D(_BaseTex,input.uv);
            }
            ENDHLSL
        }
    }
}

效果图
不好看只能怪自己0.0

学习
学习
学习

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值