2012-12-14 11 views
5

Używam GC do pisania shaderów wewnątrz Unity3D.CG: Określ zmienną, której nie można interpolować między werteksem a modułem cieniującym

Używam atrybutów wierzchołków kolorów do przekazywania niektórych parametrów do modułu cieniującego. Nie będą one używane do definiowania kolorów i powinny być przekazywane z modułu cieniującego wierzchołka do modułu cieniującego pikseli bez modyfikowania ich.

Jest to struktura Biorę jako wejście z Unity3D do vertex shader:

struct appdata_full { 
    float4 vertex : POSITION; 
    float4 tangent : TANGENT; 
    float3 normal : NORMAL; 
    float4 texcoord : TEXCOORD0; 
    float4 texcoord1 : TEXCOORD1; 
    fixed4 color : COLOR; 
#if defined(SHADER_API_XBOX360) 
    half4 texcoord2 : TEXCOORD2; 
    half4 texcoord3 : TEXCOORD3; 
    half4 texcoord4 : TEXCOORD4; 
    half4 texcoord5 : TEXCOORD5; 
#endif 
}; 

Jest to struktura zwracana przez cieniowania wierzchołków jako wejście do fragmentu:

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

Jeśli Po prostu przekazuję ten parametr do modułu cieniującego fragmentu, oczywiście zostanie on interpolowany:

v2f vert (appdata_full v) 
{ 

    v2f output; 
    //.... 
    output.col = v.color; 
} 

Chciałbym przekazać parametr v.color nie interpolowany do modułu cieniującego fragmentu. Czy to możliwe? Jeśli tak, to w jaki sposób?


EDIT

jak Tim zauważył, jest to oczekiwane zachowanie, ze względu na cieniującego nie może nic innego niż interpolacji kolorów czy te zapadają się od cieniowania wierzchołków do fragmentu zrobić. Postaram się wyjaśnić lepiej, co próbuję osiągnąć. Używam kolorów wierzchołków do przechowywania innych informacji niż kolory. Nie mówiąc o wszystkich szczegółach dotyczących tego, co robię z tym, załóżmy, że można uznać każdy wierzchołek koloru jako identyfikator (każdy wierzchołek tego samego trójkąta, będzie miał ten sam kolor, właściwie każdy wierzchołek tej samej siatki).

Wykorzystałem więc sztuczkę koloru do maskowania niektórych parametrów, ponieważ nie mam innego sposobu, aby to zrobić. Ta informacja musi być w jakiś sposób dostępna w module cieniowania fragmentów. Jeśli jako parametr wyjściowy modułu cieniującego wierzchołka zostanie przekazana ta informacja zakodowana w kolorze, zostanie ona interpolowana na fragmencie, który nie może już jej użyć.

Poszukuję sposobu na propagowanie tych informacji w niezmienionym stanie do fragmentu shadera (być może jest możliwe użycie zmiennej globalnej lub coś podobnego ?, jeśli tak, to jak?).

+0

Jak zamierzasz pogodzić trzy wejścia (wierzchołki) na piksel jeśli nie interpolacji wartości czego można się spodziewać się zdarzyć, jeśli każdy wierzchołek trójkąta ma inną wartość – Tim

+0

@Tim? : ok .. masz rację, rozumiem twój sprzeciw . Chodzi o to, że faktycznie kolory nie są kolorami w moim cieniu. Używam wartości kolorów do przechowywania innych informacji. Muszę przesłać tę informację o wierzchołku z wierzchołka do shadera fragmentu, ostatecznie nie przekazując go jako parametru wyjściowego dla modułu cieniującego wierzchołków, ale używając jakiejś "zmiennej gloabalnej", jeśli coś takiego jest możliwe. Mam nadzieję, że będę jasny. – Heisenbug

+0

Nie ma znaczenia, czy jest to kolor, indeks czy cokolwiek innego. Powiedzmy, że rysujesz pojedynczy trójkąt. W oparciu o niektóre arbitralne obliczenia na jeden wierzchołek; vertex 0 output "5", vertex 1 outputs "10", vertex 2 outputs "15". Które z tych trzech liczb chcesz pokazać w shaderze fragmentów? Jeśli to naprawdę wartość globalna, niż użycie jednolitego, ale poza tym myślę, że nie w pełni to przemyślałeś. Chyba że po prostu powiesz "Zawsze chcę wartości wierzchołków 0 i zignorować pozostałe dwa", to nie ma większego sensu. – Tim

