Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to load a cube from gltf 2.0 and draw it in pure WebGL

I exported a default cube from Blender 3.0 to gltf+bin. I try to draw it in pure WebGL.

It is just a very simple example. I do not understand what is wrong. I do not have details: It looks like your post is mostly code; please add some more details. It looks like your post is mostly code; please add some more details. It looks like your post is mostly code; please add some more details.

enter image description here

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Sandbox demo (solved by Rabbid76): https://plnkr.co/edit/BYseznZdUBTrUmRa?preview

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"
        }
    ]
}

Source code:

<!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.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.bindAttribLocation(program, 0, "aPosition");
                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.bindAttribLocation(program, 1, "aNormal");
                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>

>Solution :

The indices appear to be 16-bit integers instead of 8-bit integers:

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

72 are 36 indices with 2 bytes each for the 2 triangles for each of the 6 sides of the cube.

Use a 16 bit array:

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

and gl.UNSIGNED_SHORT instead of gl.UNSIGNED_BYTE:

gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading