0
votes

I'm currently working on a website about WebGL. My partner and I want to use a small but interesting WebGL background.

What we're trying to do is to get a box rotating on a canvas. Now, the principle of it is already working. We already have a rotating box, however many of the triangles are using the wrong vertices to form their triangle causing the picture below:

The rotating cube with a bad triangle setup.

So, we figured: Lets use indices to set it up properly. This however causes the box to just vanish from the canvas. It doesn't appear to be anywhere anymore.

Our question is: Could someone see why this is happening? We got the feeling we're very close but just this tiny detail is really causing some trouble for us.

The code we're using is provided below. Any other feedback is always welcome too.

Current Program

// ROTATING EXAMPLE

// The canvas that the GL environment will be using.
var canvas = null;

// The Graphics Library, aka: WebGL.
var openGL = null;

// The shader used by the graphics library.
var shaderProgram = null;

// Our matrices.
var modelViewMatrix;
var modelNormalMatrix;
var perspectiveMatrix;

var VertexBuffer;
var ColorBuffer;
var NormalBuffer;
var IndicesBuffer;

var vertexPositionAttribute;
var vertexColorAttribute;
var vertexNormalAttribute;

var squareRotation = 0.0;
var lastSquareUpdateTime = null;

// Encapsulation of the initialisation of WebGL.
function initWebGL(openGLCanvas) {

    var gl = null;

    // Attempt to build the context.
    try {
        gl = openGLCanvas.getContext("webgl", { premultipliedAlpha: false })
            || openGLCanvas.getContext("experimental-webgl", { premultipliedAlpha: false });
    }

    // Report back to use when some exception is thrown.
        catch (exception) {
            console.log("An error happened when trying to initialise the openGL environment. See the exception below for details.");
            console.log(exception);

            gl = null;
        }

    return gl;

}

function initialise(){      
    // Keep this variable local. We do not need it globally.
    var openGLCanvas = document.getElementById("openGLCanvas");

    openGL = initWebGL(openGLCanvas);

    if(openGL)
        {
            // The color to use to clear the screen.
            openGL.clearColor(0.9, 0.9, 0.9, 1.0);
            openGL.clearDepth(1.0);

            // Enables the depth testing.
            openGL.enable(openGL.DEPTH_TEST);

            // Closer things will overlap with things further away.
            openGL.depthFunc(openGL.LEQUAL);

            // Clear both the color as the depth buffer.
            openGL.clear(openGL.COLOR_BUFFER_BIT |openGL.DEPTH_BUFFER_BIT);

            openGL.viewport(0, 0, openGLCanvas.width, openGLCanvas.height);

            InitialiseShaders();

            InitialiseBuffers();

            setInterval(drawScene, 15);
            //drawScene();
        }
}

function InitialiseShaders()
{
    var fragmentShader = retrieveShader(openGL, "04fragment", "f", "shader");
    var vertexShader = retrieveShader(openGL, "04vertex", "v", "shader");

    //console.log(fragmentShader);
    //console.log(vertexShader);

    shaderProgram = openGL.createProgram();
    openGL.attachShader(shaderProgram, vertexShader);
    openGL.attachShader(shaderProgram, fragmentShader);
    openGL.linkProgram(shaderProgram);

    if(!openGL.getProgramParameter(shaderProgram, openGL.LINK_STATUS))
        {
            console.log("Something went wrong during the initialisation of the shader program. See below for extra information.");
            console.log(openGL.getProgramParameter(shaderProgram, openGL.LINK_STATUS));
        }

    openGL.useProgram(shaderProgram);

    vertexPositionAttribute = openGL.getAttribLocation(shaderProgram, "position");
    openGL.enableVertexAttribArray(vertexPositionAttribute);

    vertexColorAttribute = openGL.getAttribLocation(shaderProgram, "color");
    openGL.enableVertexAttribArray(vertexColorAttribute);

    vertexNormalAttribute = openGL.getAttribLocation(shaderProgram, "normal");
    openGL.enableVertexAttribArray(vertexNormalAttribute);
}

