26

追加のライブラリ + 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 の現在のバージョンでは、既存の回答が解決策につながらなくなったと述べています。私は自分の答えを追加して受け入れました。以下を参照してください。

4

4 に答える 4

27

制服の場合、簡単な答えは次のとおりです。

頂点シェーダーで

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

そしてフラグメントシェーダーで

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

ユニフォームと属性を含む完全な答えについては、カスタムシェーダーに文字列変数がprefixVertexあり、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 );

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

編集: three.js r.73 に更新

于 2013-03-27T17:03:12.570 に答える
11

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

Three 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#L6463 ) を見ることができます: 標準のユニフォーム/属性が表示されます。 3 つの JS がシェーダーに挿入されます。それについてのエントリがある Wiki を見ることができます ( https://github.com/mrdoob/three.js/wiki - カスタム シェーダーで利用できるデフォルト属性 / ユニフォーム / バリエーションは?)上で概説した行に。

于 2013-03-27T17:00:40.650 に答える
6

この質問はかなりの数のビューを獲得しており、ユーザーの 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
    });
    

    次に、オブジェクトを少なくとも 1 回レンダリングした後:

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

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

于 2014-10-09T16:18:48.347 に答える
5

この質問に対する答えは、three.js のドキュメントにあります: https://threejs.org/docs/#api/renderers/webgl/WebGLProgram

于 2015-04-12T15:22:36.127 に答える