应该在每个渲染通道中重新计算顶点位置吗?

huangapple go评论90阅读模式
英文:

Should I recalculate vertex position for each pass?

问题

我目前正在学习HLSL和着色器语言,我在想是否应该为每个通道重新计算位置,还是是否有一种绕过的方法,因为我觉得这样做会有很多冗余计算。

下面是问题的示例,在这段代码中,我实例化了许多树形网格,并根据它们的实例ID计算每个树的随机位置。但我必须在前向通道和阴影投射通道中都计算它们的位置。非常感谢您的时间。 (+ 对代码的任何反馈将不胜感激)

  1. Shader "Tree Shader"
  2. {
  3. CGINCLUDE
  4. #include "UnityCG.cginc"
  5. #include "UnityLightingCommon.cginc"
  6. #pragma vertex vertex_shader
  7. #pragma fragment fragment_shader
  8. #pragma target 5.0
  9. uniform float _Radius;
  10. uniform float _WaveStartHeight;
  11. uniform int _InstanceCount;
  12. uniform sampler2D _MainTex;
  13. uniform float waveAmount;
  14. ENDCG
  15. Properties
  16. {
  17. _MainTex("Texture", 2D) = "white" {}
  18. }
  19. SubShader
  20. {
  21. Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }
  22. // 前向渲染通道
  23. Pass
  24. {
  25. Tags { "LightMode" = "ForwardBase" }
  26. Cull Off
  27. CGPROGRAM
  28. #pragma multi_compile_fwdbase
  29. struct APPDATA
  30. {
  31. half4 vertex : POSITION;
  32. half2 uv : TEXCOORD0;
  33. uint instanceID : SV_InstanceID;
  34. half3 normal : NORMAL;
  35. };
  36. struct SHADERDATA
  37. {
  38. half4 vertex : SV_POSITION;
  39. half2 uv : TEXCOORD0;
  40. fixed4 diff : COLOR0;
  41. };
  42. half4 ComputeScreenPos(half4 p)
  43. {
  44. half4 o = p * 0.5;
  45. return half4(o.x + o.w, o.y * _ProjectionParams.x + o.w, p.zw);
  46. }
  47. half3 GenerateRandomPosition(fixed instanceID)
  48. {
  49. half3 position;
  50. position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
  51. position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
  52. position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
  53. return position * _Radius;
  54. }
  55. SHADERDATA vertex_shader(APPDATA data)
  56. {
  57. SHADERDATA vs;
  58. half3 randomPosition = GenerateRandomPosition(data.instanceID);
  59. half waveAmount = 0.0;
  60. if (data.vertex.y >= _WaveStartHeight)
  61. {
  62. half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
  63. half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
  64. half fade = max(fadeX, fadeZ);
  65. fade = saturate(fade * 2.0 - 1.0);
  66. waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
  67. }
  68. vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
  69. vs.uv = data.uv;
  70. half3 worldNormal = UnityObjectToWorldNormal(data.normal);
  71. half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
  72. vs.diff = nl * _LightColor0;
  73. vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
  74. return vs;
  75. }
  76. half4 fragment_shader(SHADERDATA ps) : SV_Target
  77. {
  78. half4 color = tex2D(_MainTex, ps.uv);
  79. return color;
  80. }
  81. ENDCG
  82. }
  83. // 阴影投射通道
  84. Pass
  85. {
  86. Tags { "LightMode" = "ShadowCaster" }
  87. Cull Off
  88. ZWrite On
  89. ZTest LEqual
  90. Blend Zero One
  91. CGPROGRAM
  92. #pragma multi_compile_shadowcaster
  93. struct APPDATA
  94. {
  95. half4 vertex : POSITION;
  96. uint instanceID : SV_InstanceID;
  97. };
  98. struct SHADERDATA
  99. {
  100. half4 vertex : SV_POSITION;
  101. };
  102. half3 GenerateRandomPosition(fixed instanceID)
  103. {
  104. half3 position;
  105. position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
  106. position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
  107. position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
  108. return position * _Radius;
  109. }
  110. SHADERDATA vertex_shader(APPDATA data)
  111. {
  112. SHADERDATA vs;
  113. half3 randomPosition = GenerateRandomPosition(data.instanceID);
  114. half waveAmount = 0.0;
  115. if (data.vertex.y >= _WaveStartHeight)
  116. {
  117. half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
  118. half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
  119. half fade = max(fadeX, fadeZ);
  120. fade = saturate(fade * 2.0 - 1.0);
  121. waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
  122. }
  123. vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
  124. return vs;
  125. }
  126. half4 fragment_shader() : SV_Target
  127. {
  128. return half4(0, 0, 0, 0);
  129. }
  130. ENDCG
  131. }
  132. }
  133. }
