首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ObjLoader问题

ObjLoader问题
EN

Stack Overflow用户
提问于 2020-10-17 06:56:05
回答 1查看 68关注 0票数 0

我为我的webgl项目编写了一个.obj文件加载器。目前,simple.It可以加载相对简单的模板,但我不能加载斯坦福之龙。输出根本不起作用。这是结果的图片。我真的迷路了,因为我的代码似乎是正确的。但是,我没有太多使用.obj文件的经验,一定是出了什么问题

如果有人能帮助我,告诉我哪里出了问题,我真的很感激。

这是指向github存储库的链接:https://github.com/francois141/WebGlEngine

以下是OBJ Loader类的代码:

代码语言:javascript
复制
class CubeObj {

constructor(gl) {
    this.gl = gl;
    this.object = {};

    this.object.texte = `add OBJ file here`;
    
    this.object.numIndices = 0;

    this.vertexData = [0, 0, 0];
    this.textureCoords = [0, 0];
    this.vertexNormals = [0, 0, 0];
    this.vertexIndices = [];

    this.vData = [0, 0, 0];
    this.tCoords = [0, 0];
    this.vNormals = [0, 0, 0];

    this.positionBuffer = null;
    this.indicesBuffer = null;
    this.normalesBuffer = null;
    this.textureBuffer = null;

    this.processObject();
    this.computeBuffers();
}

getSize() {
    return this.object.numIndices;
}

processObject() {

    var data = this.object.texte.trim().split('\n');
    data = data.map(n => n.trim());

    data.forEach((string) => {
        if (string.startsWith('v ')) {
            let line = string.split(' ');
            this.vData.push(parseFloat(line[1]), parseFloat(line[2]), parseFloat(line[3]));
        }
        else if (string.startsWith('vt ')) {
            let line = string.split(' ');
            this.tCoords.push(parseFloat(line[1]), parseFloat(line[2]));
        }
        else if (string.startsWith('vn ')) {
            let line = string.split(' ');
            this.vNormals.push(parseFloat(line[1]), parseFloat(line[2]), parseFloat(line[3]));
        }
        else if (string.startsWith('f ')) {

            this.vertexIndices.push(++this.object.numIndices);
            this.vertexIndices.push(++this.object.numIndices);
            this.vertexIndices.push(++this.object.numIndices);

            let index1 = string.split(' ')[1]
            let index2 = string.split(' ')[2]
            let index3 = string.split(' ')[3]

            this.processVertex(index1);
            this.processVertex(index2);
            this.processVertex(index3);
        }
    });
}

processVertex(index) {

    let vertexIndex = 3 * parseInt(index.split('/')[0]);
    let textureIndex = 2 * parseInt(index.split('/')[1]);
    let normalIndex = 3 * parseInt(index.split('/')[2]);

    this.vertexData.push(this.vData[vertexIndex]);
    this.vertexData.push(this.vData[vertexIndex + 1]);
    this.vertexData.push(this.vData[vertexIndex + 2]);

    this.textureCoords.push(this.tCoords[textureIndex]);
    this.textureCoords.push(this.tCoords[textureIndex + 1]);

    this.vertexNormals.push(this.vNormals[normalIndex]);
    this.vertexNormals.push(this.vNormals[normalIndex + 1]);
    this.vertexNormals.push(this.vNormals[normalIndex + 2]);
}

computeBuffers = () => {

    this.positionBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.vertexData), this.gl.STATIC_DRAW);

    this.indicesBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
    this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(this.vertexIndices), this.gl.STATIC_DRAW);

    this.normalesBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.normalesBuffer);
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.vertexNormals), this.gl.STATIC_DRAW);

    this.textureBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.textureBuffer);
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.textureCoords), this.gl.STATIC_DRAW);

}


getBuffers = () => {
    return {
        position: this.positionBuffer,
        indices: this.indicesBuffer,
        normales: this.normalesBuffer,
        textureCoords: this.textureBuffer,
    }
}

祝您今天愉快。

弗朗索瓦

EN

回答 1

Stack Overflow用户

发布于 2020-10-17 14:26:24

