Unity Shader Normals错误

时间:2017-01-21 06:29:34

标签: opengl unity3d shader

只是想知道是否有人可以伸出援手,到目前为止花了好几个小时:

enter image description here

有谁知道为什么会这样?随着我的移动,底部总是比顶部更亮。

vert的基本流程: *获得+ X点和+ Z点,以便稍后用于交叉乘法以获得正常

*将这些点转换为世界空间,以便我可以在现实空间中寻找障碍物

*计算出我们的点的y轴位移+第一步中为交叉

制作的额外内容

*按位移增加对象空间值

*使用交叉

找到新常态

*设置正常

*设置顶点。

我认为正在发生的是法线在错误的轴上......任何帮助都会出现

enter image description here

Shader "Custom/ExtrudePointArray" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness("Smoothness", Range(0,1)) = 0.5
        _Metallic("Metallic", Range(0,1)) = 0.0

            //water stuff
            _Scale("Scale", float) = 1
            _Speed("Speed", float) = 1
            _Frequency("Frequency", float) = 1

            // wave maker
            _Height("_Height", float) = 1.0
            _Extrude_Close("_Extrude_Close", float) = 3.0

            [HideInInspector]_ExtrudePointCount("_ExtrudePointCount", int) = 0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows  vertex:vert

        //debug normals
//#pragma surface surf Standard fullforwardshadows  vertex:vert finalcolor:showNormals

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 4.0

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
            float3 newNormal;
            half3 debugColor;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        // water stuff
        float _Scale, _Speed, _Frequency;


        float _Extrude_Close, _Height;
        uniform float _ExtrudePointX[20], _ExtrudePointZ[20], _ExtrudePointCount;

        float calcWaveHeight(float2 worvldLoc) {
            //disruption
            half offsetvertDis = ((worvldLoc.x * worvldLoc.x) + (worvldLoc.y * worvldLoc.y));
            half valueDis = _Scale * sin(_Time.w * _Speed + offsetvertDis * _Frequency*1000);
            // diag wave
            half offsetvertDiag =  worvldLoc.x +worvldLoc.y;
            half valueDiag = _Scale * sin(_Time.w * _Speed * _Frequency + offsetvertDiag);

            return valueDis + valueDiag;
        }

        float calcDistFromPoint(float2 worldLoc, float2 pointToCheck) {
            float closePercent = 0;
            float dist = abs(distance(worldLoc, pointToCheck));

            if (dist < _Extrude_Close) {
                closePercent = (_Extrude_Close - dist / _Extrude_Close);
            }
            return closePercent;
        }

        float calcVertNewPos(float3 worldLoc) {
            float highestPos = 0;
            float2 worldLocHor = float2(worldLoc.x, worldLoc.z);

            for (int i = 0; i < _ExtrudePointCount; i++) {
                float2 boxPos = float2(_ExtrudePointX[i], _ExtrudePointZ[i]);

                float newPos = calcDistFromPoint(worldLocHor, boxPos) * _Height;

                // the value returned is a float so don't check for zero, check that it's not above zero
                if (newPos < 0.001) {
                    newPos = calcWaveHeight(worldLocHor);
                }

                if (newPos > highestPos) {
                    highestPos = newPos;
                }
                //highestPos = worldLoc.x * i;
            }

            return highestPos;
        }

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

            float3 v0 = v.vertex.xyz;
            float3 v1 = v0 + float3(0.05, 0, 0); // +X
            float3 v2 = v0 + float3(0, 0, 0.05); // +Z

            float3 w0 = mul(unity_ObjectToWorld, v.vertex).xyz;
            float3 w1 = w0 + float3(0.05, 0, 0); // +X
            float3 w2 = w0 + float3(0, 0, 0.05); // +Z

            float h0 = calcVertNewPos(w0);
            float h1 = calcVertNewPos(w1);
            float h2 = calcVertNewPos(w2);

            v0.y = h0;
            v1.y = h1;
            v2.y = h2;

            float3 vna = cross(v2 - v0, v1 - v0);

            // debug
            //o.debugColor = (normalize(v0) * 0.5) + 0.5;
            //o.debugColor = (normalize(v.vertex.xyz) * 0.5) + 0.5;
            //o.debugColor = (normalize(vna) * 0.5) + 0.5;

            // Put normals back in object space
            //float3x3 worlspace = float3x3(unity_WorldToObject.xyz);

            v.normal = normalize(vna);
            o.newNormal = v.normal;

            v.vertex.xyz = v0;
        }

        void showNormals(Input IN, SurfaceOutputStandard o, inout fixed4 color) {
            color.rgb = IN.debugColor.rgb;
            color.a = 1;
        }

        void surf (Input IN, inout SurfaceOutputStandard o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
            o.Normal = IN.newNormal;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

我知道我几乎肯定会做出错误的判断正常计算。但是我找不到任何好的资源而且我找到了唯一的东西:https://www.youtube.com/watch?v=1G37-Yav2ZM是为了早期版本的着色器语言和下载源的网站现在是恶意软件:(这是杀了我

此处还有运行着色器挤出点的代码(如果需要):

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ExtrudePoint : MonoBehaviour {

    public GameObject[] Waves;
    private Renderer _renderer;

    // Use this for initialization
    void Start()
    {
        if (Waves == null || Waves.Length > 8)
        {
            throw new Exception("Max of 8 waves, min of 1");
        }

        _renderer = GetComponent<Renderer>();

    }

    // Update is called once per frame
    void Update()
    {
        int totWaves = 0;
        // probably slow
        var floatArrayX = new float[Waves.Length];
        var floatArrayZ = new float[Waves.Length];
        for (var i = 0; i < Waves.Length; i++)
        {
            var wave = Waves[i];
            if (wave != null)
            {
                totWaves++;
                floatArrayX[totWaves - 1] = wave.gameObject.transform.position.x;
                floatArrayZ[totWaves - 1] = wave.gameObject.transform.position.z;
                //_renderer.material.SetFloat(WavePointExtruderConstants._ExtrudePointX, wave.gameObject.transform.position.x);
                //_renderer.material.SetFloat(WavePointExtruderConstants._ExtrudePointZ, wave.gameObject.transform.position.z);

                //Debug.Log(wave.gameObject.transform.position);
            }
        }

        // probably slow
        var xWaveArray = new float[totWaves];
        var zWaveArray = new float[totWaves];

        for(int i = 0; i < totWaves; i++)
        {
            xWaveArray[i] = floatArrayX[i];
            zWaveArray[i] = floatArrayZ[i];
        }

        //Debug.Log(totWaves);

        _renderer.material.SetFloatArray(WavePointExtruderConstants._ExtrudePointX, xWaveArray);
        _renderer.material.SetFloatArray(WavePointExtruderConstants._ExtrudePointZ, zWaveArray);
        _renderer.material.SetFloat(WavePointExtruderConstants._ExtrudePointCount, totWaves);
    }
}

public static class WavePointExtruderConstants
{
    public static string _Extrude_Close = "_Extrude_Close";
    public static string _ExtrudePointX = "_ExtrudePointX";
    public static string _ExtrudePointZ = "_ExtrudePointZ";
    public static string _ExtrudePointCount = "_ExtrudePointCount";
}

设置是一个平面,上面有着色器材质+代码。然后你制作任何游戏对象并将其放入Waves数组的脚本中。

1 个答案:

答案 0 :(得分:1)

着色器中至少有两个问题。

首先,当你在表面着色器中执行o.Normal = myNormal;时,myNormal应该在切线空间中,但是着色器正在传递在世界空间中计算的法线< /强>

所以这里有一个解决方案(从世界空间转换为切线空间的统一特定代码):

//---- before
//v.normal = normalize(vna);
//o.newNormal = v.normal;

//--- after
float3 worldNormal = normalize(vna);
// unity macro which setups "world space->tangent space" matrix in "rotation" variable
TANGENT_SPACE_ROTATION;
float3 tangentSpaceNormal = mul(rotation, worldNormal);
o.newNormal = tangentSpaceNormal;

其次,您使用的代码计算顶点的法线实际上是计算由(v0,v1,v2)定义的多边形/面法线的代码),这并非完全错误,但可能无法按预期工作。

计算顶点V法线的好方法是:

  1. 获取所有面孔V属于
  2. 计算所有这些面的法线
  3. V的法线是面法线的平均值
  4. 这里使用平面网格,因此每个面都是四边形,每个顶点属于4个四边形(对于边界顶点不是真的,但在你的情况下这不是问题)。

    所以你当前的代码在X&amp;中加了+0.05 Z实际上是计算顶点右上角的四边形/面的法线(如果您使用Unity顶视图的原因)。

    所以为了获得良好的法线,你需要计算3个其他四边形/面的法线,这将给你4个法线,最后通过平均那些你将得到顶点法线(将它们相加并除以4) )。