英文:
Should I recalculate vertex position for each pass?
问题
我目前正在学习HLSL和着色器语言,我在想是否应该为每个通道重新计算位置,还是是否有一种绕过的方法,因为我觉得这样做会有很多冗余计算。
下面是问题的示例,在这段代码中,我实例化了许多树形网格,并根据它们的实例ID计算每个树的随机位置。但我必须在前向通道和阴影投射通道中都计算它们的位置。非常感谢您的时间。 (+ 对代码的任何反馈将不胜感激)
Shader "Tree Shader"
{
CGINCLUDE
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
#pragma vertex vertex_shader
#pragma fragment fragment_shader
#pragma target 5.0
uniform float _Radius;
uniform float _WaveStartHeight;
uniform int _InstanceCount;
uniform sampler2D _MainTex;
uniform float waveAmount;
ENDCG
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }
// 前向渲染通道
Pass
{
Tags { "LightMode" = "ForwardBase" }
Cull Off
CGPROGRAM
#pragma multi_compile_fwdbase
struct APPDATA
{
half4 vertex : POSITION;
half2 uv : TEXCOORD0;
uint instanceID : SV_InstanceID;
half3 normal : NORMAL;
};
struct SHADERDATA
{
half4 vertex : SV_POSITION;
half2 uv : TEXCOORD0;
fixed4 diff : COLOR0;
};
half4 ComputeScreenPos(half4 p)
{
half4 o = p * 0.5;
return half4(o.x + o.w, o.y * _ProjectionParams.x + o.w, p.zw);
}
half3 GenerateRandomPosition(fixed instanceID)
{
half3 position;
position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
return position * _Radius;
}
SHADERDATA vertex_shader(APPDATA data)
{
SHADERDATA vs;
half3 randomPosition = GenerateRandomPosition(data.instanceID);
half waveAmount = 0.0;
if (data.vertex.y >= _WaveStartHeight)
{
half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
half fade = max(fadeX, fadeZ);
fade = saturate(fade * 2.0 - 1.0);
waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
}
vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
vs.uv = data.uv;
half3 worldNormal = UnityObjectToWorldNormal(data.normal);
half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
vs.diff = nl * _LightColor0;
vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
return vs;
}
half4 fragment_shader(SHADERDATA ps) : SV_Target
{
half4 color = tex2D(_MainTex, ps.uv);
return color;
}
ENDCG
}
// 阴影投射通道
Pass
{
Tags { "LightMode" = "ShadowCaster" }
Cull Off
ZWrite On
ZTest LEqual
Blend Zero One
CGPROGRAM
#pragma multi_compile_shadowcaster
struct APPDATA
{
half4 vertex : POSITION;
uint instanceID : SV_InstanceID;
};
struct SHADERDATA
{
half4 vertex : SV_POSITION;
};
half3 GenerateRandomPosition(fixed instanceID)
{
half3 position;
position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
return position * _Radius;
}
SHADERDATA vertex_shader(APPDATA data)
{
SHADERDATA vs;
half3 randomPosition = GenerateRandomPosition(data.instanceID);
half waveAmount = 0.0;
if (data.vertex.y >= _WaveStartHeight)
{
half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
half fade = max(fadeX, fadeZ);
fade = saturate(fade * 2.0 - 1.0);
waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
}
vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
return vs;
}
half4 fragment_shader() : SV_Target
{
return half4(0, 0, 0, 0);
}
ENDCG
}
}
}
英文:
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)
Shader "Tree Shader"
{
CGINCLUDE
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
#pragma vertex vertex_shader
#pragma fragment fragment_shader
#pragma target 5.0
uniform float _Radius;
uniform float _WaveStartHeight;
uniform int _InstanceCount;
uniform sampler2D _MainTex;
uniform float waveAmount;
ENDCG
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }
// Forward Rendering Pass
Pass
{
Tags { "LightMode" = "ForwardBase" }
Cull Off
CGPROGRAM
#pragma multi_compile_fwdbase
struct APPDATA
{
half4 vertex : POSITION;
half2 uv : TEXCOORD0;
uint instanceID : SV_InstanceID;
half3 normal : NORMAL;
};
struct SHADERDATA
{
half4 vertex : SV_POSITION;
half2 uv : TEXCOORD0;
fixed4 diff : COLOR0;
};
half4 ComputeScreenPos(half4 p)
{
half4 o = p * 0.5;
return half4(o.x + o.w, o.y * _ProjectionParams.x + o.w, p.zw);
}
half3 GenerateRandomPosition(fixed instanceID)
{
half3 position;
position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
return position * _Radius;
}
SHADERDATA vertex_shader(APPDATA data)
{
SHADERDATA vs;
half3 randomPosition = GenerateRandomPosition(data.instanceID);
half waveAmount = 0.0;
if (data.vertex.y >= _WaveStartHeight)
{
half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
half fade = max(fadeX, fadeZ);
fade = saturate(fade * 2.0 - 1.0);
waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
}
vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
vs.uv = data.uv;
half3 worldNormal = UnityObjectToWorldNormal(data.normal);
half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
vs.diff = nl * _LightColor0;
vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
return vs;
}
half4 fragment_shader(SHADERDATA ps) : SV_Target
{
half4 color = tex2D(_MainTex, ps.uv);
return color;
}
ENDCG
}
Pass
{
Tags { "LightMode" = "ShadowCaster" }
Cull Off
ZWrite On
ZTest LEqual
Blend Zero One
CGPROGRAM
#pragma multi_compile_shadowcaster
struct APPDATA
{
half4 vertex : POSITION;
uint instanceID : SV_InstanceID;
};
struct SHADERDATA
{
half4 vertex : SV_POSITION;
};
half3 GenerateRandomPosition(fixed instanceID)
{
half3 position;
position.x = frac(sin(dot(half2(instanceID, 12.345), half2(12.345, 67.890))) * 123.456);
position.y = frac(sin(dot(half2(instanceID, 98.765), half2(43.210, 9.876))) * 654.321);
position.z = frac(sin(dot(half2(instanceID, 0.123), half2(0.987, 6.543))) * 987.654);
return position * _Radius;
}
SHADERDATA vertex_shader(APPDATA data)
{
SHADERDATA vs;
half3 randomPosition = GenerateRandomPosition(data.instanceID);
half waveAmount = 0.0;
if (data.vertex.y >= _WaveStartHeight)
{
half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
half fade = max(fadeX, fadeZ);
fade = saturate(fade * 2.0 - 1.0);
waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
}
vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
return vs;
}
half4 fragment_shader() : SV_Target
{
return half4(0, 0, 0, 0);
}
ENDCG
}
}
}
答案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
我修复了你在评论中粘贴的代码中的错误。
Shader "Tree Shader"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }
CGINCLUDE
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
struct APPDATA
{
half4 vertex : POSITION;
half2 uv : TEXCOORD0;
uint instanceID : SV_InstanceID;
half3 normal : NORMAL;
};
struct SHADERDATA
{
half4 vertex : POSITION;
half2 uv : TEXCOORD0;
fixed4 diff : COLOR0;
};
ENDCG
// Forward Rendering Pass
Pass
{
Tags { "LightMode" = "ForwardBase" }
Cull Off
CGPROGRAM
#pragma target 5.0
#pragma multi_compile_fwdbase
#pragma vertex vertex_shader
#pragma fragment fragment_shader
uniform float _Radius;
uniform float _WaveStartHeight;
uniform int _InstanceCount;
uniform sampler2D _MainTex;
uniform float waveAmount;
SHADERDATA vertex_shader(APPDATA data)
{
SHADERDATA vs;
half waveAmount = 0.0;
half3 randomPosition = half3(
frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
);
if (data.vertex.y >= _WaveStartHeight)
{
half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
half fade = max(fadeX, fadeZ);
fade = saturate(fade * 2.0 - 1.0);
waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
}
vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
vs.uv = data.uv;
half3 worldNormal = UnityObjectToWorldNormal(data.normal);
half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
vs.diff = nl * _LightColor0;
vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
return vs;
}
half4 fragment_shader(SHADERDATA ps) : SV_Target
{
half4 color = tex2D(_MainTex, ps.uv);
return color;
}
ENDCG
}
Pass
{
Tags { "LightMode" = "ShadowCaster" }
Cull Off
ZWrite On
ZTest LEqual
Blend Zero One
CGPROGRAM
#pragma target 5.0
#pragma multi_compile_shadowcaster
#pragma vertex vertex_shader
#pragma fragment fragment_shader
uniform float _Radius;
uniform float _WaveStartHeight;
uniform int _InstanceCount;
uniform sampler2D _MainTex;
uniform float waveAmount;
SHADERDATA vertex_shader(APPDATA data)
{
SHADERDATA vs = (SHADERDATA)0;
half waveAmount = 0.0;
if (data.vertex.y >= _WaveStartHeight)
{
half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
half fade = max(fadeX, fadeZ);
fade = saturate(fade * 2.0 - 1.0);
waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
}
half3 randomPosition = half3(
frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
);
vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
return vs;
}
half4 fragment_shader(SHADERDATA ps) : SV_Target
{
return half4(0, 0, 0, 0);
}
ENDCG
}
}
}
英文:
I fixed the errors in your code that you paste in the comment.
Shader "Tree Shader"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "IgnoreProjector" = "False" "DisableBatching" = "True" }
CGINCLUDE
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
struct APPDATA
{
half4 vertex : POSITION;
half2 uv : TEXCOORD0;
uint instanceID : SV_InstanceID;
half3 normal : NORMAL;
};
struct SHADERDATA
{
half4 vertex : POSITION;
half2 uv : TEXCOORD0;
fixed4 diff : COLOR0;
};
ENDCG
// Forward Rendering Pass
Pass
{
Tags { "LightMode" = "ForwardBase" }
Cull Off
CGPROGRAM
#pragma target 5.0
#pragma multi_compile_fwdbase
#pragma vertex vertex_shader
#pragma fragment fragment_shader
uniform float _Radius;
uniform float _WaveStartHeight;
uniform int _InstanceCount;
uniform sampler2D _MainTex;
uniform float waveAmount;
SHADERDATA vertex_shader(APPDATA data)
{
SHADERDATA vs;
half waveAmount = 0.0;
half3 randomPosition = half3(
frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
);
if (data.vertex.y >= _WaveStartHeight)
{
half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
half fade = max(fadeX, fadeZ);
fade = saturate(fade * 2.0 - 1.0);
waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
}
vs.vertex = mul(UNITY_MATRIX_VP, half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
vs.uv = data.uv;
half3 worldNormal = UnityObjectToWorldNormal(data.normal);
half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
vs.diff = nl * _LightColor0;
vs.diff.rgb += ShadeSH9(half4(worldNormal, 1));
return vs;
}
half4 fragment_shader(SHADERDATA ps) : SV_Target
{
half4 color = tex2D(_MainTex, ps.uv);
return color;
}
ENDCG
}
Pass
{
Tags { "LightMode" = "ShadowCaster" }
Cull Off
ZWrite On
ZTest LEqual
Blend Zero One
CGPROGRAM
#pragma target 5.0
#pragma multi_compile_shadowcaster
#pragma vertex vertex_shader
#pragma fragment fragment_shader
uniform float _Radius;
uniform float _WaveStartHeight;
uniform int _InstanceCount;
uniform sampler2D _MainTex;
uniform float waveAmount;
SHADERDATA vertex_shader(APPDATA data)
{
SHADERDATA vs = (SHADERDATA)0;
half waveAmount = 0.0;
if (data.vertex.y >= _WaveStartHeight)
{
half fadeX = 1.0 - abs(data.vertex.x) / (_Radius * 0.5);
half fadeZ = 1.0 - abs(data.vertex.z) / (_Radius * 0.5);
half fade = max(fadeX, fadeZ);
fade = saturate(fade * 2.0 - 1.0);
waveAmount = sin(data.instanceID * 0.1 + _Time.y * 2.0) * 0.1 * fade;
}
half3 randomPosition = half3(
frac(sin(dot(half2(data.instanceID, 12.345), half2(12.345, 67.890))) * 123.456),
frac(sin(dot(half2(data.instanceID, 98.765), half2(43.210, 9.876))) * 654.321),
frac(sin(dot(half2(data.instanceID, 0.123), half2(0.987, 6.543))) * 987.654)
);
vs.vertex = UnityObjectToClipPos(half4(randomPosition.x + waveAmount, 0, randomPosition.z + waveAmount, 0) + data.vertex);
return vs;
}
half4 fragment_shader(SHADERDATA ps) : SV_Target
{
return half4(0, 0, 0, 0);
}
ENDCG
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论