1

編集: デモがついにオンラインになりました: http://bharling.github.io/deferred/index.htmlドロップダウンを使用してトーラス モデルに切り替え、問題をライブで確認します。注: Webgl MRT 拡張機能が必要です。

私はしばらくの間、WebGL で独自の遅延レンダリング エンジンを開発する過程にあり、いくつかのティーポットを非常に満足のいくようにレンダリングする GBuffers と MRT 拡張機能を使用した実用的なプロトタイプを作成する段階に達しました。これは主に、フレームワークを使用せずに WebGL を適切に学習し、遅延レンダリングを理解するためにゼロから開発されました。興味のある方は、こちらの github にソースがあります: https://github.com/bharling/webgl-defer

ティーポットを見るだけでは飽き飽きし、THREE.js JSON 形式モデル用のローダーを実装しようとしました。ローダーの主要部分を移植 (コピー) しました。正しい頂点とインデックス バッファーを使用してメッシュを表示できます。これは素晴らしいことですが、法線は一貫して厄介です。頂点 UV と頂点法線、および単一のマテリアルを使用するインデックス付きジオメトリのみをサポートすることを選択しているため (最終的には、これは PBR ベースになるはずです)、JSON 内の他のものは無視し、サポートするものだけを直接 Float32Arrays (など) に書き込みます。 . 以下は、私のインポート コードと、私が見ている奇妙な法線のスクリーンショットです。

  parseThreeJSModel: (data) =>

    isBitSet = (value, position) ->
      return value & ( 1 << position )

    vertices = data.vertices
    uvs = data.uvs
    indices = []
    normals = data.normals

    vertexNormals = []
    vertexUvs = []
    vertexPositions = []

    @vertexPositionBuffer = new DFIR.Buffer( new Float32Array( data.vertices ), 3, gl.STATIC_DRAW )
    @vertexTextureCoordBuffer = new DFIR.Buffer( new Float32Array( data.uvs[0] ), 2, gl.STATIC_DRAW )

    numUvLayers = data.uvs.length
    faces = data.faces

    zLength = faces.length
    offset = 0

    while offset < zLength
      type = faces[offset++]
      isQuad              = isBitSet( type, 0 )
      hasMaterial         = isBitSet( type, 1 )
      hasFaceVertexUv     = isBitSet( type, 3 )
      hasFaceNormal       = isBitSet( type, 4 )
      hasFaceVertexNormal = isBitSet( type, 5 )
      hasFaceColor       = isBitSet( type, 6 )
      hasFaceVertexColor  = isBitSet( type, 7 )

      if isQuad
        indices.push faces[ offset ]
        indices.push faces[ offset + 1 ]
        indices.push faces[ offset + 3 ]
        indices.push faces[ offset + 1 ]
        indices.push faces[ offset + 2 ]
        indices.push faces[ offset + 3 ]
        offset += 4

        if hasMaterial
          offset++

        if hasFaceVertexUv
          for i in [0 ... numUvLayers] by 1
            uvLayer = data.uvs[i]
            for j in [0 ... 4] by 1
              uvIndex = faces[offset++]
              u = uvLayer[ uvIndex * 2 ]
              v = uvLayer[ uvIndex * 2 + 1 ]

              if j isnt 2 
                vertexUvs.push u
                vertexUvs.push v
              if j isnt 0
                vertexUvs.push u
                vertexUvs.push v

        if hasFaceNormal
          offset++

        if hasFaceVertexNormal
          for i in [0 ... 4] by 1
              normalIndex = faces[ offset++ ] * 3
              normal = [ normalIndex++, normalIndex++, normalIndex ] 
              if i isnt 2
                vertexNormals.push normals[normal[0]]
                vertexNormals.push normals[normal[1]]
                vertexNormals.push normals[normal[2]]
              if i isnt 0
                vertexNormals.push normals[normal[0]]
                vertexNormals.push normals[normal[1]]
                vertexNormals.push normals[normal[2]]

        if hasFaceColor
          offset++

        if hasFaceVertexColor
          offset += 4
      else
        indices.push faces[offset++]
        indices.push faces[offset++]
        indices.push faces[offset++]

        if hasMaterial
          offset++
        if hasFaceVertexUv
          for i in [0 ... numUvLayers] by 1
            uvLayer = data.uvs[i]
            for j in [0 ... 3] by 1
              uvIndex = faces[offset++]
              u = uvLayer[ uvIndex * 2 ]
              v = uvLayer[ uvIndex * 2 + 1 ]
              if j isnt 2 
                vertexUvs.push u
                vertexUvs.push v
              if j isnt 0
                vertexUvs.push u
                vertexUvs.push v

        if hasFaceNormal
          offset++

        if hasFaceVertexNormal
          for i in [0 ... 3] by 1
            normalIndex = faces[ offset++ ] * 3

            vertexNormals.push normals[normalIndex++]
            vertexNormals.push normals[normalIndex++]
            vertexNormals.push normals[normalIndex]

        if hasFaceColor
          offset++

        if hasFaceVertexColor
          offset +=3

    @vertexNormalBuffer = new DFIR.Buffer( new Float32Array( vertexNormals ), 3, gl.STATIC_DRAW )
    @vertexIndexBuffer = new DFIR.Buffer( new Uint16Array( indices ), 1, gl.STATIC_DRAW, gl.ELEMENT_ARRAY_BUFFER )
    @loaded=true