英文:

im currently learning HLSL and shader language in general, and I was wondering if I should recalculate position for each pass or if there was a way around because it seems to me like a lot of redundant calculation.

Bellow is an exemple of the problem, in this code I instantiate a lot of tree mesh and calculate a random position for each of them based on there instance ID. But I have to calculate there position both in the forward pass and in the shadow casting pass. Thank you in advance for your time. (+ Any feedback on the code would be highly appreciated)

  1. Shader "Tree Shader"
  2. {
  3. CGINCLUDE
  4. #include "UnityCG.cginc"
  5. #include "UnityLightingCommon.cginc"
  6. #pragma vertex vertex_shader
  7. #pragma fragment fragment_shader
  8. #pragma target 5.0
  9. uniform float _Radius;
  10. uniform float _WaveStartHeight;
  11. uniform int _InstanceCount;
  12. uniform sampler2D _MainTex;
  13. uniform float waveAmount;
  14. ENDCG
  15. Properties
  16. {
  17. _MainTex("Texture", 2D) = "white" {}
  18. }
  19. SubShader
  20. {
  21. Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }
  22. // Forward Rendering Pass
  23. Pass
  24. {
  25. Tags { "LightMode" = "ForwardBase" }
  26. Cull Off
  27. CGPROGRAM
  28. #pragma multi_compile_fwdbase
  29. struct APPDATA
  30. {
  31. half4 vertex : POSITION;
  32. half2 uv : TEXCOORD0;
  33. uint instanceID : SV_InstanceID;
  34. half3 normal : NORMAL;
  35. };
  36. struct SHADERDATA
  37. {
  38. half4 vertex : SV_POSITION;
  39. half2 uv : TEXCOORD0;
  40. fixed4 diff : COLOR0;
  41. };
  42. half4 ComputeScreenPos(half4 p)
  43. {
  44. half4 o = p * 0.5;
  45. return half4(o.x + o.w, o.y * _ProjectionParams.x + o.w, p.zw);
  46. }
  47. half3 GenerateRandomPosition(fixed instanceID)
  48. {
  49. half3 position;
  50. position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
  51. position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
  52. position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
  53. return position * _Radius;
  54. }
  55. SHADERDATA vertex_shader(APPDATA data)
  56. {
  57. SHADERDATA vs;
  58. half3 randomPosition = GenerateRandomPosition(data.instanceID);
  59. half waveAmount = 0.0;
  60. if (data.vertex.y >= _WaveStartHeight)
  61. {
  62. half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
  63. half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
  64. half fade = max(fadeX, fadeZ);
  65. fade = saturate(fade * 2.0 - 1.0);
  66. waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
  67. }
  68. vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
  69. vs.uv = data.uv;
  70. half3 worldNormal = UnityObjectToWorldNormal(data.normal);
  71. half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
  72. vs.diff = nl * _LightColor0;
  73. vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
  74. return vs;
  75. }
  76. half4 fragment_shader(SHADERDATA ps) : SV_Target
  77. {
  78. half4 color = tex2D(_MainTex, ps.uv);
  79. return color;
  80. }
  81. ENDCG
  82. }
  83. Pass
  84. {
  85. Tags { "LightMode" = "ShadowCaster" }
  86. Cull Off
  87. ZWrite On
  88. ZTest LEqual
  89. Blend Zero One
  90. CGPROGRAM
  91. #pragma multi_compile_shadowcaster
  92. struct APPDATA
  93. {
  94. half4 vertex : POSITION;
  95. uint instanceID : SV_InstanceID;
  96. };
  97. struct SHADERDATA
  98. {
  99. half4 vertex : SV_POSITION;
  100. };
  101. half3 GenerateRandomPosition(fixed instanceID)
  102. {
  103. half3 position;
  104. position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
  105. position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
  106. position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
  107. return position * _Radius;
  108. }
  109. SHADERDATA vertex_shader(APPDATA data)
  110. {
  111. SHADERDATA vs;
  112. half3 randomPosition = GenerateRandomPosition(data.instanceID);
  113. half waveAmount = 0.0;
  114. if (data.vertex.y >= _WaveStartHeight)
  115. {
  116. half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
  117. half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
  118. half fade = max(fadeX, fadeZ);
  119. fade = saturate(fade * 2.0 - 1.0);
  120. waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
  121. }
  122. vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
  123. return vs;
  124. }
  125. half4 fragment_shader() : SV_Target
  126. {
  127. return half4(0, 0, 0, 0);
  128. }
  129. ENDCG
  130. }
  131. }
  132. }