为了弄清楚这一点,我编写了代码正在使用的WebGL函数的快速emu,足以按原样运行代码并查看结果。当然,我可以只在调试器中查看它。

代码语言:javascript
复制
gl = {
  createBuffer() { return []; },
  bindBuffer(t, b) { this.b = b; },
  bufferData(t, d, h) { this.b.splice(0, this.b.length, ...d); },
};

然后,我抓取了一个多维数据集.obj文件,从每个文件开始检查每个细节。

我是这样运行的

代码语言:javascript
复制
const c = new CubeObj(gl);
console.log(c.getBuffers());

这导致了

我们知道一个立方体应该有36个索引,但实际上只有18个。

问题是f线可以有3个以上的顶点。

我把代码改成这样

代码语言:javascript
复制
 } else if (string.startsWith('f ')) {

    let verts = string.split(' ').slice(1);
    const numTriangles = verts.length - 2;
    for (let i = 0; i < numTriangles; ++i) {
      this.vertexIndices.push(++this.object.numIndices);
      this.vertexIndices.push(++this.object.numIndices);
      this.vertexIndices.push(++this.object.numIndices);
      this.processVertex(verts[0]);
      this.processVertex(verts[i + 1]);
      this.processVertex(verts[i + 2]);
    }
  }

这似乎是可行的

代码语言:javascript
复制
const obj = `
# Blender v2.80 (sub 75) OBJ File: ''
# www.blender.org
mtllib cube.mtl
o Cube
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.375000 0.500000
vt 0.375000 0.750000
vt 0.125000 0.750000
vt 0.625000 0.500000
vt 0.875000 0.500000
vt 0.875000 0.750000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
usemtl Material
s off
f 1/1/1 5/2/1 7/3/1 3/4/1
f 4/5/2 3/6/2 7/7/2 8/8/2
f 8/8/3 7/7/3 5/9/3 6/10/3
f 6/10/4 2/11/4 4/12/4 8/13/4
f 2/14/5 1/15/5 3/16/5 4/17/5
f 6/18/6 5/19/6 1/20/6 2/11/6
`;

class CubeObj {

  constructor(gl) {
    this.gl = gl;
    this.object = {};

    this.object.texte = obj;

    this.object.numIndices = 0;

    this.vertexData = [0, 0, 0];
    this.textureCoords = [0, 0];
    this.vertexNormals = [0, 0, 0];
    this.vertexIndices = [];

    this.vData = [0, 0, 0];
    this.tCoords = [0, 0];
    this.vNormals = [0, 0, 0];

    this.positionBuffer = null;
    this.indicesBuffer = null;
    this.normalesBuffer = null;
    this.textureBuffer = null;

    this.processObject();
    this.computeBuffers();
  }

  getSize() {
    return this.object.numIndices;
  }

  processObject() {

    var data = this.object.texte.trim().split('\n');
    data = data.map(n => n.trim());

    data.forEach((string) => {
      if (string.startsWith('v ')) {
        let line = string.split(' ');
        this.vData.push(parseFloat(line[1]), parseFloat(line[2]), parseFloat(line[3]));
      } else if (string.startsWith('vt ')) {
        let line = string.split(' ');
        this.tCoords.push(parseFloat(line[1]), parseFloat(line[2]));
      } else if (string.startsWith('vn ')) {
        let line = string.split(' ');
        this.vNormals.push(parseFloat(line[1]), parseFloat(line[2]), parseFloat(line[3]));
      } else if (string.startsWith('f ')) {

        let verts = string.split(' ').slice(1);
        const numTriangles = verts.length - 2;
        for (let i = 0; i < numTriangles; ++i) {
          this.vertexIndices.push(++this.object.numIndices);
          this.vertexIndices.push(++this.object.numIndices);
          this.vertexIndices.push(++this.object.numIndices);
          this.processVertex(verts[0]);
          this.processVertex(verts[i + 1]);
          this.processVertex(verts[i + 2]);
        }
      }
    });
  }