THREE.s公式エクスポーターを使用してブレンダーからエクスポートされた単純なインポートキューブからの奇妙な法線

上のスクリーンショットは、拡張されたワールド空間法線 gbuffer である必要があります。

私のエンジンの大きな違いの 1 つは、顔情報をクラス ( THREE.Face3 など) に保存せず、THREE.BufferGeometry のようにデータをバッファー属性に直接書き込むことを好むことです。

これまで、「Learning WebGL」コースのユタ ティーポット モデル、具体的にはこのリンクhttp://learningwebgl.com/blog/?p=1658のみを使用してきました。このモデルは私のエンジンで正確に機能し、おそらく THREE JSON 形式の初期バージョンです。頂点、texcoords などの json 配列を webgl バッファーに直接書き込むことにより、チュートリアルのようにそのモデルをロードします。これは私のエンジンで完全に機能しますが、最新のブレンダー エクスポーターからエクスポートされた単純なキューブでさえ、うまく機能していないようです。 .

どんな提案でも大歓迎です、ありがとう!

編集: webgl チュートリアルのティーポット モデルを使用した法線パスのスクリーンショット。注: THREE エクスポーターが壊れていることを示唆しているわけではなく、それを解析する私のコードです。私はこのエンジンで GBuffer の実装を過去 1 年ほどにわたって何度も調べてきましたが、今ではこれが正しいと確信しています。THREE json モデル形式を理解するのに少し問題があります。

ここに画像の説明を入力

4

2 に答える 2

1

Three.Face3 からバッファへの変換が正しいかどうかはわかりません。これは、アニメーション化されたスキンメッシュをブレンダーからロードするために使用する私自身の Three Json パーサーです。同様に、部分的な機能のみがサポートされています。.drawElementsではなく で使用するインデックス付きバッファを返します.drawArrays

function parsePackedArrayHelper(outArray, index, dataArray, componentSize){
    for (var c = 0; c<componentSize; c++){
        outArray.push(dataArray[index*componentSize + c]);
    }
}

function parseThreeJson(geometry){
    if (isString(geometry)){
        geometry = JSON.parse(geometry);
    }

    var faces = geometry["faces"];
    faces = convertQuadToTrig(faces); // can use the triangulate modifer in blender to skip this 
    // and others data etc... 

    var seenVertices = new Map();
    var currentIndex = 0;
    var maxIndex = 0;

    var c = 0; // current index into the .faces array
    while (c < faces.length){
        var bitInfo = faces[c];
        var hasMaterials = (bitInfo &(1<<1)) !== 0;
        var hasVertexUvs = (bitInfo &(1<<3)) !== 0;
        var hasVertexNormals = (bitInfo &(1<<5)) !== 0;
        var faceIndex = c+1;

        c += (
            4 + //1 for the bitflag and 3 for vertex positions
            (hasMaterials? 1: 0) +
            (hasVertexUvs? 3: 0) +
            (hasVertexNormals ? 3: 0)
        );

        for (var v = 0;v<3;v++){
            var s = 0; 
            var vertIndex = faces[faceIndex+v];
            var uvIndex = -1;
            var normalIndex = -1;
            var materialIndex = -1;
            if (hasMaterials){
                s += 1;
                materialIndex = faces[faceIndex+3];
            }
            if (hasVertexUvs){
                s += 3;
                uvIndex = faces[faceIndex+s+v];
            }
            if (hasVertexNormals){
                s += 3;
                normalIndex = faces[faceIndex+s+v];
            }

            var hash = ""+vertIndex+","+uvIndex+","+normalIndex;
            if (seenVertices.has(hash)){
                indices[currentIndex++] = seenVertices.get(hash);
            } else {
                seenVertices.set(hash, maxIndex);
                indices[currentIndex++] = maxIndex++;
                parsePackedArrayHelper(verticesOut, vertIndex, verticesData, 3);
                if (boneInfluences > 1){
                    // skinning data skipped
                }
                if (hasVertexUvs){
                    parsePackedArrayHelper(uvsOut, uvIndex, uvsData[0], 2);

                    // flip uv vertically; may or may not be needed
                    var lastV = uvsOut[uvsOut.length-1];
                    uvsOut[uvsOut.length-1] = 1.0 - lastV;

                }
                if (hasVertexNormals){
                    parsePackedArrayHelper(normalsOut, normalIndex, normalsData, 3);
                }

                if (hasMaterials){
                    materialIndexOut.push(materialIndex);
                }
            }
        }
    }
}
于 2016-02-15T23:16:01.183 に答える
0

問題の直接的な解決策ではありませんが、とにかく役立つかもしれません。

上記の例のボックスのようなプリミティブ シェイプがある場合は、THREE.FlatShading法線の設定をまとめて使用およびスキップすることもできます。いくつかのケースではより簡単かもしれません:

var material = new THREE.???Material({ shading: THREE.FlatShading });
于 2016-02-15T09:47:58.380 に答える