曲面细分着色器加几何着色器实现草的渲染
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