function retrieveShader(openGL, filename, type, filetype)
{       // Ensure the file type is always given.
    filetype = filetype || "txt";

        // Read out the source file.
    var source = "";    
    $.ajax({
        url: "Shaders/" + filename + "." + filetype,
        async: false,
        success: function(data) { source = data; }
    });

    console.info("Found source for the following filename: " + filename + ", of type: " + type + ".");
    console.info(source);

        // Check what type the shader should be.
        // If the type is unknown we can see the error report within the console.
    var shader;
    if(type == "f")
    { shader = openGL.createShader(openGL.FRAGMENT_SHADER);}
    else if (type == "v")
        { shader = openGL.createShader(openGL.VERTEX_SHADER);}
    else 
        {
            console.log("Unknown shader type. See below for extra information.");
            console.log(identification);
            console.log(shaderScript.type);
            return null;
        }

        // Attempt to compile the shader.
    openGL.shaderSource(shader, source);
    openGL.compileShader(shader);

        // Check whether or not there are any compilation errors.
        // If there are any, we'll be able to see the error report within the console.
    if(!openGL.getShaderParameter(shader, openGL.COMPILE_STATUS))
        {
            console.log("An error occured during the compilation of the shader. See below for extra information.");
            console.log(openGL.getShaderInfoLog(shader));
            return null;
        }

        // All is green. 
        // Lets start this baby up.
    return shader;
}

function InitialiseBuffers()
{
    bufferPosition();
    bufferColor();
    bufferNormal();
    bufferIndices();
}

function bufferIndices(){

    var indices = [
      0,  1,  2,      0,  2,  3,    // front
      4,  5,  6,      4,  6,  7,    // back
      8,  9,  10,     8,  10, 11,   // top
      12, 13, 14,     12, 14, 15,   // bottom
      16, 17, 18,     16, 18, 19,   // right
      20, 21, 22,     20, 22, 23    // left
    ];

    IndicesBuffer = openGL.createBuffer();
    openGL.bindBuffer(openGL.ELEMENT_ARRAY_BUFFER, IndicesBuffer);
    openGL.bufferData(openGL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), openGL.STATIC_DRAW);
}

function bufferPosition()
{
    // Vertex data for a 3D box.
    var vertices = [
      // Front face
      -1.0, -1.0,  1.0,
       1.0, -1.0,  1.0,
       1.0,  1.0,  1.0,
      -1.0,  1.0,  1.0,

      // Back face
      -1.0, -1.0, -1.0,
      -1.0,  1.0, -1.0,
       1.0,  1.0, -1.0,
       1.0, -1.0, -1.0,

      // Top face
      -1.0,  1.0, -1.0,
      -1.0,  1.0,  1.0,
       1.0,  1.0,  1.0,
       1.0,  1.0, -1.0,

      // Bottom face
      -1.0, -1.0, -1.0,
       1.0, -1.0, -1.0,
       1.0, -1.0,  1.0,
      -1.0, -1.0,  1.0,

      // Right face
       1.0, -1.0, -1.0,
       1.0,  1.0, -1.0,
       1.0,  1.0,  1.0,
       1.0, -1.0,  1.0,

      // Left face
      -1.0, -1.0, -1.0,
      -1.0, -1.0,  1.0,
      -1.0,  1.0,  1.0,
      -1.0,  1.0, -1.0
    ];

    // Create a buffer, prep it for filling and then fill it.
    VertexBuffer = openGL.createBuffer();
    openGL.bindBuffer(openGL.ARRAY_BUFFER, VertexBuffer);
    openGL.bufferData(openGL.ARRAY_BUFFER, new Float32Array(vertices), openGL.STATIC_DRAW);
}

