- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我将默认立方体从 Blender 3.0 导出到 gltf+bin。我尝试用纯 WebGL 绘制它。
这只是一个非常简单的例子。您将在此示例中看到魔数(Magic Number),例如:
const normalData = new Float32Array(binData, 288, 288 / Float32Array.BYTES_PER_ELEMENT);
这些数字是byteLength
和byteOffset
。我直接从 BoxBlender3.gltf 文件中获取这些数字。
沙盒演示(由 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/
我有一个 gltf,它是一组建筑。 我想为每个建筑物添加一些信息,为此,我需要向我的 gltf 模型添加一些属性。 但是,我试着添加这样的东西 { "accessors": [ {
我有一个 gltf,它是一组建筑。 我想为每个建筑物添加一些信息,为此,我需要向我的 gltf 模型添加一些属性。 但是,我试着添加这样的东西 { "accessors": [ {
我之前曾在 gltf 1.0 上工作,现在正尝试更新我的应用程序以呈现 khronos 提供的 gltf2.0 示例模型。我了解着色器 (glsl) 和技术不再是 gltf 2.0 中核心属性的一部分
我正在阅读规范,但我无法理解采样器的属性。 这是我的动画 "animations" : [ { "channels" : [ {
您好,我正在尝试使用 Three.Js 实现 3D 模型查看器,但是我在加载时间方面遇到了问题,我不知道问题出在哪里。 作为一个例子,我试图在这里上传这个模型(下载链接):https://opensp
所以官方文档说: Note that the node transform is the local transform of the node relative to the joint, like
阅读 tinygltf 的源代码,我看到了这个: struct Skin { std::string name; int inverseBindMatrices; // required h
我已经使用网站上的 Collada 转换器将 dae 文件转换为 gltf 文件(我使用的是 Linux,所以我找不到转换前后的调试说明)。当我将模型加载到铯中时,它太暗了。然后我编辑 gltf 文件
我正在努力学习 WebGL,玩得很开心!我决定使用 glTF 作为这个项目的 3d 格式。我让它运行良好,但有一个奇怪的异常(exception)。当索引计数较低时(比如一个简单的三 Angular
我在 Blender (2.79) 中制作了一个非常基本的动画,我正在尝试将其导出为 GLTF 或 GLB。我已经成功安装了 gltf exporter并且能够毫无问题地导出非动画模型的 gltfs
IM 使用三个 js 并尝试从 blender 导入 3d 模型,我还使用 webpack 来处理它。我试图加载一个 glb 文件,但无法让它工作。它现在将文件添加到构建时的 dist 文件夹,但它没
我写了一个关于故障的演示场景来测试我在一个框架中导出的 gltf 模型,但我在控制台中收到一个错误: 我的代码 Basic Scene - A-Frame
我们正在尝试在服务器端合并多个 GLTF,并将合并的 gltf 作为最终结果导出到服务器上。 我们已经证实有效但无效的事情: 我们使用了三个 js GLTFLoader 解析方法来加载多个 gltf
我有一个大 obj 306 mb 的文件.所以我把它转换成 glb文件以减小其大小。文件的大小减少了很多到82 mb ,但还是很大。我想让这个文件更小。有办法吗?如果有,请告诉我。 如果不能减少glb
出于调试目的,我想渲染蒙皮网格的骨架。但是,在 glTF 中,它们似乎以非常抽象的方式定义。也就是说,没有“骨架”,一组由线连接的顶点。换句话说,这没有明确定义: 相反,“骨架”实际上是节点的集合,它
我正在尝试操作 gltf 3D 模型,但我不确定颜色是如何导出的。 baseColorFactor 中介于 0 到 1(或小于 1)之间的所有数字。 这肯定不是RGB也不是RGBA(我把这个页面作为引
我是 THREEJS 的新人。过去,我使用过 AFRAME、CESIUM、XEOGL 和 BABYLONJS。但最终,由于内存消耗和性能,我意识到制作 CAD 可视化工具的最佳产品是 THREEJS。
我正在尝试操作 gltf 3D 模型,但我不确定颜色是如何导出的。 baseColorFactor 中介于 0 到 1(或小于 1)之间的所有数字。 这肯定不是RGB也不是RGBA(我把这个页面作为引
有了这个答案作为引用,我已经成功改变了gltf模型的颜色。 ( Change the color of an object (.dae or gltf) in "AR.JS" ) 但是,模型纹理会消失
我正在测试 a-frame 并尝试加载不是本教程中提供的示例的其他 glTF 文件。我从 Sketchfab 下载了几个 glTF 包文件,但它们似乎无法加载。 如果我使用给定文件链接的 aframe
我是一名优秀的程序员,十分优秀!