Odpowiedz

10

Nie jestem pewien, czy chodzi o odpowiedź, ale to trochę za komentarz. Jak wskazuje Bjorke, moduł cieniujący zawsze otrzyma wartość interpolowaną. Jeśli/kiedy Unity obsługuje Opengl 4.0, możesz mieć dostęp do Interpolation qualifiers, a mianowicie "płaskiego", który wyłącza interpolację, wyprowadzając wszystkie wartości z provoking vertex.

To powiedziawszy, problem z próbą przypisania tej samej wartości "koloru" do wszystkich wierzchołków trójkąta polega na tym, że verter shader iteruje raz na wierzchołki, a nie na trójkąt. Zawsze znajdzie się region "graniczny", w którym niektóre wierzchołki dzielą wiele krawędzi z innymi wierzchołkami o innym "kolorze" lub "id", zobacz mój głupi przykład poniżej. Po nałożeniu na pudło w punkcie (0,0,0), góra będzie czerwona, dolna zielona, ​​a środkowa niebieska.

Shader "custom/colorbyheight" { 
Properties { 
_Unique_ID ("Unique Identifier", float) = 1.0 
} 
SubShader { 
Pass { 
    CGPROGRAM 
    #pragma vertex vert 
    #pragma fragment frag 
    #include "UnityCG.cginc" 
    struct v2f { 
     float4 pos : SV_POSITION; 
     fixed4 color : COLOR; 
    }; 
    uniform float _Unique_ID; 
    v2f vert (appdata_base v) 
    { 
     v2f o; 
     o.pos = mul (UNITY_MATRIX_MVP, v.vertex); 
     float3 worldpos = mul(_Object2World, v.vertex).xyz; 
     if(worldpos[1] >= 0.0) 
     o.color.xyz = 0.35; //unique_id = 0.35 
     else 
     o.color.xyz = 0.1; //unique_id = 0.1 
     o.color.w = 1.0; 
     return o; 
    } 


    fixed4 frag (v2f i) : COLOR0 { 
    // local unique_id's set by the vertex shader and stored in the color 
    if(i.color.x >= 0.349 && i.color.x <=0.351) 
     return float4(1.0,0.0,0.0,1.0); //red 
    else if(i.color.x >= 0.099 && i.color.x <=0.11) 
     return float4(0.0,1.0,0.0,1.0); //green 

    // global unique_id set by a Unity script 
    if(_Unique_ID == 42.0) 
     return float4(1.0,1.0,1.0,1.0); //white 

    // Fallback color = blue 
    return float4(0.0,0.0,1.0,1.0); 
    } 
    ENDCG 
} 
} 
} 

W swoim addendum mówisz "Właściwie każdy wierzchołek tej samej siatki." Jeśli tak jest, może warto użyć modyfikowalnej właściwości, takiej jak powyżej. Każda siatka wymaga tylko skryptu, aby zmienić unikalny identyfikator.

public class ModifyShader : MonoBehaviour { 
public float unique_id = 1; 
// Use this for initialization 
void Start() { 

} 

// Update is called once per frame 
void Update() { 
    renderer.material.SetFloat("_Unique_ID", unique_id); 
} 
} 
+0

cóż, dziękuję za odpowiedź też.Nie mogę używać SetFloat, ponieważ jestem grupowanie wywołania rysowania przez StaticBatchingUtility. Jeśli zmodyfikuję wartość Materiału, Unity utworzy instancję nowej Material dla każdego obiektu, uniemożliwiając mu użycie sharedMaterial i w konsekwencji nie będzie już w partiach. Tak więc jestem zmuszony do używania parametrów kolorów przypisanych do każdego wierzchołka w celu przypisania niestandardowej wartości modułu cieniującego do każdej siatki. – Heisenbug

+0

Właściwie używam każdego wierzchołka koloru jako indeksu i indeksu teksturowania. Niestety wartości te powinny być używane wewnątrz modułu cieniującego fragmentu. Używanie 3-kolorowej globalnej zmiennej współdzielonej pomiędzy programami fragmentów i wierzchołków (lub niektórymi określonymi parametrami, które nie mają być interpolowane) może mi pomóc w realizacji bardziej wydajnej implementacji niektórych pośrednich. – Heisenbug

+0

Bugger, tak, to by nie działało dla ciebie. Jednym z "rozwiązań", a nie podoba mi się to, ponieważ jest hacky i wolno, polega na tym, że wszystkie trójkąty siatki są unikalne, pozwalając każdemu wierzchołkowi utworzyć 2 krawędzie. W ten sposób interpolacja liniowa zachodzi tylko pomiędzy wersetami pojedynczego trójkąta, dając ci właściwy "id". – Jerdak

2

Procesor graficzny zawsze interpoluje wartości. Jeśli chcesz uzyskać stałą wartość trójkąta, musisz ustawić tę samą wartość dla wszystkich wierzchołków tego trójkąta. Może to czasami być nieefektywne, ale tak działa OpenGL (i DirectX). Nie ma nieodłącznego pojęcia wartości "twarzy".

+0

Nie mogę użyć jakiejś zmiennej globalnej współużytkowanej między instancją vertex shader a wszystkimi pokrewnymi shaderów fragmentów? – Heisenbug

+0

to nie jest sposób rozmieszczenia sprzętu. Stałe to per-mesh, a nie per-triangle, a każda siatka pobiera tylko jeden vertex i jeden fragment shadera Rejestry "łącznika", które są interpolowane, są jedynym kanałem komunikacji między tymi dwoma. – bjorke

+0

dzięki za wyjaśnienie – Heisenbug

1

Możesz to zrobić: glShadeModel(GL_FLAT). To wyłącza interpolację dla wszystkich wejściowych modułów cieniujących i jest dostępne również w starszych OpenGL (pre 4.0).

Jeśli masz jakieś wejścia, które chcesz interpolować, a niektóre nie, wyrenderuj raz z GL_FLAT na teksturę o tej samej rozdzielczości co wyjście, a następnie wyrenderuj ponownie za pomocą GL_SMOOTH i wypróbuj teksturę, aby odczytać płaskie wartości dla każdego piksela (przy równoczesnym uzyskiwaniu interpolowanych wartości w zwykły sposób).

Jeśli zamiast tego można użyć DirectX9, można użyć modyfikatora nointerpolation na wejściach modułów cieniujących poszczególnych fragmentów (model cieniowania 4 lub nowszy).

+1

glShadeModel nie jest odsłonięty przez Unity API. – Jerdak

+0

ani w OpenGL ES (a tym samym webgl) – bjorke

3

To jest dość stary wątek, ale ostatnio miałem podobny problem i znalazłem super prostą odpowiedź. OSX Mavericks obsługuje teraz OpenGL 4.1, więc wkrótce nie będzie problemu, ale może jeszcze trochę potrwać, zanim Unity3d je odbierze. W każdym razie, istnieje dobry sposób na włączenie cieniowania w Unity nawet na wcześniejszym OSX (np. Mountain Lion)!

Shader poniżej będzie wykonać zadanie (kluczowym elementem jest linia z #extension, w przeciwnym razie można dostać błąd kompilacji za korzystanie z mieszkania kluczowe”

Shader "GLSL flat shader" { 
SubShader { 
    Pass { 
    GLSLPROGRAM 

    #extension GL_EXT_gpu_shader4 : require 
    flat varying vec4 color; 

    #ifdef VERTEX 
    void main() 
    { 
     color = gl_Color; 
     gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
    } 
    #endif 

    #ifdef FRAGMENT 
    void main() 
    { 
     gl_FragColor = color; // set the output fragment color 
    } 
    #endif 

    ENDGLSL 
    } 
    } 
} 

zajechaliśmy do niego poprzez łączenie rzeczy z : http://poniesandlight.co.uk/notes/flat_shading_on_osx/ http://en.wikibooks.org/wiki/GLSL_Programming/Unity/Debugging_of_Shaders

Powiązane problemy