function bufferColor()
{
    // Color data for a 3D Box.
    var colorPerFace = [
      [0.8,  0.9,  0.75,  1.0],    // Front face
      [0.8,  0.9,  0.75,  1.0],   // Back face
      [0.8,  0.9,  0.75,  1.0],    // Top face
      [0.8,  0.9,  0.75,  1.0],    // Bottom face
      [0.8,  0.9,  0.75,  1.0],    // Right face
      [0.8,  0.9,  0.75,  1.0],     // Left face
    ];

    var colors = [];

    // For each face.
    for (j=0; j<6; j++) {
      var c = colorPerFace[j];
        // generate a color for every vertex on that face.
      for (var i=0; i<4; i++) {
        colors = colors.concat(c);
      }
    }

    // Create a buffer, prep it and then fill it.
    ColorBuffer = openGL.createBuffer();
    openGL.bindBuffer(openGL.ARRAY_BUFFER, ColorBuffer);
    openGL.bufferData(openGL.ARRAY_BUFFER, new Float32Array(colors), openGL.STATIC_DRAW);
}

function bufferNormal()
{

    var vertexNormals = [
      // Front
       0.0,  0.0,  1.0,
       0.0,  0.0,  1.0,
       0.0,  0.0,  1.0,
       0.0,  0.0,  1.0,

      // Back
       0.0,  0.0, -1.0,
       0.0,  0.0, -1.0,
       0.0,  0.0, -1.0,
       0.0,  0.0, -1.0,

      // Top
       0.0,  1.0,  0.0,
       0.0,  1.0,  0.0,
       0.0,  1.0,  0.0,
       0.0,  1.0,  0.0,

      // Bottom
       0.0, -1.0,  0.0,
       0.0, -1.0,  0.0,
       0.0, -1.0,  0.0,
       0.0, -1.0,  0.0,

      // Right
       1.0,  0.0,  0.0,
       1.0,  0.0,  0.0,
       1.0,  0.0,  0.0,
       1.0,  0.0,  0.0,

      // Left
      -1.0,  0.0,  0.0,
      -1.0,  0.0,  0.0,
      -1.0,  0.0,  0.0,
      -1.0,  0.0,  0.0
    ];

    NormalBuffer = openGL.createBuffer();
    openGL.bindBuffer(openGL.ARRAY_BUFFER, NormalBuffer);
    openGL.bufferData(openGL.ARRAY_BUFFER, new Float32Array(vertexNormals), openGL.STATIC_DRAW);
}

function drawScene()
{           
    openGL.clear(openGL.GL_COLOR_BUFFER_BIT | openGL.DEPTH_BUFFER_BIT);

    updateScene();

    // Clear both the color as the depth buffer.


    openGLBindings();

    openGL.drawElements(openGL.TRIANGLE, 24, openGL.UNSIGNED_SHORT, 0);
    openGL.drawArrays(openGL.TRIANGLE_STRIP, 0, 24);
    console.log("Scene made!");
}

function updateScene()
{
    var currentTime = Date.now();
    if (lastSquareUpdateTime) {
      var delta = currentTime - lastSquareUpdateTime;

      squareRotation += (30 * delta) / 2000.0;
    }

    lastSquareUpdateTime = currentTime;


    // Calculate the matrices

    modelViewMatrix = Matrix.I(4);

    var inRadians = squareRotation * Math.PI / 180;
    modelViewMatrix = modelViewMatrix.x(Matrix.Translation($V([0.0, 0.0, -12.0])).ensure4x4());
    modelViewMatrix = modelViewMatrix.x(Matrix.Rotation(inRadians, $V([1, 1, 0])).ensure4x4());

    modelNormalMatrix = modelViewMatrix.inverse();
    modelNormalMatrix = modelNormalMatrix.transpose();

    perspectiveMatrix = makePerspective(45, 520 / 520, 0.1, 100.0);


    // Send the matrices to the GPU.

    var mvUniform = openGL.getUniformLocation(shaderProgram, "matrixModelView");
    openGL.uniformMatrix4fv(mvUniform, 
                            false, 
                            new Float32Array(modelViewMatrix.flatten()));

    var pUniform = openGL.getUniformLocation(shaderProgram, "matrixPerspective");
    openGL.uniformMatrix4fv(pUniform, 
                            false, 
                            new Float32Array(perspectiveMatrix.flatten()));

    var nUniform = openGL.getUniformLocation(shaderProgram, "matrixNormal");
    openGL.uniformMatrix4fv(nUniform, 
                            false, 
                            new Float32Array(modelNormalMatrix.flatten()));
}

