Unity 3D次表面着色器设置正常以适当的照明

时间:2018-03-08 12:32:28

标签: unity3d shader cg

我正在尝试使用sin函数在Unity 2017.1.0f3中编写一个简单的类似波形的着色器,但是它是一个未定义的一种颜色形状而没有重新定义法线,因此它可以使阴影正确。然而,尽管我的数学,我似乎无法让这些法线看起来正确,正如你在GIF中看到的那样,它们都是超级混乱。

The Wave

所以这就是我正在做的事情:

void vert(inout appdata_full v, out Input o)
{
    UNITY_INITIALIZE_OUTPUT(Input, o);

    //Just basing the height of the wave on distance from the center and time

    half offsetvert = o.offsetVert = ((v.vertex.x*v.vertex.x) + (v.vertex.z * v.vertex.z))*100;//The 100 is to compensate for the massive scaling of the object
    half value = _Scale * sin(-_Time.w * _Speed + offsetvert * _Frequency)/100;

    v.vertex.y += value;
    o.pos = v.vertex.xyz;

}

// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_CBUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_CBUFFER_END

void surf (Input IN, inout SurfaceOutputStandard o) 
{

    //Calculate new normals

    //Refer to MATH (1) for how I'm getting the y
    float3 norm = (0,sqrt(1/(1+1/(-100/(_Scale*_Frequency*cos(_Time.w * _Speed + IN.offsetVert * _Frequency))))),0);

    //Refer to Math (2) for how I'm getting the x and z
    float derrivative = _Scale*_Frequency*cos(-_Time.w * _Speed + IN.offsetVert * _Frequency)/100;
    float3 norm = (0,sqrt(1/(1+1/(-1/(derrivative)))),0);
    float remaining = 1 - pow(norm.y,2);
    norm.x = sqrt(remaining/(1 + IN.pos.z*IN.pos.z/(IN.pos.x*IN.pos.x)));
    norm.z = sqrt(1-norm.y*norm.y-norm.x*norm.x);

    //Assume this is facing away from the center
    if (IN.pos.z<0)
        norm.z = -norm.z;
    if (IN.pos.x<0)
        norm.x = -norm.x;

    //Flip the direction if necessary
    if (derrivative > 0){
        norm.x = -norm.x;
        norm.z = -norm.z;
    }

    norm.y = abs(norm.y);
    norm = normalize(norm);//Just to be safe

    o.Albedo = _Color.rgb;

    // Metallic and smoothness come from slider variables
    o.Metallic = _Metallic;
    o.Smoothness = _Glossiness;
    o.Alpha = c.a;
    o.Normal.xyz = norm;
}

MATH 1 如果y是距离的函数

  

y =(scale / 100)sin(time.w * speed + distance * frequency)

然后

  

dy / d(距离)=(比例/ 100)*频率* cos(time.w *速度+距离*频率)

制作

法线的渐变
  

y /(某些x和z方向)-100 /(标度*频率* cos(time.w *速度+距离*频率))。

我们也知道

  

(y分量)^ 2 +(某些xz分量)^ 2 = 1,

     

其中

     

(y分量)/(某些xz分量)=定义的正常梯度。

解决这两个联立方程式

  

y component = sqrt(1 /(1 + 1 /(gradient ^ 2)))

MATH 2 我们知道

  

(x分量)/(z分量)=(x位置)/(z位置)

和毕达哥拉斯,

  

(x分量)^ 2 +(z分量)^ 2 = 1 - (y分量)^ 2

并解决这些联立方程式

  

x component = sqrt((1 - (y component)^ 2)/(1 +(z position / x position)^ 2))

然后我们可以通过Pythagoras获得z组件。

如果你弄清楚出了什么问题,请告诉我。)

1 个答案:

答案 0 :(得分:0)

为什么要计算曲面函数的法线?这是每个片段完成的,效率很低。为什么不仅仅计算顶点函数中的法线?

我要做的是与顶点偏移量相同的计算,只不过是针对从顶点在X和Y方向上偏移的另外两个点再次进行计算-然后您使用向量之间的叉积和偏移顶点以获得法线。

假设您已将偏移量移至其自己的函数,该函数将坐标作为参数。然后,您可以这样做:

float3 offsetPos = VertexOffset(v.vertex.xy)
float3 offsetPosX = offsetPos - VertexOffset(v.vertex.xy + float2(0.1, 0))
float3 offsetPosY = offsetPos - VertexOffset(v.vertex.xy + float2(0, 0.1))

v.vertex.xyz = offsetPos
v.normal.xyz = cross(normalize(offsetPosX), normalize(offsetPosY))