web-dev-qa-db-ja.com

ThreeJSで事前定義されたシェーダー属性/ユニフォーム

追加のライブラリとGLSLシェーダーを使用せずに「通常の」WebGLを実行した後、ThreeJSのWebGLレンダラーを使用し始めました。私は今ThreeJSプログラムでカスタムシェーダーを書き込もうとしていますが、ThreeJSがプロジェクションやモデル/ビューマトリックスなどの多くの標準的なものを処理していることに気づきました。私の単純な頂点シェーダーは次のようになります。

// 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);
}

私の質問は次のとおりです。使用できる頂点シェーダーとフラグメントシェーダーには、他にどの変数(ユニフォームだと思います)が事前定義されていますか? ThreeJSは、たとえば光ベクトル/光の色をサポートしますか(もちろん、ThreeJSシーンに1つ以上のライトを追加したと仮定します)?

更新(2014年10月9日):この質問はかなりの数のビューを獲得しており、ユーザーKillahは、既存の回答は現在のバージョンのthree.jsでは解決策につながらないと述べました。私は自分の答えを追加して受け入れました。以下を参照してください。

25
Grüse

この質問はかなりの数の見解を得ており、ユーザーKillahは、既存の回答は現在のバージョンのthree.jsではもはや解決策につながらないと述べました。これが私が問題をもう一度解決しようとした理由であり、私が見つけたいくつかのオプションの概要を説明したいと思います。

  • 最も速くて簡単な方法は(あまりエレガントではありませんが)、シェーダーにランダムエラーを入れることです。 three.jsが追加するすべてのものを含む、シェーダーコード全体でコンソールエラーが発生します。

  • より良い解決策は、コンパイルされた場所からシェーダーソース、つまりTHREE.WebGLShader(現在のthree.jsバージョンr68)を出力することです。コンパイルする前にすべてのシェーダーソースを出力するクイックコピーアンドペーストを実行しました。

    Three.jsをインクルードした後、独自のコードの前にこれを追加します。

    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;
        };
    } )();
    

    このスニペットは、three.jsソースからコピーされただけであり(わずかに変更されている)、実際にコードを使用する前に削除する必要があることに注意してください。デバッグのためだけに!

  • 侵襲性の低いもう1つのオプションがあります。次のように、ShaderMaterialを少なくとも1回作成してレンダリングした後、検査できます。

    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
    });
    

    次に、afterオブジェクトを少なくとも1回レンダリングします。

    console.log(material.program.attributes);
    console.log(material.program.uniforms);
    

これがみんなのお役に立てば幸いです!シェーダーコードを取得するためのより多くの方法やより良い方法を知っている場合は、コメントを自由に追加してください。

5
Grüse

ユニフォームの場合、簡単な答えは次のとおりです。

頂点シェーダー内

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

フラグメントシェーダー内

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

ユニフォームと属性を含む完全な答えのために、カスタムシェーダーには文字列変数prefixVertexprefixFragmentが事前に追加されています。

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 );

prefixVertexおよびprefixFragment変数の定義は、WebGLProgram.jsまたは縮小されていないバージョンのthree.jsにあります。

編集:three.jsr.73に更新

25
WestLangley

シェーダーで使用できるユニフォームはすべて、マテリアルの設定方法によって異なります。ライトを有効にしましたか?頂点の色?スキニング? .。

3つのJSは、上記で説明したパラメーターに応じてプログラムの先頭に挿入されるいくつかの定義(コード内の#ifdef)に大きく依存するプログラムを作成します。

何が起こっているのかを知る最良の方法は、3つのJSが生成するシェーダーを印刷することです。すでにGLSLを知っているので、コードの意味と使用できるユニフォームを簡単に理解できます。 3つのJSソースでbuildProgramを探し、次に(r57):

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

これらの行の後に、次を追加します。

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

そして、シェーダーの内容を見ることができます。

[編集]あなたの質問を読み直して、あなたがあなた自身のシェーダーを作成するので、私は少し答えたと思います...

WebGLRendererの行6463と6490を見ることができます( https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js#L646 ):あなた3つのJSがシェーダーに注入する標準のユニフォーム/属性が表示されます。それについてのエントリがあるWikiを見ることができます( https://github.com/mrdoob/three.js/wiki -カスタムで使用できるデフォルトの属性/ユニフォーム/バリエーションシェーダー?)しかし、それは私が上で概説した線にあなたを導きます。

11
Popov

この質問への回答は、three.jsのドキュメントに記載されています。 https://threejs.org/docs/#api/renderers/webgl/WebGLProgram

3
Kalisen