问题描述
我创建了一个带有以下节点的脉动闪亮效果:
Abs(Time * speed) => sine
我的振荡值介于0到1之间,但问题是该值可能从0到1之间的任何值开始,具体取决于时间值。
我正在尝试找出一种方法,可以在着色器之外获取该值,以便脚本可以将属性设置为offset:
float offset = GetTimeFromShader();
material.SetFloat("_Offset",offset);
并且着色器最终以:
Abs((Time - offset) * speed) => sine
这将确保脉动从0开始。
另一种可能性是在着色器中创建一个递增的vector1来模拟:
temp += Time.deltaTime * speed;
但是Shader图可以防止节点循环。
我可以在脚本中完成此操作并将其传递给着色器属性,但是如果有一种方法可以将其全部保留在着色器中。
解决方法
我认为问题在于,无法保证在开始渲染着色器时Time的值是多少。这也意味着提供偏移量是没有意义的,因为您不知道偏移量需要为多少(并且可能每次都在变化)。要执行您要的操作,需要使用脚本化的MaterialPropertyBlock
设置的着色器属性。
我有一个介于 0 和 1 之间的振荡值,但问题是 该值可以从 0 到 1 之间的任何值开始,具体取决于 时间价值。
这就是你的问题。你可以很容易地改变你的着色器,而不是让振荡从 0 开始并且独立于内置的着色器时间,不是吗?这将意味着从您不想要的脚本驱动着色器,但我认为在这种情况下这不是不好的做法,因为听起来您希望振荡直接与游戏中的特定事件相关联- 所以尝试将着色器代码与应用程序代码分离开来这里有点多余 - 它们需要以某种方式链接到某处。
为了将您的着色器与内置着色器时间分离,而不是将 Abs(Time * speed)
替换为您控制的属性,即 Abs(phase * speed)
。
我使用以下代码来播放冲击波效果,并始终确保它从我想要的位置开始:
// ensures shockwave plays once and does a full wave over duration
IEnumerator PlayShockwave(float duration,Renderer shockwave)
{
float timeElapsed = 0f;
float speed = Mathf.Abs(shockwave.material.GetFloat("_Speed"));
float phase = shockwave.material.GetFloat("_Phase");
float targetPhase = 1 / speed;
while (timeElapsed <= duration)
{
timeElapsed += Time.deltaTime;
shockwave.material.SetFloat("_Phase",Mathf.Lerp(phase,targetPhase,timeElapsed / duration));
yield return new WaitForEndOfFrame();
}
}
并用 StartCoroutine(PlayShockwave(2.0f,YourRenderer));