  processVertex(index) {

    let vertexIndex = 3 * parseInt(index.split('/')[0]);
    let textureIndex = 2 * parseInt(index.split('/')[1]);
    let normalIndex = 3 * parseInt(index.split('/')[2]);

    this.vertexData.push(this.vData[vertexIndex]);
    this.vertexData.push(this.vData[vertexIndex + 1]);
    this.vertexData.push(this.vData[vertexIndex + 2]);

    this.textureCoords.push(this.tCoords[textureIndex]);
    this.textureCoords.push(this.tCoords[textureIndex + 1]);

    this.vertexNormals.push(this.vNormals[normalIndex]);
    this.vertexNormals.push(this.vNormals[normalIndex + 1]);
    this.vertexNormals.push(this.vNormals[normalIndex + 2]);
  }

  computeBuffers = () => {

    this.positionBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.vertexData), this.gl.STATIC_DRAW);

    this.indicesBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
    this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(this.vertexIndices), this.gl.STATIC_DRAW);

    this.normalesBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.normalesBuffer);
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.vertexNormals), this.gl.STATIC_DRAW);

    this.textureBuffer = this.gl.createBuffer();
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.textureBuffer);
    this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.textureCoords), this.gl.STATIC_DRAW);

  }


  getBuffers = () => {
    return {
      position: this.positionBuffer,
      indices: this.indicesBuffer,
      normales: this.normalesBuffer,
      textureCoords: this.textureBuffer,
    }
  }
}

gl = {
  createBuffer() {
    return [];
  },
  bindBuffer(t, b) {
    this.b = b;
  },
  bufferData(t, d, h) {
    this.b.splice(0, this.b.length, ...d);
  },
};

const c = new CubeObj(gl);
const buffers = c.getBuffers();

const m4 = twgl.m4;
const ctx = document.querySelector('canvas').getContext('2d');

function render(time) {
  const clock = time * 0.001;
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.save();
  ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2);
  ctx.scale(ctx.canvas.width, ctx.canvas.height);
  ctx.lineWidth = 1 / ctx.canvas.width;
  ctx.strokeStyle = "black";

  const fieldOfView = Math.PI * 0.25;
  const aspect = ctx.canvas.clientWidth / ctx.canvas.clientHeight;
  const projection = m4.perspective(fieldOfView, aspect, 0.01, 5);
  const radius = 8;
  const eye = [
    Math.sin(clock) * radius, -2,
    Math.cos(clock) * radius
  ];
  const target = [0, 0, 0];
  const up = [0, 1, 0];
  const camera = m4.lookAt(eye, target, up);
  const view = m4.inverse(camera);

  const worldViewProjection = m4.multiply(projection, view);

  drawLines(buffers.position, buffers.indices, worldViewProjection);
  ctx.restore();
  requestAnimationFrame(render);
}
requestAnimationFrame(render);

function drawLines(cubeVertices, indices, worldViewProjection) {
  ctx.beginPath();
  // transform points
  const points = [];
  for (var ii = 0; ii < cubeVertices.length; ii += 3) {
    points.push(m4.transformPoint(
      worldViewProjection, [cubeVertices[ii + 0], cubeVertices[ii + 1], cubeVertices[ii + 2]]));
  }
  for (var ii = 0; ii < indices.length; ii += 3) {
    var p0 = points[indices[ii + 0]];
    var p1 = points[indices[ii + 1]];
    var p2 = points[indices[ii + 2]];
    ctx.moveTo(p0[0], p0[1]);
    ctx.lineTo(p1[0], p1[1]);
    ctx.lineTo(p2[0], p2[1]);
    ctx.lineTo(p0[0], p0[1]);
  }
  ctx.stroke();
}
代码语言:javascript
复制
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>

您可能会发现this article作为参考很有用。

同样在将来,发布一个可运行的snippet会非常有帮助

所以问题是你的龙有300000个顶点,但是默认情况下,使用索引顶点WebGL只能处理65536个顶点(Uint16)。您可以检查并启用OES_index_element_uint以启用使用32位索引。或者,您可以不使用索引,因为加载器只是将每个顶点视为唯一的。或者,您可以尝试将模型拆分为块,每个块使用的顶点不超过65536个。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64397411

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档