在 Unity 着色器中波动浮点值
Fluctuate float value in an Unity shader
我试图在着色器内的两个值之间波动以实现发光效果。
我需要它在着色器本身内部完成,而不是通过 C# 脚本。
我尝试使用 Unity 为着色器动画提供的 _Time
值,但它不起作用:
Shader "Test shader" {
Properties {
_ColorTint ("Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_GlowColor("Glow Color", Color) = (1,0,0,1)
_GlowPower("Glow Power", Float) = 3.0
_UpDown("Shine Emitter Don't Change", Float) = 0
}
SubShader {
Tags {
"RenderType"="Opaque"
}
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : Color;
float2 uv_MainTex;
float3 viewDir;
float4 _Time;
};
float4 _ColorTint;
sampler2D _MainTex;
float4 _GlowColor;
float _GlowPower;
float _UpDown;
void surf(Input IN, inout SurfaceOutput o) {
if (_UpDown == 0) {
_GlowPower += _Time.y;
}
if (_UpDown == 1) {
_GlowPower -= _Time.y;
}
if (_GlowPower <= 1) {
_UpDown = 0;
}
if (_GlowPower >= 3) {
_UpDown = 1;
}
IN.color = _ColorTint;
o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * IN.color;
half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
o.Emission = _GlowColor.rgb * pow(rim, _GlowPower);
}
ENDCG
}
FallBack "Diffuse"
}
这使得辉光增长到无限。
我做错了什么?
稍微扩展一下我的评论:
在这种情况下不能使用_Time.y
,因为它是游戏开始后经过的时间,会随着时间增加。
可以用_SinTime.y
代替,代表sin(_Time.y)
。这意味着它在值 -1 和 1 之间振荡。您可以使用它并将(可能是 _SinTime 的缩放版本)分配给您的变量:_GlowPower = C * _SinTime.y
有关内置着色器变量的更多信息:http://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
为了做一个脉冲发光...我有一个脚本 'outside' 着色器并发送参数 (_GlowPower) 在 c# 脚本中计算,像这样....
glowPow = Mathf.Sin(time);
那你只需要计算一次就可以了。如果你把它放在顶点着色器中......它每个顶点执行一次,如果它在表面着色器中......那么每个像素一次=性能浪费。
你可以像这样将变量发送到你的着色器...(非常方便)
material.SetFloat(propertyName, valueToSend);
所以你可以发送,时间,强度,发光或任何你想要的。
如果您确实需要对每个顶点或每个像素进行发光计算,请使用
_glowPow = sin(_time);
在着色器内部。
我试图在着色器内的两个值之间波动以实现发光效果。
我需要它在着色器本身内部完成,而不是通过 C# 脚本。
我尝试使用 Unity 为着色器动画提供的 _Time
值,但它不起作用:
Shader "Test shader" {
Properties {
_ColorTint ("Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_GlowColor("Glow Color", Color) = (1,0,0,1)
_GlowPower("Glow Power", Float) = 3.0
_UpDown("Shine Emitter Don't Change", Float) = 0
}
SubShader {
Tags {
"RenderType"="Opaque"
}
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : Color;
float2 uv_MainTex;
float3 viewDir;
float4 _Time;
};
float4 _ColorTint;
sampler2D _MainTex;
float4 _GlowColor;
float _GlowPower;
float _UpDown;
void surf(Input IN, inout SurfaceOutput o) {
if (_UpDown == 0) {
_GlowPower += _Time.y;
}
if (_UpDown == 1) {
_GlowPower -= _Time.y;
}
if (_GlowPower <= 1) {
_UpDown = 0;
}
if (_GlowPower >= 3) {
_UpDown = 1;
}
IN.color = _ColorTint;
o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * IN.color;
half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
o.Emission = _GlowColor.rgb * pow(rim, _GlowPower);
}
ENDCG
}
FallBack "Diffuse"
}
这使得辉光增长到无限。
我做错了什么?
稍微扩展一下我的评论:
在这种情况下不能使用_Time.y
,因为它是游戏开始后经过的时间,会随着时间增加。
可以用_SinTime.y
代替,代表sin(_Time.y)
。这意味着它在值 -1 和 1 之间振荡。您可以使用它并将(可能是 _SinTime 的缩放版本)分配给您的变量:_GlowPower = C * _SinTime.y
有关内置着色器变量的更多信息:http://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
为了做一个脉冲发光...我有一个脚本 'outside' 着色器并发送参数 (_GlowPower) 在 c# 脚本中计算,像这样....
glowPow = Mathf.Sin(time);
那你只需要计算一次就可以了。如果你把它放在顶点着色器中......它每个顶点执行一次,如果它在表面着色器中......那么每个像素一次=性能浪费。
你可以像这样将变量发送到你的着色器...(非常方便)
material.SetFloat(propertyName, valueToSend);
所以你可以发送,时间,强度,发光或任何你想要的。
如果您确实需要对每个顶点或每个像素进行发光计算,请使用
_glowPow = sin(_time);
在着色器内部。