function openGLBindings()
{   
    // Send the data to the GPU.

    openGL.bindBuffer(openGL.ARRAY_BUFFER, VertexBuffer);
    openGL.vertexAttribPointer(vertexPositionAttribute,     // Where to bind it to
                               3,                           // The number of data per set.
                               openGL.FLOAT,                // The type of data
                               false,                       // Normalisation (or not).
                               0,                           // Stride
                               0);                          // Offset

    openGL.bindBuffer(openGL.ARRAY_BUFFER, ColorBuffer);
    openGL.vertexAttribPointer(vertexColorAttribute,        // Where to bind it to
                               4,                           // The number of data per set.
                               openGL.FLOAT,                    // The type of data.
                               false,                       // Normalisation (or not).
                               0,                           // Stride
                               0);                          // Offset

    openGL.bindBuffer(openGL.ARRAY_BUFFER, NormalBuffer);
    openGL.vertexAttribPointer(vertexNormalAttribute,       // Where to bind it to
                               3,                           // The number of data per set.
                               openGL.FLOAT,                // The type of data.
                               false,                       // Normalisation (or not).
                               0,                           // Stride
                               0);                          // Offset

    openGL.bindBuffer(openGL.ELEMENT_ARRAY_BUFFER, IndicesBuffer);
}

Fragment Shader

varying lowp vec4 fColor;

void main(void) {
    gl_FragColor = fColor;
}

Vertex Shader

attribute vec3 position;
attribute vec3 normal;
attribute vec4 color;

uniform mat4 matrixModelView;
uniform mat4 matrixPerspective;
uniform mat4 matrixNormal;

varying lowp vec4 fColor;

void main(void) {
    gl_Position = matrixPerspective * matrixModelView * vec4(position, 1.0);

    highp vec3 directionalVector = vec3(1.0, 0.85, 0.6);

    highp vec4 transformedNormal = matrixNormal * vec4(normal, 1.0);
    highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);

    fColor = color * directional;
}
1

1 Answers

1
votes

After a quick browsing through your code I found the following line

openGL.drawElements(openGL.TRIANGLE, 24, openGL.UNSIGNED_SHORT, 0);

quite suspicious. You have a total of 6(quad) * 2(triangles/quad) * 3(vertices/triangles) = 36 indices instead of 24. Also your bufferindices contains 36 ints.

However, the immediate following line

openGL.drawArrays(openGL.TRIANGLE_STRIP, 0, 24);

shows that your are drawing the quad as triangle strip. You need to be consistent when drawing the triangles, i.e. rendering them all either as TRIANGLES or TRIANGLE_STRIP. If you want to draw as TRIANGLE_STRIP, then the definition of

 var vertices = [
  // Front face
  -1.0, -1.0,  1.0,
   1.0, -1.0,  1.0,
   1.0,  1.0,  1.0,
  -1.0,  1.0,  1.0,
........
];

is not a correct ordering of defining a quad a triangle trip. The correct way should be

 var vertices = [
  // Front face
  -1.0, -1.0,  1.0,
   1.0, -1.0,  1.0,
  -1.0,  1.0,  1.0,
   1.0,  1.0,  1.0,
...
]

The same thing applied to the definition of other faces.