【问题标题】:Unity Shader Normals wrongUnity Shader Normals 错误
【发布时间】:2017-01-21 06:29:34
【问题描述】:

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

有人知道为什么会这样吗???当我继续前进时,底部总是比顶部亮。

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

*将这些点翻译到世界空间,这样我就可以在真实空间中寻找obsticals

*计算出我们点的 y 轴位移 + 第一步中为交叉所做的额外内容

*按位移增加对象空间值

*使用交叉法寻找新常态

*设置正常

*设置顶点。

我认为正在发生的事情是法线在错误的轴上……感谢任何帮助

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 数组中。

【问题讨论】:

    标签: opengl unity3d shader


    【解决方案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 个四边形(边界顶点不正确,但在您的情况下这不是问题)。

    因此,您当前在 X 和 Z 中添加 +0.05 的代码实际上是在计算 顶点右上角的四边形/面的法线(如果您使用 Unity 顶视图进行推理) .

    因此,要获得良好的法线,您需要计算其他 3 个四边形/面的法线,这将为您提供 4 条法线,最后通过平均这些法线,您将获得顶点法线(将它们相加并除以 4 )。

    【讨论】:

    • 会在我有能力的时候尝试一下!谢谢
    猜你喜欢
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-16
    相关资源
    最近更新 更多