WebGL JavaScript

Viewing the Default Viewing Space

This JavaScript program demonstrates the default viewing space for a WebGL program. The default viewing space is a the 2 by 2 by 2 cube from -1 to 1 in the x, y, and z dimensions.

ViewingTheDefaultViewingSpace.html

<!DOCTYPE html>
<html>
  <head>
    <title>XoaX.net's WebGL</title>

    <script  id="idModelVertexShader" type="c">
      attribute vec4 av4Vertex;
      attribute vec4 av4Color;
      varying vec4 vv4Color;
      void main() {
        gl_Position = av4Vertex;
        vv4Color = av4Color;
      }
    </script>

    <script  id="idModelFragmantShader" type="c">
      precision mediump float;
      varying vec4 vv4Color;
      void main() {
        gl_FragColor = vv4Color;
      }
    </script>

    <script  id="idViewVertexShader" type="c">
      attribute vec4 av4Vertex;
      attribute vec4 av4Color;
      varying vec4 vv4Color;
      void main() {
        gl_Position = av4Vertex;
        vv4Color = av4Color;
      }
    </script>

    <script  id="idViewFragmantShader" type="c">
      precision mediump float;
      varying vec4 vv4Color;
      void main() {
        gl_FragColor = vv4Color;
      }
    </script>

    <script type="text/javascript">
    var gqModelWebGL = null;
    var gqViewWebGL = null;
    function CreateProgramAndContext(qInstanceWebGL) {
      // Get the WebGL Context
      var qCanvas = document.querySelector("#"+qInstanceWebGL.msCanvasID);
      qInstanceWebGL.mqGL = qCanvas.getContext("webgl");
      var qGL = qInstanceWebGL.mqGL;

      // Compile the vertex shader
      var sVertexShaderCode = document.querySelector("#"+qInstanceWebGL.msVertexShaderID).text;
      var qVertexShader = qGL.createShader(qGL.VERTEX_SHADER);
      qGL.shaderSource(qVertexShader, sVertexShaderCode);
      qGL.compileShader(qVertexShader);

      // Compile the fragment shader
      var sFragmentShaderCode = document.querySelector("#"+qInstanceWebGL.msFragmentShaderID).text;
      var qFragmentShader = qGL.createShader(qGL.FRAGMENT_SHADER);
      qGL.shaderSource(qFragmentShader, sFragmentShaderCode);
      qGL.compileShader(qFragmentShader);

      // Compile and link the program
      qInstanceWebGL.mqProgram = qGL.createProgram();
      qGL.attachShader(qInstanceWebGL.mqProgram, qVertexShader);
      qGL.attachShader(qInstanceWebGL.mqProgram, qFragmentShader);
      qGL.linkProgram(qInstanceWebGL.mqProgram);
      qGL.useProgram(qInstanceWebGL.mqProgram);
    }
	function CreateBuffers(qInstanceWebGL) {
	  var qGL = qInstanceWebGL.mqGL;
      var qVerticesBuffer = qGL.createBuffer();
      qGL.bindBuffer(qGL.ARRAY_BUFFER, qVerticesBuffer);
      qGL.bufferData(qGL.ARRAY_BUFFER, qInstanceWebGL.mfaTransformedVertices, qGL.STATIC_DRAW);

      var qVertexLoc = qGL.getAttribLocation(qInstanceWebGL.mqProgram, 'av4Vertex');
      qGL.vertexAttribPointer(qVertexLoc, 4, qGL.FLOAT, false, 0, 0);
      qGL.enableVertexAttribArray(qVertexLoc);

      var qColorsBuffer = qGL.createBuffer();
	  qGL.bindBuffer(qGL.ARRAY_BUFFER, qColorsBuffer);
	  qGL.bufferData(qGL.ARRAY_BUFFER, qInstanceWebGL.mfaVertexColors, qGL.STATIC_DRAW);

	  var qColors = qGL.getAttribLocation(qInstanceWebGL.mqProgram, 'av4Color');
	  qGL.vertexAttribPointer(qColors, 4, qGL.FLOAT, false, 0, 0);
      qGL.enableVertexAttribArray(qColors);
	}
    var gfaVertices = null;
    function Initialization() {
      gfaVertices = new Float32Array([
        // Put the vertices for the diamond first, then the cube vertices
        0.0, 0.85, 0.0, 1.0,  0.85, 0.0, 0.85, 1.0,   -0.85, 0.0, -0.85, 1.0,  0.0, -0.85, 0.0, 1.0,
        // These must be drawn back to front to render it correctly with the alpha blending
        -1.0, 1.0, 1.0, 1.0,  -1.0, 1.0, -1.0, 1.0,   -1.0, -1.0, 1.0, 1.0,   -1.0, -1.0, -1.0, 1.0,  // x = -1
        1.0, -1.0, 1.0, 1.0,  1.0, -1.0, -1.0, 1.0,   -1.0, -1.0, 1.0, 1.0,   -1.0, -1.0, -1.0, 1.0,  // y = -1
        1.0, 1.0, -1.0, 1.0,  1.0, -1.0, -1.0, 1.0,   -1.0, 1.0, -1.0, 1.0,   -1.0, -1.0, -1.0, 1.0,  // z = -1
        1.0, 1.0, 1.0, 1.0,   1.0, -1.0, 1.0, 1.0,   1.0, 1.0, -1.0, 1.0,   1.0, -1.0, -1.0, 1.0,    // x = 1
        1.0, 1.0, 1.0, 1.0,   1.0, 1.0, -1.0, 1.0,   -1.0, 1.0, 1.0, 1.0,    -1.0, 1.0, -1.0, 1.0,  // y = 1
        1.0, 1.0, 1.0, 1.0,   -1.0, 1.0, 1.0, 1.0,   1.0, -1.0, 1.0, 1.0,    -1.0, -1.0, 1.0, 1.0  // z = 1
      ]);
      gqModelWebGL = new CInstanceWebGL("idModelCanvas", "idModelVertexShader", "idModelFragmantShader", 4);
      gqViewWebGL = new CInstanceWebGL("idViewCanvas", "idViewVertexShader", "idViewFragmantShader", 7*4);
      CreateProgramAndContext(gqModelWebGL);
      CreateProgramAndContext(gqViewWebGL);
      CreateBuffers(gqModelWebGL);
      CreateBuffers(gqViewWebGL);
      // Begin the animation loop.
      const kiIntervalId = setInterval(Render, 20);
    }
    function Render() {
	  RenderModel(gqModelWebGL);
	  RenderModel(gqViewWebGL);
    }

    var gfAngle = 0.0;
    function RenderModel(qInstanceWebGL) {
      var qGL = qInstanceWebGL.mqGL;
      var faVert = qInstanceWebGL.mfaTransformedVertices;
      var faClr = qInstanceWebGL.mfaVertexColors;
      // Create the rotation matrix
      var faRotationMatrix = CreateARotationAroundYMatrix(gfAngle);
      // Transform the first four vertices by the rotation: 4 vertices with 4 coordinates
      // First copy the vertices before the transformation
      for (var i = 0; i < 16; ++i) {
        faVert[i] = gfaVertices[i];
      }
      // Transform each diamond vertex
      for (var i = 0; i < 4; ++i) {
        MultiplyMatrixVertex(faRotationMatrix, faVert, 4*i);
        // Set the colors too
        faClr[4*i]      = .25;
        faClr[4*i + 1]  = .4 + Math.min(Math.max(Math.sin(faVert[4*i + 2]), -.4), .4);
        faClr[4*i + 2]  = .25;
        faClr[4*i + 3]  = 1.0;
      }
      gfAngle += .01;
      gfAngle = ((gfAngle >= 2.0*Math.PI) ? (gfAngle - 2.0*Math.PI) : gfAngle);
      if (qInstanceWebGL === gqViewWebGL) {
        var faLookAtMatrix = CreateLookAtMatrix([1, 3, 2],[0, 0, 0],[0, 1, 0]);
        // Create the orthographic matrix
        var faOrthoMatrix =  CreateOrthographicMatrix(-2.0, 2.0, -2.0, 2.0, 2.0, -2.0);
        MultiplyMatrices(faOrthoMatrix, faLookAtMatrix);
        // Add the extra colors for the view cube
        for (var iFace = 0; iFace < 6; ++iFace) {
          var fBrightness = 0.0;
          if (iFace % 3 == 0) {
            fBrightness = 1.0/7.0;
          } else if (iFace % 3 == 2) {
            fBrightness = 2.0/7.0;
          } else {
            fBrightness = 4.0/7.0;
          }
          var iBase = 16 + 16*iFace;
          for (var iVertex = 0; iVertex < 4; ++iVertex) {
            var iOffset = iBase + 4*iVertex;
            faVert[iOffset] = gfaVertices[iOffset];
            faVert[iOffset + 1] = gfaVertices[iOffset + 1];
            faVert[iOffset + 2] = gfaVertices[iOffset + 2];
            faVert[iOffset + 3] = gfaVertices[iOffset + 3];
            faClr[iOffset]     = fBrightness;
            faClr[iOffset + 1] = fBrightness;
            faClr[iOffset + 2] = fBrightness;
            faClr[iOffset + 3] = .2;
          }
        }
        for (var i = 0; i < 28; ++i) {
          MultiplyMatrixVertex(faOrthoMatrix, faVert, 4*i);
        }
      }
      // We need to create the buffers afterward
      CreateBuffers(qInstanceWebGL);
      qGL.clearColor(0.0, 0.0, 0.0, 1.0);
      if (qInstanceWebGL !== gqViewWebGL) {
        qGL.clear(qGL.COLOR_BUFFER_BIT);
        qGL.drawArrays(qGL.TRIANGLE_STRIP, 0, 4);
      } else {
        qGL.enable(qGL.DEPTH_TEST);
        qGL.clear(qGL.COLOR_BUFFER_BIT | qGL.DEPTH_BUFFER_BIT);
        // Enable alpha blending
        qGL.enable(qGL.BLEND);
        // Set blending function
        qGL.blendFunc(qGL.SRC_ALPHA, qGL.ONE_MINUS_SRC_ALPHA);
        qGL.drawArrays(qGL.TRIANGLE_STRIP, 0, 4);
        // The six sides
        qGL.drawArrays(qGL.TRIANGLE_STRIP, 4, 4);
        qGL.drawArrays(qGL.TRIANGLE_STRIP, 8, 4);
        qGL.drawArrays(qGL.TRIANGLE_STRIP, 12, 4);
        qGL.drawArrays(qGL.TRIANGLE_STRIP, 16, 4);
        qGL.drawArrays(qGL.TRIANGLE_STRIP, 20, 4);
        qGL.drawArrays(qGL.TRIANGLE_STRIP, 24, 4);
      }
    }

    function CreateARotationAroundYMatrix(fRotateRadians) {
      var fSin = Math.sin(fRotateRadians);
      var fCos = Math.cos(fRotateRadians);
      var faMatrix = new Float32Array([
        fCos,   0.0,  -fSin,   0.0,
        0.0,    1.0,   0.0,    0.0,
        fSin,   0.0,   fCos,   0.0,
        0.0,    0.0,   0.0,    1.0]);
      return faMatrix;
    }
    // Multiply the four coordinate vertex in V at the start index
    function MultiplyMatrixVertex(faM, faV, iStart) { // V = M*V
      var faCopy = [0,0,0,0];
      for (var i = 0; i < 4; ++i) {
        faCopy[i] = faV[iStart + i];
      }
      for (iRow = 0; iRow < 4; ++iRow) {
        faV[iStart + iRow] = faM[iRow]*faCopy[0] + faM[iRow + 4]*faCopy[1] + faM[iRow + 8]*faCopy[2] + faM[iRow + 12]*faCopy[3];
      }
    }
    function Normalize(faV) {
      var fL = Math.sqrt(faV[0]*faV[0] + faV[1]*faV[1] + faV[2]*faV[2]);
      faV[0] /= fL; faV[1] /= fL; faV[2] /= fL;
    }
    function Dot(faV1, faV2) {
      return (faV1[0]*faV2[0] + faV1[1]*faV2[1] + faV1[2]*faV2[2]);
    }
    function Cross(faV1, faV2) {
      return [faV1[1]*faV2[2]-faV1[2]*faV2[1], faV1[2]*faV2[0]-faV1[0]*faV2[2], faV1[0]*faV2[1]-faV1[1]*faV2[0]];
    }
    function Difference(faV1, faV2) {
      return [faV1[0]-faV2[0], faV1[1]-faV2[1], faV1[2]-faV2[2]];
    }
    function CreateLookAtMatrix(faEye, faObject, faUp) {
      var faViewDirection = Difference(faObject, faEye);
      Normalize(faViewDirection);
      var faRight = Cross(faViewDirection, faUp);
      Normalize(faRight);
      var faStraightUp = Cross(faRight, faViewDirection);
      var faMatrix = new Float32Array([
	    faRight[0], faStraightUp[0], faViewDirection[0], 0.0,
	    faRight[1], faStraightUp[1], faViewDirection[1], 0.0,
	    faRight[2], faStraightUp[2], faViewDirection[2], 0.0,
        -Dot(faObject, faRight), -Dot(faObject, faStraightUp), -Dot(faObject, faViewDirection), 1.0]);
      return faMatrix;
    }
    function CreateOrthographicMatrix(fLeft, fRight, fBottom, fTop, fNear, fFar) {
      if (fLeft >= fRight || fBottom >=  fTop || fFar >= fNear) {
        throw 'Improper Orthographic Projection Matrix';
      }
      fDx = fRight - fLeft;
      fDy = fTop - fBottom;
      fDz = fNear - fFar;
      var faMatrix = new Float32Array([
        2.0/fDx,                 0.0,                     0.0,                   0.0,
        0.0,                     2.0/fDy,                 0.0,                   0.0,
        0.0,                     0.0,                     2.0/fDz,               0.0,
        -(fLeft + fRight)/fDx,   -(fBottom + fTop)/fDy,   -(fNear + fFar)/fDz,   1.0]);
      return faMatrix;
    }
    function MultiplyMatrices(faaM, faaA) { // M = M*A, Note M != A
      var faRow = [0,0,0,0];
      for (iRow = 0; iRow < 4; ++iRow) {
        // Copy the current row
        for(iCol = 0; iCol < 4; ++iCol) {
          faRow[iCol] = faaM[iRow + 4*iCol];
        }
        for(iCol = 0; iCol < 4; ++iCol) {
          faaM[iRow + 4*iCol] = 0.0;
          for (k = 0; k < 4; ++k) {
            faaM[iRow + 4*iCol] += faRow[k]*faaA[4*iCol + k];
          }
        }
      }
    }
    function CInstanceWebGL(sCanvasID, sVertexShaderID, sFragmentShaderID, iVertices) {
	  this.mqGL = null;
	  this.mqProgram = null;
	  this.msCanvasID = sCanvasID;
	  this.msVertexShaderID = sVertexShaderID;
	  this.msFragmentShaderID = sFragmentShaderID;
	  this.mfaTransformedVertices = new Float32Array(4*iVertices);
	  this.mfaVertexColors = new Float32Array(4*iVertices);
	}
    </script>
  </head>
  <body onload="Initialization();">
    <canvas id="idModelCanvas" width="400", height="400" style="border:1px solid lightgray"></canvas>
    <canvas id="idViewCanvas" width="400", height="400" style="border:1px solid lightgray"></canvas>
  </body>
</html>
 

Output

 
 

© 2007–2024 XoaX.net LLC. All rights reserved.