我正在使用 WebGL 开发一个项目,并且尝试显示一个简单的 OBJ,但是没有显示任何内容。这就是控制台显示的原因:
Unhandled Model Keyword: mtllib at line 1 loadModel.js:85:21
Unhandled Model Keyword: o at line 2 loadModel.js:85:21
Unhandled Model Keyword: usemtl at line 37 loadModel.js:85:21
Unhandled Model Keyword: s at line 38 loadModel.js:85:21
<empty string> app.js:68:13
<empty string> app.js:74:13
WebGL warning: drawArraysInstanced: Vertex fetch requires 36, but attribs only supply 26. 32
After reporting 32, no further warnings will be reported for this WebGL context.
这是我的代码:
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="index.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro&display=swap" rel="stylesheet">
<script src="gl-matrix-min.js" defer></script>
<script type="module" src="app.js" defer></script>
</head>
<body>
<canvas></canvas>
<script>
const c = document.getElementsByTagName("canvas")[0];
c.width = window.innerWidth;
c.height = window.innerHeight;
</script>
</body>
</html>
App.js:
import "./gl-matrix-min.js";
const { mat2, mat2d, mat4, mat3, quat, quat2, vec2, vec3, vec4 } = glMatrix;
import { loadTexture } from "./loadTexture.js"
import { parseOBJ } from "./loadModel.js";
import { loadTextResource, repeat } from "./util.js";
window.onload = function (){
loadTextResource('/Shaders/shader.vs.glsl', function(vsErr, vsText){
if(vsErr){
alert("Error getting vertex shader (check console for more info)");
console.error(vsErr);
}else{
loadTextResource('/Shaders/shader.fs.glsl', function(fsErr, fsText){
if(fsErr){
alert("Error getting fragment shader (check console for more info)");
console.error(fsErr);
}else{
RunScene(vsText, fsText);
}
});
}
});
}
async function RunScene(vsText, fsText){
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
if(!gl){
console.error("WebGL not supported on this browser!");
}
const response = await fetch('Models/test.obj');
const text = await response.text();
const data = parseOBJ(text);
//Vertex Data
const vertexData = data.positions;
// Image UV Data
const uvData = data.texCoords;
// F|L|B|R|T|U
const normalData = data.normals;
// console.log(normalData);
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
const uvBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(uvData), gl.STATIC_DRAW);
const normalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normalData), gl.STATIC_DRAW);
const picture = loadTexture(gl, `Textures/Pablo.png`);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, picture);
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vsText);
gl.compileShader(vertexShader);
console.log(gl.getShaderInfoLog(vertexShader));
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fsText);
gl.compileShader(fragmentShader);
console.log(gl.getShaderInfoLog(fragmentShader));
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
const positionLocation = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(positionLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
const uvLocation = gl.getAttribLocation(program, 'uv');
gl.enableVertexAttribArray(uvLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
gl.vertexAttribPointer(uvLocation, 2, gl.FLOAT, false, 0, 0);
const normalLocation = gl.getAttribLocation(program, 'normal');
gl.enableVertexAttribArray(normalLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.vertexAttribPointer(normalLocation, 3, gl.FLOAT, false, 0, 0);
gl.useProgram(program);
gl.enable(gl.DEPTH_TEST);
const uniformLocations = {
matrix: gl.getUniformLocation(program, 'matrix'),
normalMatrix: gl.getUniformLocation(program, 'normalMatrix'),
textureLocation: gl.getUniformLocation(program, 'textureID'),
};
const modelMatrix = mat4.create();
const viewMatrix = mat4.create();
const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, 75 * Math.PI/180, canvas.width/canvas.height, 1e-4, 1e4);
const mvMatrix = mat4.create();
const mvpMatrix = mat4.create();
const normalMatrix = mat4.create();
mat4.translate(viewMatrix, viewMatrix, [0, 0.01, 2]);
mat4.invert(viewMatrix, viewMatrix);
gl.uniform1i(uniformLocations.textureLocation, 0);
function animate(){
requestAnimationFrame(animate);
mat4.rotateX(modelMatrix, modelMatrix, Math.PI/100);
mat4.rotateY(modelMatrix, modelMatrix, Math.PI/200);
mat4.multiply(mvMatrix, viewMatrix, modelMatrix);
mat4.multiply(mvpMatrix, projectionMatrix, mvMatrix);
mat4.invert(normalMatrix, mvMatrix);
mat4.transpose(normalMatrix, normalMatrix);
gl.uniformMatrix4fv(uniformLocations.matrix, false, mvpMatrix);
gl.uniformMatrix4fv(uniformLocations.normalMatrix, false, normalMatrix);
gl.drawArrays(gl.TRIANGLES, 0, vertexData.length/3);
}
animate();
}
loadModel.js:
export function parseOBJ(text){
const objPositions = [[0, 0, 0]];
const objTexCoords = [[0, 0]];
const objNormals = [[0, 0, 0]];
const objVertexData = [
objPositions,
objTexCoords,
objNormals,
];
let webglVertexData = [
[], //Verts
[], //UV
[], //Normals
];
function addVertex(vert) {
const ptn = vert.split('/');
ptn.forEach((objIndexStr, i) => {
if (!objIndexStr) {
return;
}
const objIndex = parseInt(objIndexStr);
const dataArray = objVertexData[i];
if (dataArray && dataArray.length > 0) {
let index = objIndex > 0 ? objIndex - 1 : dataArray.length + objIndex;
// Ensure the index is within bounds
index = Math.max(0, Math.min(index, dataArray.length - 1));
const data = dataArray[index];
if (data !== undefined) {
webglVertexData[i].push(...dataArray[index]);
} else {
console.error(`Error: Undefined data at index ${index} for objVertexData[${i}]`);
}
} else {
console.error(`Error: No data found for objVertexData[${i}]`);
}
});
}
const keywords = {
v(parts){
objPositions.push(parts.map(parseFloat));
},
vn(parts){
objTexCoords.push(parts.map(parseFloat));
},
vt(parts){
objNormals.push(parts.map(parseFloat));
},
f(parts){
const numTriangles = parts.length - 2;
for(let tri = 0; tri < numTriangles; ++tri){
addVertex(parts[0]);
addVertex(parts[tri + 1]);
addVertex(parts[tri + 2]);
}
}
};
const keywordRE = /(\w*)(?: )*(.*)/;
const lines = text.split('\n');
for(let lineNum = 0; lineNum < lines.length; ++lineNum){
const line = lines[lineNum].trim();
if(line === '' || line.startsWith('#')){
continue;
}
const m = keywordRE.exec(line);
if(!m){
continue;
}
const [, keyword, unparsedArgs] = m;
const parts = line.split(/\s+/).slice(1);
const handler = keywords[keyword];
if(!handler){
console.warn('Unhandled Model Keyword:', keyword, 'at line', lineNum + 1);
continue;
}
handler(parts, unparsedArgs);
}
return {
positions: webglVertexData[0],
texCoords: webglVertexData[1],
normals: webglVertexData[2]
};
}
我相信某些顶点没有提供给 WebGL,但是,当我打印出顶点时,它显示长度为 36 并且顶点本身与 OBJ 文件的顶点匹配。
检查您的 OBJ 文件。您报告的错误通常意味着您没有正确定义 OBJ 文件。它们应该看起来像这样:
# Blender v2.80 (sub 74) OBJ File: ''
# www.blender.org
mtllib test_with_texture.mtl
o Cube
v 1.000000 1.000000 -1.000000
...
...
...
v -1.000000 -1.000000 -1.000000
注意
mtllib
和 o cube
。可能意味着您没有正确定义 OBJ 纹理。
未处理的模型关键字:第 1 行的 mtllib loadModel.js:85:21 未处理的模型关键字:o 在第 2 行 loadModel.js:85:21
请参阅此答案了解更多信息。