Skip to content

Instantly share code, notes, and snippets.

@jeantimex
Created July 22, 2024 01:00
Show Gist options
  • Save jeantimex/0dcd6c5b1c20112a49695c5048925ce7 to your computer and use it in GitHub Desktop.
Save jeantimex/0dcd6c5b1c20112a49695c5048925ce7 to your computer and use it in GitHub Desktop.
Load glTF for a simple cube
{
"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"
}
]
}
<!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/[email protected]/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);
const indexData = new Uint16Array(binData, 576, 36);
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, [10, 15, 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(7, 8, 9);
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_SHORT, 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>
@jeantimex
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment