gpt4 book ai didi

webgl - 如何从 gltf 2.0 加载立方体并在纯 WebGL 中绘制它

转载 作者:行者123 更新时间:2023-12-05 05:51:39 25 4
gpt4 key购买 nike

我将默认立方体从 Blender 3.0 导出到 gltf+bin。我尝试用纯 WebGL 绘制它。

这只是一个非常简单的例子。您将在此示例中看到魔数(Magic Number),例如:

const normalData = new Float32Array(binData, 288, 288 / Float32Array.BYTES_PER_ELEMENT);

这些数字是byteLengthbyteOffset。我直接从 BoxBlender3.gltf 文件中获取这些数字。

enter image description here

沙盒演示(由 Rabbid76 解决):https://plnkr.co/edit/BYseznZdUBTrUmRa?preview

源代码:

<!DOCTYPE html>
<html lang="en">

<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">
<title>Loading a cube from gltf 2.0. WebGL, JavaScript</title>
<script src="https://cdn.jsdelivr.net/npm/gl-matrix@3.4.3/gl-matrix-min.js"></script>
</head>

<body>
<canvas id="renderCanvas" width="400" height="400"></canvas>
<script>
loadFile("assets/BoxBlender3.gltf", (content) =>
{
const gltf = JSON.parse(content);

loadBin("assets/BoxBlender3.bin", (binData) =>
{
const canvas = document.getElementById("renderCanvas");
const gl = canvas.getContext("webgl");

gl.enable(gl.DEPTH_TEST);

const vertShaderSource =
`attribute vec4 aPosition;
attribute vec4 aNormal;
uniform mat4 uMvpMatrix;
uniform mat4 uModelMatrix;
uniform mat4 uNormalMatrix;
varying vec3 vPosition;
varying vec3 vNormal;
void main()
{
gl_Position = uMvpMatrix * aPosition;
vPosition = vec3(uModelMatrix * aPosition);
vNormal = normalize(vec3(uNormalMatrix * aNormal));
}`;

const fragShaderSource =
`precision mediump float;
const vec3 lightColor = vec3(1.0, 1.0, 1.0);
const vec3 ambientLight = vec3(0.2, 0.2, 0.2);
uniform vec3 uLightPosition;
varying vec3 vPosition;
varying vec3 vNormal;
void main()
{
vec4 color = vec4(0.5, 1.0, 0.5, 1.0);
vec3 normal = normalize(vNormal);
vec3 lightDirection = normalize(uLightPosition - vPosition);
float nDotL = max(dot(lightDirection, normal), 0.0);
vec3 diffuse = lightColor * color.rgb * nDotL;
vec3 ambient = ambientLight * color.rgb;
gl_FragColor = vec4(diffuse + ambient, color.a);
}`;

const vShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vShader, vertShaderSource);
gl.compileShader(vShader);
let ok = gl.getShaderParameter(vShader, gl.COMPILE_STATUS);
if (!ok) { console.log("vert: " + gl.getShaderInfoLog(vShader)); };

const fShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fShader, fragShaderSource);
gl.compileShader(fShader);
ok = gl.getShaderParameter(vShader, gl.COMPILE_STATUS);
if (!ok) { console.log("frag: " + gl.getShaderInfoLog(fShader)); };

const program = gl.createProgram();
gl.attachShader(program, vShader);
gl.attachShader(program, fShader);
gl.bindAttribLocation(program, 0, "aPosition");
gl.bindAttribLocation(program, 1, "aNormal");
gl.linkProgram(program);
ok = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!ok) { console.log("link: " + gl.getProgramInfoLog(program)); };
gl.useProgram(program);

// Create a cube
// v6----- v5
// /| /|
// v1------v0|
// | | | |
// | |v7---|-|v4
// |/ |/
// v2------v3

// const vertPositions = [
// 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, // v0-v1-v2-v3 front
// 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, // v0-v3-v4-v5 right
// 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, // v0-v5-v6-v1 up
// -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, // v1-v6-v7-v2 left
// -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, // v7-v4-v3-v2 down
// 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5 // v4-v7-v6-v5 back
// ];
const vertPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertPosBuffer);
// gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertPositions), gl.STATIC_DRAW);
// const vertPosData = new Uint8Array(binData, 0, 288);
const vertPosData = new Float32Array(binData, 0, 288 / Float32Array.BYTES_PER_ELEMENT);
gl.bufferData(gl.ARRAY_BUFFER, vertPosData, gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(0);

// const normals = [
// 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front
// 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
// 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
// -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
// 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, // v7-v4-v3-v2 down
// 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0 // v4-v7-v6-v5 back
// ];
const normalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
// gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
// const normalData = new Uint8Array(binData, 288, 288);
const normalData = new Float32Array(binData, 288, 288 / Float32Array.BYTES_PER_ELEMENT);
gl.bufferData(gl.ARRAY_BUFFER, normalData, gl.STATIC_DRAW);
gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(1);

// const indices = [
// 0, 1, 2, 0, 2, 3, // front
// 4, 5, 6, 4, 6, 7, // right
// 8, 9, 10, 8, 10, 11, // up
// 12, 13, 14, 12, 14, 15, // left
// 16, 17, 18, 16, 18, 19, // down
// 20, 21, 22, 20, 22, 23 // back
// ];
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
const indexData = new Uint8Array(binData, 576, 72);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexData, gl.STATIC_DRAW);

