网站开发工程师学什么,wordpress底面有虚线这么办,logo设计在线生成免费免费设计logo,客户网站开发全流程左边是默认Cube在网格模式下经过曲面细分的结果#xff0c;右边是原状态。
曲面细分着色器在顶点着色器、几何着色器之后#xff0c;像素着色器之前。
它的作用时根据配置信息生成额外的顶点以切割原本的面片。
关于这部分有一个详细的英文教程#xff0c;感兴趣可以看一…
左边是默认Cube在网格模式下经过曲面细分的结果右边是原状态。
曲面细分着色器在顶点着色器、几何着色器之后像素着色器之前。
它的作用时根据配置信息生成额外的顶点以切割原本的面片。
关于这部分有一个详细的英文教程感兴趣可以看一下。
https://catlikecoding.com/unity/tutorials/advanced-rendering/tessellation/
以下是完整代码
Shader Kerzh/KerzhCgShaderTemplate
{Properties{_Color(Color, Color) (1,1,1,1)_TessellationUniform (Tessellation Uniform, Vector) (1,1,1,1)}SubShader{Tags { RenderType Opaque RenderPipeline UniversalRenderPipeline }Pass{CGPROGRAM#pragma vertex vert#pragma hull hull#pragma domain domain#pragma geometry geom#pragma fragment frag#pragma target 4.6#include UnityCG.cginc#include Assets/TA/ShaderLib/CgincInclude//CommonCgInc.cginc#include Assets/TA/ShaderLib/CgincInclude//CustomTessellation.cgincMeshData vert (MeshData input){return input;}//如果不正确配置会报错[UNITY_domain(tri)] // 正在处理三角形 tri, quad, or isoline[UNITY_outputcontrolpoints(3)] // 每个面片输出的顶点为3个[UNITY_outputtopology(triangle_cw)] // 当创建三角形时应是顺时针还是逆时针这里应是顺时针 point, line, triangle_cw, or triangle_ccw[UNITY_partitioning(integer)] // 如何细分切割面片 integer, pow2, fractional_even, or fractional_odd[UNITY_patchconstantfunc(patchConstantFunction)] // 细分切割部分还必须提供函数处理每个面片调用一次MeshData hull (InputPatchMeshData, 3 patch, uint id : SV_OutputControlPointID) // 每个顶点调用一次如果是处理三角形就是调用三次{// 如果_TessellationUniform输入值为1不产生任何变化但当输入值为2时具体发生了什么// 对于一个三角形(因为我们配置的是处理三角形)根据三条边的二等分位置添加额外的一个顶点如果是3就是三等分位置添加两个顶点// 对于一个三角形(因为我们配置的是处理三角形)根据三条个顶点添加一个中心顶点// 根据patchConstantFunction赋值分配生成顶点的插值权重return patch[id];}// barycentricCoordinates分别代表各个点的插值权重,每个面片调用一次对细分后的三角顶点形进行处理(也就是说原顶点不经过此处理)[UNITY_domain(tri)] // 正在处理三角形MeshData domain(TessellationFactors factors, OutputPatchMeshData, 3 patch, float3 barycentricCoordinates : SV_DomainLocation) {MeshData data; // 新的插值权重顶点#define MY_DOMAIN_PROGRAM_INTERPOLATE(fieldName) data.fieldName \patch[0].fieldName * barycentricCoordinates.x \patch[1].fieldName * barycentricCoordinates.y \patch[2].fieldName * barycentricCoordinates.z;//对所有信息利用插值权重进行插值计算MY_DOMAIN_PROGRAM_INTERPOLATE(vertex)MY_DOMAIN_PROGRAM_INTERPOLATE(normalOS)MY_DOMAIN_PROGRAM_INTERPOLATE(tangentOS)MY_DOMAIN_PROGRAM_INTERPOLATE(uv1)MY_DOMAIN_PROGRAM_INTERPOLATE(uv2)MY_DOMAIN_PROGRAM_INTERPOLATE(vertexColor)return data;}//最大的顶点数这里比如你要生成三个三角形面片那么一个面片需要三个顶点就是9个顶点一般来讲这里直接填多一点即可不过可能填太多了会导致内存占用[maxvertexcount(9)]void geom (triangle MeshData input[3],inout TriangleStreamVOutData triStream){//原样转换过去VOutData output[3];for(int i0;i3;i){VOutData p0;p0 FillBaseV2FData(input[i]);output[i] p0;}triStream.RestartStrip(); // 重新开始一个新的三角形triStream.Append(output[0]);triStream.Append(output[1]);triStream.Append(output[2]);return;//验证准确性用 勿删MeshData centerMeshData;centerMeshData.vertex (input[0].vertex input[1].vertex input[2].vertex)/3.0;centerMeshData.uv1 (input[0].uv1 input[1].uv1 input[2].uv1)/3.0;centerMeshData.uv2 (input[0].uv2 input[1].uv2 input[2].uv2)/3.0;centerMeshData.tangentOS (input[0].tangentOS input[1].tangentOS input[2].tangentOS)/3.0;centerMeshData.normalOS (input[0].normalOS input[1].normalOS input[2].normalOS)/3.0;centerMeshData.vertexColor (input[0].vertexColor input[1].vertexColor input[2].vertexColor)/3.0;centerMeshData.vertex float4((centerMeshData.normalOS * 0.35), 0);VOutData center FillBaseV2FData(centerMeshData);// 根据这三个点分别和中心点制造三角形输出triStream.RestartStrip(); // 重新开始一个新的三角形triStream.Append(output[1]);triStream.Append(center);triStream.Append(output[0]);triStream.RestartStrip(); // 重新开始一个新的三角形triStream.Append(output[2]);triStream.Append(center);triStream.Append(output[1]);triStream.RestartStrip(); // 重新开始一个新的三角形triStream.Append(output[0]);triStream.Append(center);triStream.Append(output[2]);}float4 _Color;float4 frag (VOutData i) : SV_Target{return _Color;}ENDCG}}
}
依赖文件CommonCgInc.cginc
#ifndef CommonCgInc
#define CommonCgIncfloat3 FromScript_LocalPositionWS;
float3 FromScript_LocalRotationWS;
float3 FromScript_LocalScaleWS;//输入结构
struct MeshData
{float4 vertex : POSITION;float2 uv1 : TEXCOORD0;float2 uv2 : TEXCOORD1;float4 tangentOS :TANGENT;float3 normalOS : NORMAL;float4 vertexColor : COLOR;
};//传递结构
struct VOutData
{float4 pos : SV_POSITION; // 必须命名为pos 因为 TRANSFER_VERTEX_TO_FRAGMENT 是这么命名的为了正确地获取到Shadowfloat2 uv1 : TEXCOORD0;float3 tangentWS : TEXCOORD1;float3 bitangentWS : TEXCOORD2;float3 normalWS : TEXCOORD3;float3 posWS : TEXCOORD4;float3 posOS : TEXCOORD5;float3 normalOS : TEXCOORD6;float4 vertexColor : TEXCOORD7;float2 uv2 : TEXCOORD8;
};//传递结构赋值
VOutData FillBaseV2FData(MeshData input)
{VOutData output;output.pos UnityObjectToClipPos(input.vertex);output.uv1 input.uv1;output.uv2 input.uv2;output.normalWS normalize(UnityObjectToWorldNormal(input.normalOS));output.posWS mul(unity_ObjectToWorld, input.vertex);output.posOS input.vertex.xyz;output.tangentWS normalize(UnityObjectToWorldDir(input.tangentOS));output.bitangentWS cross(output.normalWS, output.tangentWS) * input.tangentOS.w; //乘上input.tangentOS.w 是unity引擎的bug,有的模型是 1 有的模型是 -1必须这么写output.normalOS input.normalOS;output.vertexColor input.vertexColor;return output;
}// Hue, Saturation, Value
// Ranges:
// Hue [0.0, 1.0]
// Sat [0.0, 1.0]
// Lum [0.0, HALF_MAX]
// //HSV色彩模型转为RGB色彩模型 FROM::color.hlsl
float3 HSV2RGB( float3 hsv ){const float4 K float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);float3 p abs(frac(hsv.xxx K.xyz) * 6.0 - K.www);return hsv.z * lerp(K.xxx, saturate(p - K.xxx), hsv.y);
}
//RGB色彩模型转为HSV色彩模型 FROM::color.hlsl
float3 RGB2HSV(float3 rgb)
{float4 K float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);float4 p lerp(float4(rgb.bg, K.wz), float4(rgb.gb, K.xy), step(rgb.b, rgb.g));float4 q lerp(float4(p.xyw, rgb.r), float4(rgb.r, p.yzx), step(p.x, rgb.r));float d q.x - min(q.w, q.y);float e 1.0e-10;return float3(abs(q.z (q.w - q.y) / (6.0 * d e)), d / (q.x e), q.x);
}//Gooch光照模型 ⻛格化的着⾊模型 强调冷暖色调 FROM::render4th P146
float3 GoochModel(float3 baseColor, float3 highLightColor, float3 normalWs, float3 lightDirWs, float3 viewDirWs){normalWs normalize(normalWs);lightDirWs normalize(lightDirWs);float3 coolColor float3(0,0,0.55) 0.25*baseColor;float3 warmColor float3(0.3,0.3,0) 0.25*baseColor;float size clamp(100*(dot(reflect(lightDirWs, normalWs), viewDirWs) - 97), 0, 1);float4 halfLambert dot(normalWs, lightDirWs) * 0.5 0.5;return size*highLightColor (1-size)*(halfLambert*warmColor (1 - halfLambert)* coolColor);
}//添加虚拟点光源 _VirtualLightFade越大衰减越快
float3 CalculatePointVirtualLight(float3 _VirtualLightPos, float3 positionOS, float _VirtualLightFade, float3 _VirtualLightColor)
{float virtualLightDis distance(_VirtualLightPos,positionOS);float3 virtualLight exp(-_VirtualLightFade*virtualLightDis)*_VirtualLightColor;//TODO:也许补充方向衰减return virtualLight;
}//切线空间计算视差uv 根据视角方向以深度反追命中点uv
float2 CalculateRealUVAfterDepth(float2 originUV, float3 viewDirTS, float depth)
{//计算视角方向和深度方向的cos值float cosTheta dot(normalize(viewDirTS), float3(0,0,-1)); // 一般来讲unity是左手坐标系但在切线和观察空间较为特殊是右手坐标系不过这并不影响z轴方向的判断//根据深度差算出两点间距离float dis depth / cosTheta;//算出应用深度差后对应点位float3 originUVPoint float3(originUV, 0);float3 afrerDepthUVPoint originUVPoint normalize(viewDirTS) * dis;//返回应用深度差后对应UVreturn afrerDepthUVPoint.xy;
}
#endif
依赖文件CustomTessellation.cginc
// Tessellation programs based on this article by Catlike Coding:
// https://catlikecoding.com/unity/tutorials/advanced-rendering/tessellation/
// 关于参数的详细说明
// https://zhuanlan.zhihu.com/p/479792793#include Assets/TA/ShaderLib/CgincInclude//CommonCgInc.cginc//细分切割函数对于每个面片调用一次对于每一个面片比如三角形每条边需要一个切割因子内部需要一个切割因子
struct TessellationFactors {float edge[3] : SV_TessFactor; // 对应三条边的切割因子float inside : SV_InsideTessFactor; // 对应内部的切割因子
};float4 _TessellationUniform; // 细分因子当值为1时不发生细分切割。因子可以分别设置比如边因子是1内部因子是5那就不会在边上生成顶点会在中心生成五个顶点
//自定义的细分切割方法每个面片调用一次
TessellationFactors patchConstantFunction (InputPatchMeshData, 3 patch)
{TessellationFactors f;f.edge[0] _TessellationUniform.x;f.edge[1] _TessellationUniform.y;f.edge[2] _TessellationUniform.z;f.inside _TessellationUniform.w;return f;
}
其中通过
#pragma hull hull
#pragma domain domain
定义hull和domain着色器其中hull负责切割domain用于根据权重处理细分后的顶点数据。
hull部分
//细分切割函数对于每个面片调用一次对于每一个面片比如三角形每条边需要一个切割因子内部需要一个切割因子
struct TessellationFactors {float edge[3] : SV_TessFactor; // 对应三条边的切割因子float inside : SV_InsideTessFactor; // 对应内部的切割因子
};float4 _TessellationUniform; // 细分因子当值为1时不发生细分切割。因子可以分别设置比如边因子是1内部因子是5那就不会在边上生成顶点会在中心生成五个顶点
//自定义的细分切割方法每个面片调用一次
TessellationFactors patchConstantFunction (InputPatchMeshData, 3 patch)
{TessellationFactors f;f.edge[0] _TessellationUniform.x;f.edge[1] _TessellationUniform.y;f.edge[2] _TessellationUniform.z;f.inside _TessellationUniform.w;return f;
}//如果不正确配置会报错[UNITY_domain(tri)] // 正在处理三角形 tri, quad, or isoline[UNITY_outputcontrolpoints(3)] // 每个面片输出的顶点为3个[UNITY_outputtopology(triangle_cw)] // 当创建三角形时应是顺时针还是逆时针这里应是顺时针 point, line, triangle_cw, or triangle_ccw[UNITY_partitioning(integer)] // 如何细分切割面片 integer, pow2, fractional_even, or fractional_odd[UNITY_patchconstantfunc(patchConstantFunction)] // 细分切割部分还必须提供函数处理每个面片调用一次MeshData hull (InputPatchMeshData, 3 patch, uint id : SV_OutputControlPointID) // 每个顶点调用一次如果是处理三角形就是调用三次{// 如果_TessellationUniform输入值为1不产生任何变化但当输入值为2时具体发生了什么// 对于一个三角形(因为我们配置的是处理三角形)根据三条边的二等分位置添加额外的一个顶点如果是3就是三等分位置添加两个顶点// 对于一个三角形(因为我们配置的是处理三角形)根据三条个顶点添加一个中心顶点// 根据patchConstantFunction赋值分配生成顶点的插值权重return patch[id];}
这里做的操作比较少只是传入每个面片的切割因子一个面片(三角形)的每条边需要一个切割因子内部需要一个切割因子一共四个切割因子。
domain部分 // barycentricCoordinates分别代表各个点的插值权重,每个面片调用一次对细分后的三角顶点形进行处理(也就是说原顶点不经过此处理)[UNITY_domain(tri)] // 正在处理三角形MeshData domain(TessellationFactors factors, OutputPatchMeshData, 3 patch, float3 barycentricCoordinates : SV_DomainLocation) {MeshData data; // 新的插值权重顶点#define MY_DOMAIN_PROGRAM_INTERPOLATE(fieldName) data.fieldName \patch[0].fieldName * barycentricCoordinates.x \patch[1].fieldName * barycentricCoordinates.y \patch[2].fieldName * barycentricCoordinates.z;//对所有信息利用插值权重进行插值计算MY_DOMAIN_PROGRAM_INTERPOLATE(vertex)MY_DOMAIN_PROGRAM_INTERPOLATE(normalOS)MY_DOMAIN_PROGRAM_INTERPOLATE(tangentOS)MY_DOMAIN_PROGRAM_INTERPOLATE(uv1)MY_DOMAIN_PROGRAM_INTERPOLATE(uv2)MY_DOMAIN_PROGRAM_INTERPOLATE(vertexColor)return data;}
这里则是根据传入的边和内部的切割因子的权重对于新增加的顶点使用这个方法中的规则填充顶点的对应信息以完成切割。
MY_DOMAIN_PROGRAM_INTERPOLATE
是定义了一个宏用于重复处理所有的属性还是要根据实际情况对应处理方法。