javascript - 解析 THREE.js json 网格格式法线错误

标签 javascript three.js webgl deferred-rendering

编辑:演示终于上线:http://bharling.github.io/deferred/index.html使用下拉菜单切换到环面模型以实时查看问题。注意:需要 Webgl MRT 扩展。

我在 WebGL 中开发自己的延迟渲染引擎已经有一段时间了,现在已经到了这样的阶段:我有一个使用 GBuffers 和 MRT 扩展的工作原型(prototype),可以相当令人满意地渲染一些茶壶。这是从头开始开发的,主要是为了让我在不使用任何框架的情况下正确学习WebGL,并了解延迟渲染。对于任何感兴趣的人 - 源代码位于 github 上:https://github.com/bharling/webgl-defer

我已经厌倦了只看到茶壶,并尝试为 THREE.js JSON 格式模型实现一个加载器。我已经移植(复制)了加载器的主要部分,并且我可以让网格体显示出正确的顶点和索引缓冲区,这很棒,但法线始终很奇怪。我选择仅支持带有顶点 UV 和顶点法线以及单一 Material 的索引几何体(最终这应该是基于 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

Weird Normals from simple imported cube exported from blender using THREE.s official exporter

上面的屏幕截图应该是扩展的世界空间法线 gbuffer。

我的引擎的一个很大的区别是,我不在类中存储面部信息(例如 THREE.Face3 ),而更喜欢将数据直接写入缓冲区属性,更像 THREE.BufferGeometry。

到目前为止,我一直在使用“学习 WebGL”类(class)中的 utah 茶壶模型,特别是此链接 http://learningwebgl.com/blog/?p=1658 。这个模型在我的引擎中工作得完全正确,并且被认为是 THREE JSON 格式的早期版本。我按照教程中的方式加载该模型,将顶点、texcoords 等的 json 数组直接写入 webgl 缓冲区,这在我的引擎中完美运行,但即使是从最新的 blender 导出器导出的简单立方体似乎也不能很好地工作.

非常感谢任何建议,谢谢!

编辑:使用 webgl 教程中的茶壶模型进行法线传递的屏幕截图。注意:我并不是说三个导出器已损坏,而是我的解析它的代码已损坏。在过去一年左右的时间里,我已经在这个引擎中多次讨论过 GBuffer 实现,并且我非常确定现在这是正确的,我只是在理解三种 json 模型格式时遇到了一些问题。

enter image description here

最佳答案

不确定您在 Three.Face3 到缓冲区之间的转换是否正确。这是我自己的三个 Json 解析器,我用它从 blender 加载动画蒙皮网格,这可能对你有一些帮助。同样,仅支持部分功能。它返回与 .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);
                }
            }
        }
    }
}

关于javascript - 解析 THREE.js json 网格格式法线错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35386518/

相关文章:

javascript - 居中对齐叠加层

javascript - 使用 webgl 创建六 Angular 星

javascript - 将回调添加到 javascript while 循环

javascript - 移动 JavaScript 下拉菜单无法打开

javascript - CubeTextureLoader 未在 Three.js 中加载天空盒

javascript - WebGL 在像素级别混合颜色

three.js - 为什么我墙上的灯看起来很奇怪?三.js

javascript - 如何围绕特定点旋转几何图形?

webgl - 获取 webGL2 片段着色器上的当前像素位置

javascript - NativeScript 创建类似砖石的布局