const projMatrix = glMatrix.mat4.create();
glMatrix.mat4.perspective(projMatrix, 55 * Math.PI / 180, 1, 0.1, 500);
const viewMatrix = glMatrix.mat4.create();
glMatrix.mat4.lookAt(viewMatrix, [4, 5, 20], [0, 0, 0], [0, 1, 0]);
const projViewMatrix = glMatrix.mat4.create();
glMatrix.mat4.mul(projViewMatrix, projMatrix, viewMatrix);

const modelMatrix = glMatrix.mat4.create();
glMatrix.mat4.fromTranslation(modelMatrix, [0, 0, 0]);
glMatrix.mat4.rotate(modelMatrix, modelMatrix, 0 * Math.PI / 180, [1, 0, 0]);
glMatrix.mat4.scale(modelMatrix, modelMatrix, [5, 5, 5]);
const mvpMatrix = glMatrix.mat4.create();
glMatrix.mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
const uMvpMatrixLocation = gl.getUniformLocation(program, "uMvpMatrix");
gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);
const uModelMatrixLocation = gl.getUniformLocation(program, "uModelMatrix");
gl.uniformMatrix4fv(uModelMatrixLocation, false, modelMatrix);

const normalMatrix = glMatrix.mat4.create();
glMatrix.mat4.invert(normalMatrix, modelMatrix);
glMatrix.mat4.transpose(normalMatrix, normalMatrix);
const uNormalMatrixLocation = gl.getUniformLocation(program, "uNormalMatrix");
gl.uniformMatrix4fv(uNormalMatrixLocation, false, normalMatrix);

const lightPosition = glMatrix.vec3.fromValues(4, 7, 5);
const uLightPositionLocation = gl.getUniformLocation(program, "uLightPosition");
gl.uniform3fv(uLightPositionLocation, lightPosition);

gl.clearColor(0.2, 0.2, 0.2, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_BYTE, 0);
});
});

function loadFile(path, callback)
{
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () =>
{
if (xhr.readyState === 4 && xhr.status != 404)
{
callback(xhr.responseText);
}
};
xhr.open("GET", path, true);
xhr.send();
}

function loadBin(path, callback)
{
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () =>
{
if (xhr.readyState === 4 && xhr.status != 404)
{
callback(xhr.response);
}
};

xhr.open("GET", path, true);
xhr.responseType = "arraybuffer";
xhr.send();
}
</script>
</body>

</html>

BoxBlender3.gltf

{
"asset" : {
"generator" : "Khronos glTF Blender I/O v1.7.33",
"version" : "2.0"
},
"scene" : 0,
"scenes" : [
{
"name" : "Scene",
"nodes" : [
0
]
}
],
"nodes" : [
{
"mesh" : 0,
"name" : "Cube"
}
],
"materials" : [
{
"doubleSided" : true,
"name" : "Material",
"pbrMetallicRoughness" : {
"baseColorFactor" : [
0.800000011920929,
0.800000011920929,
0.800000011920929,
1
],
"metallicFactor" : 0,
"roughnessFactor" : 0.4000000059604645
}
}
],
"meshes" : [
{
"name" : "Cube",
"primitives" : [
{
"attributes" : {
"POSITION" : 0,
"NORMAL" : 1
},
"indices" : 2,
"material" : 0
}
]
}
],
"accessors" : [
{
"bufferView" : 0,
"componentType" : 5126,
"count" : 24,
"max" : [
1,
1,
1
],
"min" : [
-1,
-1,
-1
],
"type" : "VEC3"
},
{
"bufferView" : 1,
"componentType" : 5126,
"count" : 24,
"type" : "VEC3"
},
{
"bufferView" : 2,
"componentType" : 5123,
"count" : 36,
"type" : "SCALAR"
}
],
"bufferViews" : [
{
"buffer" : 0,
"byteLength" : 288,
"byteOffset" : 0
},
{
"buffer" : 0,
"byteLength" : 288,
"byteOffset" : 288
},
{
"buffer" : 0,
"byteLength" : 72,
"byteOffset" : 576
}
],
"buffers" : [
{
"byteLength" : 648,
"uri" : "BoxBlender3.bin"
}
]
}

最佳答案

索引似乎是 16 位整数而不是 8 位整数:

const indexData = new Uint8Array(binData, 576, 72);

72 是 36 个索引,每个 2 个字节用于立方体 6 个边的 2 个三角形。

使用 16 位数组:

const indexData = new Uint16Array(binData, 576, 36);

gl.UNSIGNED_SHORT 而不是 gl.UNSIGNED_BYTE:

gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);

关于webgl - 如何从 gltf 2.0 加载立方体并在纯 WebGL 中绘制它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70346520/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com