答案1

得分: 0

如果您想要正确的阴影效果,那么需要重新计算顶点位置。您可以将通用代码提取到SubShader中,并将其包装在CGINCLUDE/ENDCG内。

英文:

If you want correct shadows, then the vertex position recaculation is necessary. You can extract the common code into SubShader and wrap it inside CGINCLUDE/ENDCG.

答案2

得分: 0

我修复了你在评论中粘贴的代码中的错误。

  1. Shader "Tree Shader"
  2. {
  3. Properties
  4. {
  5. _MainTex("Texture", 2D) = "white" {}
  6. }
  7. SubShader
  8. {
  9. Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }
  10. CGINCLUDE
  11. #include "UnityCG.cginc"
  12. #include "UnityLightingCommon.cginc"
  13. struct APPDATA
  14. {
  15. half4 vertex : POSITION;
  16. half2 uv : TEXCOORD0;
  17. uint instanceID : SV_InstanceID;
  18. half3 normal : NORMAL;
  19. };
  20. struct SHADERDATA
  21. {
  22. half4 vertex : POSITION;
  23. half2 uv : TEXCOORD0;
  24. fixed4 diff : COLOR0;
  25. };
  26. ENDCG
  27. // Forward Rendering Pass
  28. Pass
  29. {
  30. Tags { "LightMode" = "ForwardBase" }
  31. Cull Off
  32. CGPROGRAM
  33. #pragma target 5.0
  34. #pragma multi_compile_fwdbase
  35. #pragma vertex vertex_shader
  36. #pragma fragment fragment_shader
  37. uniform float _Radius;
  38. uniform float _WaveStartHeight;
  39. uniform int _InstanceCount;
  40. uniform sampler2D _MainTex;
  41. uniform float waveAmount;
  42. SHADERDATA vertex_shader(APPDATA data)
  43. {
  44. SHADERDATA vs;
  45. half waveAmount = 0.0;
  46. half3 randomPosition = half3(
  47. frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
  48. frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
  49. frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
  50. );
  51. if (data.vertex.y >= _WaveStartHeight)
  52. {
  53. half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
  54. half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
  55. half fade = max(fadeX, fadeZ);
  56. fade = saturate(fade * 2.0 - 1.0);
  57. waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
  58. }
  59. vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
  60. vs.uv = data.uv;
  61. half3 worldNormal = UnityObjectToWorldNormal(data.normal);
  62. half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
  63. vs.diff = nl * _LightColor0;
  64. vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
  65. return vs;
  66. }
  67. half4 fragment_shader(SHADERDATA ps) : SV_Target
  68. {
  69. half4 color = tex2D(_MainTex, ps.uv);
  70. return color;
  71. }
  72. ENDCG
  73. }
  74. Pass
  75. {
  76. Tags { "LightMode" = "ShadowCaster" }
  77. Cull Off
  78. ZWrite On
  79. ZTest LEqual
  80. Blend Zero One
  81. CGPROGRAM
  82. #pragma target 5.0
  83. #pragma multi_compile_shadowcaster
  84. #pragma vertex vertex_shader
  85. #pragma fragment fragment_shader
  86. uniform float _Radius;
  87. uniform float _WaveStartHeight;
  88. uniform int _InstanceCount;
  89. uniform sampler2D _MainTex;
  90. uniform float waveAmount;
  91. SHADERDATA vertex_shader(APPDATA data)
  92. {
  93. SHADERDATA vs = (SHADERDATA)0;
  94. half waveAmount = 0.0;
  95. if (data.vertex.y >= _WaveStartHeight)
  96. {
  97. half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
  98. half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
  99. half fade = max(fadeX, fadeZ);
  100. fade = saturate(fade * 2.0 - 1.0);
  101. waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
  102. }
  103. half3 randomPosition = half3(
  104. frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
  105. frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
  106. frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
  107. );
  108. vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
  109. return vs;
  110. }
  111. half4 fragment_shader(SHADERDATA ps) : SV_Target
  112. {
  113. return half4(0, 0, 0, 0);
  114. }
  115. ENDCG
  116. }
  117. }
  118. }
