Warum führt das Duplizieren meines Objekts dazu, dass der Vertex-Animations-Shader es verzerrt?

7

Ich habe einen Vertex-Shader ( basierend auf diesem Beispiel ) verwendet, um ein wehendes Flag zu animieren. Wenn ich eine einzelne Flagge in meiner Szene habe, funktioniert sie korrekt.

Wenn ich die Flagge dupliziere, werden alle Kopien nach dem Drücken von "Play" stark verzerrt.

Animation mit normalem Verhalten und Verzerrung nach dem Duplizieren.

Hier ist der Shader-Code, den ich verwende:

Shader "Custom/Flag" {
    Properties {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Speed ("Speed", Range(0, 5.0)) = 1
        _Frequency ("Frequency", Range(0, 1.3)) = 1
        _Amplitude ("Amplitude", Range(0, 5.0)) = 1
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        Cull off

        Pass {

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;

            struct v2f {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            float _Speed;
            float _Frequency;
            float _Amplitude;

            v2f vert(appdata_base v)
            {
                v2f o;
                v.vertex.y +=  cos((v.vertex.x + _Time.y * _Speed) * _Frequency) * _Amplitude * (v.vertex.x - 5);
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                return tex2D(_MainTex, i.uv);
            }

            ENDCG

        }
    }
    FallBack "Diffuse"
}

Wie kann ich dafür sorgen, dass mehrere Flags mit demselben Material verwendet werden?

Sollte ich für jedes Objekt wie dieses eine neue Materialinstanz verwenden? Es scheint nicht optimal:

    material = new Material (Shader); // Create new material
    material.SetFloat ("_Speed", _Speed);
    material.SetFloat ("_Frequency", _Frequency);
    material.SetFloat ("_Amplitude", _Amplitude);
    material.SetTexture ("_MainTex", _MainTex);
    flagObj.GetComponent<MeshRenderer>().sharedMaterial = material; // Set values
Seyed Morteza Kamali
quelle

Antworten:

7

Dies sind die automatischen Dosiersysteme von Unity bei der Arbeit.

Wenn Sie in Unity mehrere (kleine) Modelle mit demselben Material sehen, werden beim Zeichnen mehrere Anrufe zu einem einzigen Netz zusammengefasst, sodass alle zusammen gerendert werden können.

Um die individuelle Transformation (Translation / Rotation / Scale) jedes Modells im Raum beizubehalten, werden die Transformationen in einem einzigen gemeinsamen Koordinatensystem für den gesamten Stapel in die Scheitelpunktpositionen eingebrannt, was möglicherweise stark vom ursprünglichen lokalen Koordinatensystem des Modells abweicht.

Dies ist normalerweise für die meisten Materialien sicher, da es uns normalerweise egal ist, wo sich unsere Geometrie im lokalen Raum befindet, sondern nur die resultierende Position in der Kameraansicht / Ausrichtung zu Lichtquellen.

Es kann jedoch zu Verwüstungen mit Scheitelpunkt-Shadern führen, die Annahmen darüber treffen, wie die Scheitelpunkte im lokalen Koordinatensystem des Modells angeordnet sind - wie Scheitelpunktanimationen, die Scheitelpunkte im lokalen Raum verschieben oder ihre Intensität basierend auf der lokalen Position skalieren.

Eine schnelle Lösung für diese Shader besteht darin, das Tag "DisableBatching"="True"zu den ShaderLab-Tags oben im Subshader hinzuzufügen. Dies teilt Unity mit, dass dieses Material nicht stapelbar ist, und es wird wieder jedes Modell einzeln mit seinem ursprünglichen Koordinatensystem gerendert, wobei einige Kosten für Zeichnungsaufrufe anfallen.

Wenn Sie viele dieser Modelle rendern und dennoch den Vorteil der Stapelverarbeitung nutzen möchten, können Sie einige Shader so ändern, dass hier andere Informationsquellen verwendet werden (z. B. die Scheitelpunktnormalen als Verschiebungsrichtung verwenden, anstatt davon auszugehen, dass sie entlang eines bestimmten lokalen Bereichs zeigen Achse oder Verwendung von UV-Koordinaten zum Skalieren und Versetzen des Effekts anstelle der lokalen Position). Wenn Sie eine zusätzliche Eingabequelle benötigen, können Sie eine Scheitelpunktfarbe oder einen zusätzlichen UV-Koordinatenkanal hinzufügen. Diese Attribute werden beim Stapeln nicht geändert, sodass sich Ihr Effekt beim Stapeln nicht ändert (obwohl das Hinzufügen weiterer Scheitelpunktattribute bedeutet, dass die maximale Anzahl von Modellen, die zusammen gestapelt werden können, geringer ist, da jedes Modell jetzt mehr Daten verwendet).

DMGregory
quelle