I have to solve a task where is required to apply an orthogonal projection by using sliders or buttons to control the near and far plane of projection.
The object is a rotating cube. I've already defined many transformation functions , like rotation, scaling. It works, but when I tried to apply the model view matrix and the projection matrix it stops to work and the html does not show the cube.
The console said to me that there is a normalization problem of a NaN vector.
Here is my code :
HTML
<!DOCTYPE html>
<html>
<button id = "ButtonX">Rotate X</button>
<button id = "ButtonY">Rotate Y</button>
<button id = "ButtonZ">Rotate Z</button>
<button id = "ButtonT">Toggle Rotation</button>
<button id="Direction">Change Direction</button>
<div>Traslation on X -1 <input id="slideX" type="range"
min="-1" max="1" step="0.1" value="0" />
1 </div>
<div>Traslation on Y -1 <input id="slideY" type="range"
min="-1" max="1" step="0.1" value="0" />
1 </div>
<div>Traslation on Z -1 <input id="slideZ" type="range"
min="-1" max="1" step="0.1" value="0" />
1 </div>
<div>Scaling on X -1 <input id="ScalingX" type="range"
min="0" max="1" step="0.1" value="0" />
1 </div>
<div>Scaling on Y -1 <input id="ScalingY" type="range"
min="0" max="1" step="0.1" value="0" />
1 </div>
<div>Scaling on Z -1 <input id="ScalingZ" type="range"
min="0" max="1" step="0.1" value="0" />
1 </div>
<button id="Button1">Increase Z</button>
<button id="Button2">Decrease Z</button>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
//uniform vec3 theta;
// Point 2 -> Move the matrices
// Per spostare le matrici le abbiamo dovuto dichiarare nel file GLSL come uniform
// le matrici rx ry e rz sono rispettivamente le matrici di rotazione sugli assi
uniform mat4 rx;
uniform mat4 ry;
uniform mat4 rz;
// Points 3 -> Traslation Matrix
uniform mat4 traslation;
// Points 3 -> Scaling Matrix
uniform mat4 scaling;
//Point 4 -> MV and P matrices
uniform mat4 modelView;
uniform mat4 projection;
void main()
{
// Compute the sines and cosines of theta for each of
// the three axes in one computation.
//vec3 angles = radians( theta );
//vec3 c = cos( angles );
//vec3 s = sin( angles );
// Remember: the matrices are column-major
/*
mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0,
0.0, c.x, s.x, 0.0,
0.0, -s.x, c.x, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 ry = mat4( c.y, 0.0, -s.y, 0.0,
0.0, 1.0, 0.0, 0.0,
s.y, 0.0, c.y, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 rz = mat4( c.z, s.z, 0.0, 0.0,
-s.z, c.z, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 );
*/
fColor = vColor;
gl_Position = scaling *rz * ry * rx * traslation * vPosition ; // ORDINE : scaling -> rotazione -> traslation
//gl_Position = scaling *rz * ry * rx * traslation *projection*modelView*vPosition ;
gl_Position.z = -gl_Position.z;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 fColor;
void
main()
{
gl_FragColor = fColor;
}
</script>
<script type="text/javascript" src="../Common/webgl-utils.js"></script>
<script type="text/javascript" src="../Common/initShaders.js"></script>
<script type="text/javascript" src="../Common/MV.js"></script>
<script type="text/javascript" src="Homework1.js"></script>
<body>
<canvas id="gl-canvas" width="1024" height="1024">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>
JS
"use strict";
var canvas;
var gl;
var numVertices = 36;
var numChecks = 8;
var program;
var c;
var flag = true;
var direction = true;
var rx;
var ry;
var rz;
var traslation_loc;
var tx = 0 ;
var ty = 0;
var tz = 0;
var scaling_loc;
var sx = 1.0;
var sy = 1.0;
var sz = 1.0;
var pointsArray = [];
var colorsArray = [];
//Point 4
var near = -1;
var far = 1;
var radius = 1.0;
var theta = 0.0;
var phi = 0.0;
var dr = 5.0 * Math.PI/180.0;
var left = -1.0;
var right = 1.0;
var ytop = 1.0;
var bottom = -1.0;
var mvMatrix, pMatrix;
var modelView, projection;
var eye;
const at = vec3(0.0, 0.0, 0.0);
const up = vec3(0.0, 1.0, 0.0);
//
var vertices = [
vec4( -0.5, -0.5, 0.5, 1.0 ),
vec4( -0.5, 0.5, 0.5, 1.0 ),
vec4( 0.5, 0.5, 0.5, 1.0 ),
vec4( 0.5, -0.5, 0.5, 1.0 ),
vec4( -0.5, -0.5, -0.5, 1.0 ),
vec4( -0.5, 0.5, -0.5, 1.0 ),
vec4( 0.5, 0.5, -0.5, 1.0 ),
vec4( 0.5, -0.5, -0.5, 1.0 )
];
var vertexColors = [
vec4( 0.0, 0.0, 0.0, 1.0 ), // black
vec4( 1.0, 0.0, 0.0, 1.0 ), // red
vec4( 1.0, 1.0, 0.0, 1.0 ), // yellow
vec4( 0.0, 1.0, 0.0, 1.0 ), // green
vec4( 0.0, 0.0, 1.0, 1.0 ), // blue
vec4( 1.0, 0.0, 1.0, 1.0 ), // magenta
vec4( 0.0, 1.0, 1.0, 1.0 ), // white
vec4( 0.0, 1.0, 1.0, 1.0 ) // cyan
];
var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = xAxis;
var theta = [45.0, 45.0, 45.0];
//var thetaLoc;
function quad(a, b, c, d) {
pointsArray.push(vertices[a]);
colorsArray.push(vertexColors[a]);
pointsArray.push(vertices[b]);
colorsArray.push(vertexColors[a]);
pointsArray.push(vertices[c]);
colorsArray.push(vertexColors[a]);
pointsArray.push(vertices[a]);
colorsArray.push(vertexColors[a]);
pointsArray.push(vertices[c]);
colorsArray.push(vertexColors[a]);
pointsArray.push(vertices[d]);
colorsArray.push(vertexColors[a]);
}
function colorCube()
{
quad( 1, 0, 3, 2 );
quad( 2, 3, 7, 6 );
quad( 3, 0, 4, 7 );
quad( 6, 5, 1, 2 );
quad( 4, 5, 6, 7 );
quad( 5, 4, 0, 1 );
}
window.onload = function init() {
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
gl.enable(gl.DEPTH_TEST);
//
// Load shaders and initialize attribute buffers
//
program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
colorCube();
var cBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(colorsArray), gl.STATIC_DRAW );
var vColor = gl.getAttribLocation( program, "vColor" );
gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vColor );
var vBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer);
gl.bufferData( gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW );
var vPosition = gl.getAttribLocation( program, "vPosition" );
gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );
// Possiamo commentare quello che riguarda il theta per il punto 2
//thetaLoc = gl.getUniformLocation(program, "theta");
// Point 2 - Rotation
//X AXIS
rx = gl.getUniformLocation(program, "rx");
//Y AXIS
ry = gl.getUniformLocation(program, "ry");
//Z AXIS
rz = gl.getUniformLocation(program, "rz");
// Traslation Matrix
traslation_loc = gl.getUniformLocation(program , "traslation");
// Scaling Matrix
scaling_loc = gl.getUniformLocation(program , "scaling");
// Projection and Model matrix
modelView = gl.getUniformLocation( program, "modelView" );
projection = gl.getUniformLocation( program, "projection" );
//**************
document.getElementById("ButtonX").onclick = function(){axis = xAxis;};
document.getElementById("ButtonY").onclick = function(){axis = yAxis;};
document.getElementById("ButtonZ").onclick = function(){axis = zAxis;};
document.getElementById("ButtonT").onclick = function(){flag = !flag;};
document.getElementById("Direction").onclick = function() { direction = !direction;};
document.getElementById( "slideX" ).oninput = function(){ tx = parseFloat(event.target.value,10); };
document.getElementById( "slideY" ).oninput = function(){ ty = parseFloat(event.target.value,10); };
document.getElementById( "slideZ" ).oninput = function(){ tz = parseFloat(event.target.value,10); };
document.getElementById( "ScalingX" ).oninput = function(){ sx = parseFloat(event.target.value,10); };
document.getElementById( "ScalingY" ).oninput = function(){ sy = parseFloat(event.target.value,10); };
document.getElementById( "ScalingZ" ).oninput = function(){ sz = parseFloat(event.target.value,10); };
// Point 4
document.getElementById("Button1").onclick = function(){near *= 1.1; far *= 1.1;};
document.getElementById("Button2").onclick = function(){near *= 0.9; far *= 0.9;};
render();
}
var render = function() {
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Point 4
//*************************************
eye = vec3(radius*Math.sin(phi), radius*Math.sin(theta),
radius*Math.cos(phi));
mvMatrix = lookAt(eye, at , up);
pMatrix = ortho(left, right, bottom, ytop, near, far);
gl.uniformMatrix4fv( modelView, false, flatten(mvMatrix) );
gl.uniformMatrix4fv( projection, false, flatten(pMatrix) );
//*************************************
// Point 3 -> Scaling
var scaling = [sx , 0.0 , 0.0 , 0.0,
0.0 , sy, 0.0 , 0.0,
0.0 , 0.0 , sz , 0.0,
0.0 , 0.0 , 0.0 , 1];
gl.uniformMatrix4fv(scaling_loc,false,scaling);
// ****************************************
//X AXIS - Point 2
var theta_x_degree = theta[0];
var theta_x_radians = theta_x_degree * Math.PI / 180;
var s_x = Math.sin(theta_x_radians);
var c_x = Math.cos(theta_x_radians);
var rx_loc = [ 1.0, 0.0, 0.0, 0.0,
0.0, c_x, s_x, 0.0,
0.0, -s_x, c_x, 0.0,
0.0, 0.0, 0.0, 1.0 ];
gl.uniformMatrix4fv(rx, false, rx_loc);
//Y AXIS - Point 2
var theta_y_degree = theta[1];
var theta_y_radians = theta_y_degree * Math.PI / 180;
var s_y = Math.sin(theta_y_radians);
var c_y = Math.cos(theta_y_radians);
var ry_loc = [ c_y, 0.0, -s_y, 0.0,
0.0, 1.0, 0.0, 0.0,
s_y, 0.0, c_y, 0.0,
0.0, 0.0, 0.0, 1.0 ];
gl.uniformMatrix4fv(ry, false, ry_loc);
//Z AXIS - Point 2
var theta_z_degree = theta[2];
var theta_z_radians = theta_z_degree * Math.PI / 180;
var s_z = Math.sin(theta_z_radians);
var c_z = Math.cos(theta_z_radians);
var rz_loc = [ c_z, s_z, 0.0, 0.0,
-s_z, c_z, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 ];
gl.uniformMatrix4fv(rz, false, rz_loc);
// ****************************************
// Point 3 -> Traslation
var traslation = [1.0 , 0.0 , 0.0 , 0.0,
0.0 , 1.0 , 0.0 , 0.0,
0.0 , 0.0 , 1.0 , 0.0,
tx , ty , tz , 1.0];
gl.uniformMatrix4fv(traslation_loc,false,traslation);
// ****************************************
// ****************************************
// Point 1 --> Change and Toggle Rotation
if((direction)&&(!flag)) theta[axis] += -2.0;
if((!direction)&&(!flag)) theta[axis] += +2.0;
if(!direction) {theta[axis] += -2.0; }
if(direction) {theta[axis] += 2.0 ; }
// ****************************************
//gl.uniform3fv(thetaLoc, theta);
gl.drawArrays( gl.TRIANGLES, 0, numVertices );
requestAnimFrame(render);
}
I found the problem , it was the initialization of the var "eye" . There was a "0" that can not be computed.
Related
I am trying to create a 4-sided pyramid in WebGL where each face is a different color and I believe I'm running into issues with the indices. From my understanding, if I specify an indexed array, WebGL should be drawing a line between the corresponding vertices. I believe my code has all the necessary lines covered but I just can't get the pyramid to form correctly.
If someone could take a look at my code and help me figure out where I'm going wrong, that would be greatly appreciated!
Javascript code:
"use strict";
var canvas;
var gl;
var numPositions = 12;
var positions = [];
var colors = [];
var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = 0;
var theta = [0, 0, 0];
var thetaLoc;
window.onload = function init()
{
canvas = document.getElementById("gl-canvas");
gl = canvas.getContext('webgl2');
if (!gl) alert("WebGL 2.0 isn't available");
colorPyramid();
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.enable(gl.DEPTH_TEST);
//
// Load shaders and initialize attribute buffers
//
var program = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(program);
var cBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW);
var colorLoc = gl.getAttribLocation( program, "aColor" );
gl.vertexAttribPointer( colorLoc, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( colorLoc );
var vBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(positions), gl.STATIC_DRAW);
var positionLoc = gl.getAttribLocation(program, "aPosition");
gl.vertexAttribPointer(positionLoc, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionLoc);
thetaLoc = gl.getUniformLocation(program, "uTheta");
//event listeners for buttons
document.getElementById( "xButton" ).onclick = function () {
axis = xAxis;
};
document.getElementById( "yButton" ).onclick = function () {
axis = yAxis;
};
document.getElementById( "zButton" ).onclick = function () {
axis = zAxis;
};
render();
}
function colorPyramid()
{
triple(0, 3, 2); //base
triple(2, 0, 1);
triple(3, 1, 2);
triple(0, 1, 3);
}
function triple(a, b, c)
{
var vertices = [
vec3(0.5, -0.2722, 0.2886),
vec3(0.0, -0.2772, -0.5773),
vec3(-0.5, -0.2722, 0.2886),
vec3(0.0, 0.5443, 0.0)
];
var vertexColors = [
vec4(0.0, 0.0, 0.0, 1.0), // black
vec4(1.0, 0.0, 0.0, 1.0), // red
vec4(0.0, 1.0, 0.0, 1.0), // green
vec4(0.0, 0.0, 1.0, 1.0) // blue
];
// We need to parition the quad into two triangles in order for
// WebGL to be able to render it. In this case, we create two
// triangles from the quad indices
//vertex color assigned by the index of the vertex
var indices = [a, b, c];
for ( var i = 0; i < indices.length; ++i ) {
positions.push( vertices[indices[i]] );
//colors.push( vertexColors[indices[i]] );
// for solid colored faces use
colors.push(vertexColors[a]);
}
}
function render()
{
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
theta[axis] += 2.0;
gl.uniform3fv(thetaLoc, theta);
gl.drawArrays(gl.TRIANGLES, 0, numPositions);
requestAnimationFrame(render);
}
I don't think the issue is my HTML code, but it never hurts to include it!
HTML:
<!DOCTYPE html>
<html>
<script id="vertex-shader" type="x-shader/x-vertex">
#version 300 es
in vec4 aPosition;
in vec4 aColor;
out vec4 vColor;
uniform vec3 uTheta;
void main()
{
// Compute the sines and cosines of theta for each of
// the three axes in one computation.
vec3 angles = radians(uTheta);
vec3 c = cos(angles);
vec3 s = sin(angles);
// Remeber: thse matrices are column-major
mat4 rx = mat4(1.0, 0.0, 0.0, 0.0,
0.0, c.x, s.x, 0.0,
0.0, -s.x, c.x, 0.0,
0.0, 0.0, 0.0, 1.0);
mat4 ry = mat4(c.y, 0.0, -s.y, 0.0,
0.0, 1.0, 0.0, 0.0,
s.y, 0.0, c.y, 0.0,
0.0, 0.0, 0.0, 1.0);
mat4 rz = mat4(c.z, s.z, 0.0, 0.0,
-s.z, c.z, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
vColor = aColor;
gl_Position = rz * ry * rx * aPosition;
gl_Position.z = -gl_Position.z;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
#version 300 es
precision mediump float;
in vec4 vColor;
out vec4 fColor;
void
main()
{
fColor = vColor;
}
</script>
<script type="text/javascript" src="http://interactivecomputergraphics.com/Code/Common/utility.js"></script>
<script type="text/javascript" src="http://interactivecomputergraphics.com/Code/Common/initShaders.js"></script>
<script type="text/javascript" src="http://interactivecomputergraphics.com/Code/Common/MV.js"></script>
<script type="text/javascript" src="ASPyramid.js"></script>
<body>
<canvas id="gl-canvas" width="512" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
<br/>
<button id= "xButton">Rotate X</button>
<button id= "yButton">Rotate Y</button>
<button id= "zButton">Rotate Z</button>
</body>
</html>
Ended up figuring out the issue with the help of a nice Redditor. I forgot to update the vertexAttribPointer for positionLoc to 3 instead of 4. The pyramid renders properly now.
Objective: I am trying to display a Triangular Pyramid with different
perspective views as you change the values of zNear, zFar, radius, theta, phi, fov, and aspect through the corresponding sliders. and the buttons rotate x,y,z is to rotate the pyramid on different axis.
Issue: So far I came up with the below code, everything looks in place but I don't see the pyramid, it errors out when I try to display the HTML file.
var canvas;
var gl;
var NumVertices = 12;
var pointsArray = [];
var colorsArray = [];
var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = 0;
var theta = [ 0, 0, 0 ];
var near = 0.3;
var far = 3.0;
var radius = 4.0;
var theta = 0.0;
var phi = 0.0;
var dr = 5.0 * Math.PI/180.0;
//var thetaLoc;
var fovy = 45.0; // Field-of-view in Y direction angle (in degrees)
var aspect = 1.0; // Viewport aspect ratio
var modelViewMatrix, projectionMatrix;
var modelViewMatrixLoc, projectionMatrixLoc;
var eye;
const at = vec3(0.0, 0.0, 0.0);
const up = vec3(0.0, 1.0, 0.0);
var vertices = [
vec3(0.5, -0.2722, 0.2886),
vec3(0.0, -0.2722, -0.5773),
vec3(-0.5, -0.2722, 0.2886),
vec3(0.5, -0.5443, 0.0)
]
var vertexColors = [
[ 0.0, 0.0, 0.0, 1.0 ], // black
[ 1.0, 0.0, 0.0, 1.0 ], // red
[ 1.0, 1.0, 0.0, 1.0 ], // yellow
[ 0.0, 1.0, 0.0, 1.0 ] // green
];
window.onload = function init()
{
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
gl.viewport( 0, 0, canvas.width, canvas.height );
aspect = canvas.width/canvas.height;
gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
gl.enable(gl.DEPTH_TEST);
//
// Load shaders and initialize attribute buffers
//
var program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
colorPyramid();
var cBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer);
gl.bufferData( gl.ARRAY_BUFFER, flatten(colorsArray), gl.STATIC_DRAW );
var vColor = gl.getAttribLocation( program, "vColor" );
gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vColor);
var vBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer);
gl.bufferData( gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW );
var vPosition = gl.getAttribLocation( program, "vPosition" );
gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );
modelViewMatrixLoc = gl.getUniformLocation( program, "modelViewMatrix" );
projectionMatrixLoc = gl.getUniformLocation( program, "projectionMatrix" );
// sliders for viewing parameters
document.getElementById("zFarSlider").onchange = function() {
far = event.srcElement.value;
};
document.getElementById("zNearSlider").onchange = function() {
near = event.srcElement.value;
};
document.getElementById("radiusSlider").onchange = function() {
radius = event.srcElement.value;
};
document.getElementById("thetaSlider").onchange = function() {
theta = event.srcElement.value* Math.PI/180.0;
};
document.getElementById("phiSlider").onchange = function() {
phi = event.srcElement.value* Math.PI/180.0;
};
document.getElementById("aspectSlider").onchange = function() {
aspect = event.srcElement.value;
};
document.getElementById("fovSlider").onchange = function() {
fovy = event.srcElement.value;
};
render();
}
function colorPyramid()
{
quad( 0, 1, 2 ); // bottom
quad( 1, 0, 3 ); // side0
quad( 1, 2, 3 ); // side1
quad( 2, 0, 3 ); // side3
}
function quad(a, b, c)
{
var indices = [ a, b, c];
var ndx = pointsArray.length % vertexColors.length;
for ( var i = 0; i < indices.length; ++i ) {
pointsArray.push( vertices[indices[i]] );
colorsArray.push(vertexColors[ndx]);
}
}
function render()
{
// gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
theta[axis] += 2.0;
// gl.uniform3fv(thetaLoc, theta);
// gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
// requestAnimFrame( render );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
eye = vec3(radius*Math.sin(theta)*Math.cos(phi),
radius*Math.sin(theta)*Math.sin(phi), radius*Math.cos(theta));
modelViewMatrix = lookAt(eye, at , up);
projectionMatrix = perspective(fovy, aspect, near, far);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(modelViewMatrix) );
gl.uniformMatrix4fv( projectionMatrixLoc, false, flatten(projectionMatrix) );
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
requestAnimFrame(render);
}
<div>
zNear .01<input id="zNearSlider" type="range"
min=".01" max="3" step="0.1" value="0.3" />
3
</div>
<div>
zFar 3<input id="zFarSlider" type="range"
min="3" max="10" step="3.0" value="3" />
10
</div>
<div>
radius 0.05<input id="radiusSlider" type="range"
min="0.05" max="10" step="0.1" value="4" />
10
</div>
<div>
theta -90<input id="thetaSlider" type="range"
min="-90" max="90" step="5" value="0" />
90
</div>
<div>
phi -90<input id="phiSlider" type="range"
min="-90" max="90" step="5" value="0" />
90
</div>
<div>
fov 10<input id="fovSlider" type="range"
min="10" max="120" step="5" value="45" />
120
</div>
<div>
aspect 0.5<input id="aspectSlider" type="range"
min="0.5" max="2" step="0.1" value="1" />
2
</div>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
uniform vec3 theta;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main()
{
// Compute the sines and cosines of theta for each of
// the three axes in one computation.
<!-- vec3 angles = radians( theta ); -->
<!-- vec3 c = cos( angles ); -->
<!-- vec3 s = sin( angles ); -->
<!-- // Remeber: thse matrices are column-major -->
<!-- mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0, -->
<!-- 0.0, c.x, s.x, 0.0, -->
<!-- 0.0, -s.x, c.x, 0.0, -->
<!-- 0.0, 0.0, 0.0, 1.0 ); -->
<!-- mat4 ry = mat4( c.y, 0.0, -s.y, 0.0, -->
<!-- 0.0, 1.0, 0.0, 0.0, -->
<!-- s.y, 0.0, c.y, 0.0, -->
<!-- 0.0, 0.0, 0.0, 1.0 ); -->
<!-- mat4 rz = mat4( c.z, -s.z, 0.0, 0.0, -->
<!-- s.z, c.z, 0.0, 0.0, -->
<!-- 0.0, 0.0, 1.0, 0.0, -->
<!-- 0.0, 0.0, 0.0, 1.0 ); -->
<!-- fColor = vColor; -->
<!-- gl_Position = rz * ry * rx * vPosition; -->
gl_Position = projectionMatrix*modelViewMatrix*vPosition;
fColor = vColor;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 fColor;
void
main()
{
gl_FragColor = fColor;
}
</script>
<script src="https://esangel.github.io/WebGL/Common/webgl-utils.js"></script>
<script src="https://esangel.github.io/WebGL/Common/initShaders.js"></script>
<script src="https://esangel.github.io/WebGL/Common/MV.js"></script>
<script type="text/javascript" src="Pyramid.js"></script>
<body>
<canvas id="gl-canvas" width="512"" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
<br/>
<button id= "xButton">Rotate X</button>
<button id= "yButton">Rotate Y</button>
<button id= "zButton">Rotate Z</button>
There are several issues
<!-- ... --> are not valid comments inside GLSL shaders. Use /* ... */ or `//
The code had a size of 4 for positions when calling gl.vertexAttribPointer. It needed to be 3.
The code had 2 variables called theta. One a number, the other an array, the code tries to use them both ways. One way to avoid this issue is use let instead of var. var is basically deprecated at this point. With let you'd have gotten an error. Also put "use strict"; at the top of your JavaScript. It will help find more errors. I renamed one of them theta2
The pyramid is 4 units from the view but far plane of the frustum is set to 3 so the pyramid is outside the frustum
The rotation of the view is rotated by +2 each frame but rotation is in radians so +2 is about 1/3 the way around so it would rotate way too fast.
'use strict';
let canvas;
let gl;
let NumVertices = 12;
let pointsArray = [];
let colorsArray = [];
let xAxis = 0;
let yAxis = 1;
let zAxis = 2;
let axis = 0;
let theta = [ 0, 0, 0 ];
let near = 0.3;
let far = 10.0;
let radius = 4.0;
let theta2 = 0.0;
let phi = 0.0;
let dr = 5.0 * Math.PI/180.0;
//var thetaLoc;
let fovy = 45.0; // Field-of-view in Y direction angle (in degrees)
let aspect = 1.0; // Viewport aspect ratio
let modelViewMatrix, projectionMatrix;
let modelViewMatrixLoc, projectionMatrixLoc;
let eye;
const at = vec3(0.0, 0.0, 0.0);
const up = vec3(0.0, 1.0, 0.0);
var vertices = [
vec3(0.5, -0.2722, 0.2886),
vec3(0.0, -0.2722, -0.5773),
vec3(-0.5, -0.2722, 0.2886),
vec3(0.5, -0.5443, 0.0)
]
var vertexColors = [
[ 0.0, 0.0, 0.0, 1.0 ], // black
[ 1.0, 0.0, 0.0, 1.0 ], // red
[ 1.0, 1.0, 0.0, 1.0 ], // yellow
[ 0.0, 1.0, 0.0, 1.0 ] // green
];
window.onload = function init()
{
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
gl.viewport( 0, 0, canvas.width, canvas.height );
aspect = canvas.width/canvas.height;
gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
gl.enable(gl.DEPTH_TEST);
//
// Load shaders and initialize attribute buffers
//
let program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
colorPyramid();
let cBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer);
gl.bufferData( gl.ARRAY_BUFFER, flatten(colorsArray), gl.STATIC_DRAW );
let vColor = gl.getAttribLocation( program, "vColor" );
gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vColor);
let vBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer);
gl.bufferData( gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW );
let vPosition = gl.getAttribLocation( program, "vPosition" );
gl.vertexAttribPointer( vPosition, 3, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );
modelViewMatrixLoc = gl.getUniformLocation( program, "modelViewMatrix" );
projectionMatrixLoc = gl.getUniformLocation( program, "projectionMatrix" );
// sliders for viewing parameters
document.getElementById("zFarSlider").onchange = function() {
far = event.srcElement.value;
};
document.getElementById("zNearSlider").onchange = function() {
near = event.srcElement.value;
};
document.getElementById("radiusSlider").onchange = function() {
radius = event.srcElement.value;
};
document.getElementById("thetaSlider").onchange = function() {
theta2 = event.srcElement.value* Math.PI/180.0;
};
document.getElementById("phiSlider").onchange = function() {
phi = event.srcElement.value* Math.PI/180.0;
};
document.getElementById("aspectSlider").onchange = function() {
aspect = event.srcElement.value;
};
document.getElementById("fovSlider").onchange = function() {
fovy = event.srcElement.value;
};
render();
}
function colorPyramid()
{
quad( 0, 1, 2 ); // bottom
quad( 1, 0, 3 ); // side0
quad( 1, 2, 3 ); // side1
quad( 2, 0, 3 ); // side3
}
function quad(a, b, c)
{
let indices = [ a, b, c];
let ndx = pointsArray.length % vertexColors.length;
for ( let i = 0; i < indices.length; ++i ) {
pointsArray.push( vertices[indices[i]] );
colorsArray.push(vertexColors[ndx]);
}
}
function render()
{
// gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
theta[axis] += 2.0;
theta2 += .02;
// gl.uniform3fv(thetaLoc, theta);
// gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
// requestAnimFrame( render );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
eye = vec3(radius*Math.sin(theta2)*Math.cos(phi),
radius*Math.sin(theta2)*Math.sin(phi), radius*Math.cos(theta2));
modelViewMatrix = lookAt(eye, at , up);
projectionMatrix = perspective(fovy, aspect, near, far);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(modelViewMatrix) );
gl.uniformMatrix4fv( projectionMatrixLoc, false, flatten(projectionMatrix) );
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
requestAnimFrame(render);
}
<div>
zNear .01<input id="zNearSlider" type="range"
min=".01" max="3" step="0.1" value="0.3" />
3
</div>
<div>
zFar 3<input id="zFarSlider" type="range"
min="3" max="10" step="3.0" value="3" />
10
</div>
<div>
radius 0.05<input id="radiusSlider" type="range"
min="0.05" max="10" step="0.1" value="4" />
10
</div>
<div>
theta -90<input id="thetaSlider" type="range"
min="-90" max="90" step="5" value="0" />
90
</div>
<div>
phi -90<input id="phiSlider" type="range"
min="-90" max="90" step="5" value="0" />
90
</div>
<div>
fov 10<input id="fovSlider" type="range"
min="10" max="120" step="5" value="45" />
120
</div>
<div>
aspect 0.5<input id="aspectSlider" type="range"
min="0.5" max="2" step="0.1" value="1" />
2
</div>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
uniform vec3 theta;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main()
{
// Compute the sines and cosines of theta for each of
// the three axes in one computation.
//<!-- vec3 angles = radians( theta ); -->
//<!-- vec3 c = cos( angles ); -->
//<!-- vec3 s = sin( angles ); -->
//<!-- // Remeber: thse matrices are column-major -->
//<!-- mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0, -->
// <!-- 0.0, c.x, s.x, 0.0, -->
// <!-- 0.0, -s.x, c.x, 0.0, -->
// <!-- 0.0, 0.0, 0.0, 1.0 ); -->
//<!-- mat4 ry = mat4( c.y, 0.0, -s.y, 0.0, -->
// <!-- 0.0, 1.0, 0.0, 0.0, -->
// <!-- s.y, 0.0, c.y, 0.0, -->
// <!-- 0.0, 0.0, 0.0, 1.0 ); -->
//<!-- mat4 rz = mat4( c.z, -s.z, 0.0, 0.0, -->
// <!-- s.z, c.z, 0.0, 0.0, -->
// <!-- 0.0, 0.0, 1.0, 0.0, -->
// <!-- 0.0, 0.0, 0.0, 1.0 ); -->
//<!-- fColor = vColor; -->
//<!-- gl_Position = rz * ry * rx * vPosition; -->
gl_Position = projectionMatrix*modelViewMatrix*vPosition;
fColor = vColor;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 fColor;
void
main()
{
gl_FragColor = fColor;
}
</script>
<script src="https://esangel.github.io/WebGL/Common/webgl-utils.js"></script>
<script src="https://esangel.github.io/WebGL/Common/initShaders.js"></script>
<script src="https://esangel.github.io/WebGL/Common/MV.js"></script>
<canvas id="gl-canvas" width="512"" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
<br/>
<button id= "xButton">Rotate X</button>
<button id= "yButton">Rotate Y</button>
<button id= "zButton">Rotate Z</button>
Other tips
Learn how to use a snippet
Make your code runnable by linking to the libraries you use
<script src="https://esangel.github.io/WebGL/Common/webgl-utils.js"></script>
<script src="https://esangel.github.io/WebGL/Common/initShaders.js"></script>
<script src="https://esangel.github.io/WebGL/Common/MV.js"></script>
Consider adding webgl-lint to help find errors.
Learn from some different lessons.
I'm trying to have two external images as textures for my cube. When I use one image, it works perfectly and my cube is rendered but I'm having problems rendering two images on one cube. One is a spotlight image that has the middle cut out so the second image placed can be seen through that hole. The only warning I get is
WebGL warning: generateMipmap: Tex image TEXTURE_2D level 0 is incurring lazy initialization.
When I try to run your code in Chrome 80 I get error messages in the JavaScript console
The first one is this
Uncaught TypeError: Failed to execute 'texImage2D' on 'WebGLRenderingContext': parameter 9 is not of type 'ArrayBufferView'.
at configureTexture1 (js:148)
You're trying to pass an HTMLImageElement to texImage2D but the only form of texImage2D that takes an HTMLImageElement has 6 parameters, not 9. No width, no height, and no border parameter. It should be
gl.texImage2D(
gl.TEXTURE_2D,
0, // level
gl.RGBA, // internal format
gl.RGBA, // format
gl.UNSIGNED_BYTE, // type
someImageElement);
Fixing those 2 errors leads to a new error
WARNING: there is no texture bound to the unit 1
When you use multiple textures you need to assign each texture to a texture unit. Example
// bind "someTexture" to texture unit 0
gl.activeTexture(gl.TEXTURE0 + 0);
gl.bindTexture(gl.TEXTURE_2D, someTexture);
// bind "otherTexture" to texture unit 1
gl.activeTexture(gl.TEXTURE0 + 1);
gl.bindTexture(gl.TEXTURE_2D, otherTexture);
var canvas;
var gl;
var numVertices = 36;
var texSize = 64;
var image1 = document.getElementById("texImage1");
var image2 = document.getElementById("texImage2");
var program;
var texture1, texture2;
var pointsArray = [];
var colorsArray = [];
var texCoordsArray = [];
//texture coordinates
var texCoord = [
vec2(0, 0),
vec2(0, 1),
vec2(1, 1),
vec2(1, 0)
];
//cube dimensions
var vertices = [
vec4( -0.5, -0.5, 0.5, 1.0 ),
vec4( -0.5, 0.5, 0.5, 1.0 ),
vec4( 0.5, 0.5, 0.5, 1.0 ),
vec4( 0.5, -0.5, 0.5, 1.0 ),
vec4( -0.5, -0.5, -0.5, 1.0 ),
vec4( -0.5, 0.5, -0.5, 1.0 ),
vec4( 0.5, 0.5, -0.5, 1.0 ),
vec4( 0.5, -0.5, -0.5, 1.0 )
];
var vertexColors = [
vec4( 0.0, 0.0, 0.0, 1.0 ),
vec4( 1.0, 0.0, 0.0, 1.0 ),
vec4( 1.0, 1.0, 0.0, 1.0 ),
vec4( 0.0, 1.0, 0.0, 1.0 ),
vec4( 0.0, 0.0, 1.0, 1.0 ),
vec4( 1.0, 0.0, 1.0, 1.0 ),
vec4( 0.0, 1.0, 1.0, 1.0 ),
vec4( 0.0, 1.0, 1.0, 1.0 )
];
//rotation parameters
var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = xAxis;
var theta = [45.0, 45.0, 45.0];
var thetaLoc;
function configureTexture1( image ) {
texture1 = gl.createTexture();
gl.activeTexture( gl.TEXTURE0 + 0 );
gl.bindTexture( gl.TEXTURE_2D, texture1 );
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image1);
gl.generateMipmap( gl.TEXTURE_2D );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,gl.NEAREST_MIPMAP_LINEAR );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.uniform1i(gl.getUniformLocation( program, "texture1"), 0);
}
function configureTexture2( image ) {
texture2 = gl.createTexture();
gl.activeTexture( gl.TEXTURE0 + 1 );
gl.bindTexture( gl.TEXTURE_2D, texture2 );
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image2);
gl.generateMipmap( gl.TEXTURE_2D );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,gl.NEAREST_MIPMAP_LINEAR );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.uniform1i(gl.getUniformLocation( program, "texture2"), 1);
}
function quad(a, b, c, d) {
pointsArray.push(vertices[a]);
colorsArray.push(vertexColors[a]);
texCoordsArray.push(texCoord[0]);
pointsArray.push(vertices[b]);
colorsArray.push(vertexColors[a]);
texCoordsArray.push(texCoord[1]);
pointsArray.push(vertices[c]);
colorsArray.push(vertexColors[a]);
texCoordsArray.push(texCoord[2]);
pointsArray.push(vertices[a]);
colorsArray.push(vertexColors[a]);
texCoordsArray.push(texCoord[0]);
pointsArray.push(vertices[c]);
colorsArray.push(vertexColors[a]);
texCoordsArray.push(texCoord[2]);
pointsArray.push(vertices[d]);
colorsArray.push(vertexColors[a]);
texCoordsArray.push(texCoord[3]);
}
function colorCube()
{
quad( 1, 0, 3, 2 );
quad( 2, 3, 7, 6 );
quad( 3, 0, 4, 7 );
quad( 6, 5, 1, 2 );
quad( 4, 5, 6, 7 );
quad( 5, 4, 0, 1 );
}
window.onload = function init() {
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
gl.enable(gl.DEPTH_TEST);
program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
colorCube();
//loading/initialising/binding buffers
var cBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(colorsArray), gl.STATIC_DRAW );
var vColor = gl.getAttribLocation( program, "vColor" );
gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vColor );
var vBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer);
gl.bufferData( gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW );
var vPosition = gl.getAttribLocation( program, "vPosition" );
gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );
var tBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, tBuffer);
gl.bufferData( gl.ARRAY_BUFFER, flatten(texCoordsArray), gl.STATIC_DRAW );
var vTexCoord = gl.getAttribLocation( program, "vTexCoord" );
gl.vertexAttribPointer( vTexCoord, 2, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vTexCoord );
configureTexture1(image1);
configureTexture2(image2);
thetaLoc = gl.getUniformLocation(program, "theta");
document.getElementById("ButtonX").onclick = function(){axis = xAxis;};
document.getElementById("ButtonY").onclick = function(){axis = yAxis;};
document.getElementById("ButtonZ").onclick = function(){axis = zAxis;};
render();
}
var render = function() {
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
theta[axis] += 2.0;
gl.uniform3fv(thetaLoc, flatten(theta));
gl.drawArrays( gl.TRIANGLES, 0, numVertices );
requestAnimFrame(render);
}
<button id = "ButtonX">Rotate X</button>
<button id = "ButtonY">Rotate Y</button>
<button id = "ButtonZ">Rotate Z</button>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
attribute vec2 vTexCoord;
varying vec4 fColor;
varying vec2 fTexCoord;
uniform vec3 theta;
void main()
{
vec3 angles = radians( theta );
vec3 c = cos( angles );
vec3 s = sin( angles );
mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0,
0.0, c.x, s.x, 0.0,
0.0, -s.x, c.x, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 ry = mat4( c.y, 0.0, -s.y, 0.0,
0.0, 1.0, 0.0, 0.0,
s.y, 0.0, c.y, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 rz = mat4( c.z, s.z, 0.0, 0.0,
-s.z, c.z, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 );
fColor = vColor;
fTexCoord = vTexCoord;
gl_Position = rz * ry * rx * vPosition;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 fColor;
varying vec2 fTexCoord;
uniform sampler2D texture1;
uniform sampler2D texture2;
void
main()
{
gl_FragColor = fColor*(texture2D(texture1, fTexCoord)*texture2D(texture2, fTexCoord));
}
</script>
<script type="text/javascript"
src="https://esangel.github.io/WebGL/Common/webgl-utils.js"></script>
<script type="text/javascript" src="https://esangel.github.io/WebGL/Common/initShaders.js"></script>
<script type="text/javascript"
src="https://esangel.github.io/WebGL/Common/MV.js"></script>
<canvas id="gl-canvas" width="512" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
<img id="texImage1" crossorigin=" " src = "https://i.imgur.com/ZKMnXce.png" crossOrigin="anonymous" hidden></img>
<img id="texImage2" crossorigin=" " src = "https://i.imgur.com/aqZRuFj.png" crossOrigin="anonymous" hidden></img>
I used these 2 images
An F: https://i.imgur.com/ZKMnXce.png
A white dot: https://imgur.com/aqZRuFj
note that the code is not following normal WebGL practices. Many things are being done once at init time which will only work as long as you're onyl drawing a single thing.
See this answer and/or this page and this one too
I have to use a slider to change the angle of my rotating square :
JS
"use strict";
var canvas;
var gl;
var direction = true;
var degrees = 0;
var NumVertices = 36;
var points = [];
var colors = [];
var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = 0;
var theta = [ 0, 0, 0 ];
var thetaLoc;
window.onload = function init()
{
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
colorCube();
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
gl.enable(gl.DEPTH_TEST);
//
// Load shaders and initialize attribute buffers
//
var program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
var cBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW );
var vColor = gl.getAttribLocation( program, "vColor" );
gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vColor );
var vBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW );
var vPosition = gl.getAttribLocation( program, "vPosition" );
gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );
thetaLoc = gl.getUniformLocation(program, "theta");
//event listeners for buttons
document.getElementById( "xButton" ).onclick = function () {
axis = xAxis;
};
document.getElementById( "yButton" ).onclick = function () {
axis = yAxis;
};
document.getElementById( "zButton" ).onclick = function () {
axis = zAxis;
};
// Start or Stop
var btn = document.getElementsByTagName('input')[0];
btn.addEventListener('click', function() {
if (direction == true)
direction = false;
else
direction = true;
});
// SLIDER
document.getElementById("slide").onchange = function(){
degrees = parseInt(event.target.value, 10);
};
render();
}
function colorCube()
{
quad( 1, 0, 3, 2 );
quad( 2, 3, 7, 6 );
quad( 3, 0, 4, 7 );
quad( 6, 5, 1, 2 );
quad( 4, 5, 6, 7 );
quad( 5, 4, 0, 1 );
}
function quad(a, b, c, d)
{
var vertices = [
vec4( -0.5, -0.5, 0.5, 1.0 ),
vec4( -0.5, 0.5, 0.5, 1.0 ),
vec4( 0.5, 0.5, 0.5, 1.0 ),
vec4( 0.5, -0.5, 0.5, 1.0 ),
vec4( -0.5, -0.5, -0.5, 1.0 ),
vec4( -0.5, 0.5, -0.5, 1.0 ),
vec4( 0.5, 0.5, -0.5, 1.0 ),
vec4( 0.5, -0.5, -0.5, 1.0 )
];
var vertexColors = [
[ 0.0, 0.0, 0.0, 1.0 ], // black
[ 1.0, 0.0, 0.0, 1.0 ], // red
[ 1.0, 1.0, 0.0, 1.0 ], // yellow
[ 0.0, 1.0, 0.0, 1.0 ], // green
[ 0.0, 0.0, 1.0, 1.0 ], // blue
[ 1.0, 0.0, 1.0, 1.0 ], // magenta
[ 0.0, 1.0, 1.0, 1.0 ], // cyan
[ 1.0, 1.0, 1.0, 1.0 ] // white
];
// We need to parition the quad into two triangles in order for
// WebGL to be able to render it. In this case, we create two
// triangles from the quad indices
//vertex color assigned by the index of the vertex
var indices = [ a, b, c, a, c, d ];
for ( var i = 0; i < indices.length; ++i ) {
points.push( vertices[indices[i]] );
//colors.push( vertexColors[indices[i]] );
// for solid colored faces use
colors.push(vertexColors[a]);
}
}
function render()
{
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
if (direction == false){
theta[axis] == degrees;
//theta[axis] = degrees;
}
else {
theta[axis] += 2.0;
}
/// How to control the rotation degree ?
gl.uniform3fv(thetaLoc, theta);
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
requestAnimFrame( render );
}
HTML
<!DOCTYPE html>
<html>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
uniform vec3 theta;
void main()
{
// Compute the sines and cosines of theta for each of
// the three axes in one computation.
vec3 angles = radians( theta );
vec3 c = cos( angles );
vec3 s = sin( angles );
// Remeber: thse matrices are column-major
mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0,
0.0, c.x, s.x, 0.0,
0.0, -s.x, c.x, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 ry = mat4( c.y, 0.0, -s.y, 0.0,
0.0, 1.0, 0.0, 0.0,
s.y, 0.0, c.y, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 rz = mat4( c.z, s.z, 0.0, 0.0,
-s.z, c.z, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 );
fColor = vColor;
gl_Position = rz * ry * rx * vPosition;
gl_Position.z = -gl_Position.z;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 fColor;
void
main()
{
gl_FragColor = fColor;
}
</script>
<script type="text/javascript" src="../Common/webgl-utils.js"></script>
<script type="text/javascript" src="../Common/initShaders.js"></script>
<script type="text/javascript" src="../Common/MV.js"></script>
<script type="text/javascript" src="Exercise1_1.js"></script>
<body>
<canvas id="gl-canvas" width="512"" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
<br/>
<button id= "xButton">Rotate X</button>
<button id= "yButton">Rotate Y</button>
<button id= "zButton">Rotate Z</button>
<input type="button" value="Start or Stop" />
<div>
Angle 0 <input id="slide" type="range"
min="0" max="10" step="1" value="1" />
10 </div>
</body>
</html>
This square must stop when I click the button and restart the rotation if I click it again and this task works. The problem is that I have to change the angle using the slider and it works too if I remove the comment in the last if statement.
The problem is that if I click the start button and then I stop it , it stops in the beginning position and not in the last/current position (this happens if I remove the comment from the if statement code , if I leave the comment the start/stop works well but I can not change the angle).
Thanks for the help.
Fist of all, this line is wrong theta[axis] == degrees;
As you can see you have 2x = so you compare the theta[axis] with the degrees. This means that this line does nothing.
You want to stop the movement of the cube if the button is pressed and start it if it is pressed again, so thats why you have the variable direction.
If the direction is true, then you cube must move, so your theta[axis] should increase. If your direction is false your cube should stay still, so theta[axis] must keep its value.
So something like this:
// If cube is moving
if (direction == true) {
theta[axis] += 2.0;
}
// If no movement
else {
// Do nothing
// the theta[axis] stays the same
}
But now your cube is rotating with the same speed...
Maybe you want your cube to rotate with the degrees speed.
So you should change the static value of 2.0 to the variable degrees
that gets its value from the slider.
"use strict";
var canvas;
var gl;
var direction = true;
var degrees = 1.0; // Slider starts from value 1.0 as it has value="1" on it
var NumVertices = 36;
var points = [];
var colors = [];
var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = 0;
var theta = [ 0, 0, 0 ];
var thetaLoc;
window.onload = function init()
{
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
colorCube();
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
gl.enable(gl.DEPTH_TEST);
//
// Load shaders and initialize attribute buffers
//
var program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
var cBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW );
var vColor = gl.getAttribLocation( program, "vColor" );
gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vColor );
var vBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW );
var vPosition = gl.getAttribLocation( program, "vPosition" );
gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );
thetaLoc = gl.getUniformLocation(program, "theta");
//event listeners for buttons
document.getElementById( "xButton" ).onclick = function () {
axis = xAxis;
};
document.getElementById( "yButton" ).onclick = function () {
axis = yAxis;
};
document.getElementById( "zButton" ).onclick = function () {
axis = zAxis;
};
// Start or Stop
var btn = document.getElementsByTagName('input')[0];
btn.addEventListener('click', function() {
if (direction == true)
direction = false;
else
direction = true;
});
// SLIDER
document.getElementById("slide").onchange = function(){
// As this is an event of the slider,
// here inside the handler, the variable `this`
// points to the slider, so we can do `this.value`
// to get the slider's value
degrees = parseInt(this.value, 10);
};
render();
}
function colorCube()
{
quad( 1, 0, 3, 2 );
quad( 2, 3, 7, 6 );
quad( 3, 0, 4, 7 );
quad( 6, 5, 1, 2 );
quad( 4, 5, 6, 7 );
quad( 5, 4, 0, 1 );
}
function quad(a, b, c, d)
{
var vertices = [
vec4( -0.5, -0.5, 0.5, 1.0 ),
vec4( -0.5, 0.5, 0.5, 1.0 ),
vec4( 0.5, 0.5, 0.5, 1.0 ),
vec4( 0.5, -0.5, 0.5, 1.0 ),
vec4( -0.5, -0.5, -0.5, 1.0 ),
vec4( -0.5, 0.5, -0.5, 1.0 ),
vec4( 0.5, 0.5, -0.5, 1.0 ),
vec4( 0.5, -0.5, -0.5, 1.0 )
];
var vertexColors = [
[ 0.0, 0.0, 0.0, 1.0 ], // black
[ 1.0, 0.0, 0.0, 1.0 ], // red
[ 1.0, 1.0, 0.0, 1.0 ], // yellow
[ 0.0, 1.0, 0.0, 1.0 ], // green
[ 0.0, 0.0, 1.0, 1.0 ], // blue
[ 1.0, 0.0, 1.0, 1.0 ], // magenta
[ 0.0, 1.0, 1.0, 1.0 ], // cyan
[ 1.0, 1.0, 1.0, 1.0 ] // white
];
// We need to parition the quad into two triangles in order for
// WebGL to be able to render it. In this case, we create two
// triangles from the quad indices
//vertex color assigned by the index of the vertex
var indices = [ a, b, c, a, c, d ];
for ( var i = 0; i < indices.length; ++i ) {
points.push( vertices[indices[i]] );
//colors.push( vertexColors[indices[i]] );
// for solid colored faces use
colors.push(vertexColors[a]);
}
}
function render()
{
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
if (direction != false){
theta[axis] += degrees;
// theta[axis] is increased by the degrees variable
// that is being updated with the value of the slider
// every time we slide the slider
}
// How to control the rotation degree ?
// With a nice slider! ...
gl.uniform3fv(thetaLoc, theta);
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
requestAnimFrame( render );
}
I need to create a start/stop button to start or stop the animation of a rotating square , I used a loop variable to decide if the square should rotate or not; in the render() function , if loop = 1 the square must rotate , if loop = 0 it stops. At the beginning loop=1 so the square is loaded in the html page rotating but the idea is that if I click the stop button it should stop , but it does not work.
Here is my code :
HTML
<!DOCTYPE html>
<html>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
uniform vec3 theta;
void main()
{
// Compute the sines and cosines of theta for each of
// the three axes in one computation.
vec3 angles = radians( theta );
vec3 c = cos( angles );
vec3 s = sin( angles );
// Remeber: thse matrices are column-major
mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0,
0.0, c.x, s.x, 0.0,
0.0, -s.x, c.x, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 ry = mat4( c.y, 0.0, -s.y, 0.0,
0.0, 1.0, 0.0, 0.0,
s.y, 0.0, c.y, 0.0,
0.0, 0.0, 0.0, 1.0 );
mat4 rz = mat4( c.z, s.z, 0.0, 0.0,
-s.z, c.z, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 );
fColor = vColor;
gl_Position = rz * ry * rx * vPosition;
gl_Position.z = -gl_Position.z;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 fColor;
void
main()
{
gl_FragColor = fColor;
}
</script>
<script type="text/javascript" src="../Common/webgl-utils.js"></script>
<script type="text/javascript" src="../Common/initShaders.js"></script>
<script type="text/javascript" src="../Common/MV.js"></script>
<script type="text/javascript" src="Exercise1_1.js"></script>
<body>
<canvas id="gl-canvas" width="512"" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
<br/>
<button id= "xButton">Rotate X</button>
<button id= "yButton">Rotate Y</button>
<button id= "zButton">Rotate Z</button>
<button id="StopButton">STOP ! </button>
</body>
</html>
JS
"use strict";
var canvas;
var gl;
var loop = 1;
var NumVertices = 36;
var points = [];
var colors = [];
var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = 0;
var theta = [ 0, 0, 0 ];
var thetaLoc;
window.onload = function init()
{
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
colorCube();
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
gl.enable(gl.DEPTH_TEST);
//
// Load shaders and initialize attribute buffers
//
var program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
var cBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW );
var vColor = gl.getAttribLocation( program, "vColor" );
gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vColor );
var vBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW );
var vPosition = gl.getAttribLocation( program, "vPosition" );
gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );
thetaLoc = gl.getUniformLocation(program, "theta");
//event listeners for buttons
document.getElementById( "xButton" ).onclick = function () {
axis = xAxis;
};
document.getElementById( "yButton" ).onclick = function () {
axis = yAxis;
};
document.getElementById( "zButton" ).onclick = function () {
axis = zAxis;
};
document.getElementById("StopButton").onclick = function () {
loop = 0;
};
render();
}
function colorCube()
{
quad( 1, 0, 3, 2 );
quad( 2, 3, 7, 6 );
quad( 3, 0, 4, 7 );
quad( 6, 5, 1, 2 );
quad( 4, 5, 6, 7 );
quad( 5, 4, 0, 1 );
}
function quad(a, b, c, d)
{
var vertices = [
vec4( -0.5, -0.5, 0.5, 1.0 ),
vec4( -0.5, 0.5, 0.5, 1.0 ),
vec4( 0.5, 0.5, 0.5, 1.0 ),
vec4( 0.5, -0.5, 0.5, 1.0 ),
vec4( -0.5, -0.5, -0.5, 1.0 ),
vec4( -0.5, 0.5, -0.5, 1.0 ),
vec4( 0.5, 0.5, -0.5, 1.0 ),
vec4( 0.5, -0.5, -0.5, 1.0 )
];
var vertexColors = [
[ 0.0, 0.0, 0.0, 1.0 ], // black
[ 1.0, 0.0, 0.0, 1.0 ], // red
[ 1.0, 1.0, 0.0, 1.0 ], // yellow
[ 0.0, 1.0, 0.0, 1.0 ], // green
[ 0.0, 0.0, 1.0, 1.0 ], // blue
[ 1.0, 0.0, 1.0, 1.0 ], // magenta
[ 0.0, 1.0, 1.0, 1.0 ], // cyan
[ 1.0, 1.0, 1.0, 1.0 ] // white
];
// We need to parition the quad into two triangles in order for
// WebGL to be able to render it. In this case, we create two
// triangles from the quad indices
//vertex color assigned by the index of the vertex
var indices = [ a, b, c, a, c, d ];
for ( var i = 0; i < indices.length; ++i ) {
points.push( vertices[indices[i]] );
//colors.push( vertexColors[indices[i]] );
// for solid colored faces use
colors.push(vertexColors[a]);
}
}
function render()
{
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
if (loop = 0) {
theta[axis] = 0.0;
}
else {
theta[axis] +=2.0;
}
gl.uniform3fv(thetaLoc, theta);
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
requestAnimFrame( render );
}
Change
if (loop = 0)
To
if (loop == 0)
For a comparison in JavaScript you can use == or ===, the second option also checks the type. In your case both options can be used.
You used a single = which is used to assign a value to a variable.
If you want to stop rendering completely, you could rewrite your render function like this:
function render()
{
if (loop == 0) {
return;
}
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
theta[axis] += 2.0;
gl.uniform3fv(thetaLoc, theta);
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
requestAnimFrame( render );
}