编辑:演示终于上线: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
上面的屏幕截图应该是扩展的世界空间法线 gbuffer。
我的引擎的一个很大的区别是,我不在类中存储面部信息(例如 THREE.Face3 ),而更喜欢将数据直接写入缓冲区属性,更像 THREE.BufferGeometry。
到目前为止,我一直在使用“学习 WebGL”类(class)中的 utah 茶壶模型,特别是此链接 http://learningwebgl.com/blog/?p=1658 。这个模型在我的引擎中工作得完全正确,并且被认为是 THREE JSON 格式的早期版本。我按照教程中的方式加载该模型,将顶点、texcoords 等的 json 数组直接写入 webgl 缓冲区,这在我的引擎中完美运行,但即使是从最新的 blender 导出器导出的简单立方体似乎也不能很好地工作.
非常感谢任何建议,谢谢!
编辑:使用 webgl 教程中的茶壶模型进行法线传递的屏幕截图。注意:我并不是说三个导出器已损坏,而是我的解析它的代码已损坏。在过去一年左右的时间里,我已经在这个引擎中多次讨论过 GBuffer 实现,并且我非常确定现在这是正确的,我只是在理解三种 json 模型格式时遇到了一些问题。
最佳答案
不确定您在 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/