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.
<!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>© 20072025 XoaX.net LLC. All rights reserved.