英文:

I fixed the errors in your code that you paste in the comment.

  1. Shader "Tree Shader"
  2. {
  3. Properties
  4. {
  5. _MainTex("Texture", 2D) = "white" {}
  6. }
  7. SubShader
  8. {
  9. Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }
  10. CGINCLUDE
  11. #include "UnityCG.cginc"
  12. #include "UnityLightingCommon.cginc"
  13. struct APPDATA
  14. {
  15. half4 vertex : POSITION;
  16. half2 uv : TEXCOORD0;
  17. uint instanceID : SV_InstanceID;
  18. half3 normal : NORMAL;
  19. };
  20. struct SHADERDATA
  21. {
  22. half4 vertex : POSITION;
  23. half2 uv : TEXCOORD0;
  24. fixed4 diff : COLOR0;
  25. };
  26. ENDCG
  27. // Forward Rendering Pass
  28. Pass
  29. {
  30. Tags { "LightMode" = "ForwardBase" }
  31. Cull Off
  32. CGPROGRAM
  33. #pragma target 5.0
  34. #pragma multi_compile_fwdbase
  35. #pragma vertex vertex_shader
  36. #pragma fragment fragment_shader
  37. uniform float _Radius;
  38. uniform float _WaveStartHeight;
  39. uniform int _InstanceCount;
  40. uniform sampler2D _MainTex;
  41. uniform float waveAmount;
  42. SHADERDATA vertex_shader(APPDATA data)
  43. {
  44. SHADERDATA vs;
  45. half waveAmount = 0.0;
  46. half3 randomPosition = half3(
  47. frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
  48. frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
  49. frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
  50. );
  51. if (data.vertex.y >= _WaveStartHeight)
  52. {
  53. half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
  54. half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
  55. half fade = max(fadeX, fadeZ);
  56. fade = saturate(fade * 2.0 - 1.0);
  57. waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
  58. }
  59. vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
  60. vs.uv = data.uv;
  61. half3 worldNormal = UnityObjectToWorldNormal(data.normal);
  62. half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
  63. vs.diff = nl * _LightColor0;
  64. vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
  65. return vs;
  66. }
  67. half4 fragment_shader(SHADERDATA ps) : SV_Target
  68. {
  69. half4 color = tex2D(_MainTex, ps.uv);
  70. return color;
  71. }
  72. ENDCG
  73. }
  74. Pass
  75. {
  76. Tags { "LightMode" = "ShadowCaster" }
  77. Cull Off
  78. ZWrite On
  79. ZTest LEqual
  80. Blend Zero One
  81. CGPROGRAM
  82. #pragma target 5.0
  83. #pragma multi_compile_shadowcaster
  84. #pragma vertex vertex_shader
  85. #pragma fragment fragment_shader
  86. uniform float _Radius;
  87. uniform float _WaveStartHeight;
  88. uniform int _InstanceCount;
  89. uniform sampler2D _MainTex;
  90. uniform float waveAmount;
  91. SHADERDATA vertex_shader(APPDATA data)
  92. {
  93. SHADERDATA vs = (SHADERDATA)0;
  94. half waveAmount = 0.0;
  95. if (data.vertex.y >= _WaveStartHeight)
  96. {
  97. half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
  98. half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
  99. half fade = max(fadeX, fadeZ);
  100. fade = saturate(fade * 2.0 - 1.0);
  101. waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
  102. }
  103. half3 randomPosition = half3(
  104. frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
  105. frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
  106. frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
  107. );
  108. vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
  109. return vs;
  110. }
  111. half4 fragment_shader(SHADERDATA ps) : SV_Target
  112. {
  113. return half4(0, 0, 0, 0);
  114. }
  115. ENDCG
  116. }
  117. }
  118. }

huangapple
  • 本文由 发表于 2023年7月3日 04:11:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76600605.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定