Advertisement
Guest User

Untitled

a guest
Jul 26th, 2021
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.20 KB | None | 0 0
  1. Shader "Custom/BotWGrass"
  2. {
  3. Properties
  4. {
  5. _BaseColor("Base Color", Color) = (1, 1, 1, 1)
  6. _TipColor("Tip Color", Color) = (1, 1, 1, 1)
  7. _BladeTexture("Blade Texture", 2D) = "white" {}
  8.  
  9. _BladeWidthMin("Blade Width (Min)", Range(0, 0.1)) = 0.02
  10. _BladeWidthMax("Blade Width (Max)", Range(0, 0.1)) = 0.05
  11. _BladeHeightMin("Blade Height (Min)", Range(0, 2)) = 0.1
  12. _BladeHeightMax("Blade Height (Max)", Range(0, 2)) = 0.2
  13.  
  14. _BladeSegments("Blade Segments", Range(1, 10)) = 3
  15. _BladeBendDistance("Blade Forward Amount", Float) = 0.38
  16. _BladeBendCurve("Blade Curvature Amount", Range(1, 4)) = 2
  17.  
  18. _BendDelta("Bend Variation", Range(0, 1)) = 0.2
  19.  
  20. _TessellationGrassDistance("Tessellation Grass Distance", Range(0.01, 2)) = 0.1
  21.  
  22. _GrassMap("Grass Visibility Map", 2D) = "white" {}
  23. _GrassThreshold("Grass Visibility Threshold", Range(-0.1, 1)) = 0.5
  24. _GrassFalloff("Grass Visibility Fade-In Falloff", Range(0, 0.5)) = 0.05
  25.  
  26. _WindMap("Wind Offset Map", 2D) = "bump" {}
  27. _WindVelocity("Wind Velocity", Vector) = (1, 0, 0, 0)
  28. _WindFrequency("Wind Pulse Frequency", Range(0, 1)) = 0.01
  29. }
  30.  
  31. SubShader
  32. {
  33. Tags
  34. {
  35. "RenderType" = "Opaque"
  36. "Queue" = "Geometry"
  37. "RenderPipeline" = "UniversalPipeline"
  38. }
  39. LOD 100
  40. Cull Off
  41.  
  42. HLSLINCLUDE
  43. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
  44. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
  45.  
  46. #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
  47. #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
  48. #pragma multi_compile _ _SHADOWS_SOFT
  49.  
  50. #define UNITY_PI 3.14159265359f
  51. #define UNITY_TWO_PI 6.28318530718f
  52. #define BLADE_SEGMENTS 4
  53.  
  54. CBUFFER_START(UnityPerMaterial)
  55. float4 _BaseColor;
  56. float4 _TipColor;
  57. sampler2D _BladeTexture;
  58.  
  59. float _BladeWidthMin;
  60. float _BladeWidthMax;
  61. float _BladeHeightMin;
  62. float _BladeHeightMax;
  63.  
  64. float _BladeBendDistance;
  65. float _BladeBendCurve;
  66.  
  67. float _BendDelta;
  68.  
  69. float _TessellationGrassDistance;
  70.  
  71. sampler2D _GrassMap;
  72. float4 _GrassMap_ST;
  73. float _GrassThreshold;
  74. float _GrassFalloff;
  75.  
  76. sampler2D _WindMap;
  77. float4 _WindMap_ST;
  78. float4 _WindVelocity;
  79. float _WindFrequency;
  80.  
  81. float4 _ShadowColor;
  82. CBUFFER_END
  83.  
  84. struct VertexInput
  85. {
  86. float4 vertex : POSITION;
  87. float3 normal : NORMAL;
  88. float4 tangent : TANGENT;
  89. float2 uv : TEXCOORD0;
  90. };
  91.  
  92. struct VertexOutput
  93. {
  94. float4 vertex : SV_POSITION;
  95. float3 normal : NORMAL;
  96. float4 tangent : TANGENT;
  97. float2 uv : TEXCOORD0;
  98. };
  99.  
  100. struct TessellationFactors
  101. {
  102. float edge[3] : SV_TessFactor;
  103. float inside : SV_InsideTessFactor;
  104. };
  105.  
  106. struct GeomData
  107. {
  108. float4 pos : SV_POSITION;
  109. float2 uv : TEXCOORD0;
  110. float3 worldPos : TEXCOORD1;
  111. };
  112.  
  113. // Following functions from Roystan's code:
  114. // (https://github.com/IronWarrior/UnityGrassGeometryShader)
  115.  
  116. // Simple noise function, sourced from http://answers.unity.com/answers/624136/view.html
  117. // Extended discussion on this function can be found at the following link:
  118. // https://forum.unity.com/threads/am-i-over-complicating-this-random-function.454887/#post-2949326
  119. // Returns a number in the 0...1 range.
  120. float rand(float3 co)
  121. {
  122. return frac(sin(dot(co.xyz, float3(12.9898, 78.233, 53.539))) * 43758.5453);
  123. }
  124.  
  125. // Construct a rotation matrix that rotates around the provided axis, sourced from:
  126. // https://gist.github.com/keijiro/ee439d5e7388f3aafc5296005c8c3f33
  127. float3x3 angleAxis3x3(float angle, float3 axis)
  128. {
  129. float c, s;
  130. sincos(angle, s, c);
  131.  
  132. float t = 1 - c;
  133. float x = axis.x;
  134. float y = axis.y;
  135. float z = axis.z;
  136.  
  137. return float3x3
  138. (
  139. t * x * x + c, t * x * y - s * z, t * x * z + s * y,
  140. t * x * y + s * z, t * y * y + c, t * y * z - s * x,
  141. t * x * z - s * y, t * y * z + s * x, t * z * z + c
  142. );
  143. }
  144.  
  145. // Regular vertex shader used by typical shaders.
  146. VertexOutput vert(VertexInput v)
  147. {
  148. VertexOutput o;
  149. o.vertex = TransformObjectToHClip(v.vertex.xyz);
  150. o.normal = v.normal;
  151. o.tangent = v.tangent;
  152. o.uv = TRANSFORM_TEX(v.uv, _GrassMap);
  153. return o;
  154. }
  155.  
  156. // Vertex shader which just passes data to tessellation stage.
  157. VertexOutput tessVert(VertexInput v)
  158. {
  159. VertexOutput o;
  160. o.vertex = v.vertex;
  161. o.normal = v.normal;
  162. o.tangent = v.tangent;
  163. o.uv = v.uv;
  164. return o;
  165. }
  166.  
  167. // Vertex shader which translates from object to world space.
  168. VertexOutput geomVert (VertexInput v)
  169. {
  170. VertexOutput o;
  171. o.vertex = float4(TransformObjectToWorld(v.vertex), 1.0f);
  172. o.normal = TransformObjectToWorldNormal(v.normal);
  173. o.tangent = v.tangent;
  174. o.uv = TRANSFORM_TEX(v.uv, _GrassMap);
  175. return o;
  176. }
  177.  
  178. // This function lets us derive the tessellation factor for an edge
  179. // from the vertices.
  180. float tessellationEdgeFactor(VertexInput vert0, VertexInput vert1)
  181. {
  182. float3 v0 = vert0.vertex.xyz;
  183. float3 v1 = vert1.vertex.xyz;
  184. float edgeLength = distance(v0, v1);
  185. return edgeLength / _TessellationGrassDistance;
  186. }
  187.  
  188. // This is a test version of the tessellation that takes distance from the viewer
  189. // into account. It works fine, but I think it could do with refinement.
  190. float tessellationEdgeFactor_distanceTest(VertexInput vert0, VertexInput vert1)
  191. {
  192. float3 v0 = vert0.vertex.xyz;
  193. float3 v1 = vert1.vertex.xyz;
  194. float edgeLength = distance(v0, v1);
  195.  
  196. float3 edgeCenter = (v0 + v1) * 0.5f;
  197. float viewDist = distance(edgeCenter, _WorldSpaceCameraPos) / 10.0f;
  198.  
  199. return edgeLength * _ScreenParams.y / (_TessellationGrassDistance * viewDist);
  200. }
  201.  
  202. // Tessellation hull and domain shaders derived from Catlike Coding's tutorial:
  203. // https://catlikecoding.com/unity/tutorials/advanced-rendering/tessellation/
  204.  
  205. // The patch constant function is where we create new control
  206. // points on the patch. For the edges, increasing the tessellation
  207. // factors adds new vertices on the edge. Increasing the inside
  208. // will add more 'layers' inside the new triangle.
  209. TessellationFactors patchConstantFunc(InputPatch<VertexInput, 3> patch)
  210. {
  211. TessellationFactors f;
  212.  
  213. f.edge[0] = tessellationEdgeFactor(patch[1], patch[2]);
  214. f.edge[1] = tessellationEdgeFactor(patch[2], patch[0]);
  215. f.edge[2] = tessellationEdgeFactor(patch[0], patch[1]);
  216. f.inside = (f.edge[0] + f.edge[1] + f.edge[2]) / 3.0f;
  217.  
  218. return f;
  219. }
  220.  
  221. // The hull function is the first half of the tessellation shader.
  222. // It operates on each patch (in our case, a patch is a triangle),
  223. // and outputs new control points for the other tessellation stages.
  224. //
  225. // The patch constant function is where we create new control points
  226. // (which are kind of like new vertices).
  227. [domain("tri")]
  228. [outputcontrolpoints(3)]
  229. [outputtopology("triangle_cw")]
  230. [partitioning("integer")]
  231. [patchconstantfunc("patchConstantFunc")]
  232. VertexInput hull(InputPatch<VertexInput, 3> patch, uint id : SV_OutputControlPointID)
  233. {
  234. return patch[id];
  235. }
  236.  
  237. // In between the hull shader stage and the domain shader stage, the
  238. // tessellation stage takes place. This is where, under the hood,
  239. // the graphics pipeline actually generates the new vertices.
  240.  
  241. // The domain function is the second half of the tessellation shader.
  242. // It interpolates the properties of the vertices (position, normal, etc.)
  243. // to create new vertices.
  244. [domain("tri")]
  245. VertexOutput domain(TessellationFactors factors, OutputPatch<VertexInput, 3> patch, float3 barycentricCoordinates : SV_DomainLocation)
  246. {
  247. VertexInput i;
  248.  
  249. #define INTERPOLATE(fieldname) i.fieldname = \
  250. patch[0].fieldname * barycentricCoordinates.x + \
  251. patch[1].fieldname * barycentricCoordinates.y + \
  252. patch[2].fieldname * barycentricCoordinates.z;
  253.  
  254. INTERPOLATE(vertex)
  255. INTERPOLATE(normal)
  256. INTERPOLATE(tangent)
  257. INTERPOLATE(uv)
  258.  
  259. return tessVert(i);
  260. }
  261.  
  262. // Geometry functions derived from Roystan's tutorial:
  263. // https://roystan.net/articles/grass-shader.html
  264.  
  265. // This function applies a transformation (during the geometry shader),
  266. // converting to clip space in the process.
  267. GeomData TransformGeomToClip(float3 pos, float3 offset, float3x3 transformationMatrix, float2 uv)
  268. {
  269. GeomData o;
  270.  
  271. o.pos = TransformObjectToHClip(pos + mul(transformationMatrix, offset));
  272. o.uv = uv;
  273. o.worldPos = TransformObjectToWorld(pos + mul(transformationMatrix, offset));
  274.  
  275. return o;
  276. }
  277.  
  278. // This is the geometry shader. For each vertex on the mesh, a leaf
  279. // blade is created by generating additional vertices.
  280. [maxvertexcount(BLADE_SEGMENTS * 2 + 1)]
  281. void geom(point VertexOutput input[1], inout TriangleStream<GeomData> triStream)
  282. {
  283. float grassVisibility = tex2Dlod(_GrassMap, float4(input[0].uv, 0, 0)).r;
  284.  
  285. if (grassVisibility >= _GrassThreshold)
  286. {
  287. float3 pos = input[0].vertex.xyz;
  288.  
  289. float3 normal = input[0].normal;
  290. float4 tangent = input[0].tangent;
  291. float3 bitangent = cross(normal, tangent.xyz) * tangent.w;
  292.  
  293. float3x3 tangentToLocal = float3x3
  294. (
  295. tangent.x, bitangent.x, normal.x,
  296. tangent.y, bitangent.y, normal.y,
  297. tangent.z, bitangent.z, normal.z
  298. );
  299.  
  300. // Rotate around the y-axis a random amount.
  301. float3x3 randRotMatrix = angleAxis3x3(rand(pos) * UNITY_TWO_PI, float3(0, 0, 1.0f));
  302.  
  303. // Rotate around the bottom of the blade a random amount.
  304. float3x3 randBendMatrix = angleAxis3x3(rand(pos.zzx) * _BendDelta * UNITY_PI * 0.5f, float3(-1.0f, 0, 0));
  305.  
  306. float2 windUV = pos.xz * _WindMap_ST.xy + _WindMap_ST.zw + normalize(_WindVelocity.xzy) * _WindFrequency * _Time.y;
  307. float2 windSample = (tex2Dlod(_WindMap, float4(windUV, 0, 0)).xy * 2 - 1) * length(_WindVelocity);
  308.  
  309. float3 windAxis = normalize(float3(windSample.x, windSample.y, 0));
  310. float3x3 windMatrix = angleAxis3x3(UNITY_PI * windSample, windAxis);
  311.  
  312. // Transform the grass blades to the correct tangent space.
  313. float3x3 baseTransformationMatrix = mul(tangentToLocal, randRotMatrix);
  314. float3x3 tipTransformationMatrix = mul(mul(mul(tangentToLocal, windMatrix), randBendMatrix), randRotMatrix);
  315.  
  316. float falloff = smoothstep(_GrassThreshold, _GrassThreshold + _GrassFalloff, grassVisibility);
  317.  
  318. float width = lerp(_BladeWidthMin, _BladeWidthMax, rand(pos.xzy) * falloff);
  319. float height = lerp(_BladeHeightMin, _BladeHeightMax, rand(pos.zyx) * falloff);
  320. float forward = rand(pos.yyz) * _BladeBendDistance;
  321.  
  322. // Create blade segments by adding two vertices at once.
  323. for (int i = 0; i < BLADE_SEGMENTS; ++i)
  324. {
  325. float t = i / (float)BLADE_SEGMENTS;
  326. float3 offset = float3(width * (1 - t), pow(t, _BladeBendCurve) * forward, height * t);
  327.  
  328. float3x3 transformationMatrix = (i == 0) ? baseTransformationMatrix : tipTransformationMatrix;
  329.  
  330. triStream.Append(TransformGeomToClip(pos, float3( offset.x, offset.y, offset.z), transformationMatrix, float2(0, t)));
  331. triStream.Append(TransformGeomToClip(pos, float3(-offset.x, offset.y, offset.z), transformationMatrix, float2(1, t)));
  332. }
  333.  
  334. // Add the final vertex at the tip of the grass blade.
  335. triStream.Append(TransformGeomToClip(pos, float3(0, forward, height), tipTransformationMatrix, float2(0.5, 1)));
  336.  
  337. triStream.RestartStrip();
  338. }
  339. }
  340. ENDHLSL
  341.  
  342. // This pass draws the grass blades generated by the geometry shader.
  343. Pass
  344. {
  345. Name "GrassPass"
  346. Tags { "LightMode" = "UniversalForward" }
  347.  
  348. HLSLPROGRAM
  349. #pragma require geometry
  350. #pragma require tessellation tessHW
  351.  
  352. //#pragma vertex vert
  353. #pragma vertex geomVert
  354. #pragma hull hull
  355. #pragma domain domain
  356. #pragma geometry geom
  357. #pragma fragment frag
  358.  
  359. // The lighting sections of the frag shader taken from this helpful post by Ben Golus:
  360. // https://forum.unity.com/threads/water-shader-graph-transparency-and-shadows-universal-render-pipeline-order.748142/#post-5518747
  361. float4 frag (GeomData i) : SV_Target
  362. {
  363. float4 color = tex2D(_BladeTexture, i.uv);
  364.  
  365. #ifdef _MAIN_LIGHT_SHADOWS
  366. VertexPositionInputs vertexInput = (VertexPositionInputs)0;
  367. vertexInput.positionWS = i.worldPos;
  368.  
  369. float4 shadowCoord = GetShadowCoord(vertexInput);
  370. half shadowAttenuation = saturate(MainLightRealtimeShadow(shadowCoord) + 0.25f);
  371. float4 shadowColor = lerp(0.0f, 1.0f, shadowAttenuation);
  372. color *= shadowColor;
  373. #endif
  374.  
  375. return color * lerp(_BaseColor, _TipColor, i.uv.y);
  376. }
  377.  
  378. ENDHLSL
  379. }
  380.  
  381. Pass
  382. {
  383. Name "ShadowPass"
  384. Tags { "LightMode" = "ShadowCaster" }
  385.  
  386. HLSLPROGRAM
  387. #pragma require geometry
  388. #pragma require tessellation tessHW
  389.  
  390. //#pragma vertex vert
  391. #pragma vertex geomVert
  392. #pragma hull hull
  393. #pragma domain domain
  394. #pragma geometry geom
  395. #pragma fragment frag
  396.  
  397. float4 frag (GeomData i) : SV_Target
  398. {
  399. return 0;
  400. }
  401.  
  402. ENDHLSL
  403. }
  404. }
  405. }
  406.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement