Trzy predefiniowane atrybuty shader / Uniform

Zacząłem od renderera Threejs 'a po wykonaniu jakiegoś "zwykłego" Webgla bez dodatkowych bibliotek + shaderów GLSL. Próbuję teraz pisać własne shadery w moim programie ThreeJS i zauważyłem, że ThreeJS zajmuje się wieloma standardowymi rzeczami, takimi jak projekcja i matryce model / widok. Mój simple vertex shader wygląda teraz tak:

// All of these seem to be predefined:
// vec3 position;
// mat4 projectionMatrix;
// mat4 modelViewMatrix;
// mat3 normalMatrix;
// vec3 normal;

// I added this
varying vec3 vNormal;

void main() {
    vNormal = normalMatrix * vec3(normal);
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

Moje pytanie brzmi: które inne zmienne (zakładam, że są uniformami) są predefiniowane dla wierzchołków i shaderów fragmentów, które Przydałoby mi się? Czy ThreeJS pomaga na przykład wektorom światła / kolorze światła (oczywiście zakładając, że dodałem jedno lub więcej świateł do mojej sceny ThreeJS)?

Update (Oct. 9, 2014): to pytanie zostało coraz sporo odsłon, a użytkownik Killah wspomniał, że istniejące odpowiedzi nie doprowadziły do rozwiązania już z aktualną wersją trzech.js. Dodałem i zaakceptowałem własną odpowiedź, zobacz ją poniżej.

Author: Peter O., 2013-03-27

4 answers

W przypadku mundurów krótka odpowiedź jest następująca:

In the vertex shader

"uniform mat4 modelMatrix;",
"uniform mat4 modelViewMatrix;",
"uniform mat4 projectionMatrix;",
"uniform mat4 viewMatrix;",
"uniform mat3 normalMatrix;",
"uniform vec3 cameraPosition;",

I w Shader fragmentu

"uniform mat4 viewMatrix;",
"uniform vec3 cameraPosition;",

Aby uzyskać pełną odpowiedź, obejmującą uniformy i atrybuty, Twoje niestandardowe shadery mają wstępnie dodane zmienne łańcuchowe prefixVertex i prefixFragment.

var vertexGlsl = prefixVertex + vertexShader;
var fragmentGlsl = prefixFragment + fragmentShader;

var glVertexShader = THREE.WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
var glFragmentShader = THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );

Definicje zmiennych prefixVertex i prefixFragment można znaleźć w WebGLProgram.js lub w nie-minifikowanej wersji three.js.

EDIT: Updated to three.js R. 73

 20
Author: WestLangley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-24 06:07:00

Mundury, których możesz użyć w swoich shaderach, zależą od tego, jak skonfigurujesz swój materiał: czy włączyłeś światła ? kolory wierzchołków ? skinning ? ...

Three js tworzy program, który w dużej mierze zależy od niektórych definicji (#ifdef w kodzie), które są wstrzykiwane u góry programu w zależności od parametrów, o których mówiłem powyżej.

Znalazłem najlepszy sposób, aby dowiedzieć się, co się dzieje, To wydrukować shadery generowane przez trzy JS: jak już znasz GLSL, zrozumiesz łatwo co oznacza kod i jakie mundury można użyć. Poszukaj buildProgram w trzech źródłach JS, następnie (r57):

var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader );
var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader );

Po tych liniach dodaj:

console.log("fragment shader:", prefix_fragment + fragmentShader);
console.log("vertex shader:", prefix_vertex + vertexShader);

I będziesz mógł zobaczyć zawartość shaderów.

[edytuj] Czytając ponownie twoje pytanie, zdaję sobie sprawę, że odpowiedziałem trochę dziwnie, gdy tworzysz własne shadery...

Możesz spojrzeć na linie 6463 i 6490 WebGLRenderer ( https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js#L6463 ): zobaczysz standardowe uniformy / atrybuty, które trzy JS wstrzykują w twoje shadery. Możesz zajrzeć do Wiki gdzie masz wpis o tym ( https://github.com/mrdoob/three.js/wiki - które domyślne atrybuty / uniformy / varyingi są dostępne w niestandardowych shaderach?), ale kieruje cię do linii, które opisałem powyżej.

 11
Author: Popov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-27 17:07:59

To pytanie zyskało sporo odsłon, a użytkownik Killah wspomniał, że istniejące odpowiedzi nie doprowadziły już do rozwiązania z obecną wersją trzech.js. Dlatego próbowałem ponownie rozwiązać problem i chciałbym przedstawić kilka opcji, które znalazłem: {]}

  • Najszybszym i najłatwiejszym sposobem (choć niezbyt eleganckim) jest po prostu umieszczenie przypadkowego błędu w shaderze. Pojawi się błąd konsoli z całym kodem shader, w tym wszystkim, co trzy.js dodaje.

  • Lepszym rozwiązaniem jest wyjście źródła shadera z miejsca jego kompilacji, czyli trzech.WebGLShader (od obecnych 3.wersja js, r68). Zrobiłem szybkie kopiowanie i wklejanie, które powinny wyprowadzać wszystkie źródła shaderów przed ich kompilacją.

    Dodaj to po włączeniu trzech.js i przed własnym kodem:

    THREE.WebGLShader = ( function () {
        var addLineNumbers = function ( string ) {
            var lines = string.split( '\n' );
            for ( var i = 0; i < lines.length; i ++ ) {
                lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
            }
            return lines.join( '\n' );
        };
        return function ( gl, type, string ) {
            var shader = gl.createShader( type ); 
            console.log(string);
            gl.shaderSource( shader, string );
            gl.compileShader( shader );
            if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {
                console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );
            }
            if ( gl.getShaderInfoLog( shader ) !== '' ) {
                console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ) );
                console.warn( addLineNumbers( string ) );
            }
            return shader;
        };
    } )();
    

    Zauważ, że ten fragment jest po prostu skopiowany (i bardzo nieznacznie zmieniony) z trzech.źródła js i powinny być usunięte przed faktycznie używając kodu. Tylko do debugowania!

  • Jest jeszcze jedna opcja, która jest mniej inwazyjna: możesz sprawdzić swój ShaderMaterial po utworzeniu i renderowaniu go przynajmniej raz, w ten sposób:

    var material = new THREE.ShaderMaterial({
        uniforms: {
            uColorMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_colors.png') },
            uSpecularMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_spec.png') }, 
            uNormalMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_normal.png') }
        },
        vertexShader: document.getElementById('vShader').innerText,
        fragmentShader: document.getElementById('fShader').innerText
    });
    

    Następnie, Po renderowanie obiektu przynajmniej raz:

    console.log(material.program.attributes);
    console.log(material.program.uniforms);
    
Mam nadzieję, że to pomoże wszystkim! Możesz dodawać swoje komentarze, jeśli znasz więcej i / lub lepsze sposoby na uzyskanie kodu shadera.
 4
Author: Grüse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-09 16:18:48

Odpowiedź na to pytanie można teraz znaleźć w trzech.dokumentacja js: https://threejs.org/docs/#api/renderers/webgl/WebGLProgram

 1
Author: Kalisen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-27 22:49:48