Related
OBJECTIVE: The objective to the below code is to make a moving robot arm that has three layer's(upper, lower and middle) all of them being attach to the base. Given are the 4 sliders that can move each part indipendently except the base that will move all the arms.
PROBLEM: The problem I am having is when I try to run this code I don't get any visuals on the screen and there is no error in the console, I can't find the issue whats causing it. I have also attached a pic of the output.
SOLUTION: Haven't found yet.
var NumVertices = 36;
var points = [];
var colors = [];
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( 1.0, 1.0, 1.0, 1.0 ), // white
vec4( 0.0, 1.0, 1.0, 1.0 ) // cyan
];
var BASE_HEIGHT = 2.0;
var BASE_WIDTH = 5.0;
var LOWER_ARM_HEIGHT = 5.0;
var LOWER_ARM_WIDTH = 0.5;
var UPPER_ARM_HEIGHT = 5.0;
var UPPER_ARM_WIDTH = 0.5;
var MIDDLE_ARM_HEIGHT = 5.0;
var MIDDLE_ARM_WIDTH = 0.5;
var modelViewMatrix, projectionMatrix;
var Base = 0;
var LowerArm = 1;
var UpperArm = 2;
var MiddleArm = 3;
var theta= [ 0, 0, 0, 0];
var angle = 0;
var modelViewMatrixLoc;
var vBuffer, cBuffer;
function quad( a, b, c, d ) {
colors.push(vertexColors[a]);
points.push(vertices[a]);
colors.push(vertexColors[a]);
points.push(vertices[b]);
colors.push(vertexColors[a]);
points.push(vertices[c]);
colors.push(vertexColors[a]);
points.push(vertices[a]);
colors.push(vertexColors[a]);
points.push(vertices[c]);
colors.push(vertexColors[a]);
points.push(vertices[d]);
}
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 scale4(a, b, c, d) {
var result = mat4();
result[0][0] = a;
result[1][1] = b;
result[2][2] = c;
result[3][3] = d;
return result;
}
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();
program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
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 );
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 );
document.getElementById("slider1").onchange = function(event) {
theta[0] = event.target.value;
};
document.getElementById("slider2").onchange = function(event) {
theta[1] = event.target.value;
};
document.getElementById("slider3").onchange = function(event) {
theta[2] = event.target.value;
};
document.getElementById("slider4").onchange = function(event) {
theta[3] = event.target.value;
};
modelViewMatrixLoc = gl.getUniformLocation(program, "modelViewMatrix");
projectionMatrix = ortho(-10, 10, -10, 10, -10, 10);
gl.uniformMatrix4fv( gl.getUniformLocation(program, "projectionMatrix"), false, flatten(projectionMatrix) );
render();
}
function base() {
var s = scale4(BASE_WIDTH, BASE_HEIGHT, BASE_WIDTH);
var instanceMatrix = mult( translate( 0.0, 0.5 * BASE_HEIGHT, 0.0 ), s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(t) );
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
function upperArm() {
var s = scale4(UPPER_ARM_WIDTH, UPPER_ARM_HEIGHT, UPPER_ARM_WIDTH);
var instanceMatrix = mult(translate( 0.0, 0.5 * UPPER_ARM_HEIGHT, 0.0 ),s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(t) );
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
function lowerArm()
{
var s = scale4(LOWER_ARM_WIDTH, LOWER_ARM_HEIGHT, LOWER_ARM_WIDTH);
var instanceMatrix = mult( translate( 0.0, 0.5 * LOWER_ARM_HEIGHT, 0.0 ), s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(t) );
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
function middleArm()
{
var s = scale4(MIDDLE_ARM_WIDTH, MIDDLE_ARM_HEIGHT, MIDDLE_ARM_WIDTH);
var instanceMatrix = mult( translate( 0.0, 0.5 * MIDDLE_ARM_HEIGHT, 0.0 ), s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(t) );
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
var render = function() {
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
modelViewMatrix = rotate(theta[Base], 0, 1, 0 );
base();
modelViewMatrix = mult(modelViewMatrix, translate(0.0, BASE_HEIGHT, 0.0));
modelViewMatrix = mult(modelViewMatrix, rotate(theta[LowerArm], 0, 0, 1 ));
lowerArm();
modelViewMatrix = mult(modelViewMatrix, translate(0.0, LOWER_ARM_HEIGHT, 0.0));
modelViewMatrix = mult(modelViewMatrix, rotate(theta[UpperArm], 0, 0, 1) );
upperArm();
modelViewMatrix = mult(modelViewMatrix, translate(0.0, UPPER_ARM_HEIGHT, 0.0));
modelViewMatrix = mult(modelViewMatrix, rotate(theta[MiddleArm], 0, 0, 1) );
middleArm();
requestAnimFrame(render);
}
<html>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main()
{
fColor = vColor;
gl_Position = projectionMatrix * modelViewMatrix * vPosition;
}
</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="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>
<script type="text/javascript" src="robotArm.js"></script>
<div id="slider1">
body angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<div id="slider2">
lower arm angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<div id="slider4">
middle arm angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<div id="slider3">
upper arm angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<body>
<canvas id="gl-canvas" width="512"" height="512"
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>
The first thing I did was add webgl-lint
<script src="https://greggman.github.io/webgl-lint/webgl-lint.js" crossorigin></script>
That immediately got the error
Uncaught Error: https://greggman.github.io/webgl-lint/webgl-lint.js:2843:
error in
uniformMatrix4fv(WebGLUniformLocation("modelViewMatrix"),
false,
[5, 0, 0, 0, 0, 2, 0, 0, 0, 0, 5, 0, NaN, NaN, NaN, NaN]): element 12 of argument 2 is NaN
: trying to set uniform 'modelViewMatrix'
at reportError (webgl-lint.js:2163)
at reportFunctionError (webgl-lint.js:2924)
at checkArrayForUniformImpl (webgl-lint.js:2843)
at webgl-lint.js:2869
at checkArgs (webgl-lint.js:2972)
at WebGLRenderingContext.ctx.<computed> [as uniformMatrix4fv] (webgl-lint.js:3016)
at base (js:230)
at render (js:267)
at init (js:223)
Looking in your code the issue is rotate does not take 4 arguments, it takes 2 arguments, an angle and an axis
r = rotate(angle, x, y, z); // BAD!
r = rotate(angle, [x, y, z]); // Good
Fixing that webgl-lint printed a new error. The issue is scale4 takes 4 arguments.
s = scale4(x, y, z); // BAD!
s = scale4(x, y, z, w); // good
you want to pass 1 for w.
That fixed rendering. As for the sliders you probably want to call render in each onchange function. You also probably want to use oninput instead of onchange
var NumVertices = 36;
var points = [];
var colors = [];
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( 1.0, 1.0, 1.0, 1.0 ), // white
vec4( 0.0, 1.0, 1.0, 1.0 ) // cyan
];
var BASE_HEIGHT = 2.0;
var BASE_WIDTH = 5.0;
var LOWER_ARM_HEIGHT = 5.0;
var LOWER_ARM_WIDTH = 0.5;
var UPPER_ARM_HEIGHT = 5.0;
var UPPER_ARM_WIDTH = 0.5;
var MIDDLE_ARM_HEIGHT = 5.0;
var MIDDLE_ARM_WIDTH = 0.5;
var modelViewMatrix, projectionMatrix;
var Base = 0;
var LowerArm = 1;
var UpperArm = 2;
var MiddleArm = 3;
var theta= [ 0, 0, 0, 0];
var angle = 0;
var modelViewMatrixLoc;
var vBuffer, cBuffer;
function quad( a, b, c, d ) {
colors.push(vertexColors[a]);
points.push(vertices[a]);
colors.push(vertexColors[a]);
points.push(vertices[b]);
colors.push(vertexColors[a]);
points.push(vertices[c]);
colors.push(vertexColors[a]);
points.push(vertices[a]);
colors.push(vertexColors[a]);
points.push(vertices[c]);
colors.push(vertexColors[a]);
points.push(vertices[d]);
}
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 scale4(a, b, c, d) {
var result = mat4();
result[0][0] = a;
result[1][1] = b;
result[2][2] = c;
result[3][3] = d;
return result;
}
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();
program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
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 );
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 );
document.getElementById("slider1").oninput = function(event) {
theta[0] = event.target.value;
render();
};
document.getElementById("slider2").oninput = function(event) {
theta[1] = event.target.value;
render();
};
document.getElementById("slider3").oninput = function(event) {
theta[2] = event.target.value;
render();
};
document.getElementById("slider4").oninput = function(event) {
theta[3] = event.target.value;
render();
};
modelViewMatrixLoc = gl.getUniformLocation(program, "modelViewMatrix");
projectionMatrix = ortho(-10, 10, -10, 10, -10, 10);
gl.uniformMatrix4fv( gl.getUniformLocation(program, "projectionMatrix"), false, flatten(projectionMatrix) );
render();
}
function base() {
var s = scale4(BASE_WIDTH, BASE_HEIGHT, BASE_WIDTH, 1);
var instanceMatrix = mult( translate( 0.0, 0.5 * BASE_HEIGHT, 0.0 ), s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(t) );
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
function upperArm() {
var s = scale4(UPPER_ARM_WIDTH, UPPER_ARM_HEIGHT, UPPER_ARM_WIDTH, 1);
var instanceMatrix = mult(translate( 0.0, 0.5 * UPPER_ARM_HEIGHT, 0.0 ),s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(t) );
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
function lowerArm()
{
var s = scale4(LOWER_ARM_WIDTH, LOWER_ARM_HEIGHT, LOWER_ARM_WIDTH, 1);
var instanceMatrix = mult( translate( 0.0, 0.5 * LOWER_ARM_HEIGHT, 0.0 ), s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(t) );
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
function middleArm()
{
var s = scale4(MIDDLE_ARM_WIDTH, MIDDLE_ARM_HEIGHT, MIDDLE_ARM_WIDTH, 1);
var instanceMatrix = mult( translate( 0.0, 0.5 * MIDDLE_ARM_HEIGHT, 0.0 ), s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(t) );
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
var render = function() {
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
modelViewMatrix = rotate(theta[Base], [0, 1, 0]);
base();
modelViewMatrix = mult(modelViewMatrix, translate(0.0, BASE_HEIGHT, 0.0));
modelViewMatrix = mult(modelViewMatrix, rotate(theta[LowerArm], [0, 0, 1] ));
lowerArm();
modelViewMatrix = mult(modelViewMatrix, translate(0.0, LOWER_ARM_HEIGHT, 0.0));
modelViewMatrix = mult(modelViewMatrix, rotate(theta[UpperArm], [0, 0, 1]) );
upperArm();
modelViewMatrix = mult(modelViewMatrix, translate(0.0, UPPER_ARM_HEIGHT, 0.0));
modelViewMatrix = mult(modelViewMatrix, rotate(theta[MiddleArm], [0, 0, 1]) );
middleArm();
requestAnimFrame(render);
}
<html>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main()
{
fColor = vColor;
gl_Position = projectionMatrix * modelViewMatrix * vPosition;
}
</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://greggman.github.io/webgl-lint/webgl-lint.js" crossorigin></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>
<script type="text/javascript" src="robotArm.js"></script>
<div id="slider1">
body angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<div id="slider2">
lower arm angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<div id="slider4">
middle arm angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<div id="slider3">
upper arm angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<body>
<canvas id="gl-canvas" width="512"" height="512"
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>
I am trying to render a 3D rotating triangle, in which all the sides of the triangle has a different texture. I have made all the necessary changes but my triangle is a bit out of shape and I have tried to change the texture on each side of the triangle but I was able to do only one side of the triangle and no matter what I do it only changes one side. I am not looking to get a specific texture as it can be anything but different on all sides. Not sure what I am doing wrong.
var canvas;
var gl;
var numVertices = 36;
var texSize = 256;
var numChecks = 8;
var program;
var texture1, texture2;
var t1, t2;
var c;
var flag = true;
var image1 = new Uint8Array(4*texSize*texSize);
for ( var i = 0; i < texSize; i++ ) {
for ( var j = 0; j <texSize; j++ ) {
var patchx = Math.floor(i/(texSize/numChecks));
var patchy = Math.floor(j/(texSize/numChecks));
if(patchx%2 ^ patchy%2) c = 255;
else c = 0;
//c = 255*(((i & 0x8) == 0) ^ ((j & 0x8) == 0))
image1[8*i*texSize+8*j] = c;
image1[5*i*texSize+5*j+3] = c;
image1[6*i*texSize+6*j+4] = c;
image1[4*i*texSize+4*j+3] = 255;
}
}
var image2 = new Uint8Array(4*texSize*texSize);
// Create a checkerboard pattern
for ( var i = 0; i < texSize; i++ ) {
for ( var j = 0; j <texSize; j++ ) {
image2[4*i*texSize+4*j] = 127+127*Math.sin(0.1*i*j);
image2[6*i*texSize+6*j+1] = 127+127*Math.sin(0.1*i*j);
image2[4*i*texSize+4*j+2] = 127+127*Math.sin(0.1*i*j);
image2[4*i*texSize+4*j+3] = 255;
}
}
var pointsArray = [];
var colorsArray = [];
var texCoordsArray = [];
var texCoord = [
vec2(0, 0),
vec2(0, 1),
vec2(1, 1),
vec2(1, 0)
];
var vertices = [
vec4(0.5, -0.2722, 0.2886),
vec4(0.0, -0.2722, -0.5773),
vec4(-0.5, -0.2722, 0.2886),
vec4(0.5, -0.5443, 0.0)
];
var vertexColors = [
vec4( 0.0, 1.0, 0.0, 1.0 ), // black
vec4( 1.0, 0.0, 0.0, 1.0 ), // red
vec4( 1.0, 1.0, 1.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 configureTexture() {
texture1 = gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, texture1 );
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, 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);
texture2 = gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, texture2 );
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, 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);
}
function quad(a, b, c) {
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[b]);
colorsArray.push(vertexColors[a]);
texCoordsArray.push(texCoord[2]);
pointsArray.push(vertices[c]);
colorsArray.push(vertexColors[a]);
texCoordsArray.push(texCoord[3]);
}
function colorCube()
{
quad( 0, 1, 2 ); // bottom
quad( 1, 0, 3 ); // side0
quad( 1, 2, 3 ); // side1
quad( 2, 0, 3 ); // side3
}
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 );
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 );
configureTexture();
gl.activeTexture( gl.TEXTURE0 );
gl.bindTexture( gl.TEXTURE_2D, texture1 );
gl.uniform1i(gl.getUniformLocation( program, "Tex0"), 0);
gl.activeTexture( gl.TEXTURE1 );
gl.bindTexture( gl.TEXTURE_2D, texture2 );
gl.uniform1i(gl.getUniformLocation( program, "Tex1"), 1);
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;};
document.getElementById("ButtonT").onclick = function(){flag = !flag;};
render();
}
var render = function() {
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
if(flag) theta[axis] += 2.0;
gl.uniform3fv(thetaLoc, theta);
gl.drawArrays( gl.TRIANGLES, 0, numVertices );
requestAnimFrame(render);
}
<!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>
<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()
{
// 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;
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 Tex0;
uniform sampler2D Tex1;
void
main()
{
gl_FragColor = fColor*(texture2D(Tex0, fTexCoord)*texture2D(Tex1, 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>
<script type="text/javascript" src="texture.js"></script>
<body>
<canvas id="gl-canvas" width="1024" height="1024">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>
I'm not sure what kind of help you are looking for.
The normal way to put a different image on each side of a pyramid is to use a texture atlas. Here's an article that covers it.
Effectively you put all the images in to one texture and then use texture coordinates on each face of the pyramid to select one of the images.
The reason I ask if that's what you want is because using a texture atlas is pretty much how 99% of all WebGL apps and 3D graphics apps in general would solve the issue of putting a different texture on each face of a pyramid.
Solving it by actually using multiple textures is possible but it's generally not considered a good solution since then you'd need a different shader to shade a cube (8 textures) from a 4 sides pyramid (4 textures) and again different shaders for every number of textures. Further, there's a limit to the number of textures a single shader can use in one draw call.
Otherwise, the code you posted seems to only make 2 textures and multiplies them together
gl_FragColor = fColor*(texture2D(Tex0, fTexCoord)*texture2D(Tex1, fTexCoord));
So there's nothing in your code to select one texture or the other. You need to add some data to select the texture.
One way would be to add another attribute to your shaders to select the texture. You'd set that attribute to 0 to select Tex0 and 1 to select Tex1
varying float mixAmount; // passed in from vertex shader via attributes
...
vec4 color0 = texture2D(Tex0, fTexCoord);
vec4 color1 = texture2D(Tex1, fTexCoord);
vec4 color = mix(color0, color1, mixAmount);
gl_FragColor = fColor * color;
Where it selects texture 0 when mixAmount = 0 and texture 1 when mixAmount = 1
var canvas;
var gl;
var numVertices = 24;
var texSize = 256;
var numChecks = 8;
var program;
var texture1, texture2;
var t1, t2;
var c;
var flag = true;
var image1 = new Uint8Array(4*texSize*texSize);
for ( var i = 0; i < texSize; i++ ) {
for ( var j = 0; j <texSize; j++ ) {
var patchx = Math.floor(i/(texSize/numChecks));
var patchy = Math.floor(j/(texSize/numChecks));
if(patchx%2 ^ patchy%2) c = 255;
else c = 0;
//c = 255*(((i & 0x8) == 0) ^ ((j & 0x8) == 0))
image1[8*i*texSize+8*j] = c;
image1[5*i*texSize+5*j+3] = c;
image1[6*i*texSize+6*j+4] = c;
image1[4*i*texSize+4*j+3] = 255;
}
}
var image2 = new Uint8Array(4*texSize*texSize);
// Create a checkerboard pattern
for ( var i = 0; i < texSize; i++ ) {
for ( var j = 0; j <texSize; j++ ) {
image2[4*i*texSize+4*j] = 127+127*Math.sin(0.1*i*j);
image2[6*i*texSize+6*j+1] = 127+127*Math.sin(0.1*i*j);
image2[4*i*texSize+4*j+2] = 127+127*Math.sin(0.1*i*j);
image2[4*i*texSize+4*j+3] = 255;
}
}
var pointsArray = [];
var colorsArray = [];
var texCoordsArray = [];
var mixAmountsArray = [];
var texCoord = [
vec2(0, 0),
vec2(0, 1),
vec2(1, 1),
vec2(1, 0)
];
var vertices = [
vec4(0.5, -0.2722, 0.2886),
vec4(0.0, -0.2722, -0.5773),
vec4(-0.5, -0.2722, 0.2886),
vec4(0.5, -0.5443, 0.0)
];
var vertexColors = [
vec4( 0.0, 1.0, 0.0, 1.0 ), // green
vec4( 1.0, 0.0, 0.0, 1.0 ), // red
vec4( 1.0, 1.0, 1.0, 1.0 ), // white
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 ), // cyan
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 configureTexture() {
texture1 = gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, texture1 );
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, 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);
texture2 = gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, texture2 );
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, 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);
}
function quad(a, b, c, mixAmount) {
pointsArray.push(vertices[a]);
colorsArray.push(vertexColors[2]);
texCoordsArray.push(texCoord[0]);
mixAmountsArray.push(mixAmount);
pointsArray.push(vertices[b]);
colorsArray.push(vertexColors[2]);
texCoordsArray.push(texCoord[1]);
mixAmountsArray.push(mixAmount);
pointsArray.push(vertices[c]);
colorsArray.push(vertexColors[2]);
texCoordsArray.push(texCoord[2]);
mixAmountsArray.push(mixAmount);
pointsArray.push(vertices[a]);
colorsArray.push(vertexColors[2]);
texCoordsArray.push(texCoord[0]);
mixAmountsArray.push(mixAmount);
pointsArray.push(vertices[b]);
colorsArray.push(vertexColors[2]);
texCoordsArray.push(texCoord[2]);
mixAmountsArray.push(mixAmount);
pointsArray.push(vertices[c]);
colorsArray.push(vertexColors[2]);
texCoordsArray.push(texCoord[3]);
mixAmountsArray.push(mixAmount);
}
function colorCube()
{
quad( 0, 1, 2, 0 ); // bottom
quad( 1, 0, 3, 1 ); // side0
quad( 1, 2, 3, 0 ); // side1
quad( 2, 0, 3, 1 ); // side3
}
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 );
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 );
var mBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, mBuffer);
gl.bufferData( gl.ARRAY_BUFFER, flatten(mixAmountsArray), gl.STATIC_DRAW );
var vMixAmount = gl.getAttribLocation( program, "vMixAmount" );
gl.vertexAttribPointer( vMixAmount, 1, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vMixAmount );
configureTexture();
gl.activeTexture( gl.TEXTURE0 );
gl.bindTexture( gl.TEXTURE_2D, texture1 );
gl.uniform1i(gl.getUniformLocation( program, "Tex0"), 0);
gl.activeTexture( gl.TEXTURE1 );
gl.bindTexture( gl.TEXTURE_2D, texture2 );
gl.uniform1i(gl.getUniformLocation( program, "Tex1"), 1);
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;};
document.getElementById("ButtonT").onclick = function(){flag = !flag;};
render();
}
var render = function() {
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
if(flag) theta[axis] += 2.0;
gl.uniform3fv(thetaLoc, theta);
gl.drawArrays( gl.TRIANGLES, 0, numVertices );
requestAnimFrame(render);
}
canvas { border: 1px solid black; }
<!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>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
attribute vec2 vTexCoord;
attribute float vMixAmount;
varying vec4 fColor;
varying vec2 fTexCoord;
varying float mixAmount;
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 );
mixAmount = vMixAmount;
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;
varying float mixAmount;
uniform sampler2D Tex0;
uniform sampler2D Tex1;
void
main()
{
vec4 color0 = texture2D(Tex0, fTexCoord);
vec4 color1 = texture2D(Tex1, fTexCoord);
gl_FragColor = fColor * mix(color0, color1, mixAmount);
}
</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>
<script type="text/javascript" src="texture.js"></script>
<body>
<canvas id="gl-canvas" width="200" height="200">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>
That's only 2 textures. To do 4 textures you'd have to do more math and maybe have your mixAmount be 0 to 3
vec4 color0 = texture2D(Tex0, fTexCoord);
vec4 color1 = texture2D(Tex1, fTexCoord);
vec4 color2 = texture2D(Tex2, fTexCoord);
vec4 color3 = texture2D(Tex3, fTexCoord);
vec4 color = color0 * clamp(mixAmount, 0, 1) +
color1 * clamp(abs(1 - mixAmount, 0, 1) +
color2 * clamp(abs(2 - mixAmount, 0, 1) +
color3 * clamp(abs(3 - mixAmount, 0, 1);
gl_FragColor = fColor * color;
I am trying to render a 3D rotating triangle, I have made all the necessary changes but my triangle is way out of shape(doesn't look like a triangle). Do you guys know what I am missing here?
edit: I have attached the output, and yes I have tried playing with the vertices and it doesn't do much(as in it doesn't form a triangle)
var canvas;
var gl;
var NumVertices = 12;
var points = [];
var colors = [];
var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = 0;
var theta = [ 0, 0, 0 ];
var thetaLoc;
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" ); }
colorCube(); //change this name to pyramid
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
gl.enable(gl.DEPTH_TEST);
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, 3, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );
thetaLoc = gl.getUniformLocation(program, "theta");
document.getElementById( "xButton" ).onclick = function () {
axis = xAxis;
};
document.getElementById( "yButton" ).onclick = function () {
axis = yAxis;
};
document.getElementById( "zButton" ).onclick = function () {
axis = zAxis;
};
render();
}
function colorCube()
{
quad( 0, 1, 2 );
quad( 3, 1, 0 );
quad( 0, 1, 2 );
quad( 0, 2, 3 );
}
function quad(a, b, c)
{
var indices = [ a, b, c];
for ( var i = 0; i < indices.length; ++i ) {
points.push( vertices[indices[i]] );
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, NumVertices );
requestAnimFrame( render );
}
<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>
<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;
}
</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>
--------------------------------Output---------------------------
Here is the picture of my output, which rotates on all the axis but it doesn't have the shape of a 3d Triangle
I think you just have bad indices in colorCube
I change them to this
function colorCube()
{
quad( 0, 1, 2 ); // bottom
quad( 1, 0, 3 ); // side0
quad( 1, 2, 3 ); // side1
quad( 2, 0, 3 ); // side3
}
and it seemed to work.
I also changed the way it picks colors for the faces so it just makes each triangle the next color.
function quad(a, b, c)
{
var indices = [ a, b, c];
var ndx = points.length % vertexColors.length;
for ( var i = 0; i < indices.length; ++i ) {
points.push( vertices[indices[i]] );
colors.push(vertexColors[ndx]);
}
}
Seems to work.
var canvas;
var gl;
var NumVertices = 12;
var points = [];
var colors = [];
var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = 0;
var theta = [ 0, 0, 0 ];
var thetaLoc;
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" ); }
colorCube(); //change this name to pyramid
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
gl.enable(gl.DEPTH_TEST);
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, 3, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );
thetaLoc = gl.getUniformLocation(program, "theta");
document.getElementById( "xButton" ).onclick = function () {
axis = xAxis;
};
document.getElementById( "yButton" ).onclick = function () {
axis = yAxis;
};
document.getElementById( "zButton" ).onclick = function () {
axis = zAxis;
};
render();
}
function colorCube()
{
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 = points.length % vertexColors.length;
for ( var i = 0; i < indices.length; ++i ) {
points.push( vertices[indices[i]] );
colors.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 );
}
<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>
<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;
}
</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>
If you want perspective 3D instead of orthographic 3D you'd probably use a perspective matrix
I need to solve a task on a webGl problem where I have to apply shading on a rotating an animated cube.
When I try to do this the problem is that the shade is applied but it is fixed while. While the cube is rotating I see the same faces darker and the others with more light , when I need to see them changing in a dynamic way.
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>
<button id="OrthoPersp">Change Ortho/Persp</button>
<div>Traslation on X <input id="slideX" type="range"
min="-1" max="1" step="0.1" value="0" />
</div>
<div>Traslation on Y <input id="slideY" type="range"
min="-1" max="1" step="0.1" value="0" />
</div>
<div>Traslation on Z <input id="slideZ" type="range"
min="-1" max="1" step="0.1" value="0" />
</div>
<div>Scaling on X <input id="ScalingX" type="range"
min="0" max="1" step="0.1" value="0" />
</div>
<div>Scaling on Y <input id="ScalingY" type="range"
min="0" max="1" step="0.1" value="0" />
</div>
<div>Scaling on Z <input id="ScalingZ" type="range"
min="0" max="1" step="0.1" value="0" />
</div>
<div>
zNear Min<input id="zNearSlider" type="range" min="0.00" max="2.8" step="0.1" value="0.3">
Max
</div>
<div>
zFar Min<input id="zFarSlider" type="range" min="3" max="10" step="3.0" value="3">
Max
</div>
<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;
//Poinit 6 -> Light Source
attribute vec3 vNormal;
uniform vec4 ambientProduct, diffuseProduct, specularProduct;
uniform vec4 lightPosition;
uniform float shininess;
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;
// ORDINE : scaling -> rotazione -> traslation
//gl_Position = projection*modelView*scaling *rz * ry * rx * traslation *vPosition ;
//gl_Position.z = -gl_Position.z;
//Point 6
vec3 pos = -(modelView * vPosition).xyz;
vec3 light = lightPosition.xyz;
vec3 L = normalize( light - pos );
vec3 E = normalize( -pos );
vec3 H = normalize( L + E );
vec4 NN = vec4(vNormal,0);
vec3 N = normalize( (modelView*NN).xyz);
vec4 ambient = ambientProduct;
float Kd = max( dot(L, N), 0.0 );
vec4 diffuse = Kd*diffuseProduct;
float Ks = pow( max(dot(N, H), 0.0), shininess );
vec4 specular = Ks * specularProduct;
if( dot(L, N) < 0.0 ) {
specular = vec4(0.0, 0.0, 0.0, 1.0);
}
gl_Position = projection*modelView*scaling *rz * ry * rx * traslation *vPosition ;
//fColor = vColor;
//fColor = ambient + diffuse + specular;
fColor = (ambient + diffuse + specular);
fColor.a = 1.0;
// *******************
}
</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>
JavaScript
"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 = 0.3;
var far = 3.0;
//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 eye = vec3(1, 1, 1);
//var eye = vec3(0.02, 0.02, 0.02);
//
//Point 5
var fovy = 45.0;
var aspect;
var orthoBool = true;
var aspect = 1.0;
//
//Poinit 6
var lightAmbient = vec4(0.2, 0.2, 0.2, 1.0);
var lightDiffuse = vec4(1.0, 1.0, 1.0, 1.0);
var lightSpecular = vec4(1.0, 1.0, 1.0, 1.0);
var lightPosition = vec4(1.0, 2.0, 3.0,1.0);
var materialAmbient = vec4(1.0, 0.0, 1.0, 1.0);
var materialDiffuse = vec4(1.0, 0.8, 0.0, 1.0);
var materialSpecular = vec4(1.0, 0.8, 0.0, 1.0);
var materialShininess = 100.0;
var ambientColor, diffuseColor, specularColor;
var normalsArray = [];
//
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) {
// Point 6
var t1 = subtract(vertices[b], vertices[a]);
var t2 = subtract(vertices[c], vertices[b]);
var normal = cross(t1, t2);
var normal = vec3(normal);
// *****
//*** Abbiamo rimpizzato i colori on queli del materiale per svolgere il punto 6
pointsArray.push(vertices[a]);
//colorsArray.push(vertexColors[a]);
normalsArray.push(normal);
pointsArray.push(vertices[b]);
//colorsArray.push(vertexColors[a]);
normalsArray.push(normal);
pointsArray.push(vertices[c]);
//colorsArray.push(vertexColors[a]);
normalsArray.push(normal);
pointsArray.push(vertices[a]);
//colorsArray.push(vertexColors[a]);
normalsArray.push(normal);
pointsArray.push(vertices[c]);
//colorsArray.push(vertexColors[a]);
normalsArray.push(normal);
pointsArray.push(vertices[d]);
//colorsArray.push(vertexColors[a]);
normalsArray.push(normal);
}
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 );
// Point 5 -> define aspect
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
//
program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
colorCube();
//Point 6
var nBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, nBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(normalsArray), gl.STATIC_DRAW );
var vNormal = gl.getAttribLocation( program, "vNormal" );
gl.vertexAttribPointer( vNormal, 3, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vNormal );
//*************
// RIMPIAZZATI I COLORI PER IL PUNTO 6
//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 5
document.getElementById("OrthoPersp").onclick = function(){orthoBool = !orthoBool;};
// Point 4
// per documentazine leggi la parte sotto il codice a pag 244 con spiegazione sul clip out
// cambiato inserito due sliders // perspective -> ortho -> + lontano
document.getElementById("zFarSlider").onchange = function() {
far = event.srcElement.value;
};
document.getElementById("zNearSlider").onchange = function() {
near = event.srcElement.value;
};
//Point 6
var ambientProduct = mult(lightAmbient, materialAmbient);
var diffuseProduct = mult(lightDiffuse, materialDiffuse);
var specularProduct = mult(lightSpecular, materialSpecular);
gl.uniform4fv(gl.getUniformLocation(program, "ambientProduct"),
flatten(ambientProduct));
gl.uniform4fv(gl.getUniformLocation(program, "diffuseProduct"),
flatten(diffuseProduct) );
gl.uniform4fv(gl.getUniformLocation(program, "specularProduct"),
flatten(specularProduct) );
gl.uniform4fv(gl.getUniformLocation(program, "lightPosition"),
flatten(lightPosition) );
gl.uniform1f(gl.getUniformLocation(program, "shininess"),materialShininess);
//*************************************
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)); RIMANE COMMENTATO
//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 5
//*************************************
mvMatrix = lookAt(eye, at , up);
if (orthoBool) {
pMatrix = ortho(left, right, bottom, ytop, near, far); }
else {
pMatrix=perspective(fovy , aspect , 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);
}
Your problem seem to be stemming from the fact you're calculating your final colour in the vertex shader then passing that to the fragment shader, this approach is called gourad shading. What you want to do instead is pass along the directional vectors you use for your lighting calculations and perform them in the fragment shader, that is per pixel lighting/phong shading.
I am learning WebGL model hierarchies and wrote a program to draw a robot with independently movable arm segments that are connected to the torso. I was able to accomplish this, with the side effect that the right upper and lower arms will not render until manipulated via slider.
Things I have tried:
Declaring separate variables for both left and right arms, no effect.
Making a copy of the modelViewMatrix instead of push/popping from a stack, no effect.
Broke down the drawrobot function to render separate heirarchies (arms) in the render function directly, no effect.
Checked for typos, nothing found.
I'm really going crazy trying to locate my problem. Help/Ideas appreciated, code is below:
<html>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main()
{
fColor = vColor;
gl_Position = projectionMatrix * modelViewMatrix * vPosition;
}
</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="myrobotArm.js"></script>
<div id="slider1">
body angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<div id="slider2">
lower leftarm angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<div id="slider3">
upper leftarm angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<div id="slider4">
lower rightarm angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<div id="slider5">
upper rightarm angle -180 <input id="slide" type="range"
min="-180" max="180" step="10" value="0"
/>
180
</div><br/>
<body>
<canvas id="gl-canvas" width="512"" height="512"
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>
var NumVertices = 36; //(6 faces)(2 triangles/face)(3 vertices/triangle)
var points = [];
var colors = [];
var myStack = [];
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 )
];
// RGBA colors
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( 1.0, 1.0, 1.0, 1.0 ), // white
vec4( 0.0, 1.0, 1.0, 1.0 ) // cyan
];
// Parameters controlling the size of the Robot's arm
var BASE_HEIGHT = 5.0;
var BASE_WIDTH = 2.0;
var LOWER_ARM_HEIGHT = 0.5;
var LOWER_ARM_WIDTH = 2.0;
var UPPER_ARM_HEIGHT = 0.5;
var UPPER_ARM_WIDTH = 2.0;
var LOWERR_ARM_HEIGHT = 0.5;
var LOWERR_ARM_WIDTH = 2.0;
var UPPERR_ARM_HEIGHT = 0.5;
var UPPERR_ARM_WIDTH = 2.0;
// Shader transformation matrices
var modelViewMatrix, projectionMatrix;
// Array of rotation angles (in degrees) for each rotation axis
var Base = 0;
var LowerArmL = 1;
var UpperArmL = 2;
var LowerArmR = 3;
var UpperArmR = 4;
var theta= [ 0, 0, 0];
var angle = 0;
var modelViewMatrixLoc;
var vBuffer, cBuffer;
//----------------------------------------------------------------------------
function quad( a, b, c, d ) {
colors.push(vertexColors[a]);
points.push(vertices[a]);
colors.push(vertexColors[a]);
points.push(vertices[b]);
colors.push(vertexColors[a]);
points.push(vertices[c]);
colors.push(vertexColors[a]);
points.push(vertices[a]);
colors.push(vertexColors[a]);
points.push(vertices[c]);
colors.push(vertexColors[a]);
points.push(vertices[d]);
}
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 );
}
//____________________________________________
// Remmove when scale in MV.js supports scale matrices
function scale4(a, b, c) {
var result = mat4();
result[0][0] = a;
result[1][1] = b;
result[2][2] = c;
return result;
}
//--------------------------------------------------
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();
// Load shaders and use the resulting shader program
program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
// Create and initialize buffer objects
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 );
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 );
document.getElementById("slider1").onchange = function(event) {
theta[0] = event.target.value/2;
};
document.getElementById("slider2").onchange = function(event) {
theta[1] = event.target.value/2;
};
document.getElementById("slider3").onchange = function(event) {
theta[2] = event.target.value/2;
};
document.getElementById("slider4").onchange = function(event) {
theta[3] = event.target.value/2;
};
document.getElementById("slider5").onchange = function(event) {
theta[4] = event.target.value/2;
};
modelViewMatrixLoc = gl.getUniformLocation(program, "modelViewMatrix");
projectionMatrix = ortho(-10, 10, -10, 10, -10, 10);
gl.uniformMatrix4fv( gl.getUniformLocation(program, "projectionMatrix"), false, flatten(projectionMatrix) );
render();
}
//----------------------------------------------------------------------------
function base() {
var s = scale4(BASE_WIDTH, BASE_HEIGHT, BASE_WIDTH);
var instanceMatrix = mult( translate( 0.0, 0.5 * BASE_HEIGHT, 0.0), s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(t) );
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
//----------------------------------------------------------------------------
function upperArmL() {
var s = scale4(UPPER_ARM_WIDTH, UPPER_ARM_HEIGHT, UPPER_ARM_WIDTH);
var instanceMatrix = mult(translate( -0.5 * UPPER_ARM_WIDTH, 0.0, 0.0),s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(t));
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
//----------------------------------------------------------------------------
function lowerArmL()
{
var s = scale4(LOWER_ARM_WIDTH, LOWER_ARM_HEIGHT, LOWER_ARM_WIDTH);
var instanceMatrix = mult(translate(-0.5 * LOWER_ARM_WIDTH, 0.0, 0.0),s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(t));
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
function upperArmR() {
var s = scale4(UPPERR_ARM_WIDTH, UPPERR_ARM_HEIGHT, UPPERR_ARM_WIDTH);
var instanceMatrix = mult(translate(0.5 * UPPERR_ARM_WIDTH, 0.0, 0.0),s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(t));
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
//----------------------------------------------------------------------------
function lowerArmR()
{
var s = scale4(LOWERR_ARM_WIDTH, LOWERR_ARM_HEIGHT, LOWERR_ARM_WIDTH);
var instanceMatrix = mult(translate( 0.5 * LOWERR_ARM_WIDTH, 0.0, 0.0),s);
var t = mult(modelViewMatrix, instanceMatrix);
gl.uniformMatrix4fv( modelViewMatrixLoc, false, flatten(t));
gl.drawArrays( gl.TRIANGLES, 0, NumVertices );
}
//----------------------------------------------------------------------------
function drawRobot()
{
modelViewMatrix = rotate(theta[Base], 0, 1, 0 );
var myMVM = modelViewMatrix;
// myStack.push(modelViewMatrix);
base();
// modelViewMatrix = myStack.pop();
// modelViewMatrix = myMVM;
// myStack.push(modelViewMatrix);
modelViewMatrix = mult(modelViewMatrix, translate(-0.5 * BASE_WIDTH, BASE_HEIGHT - 0.5 * UPPER_ARM_HEIGHT, 0.0)); //POSITION OF RECT
modelViewMatrix = mult(modelViewMatrix, rotate(theta[UpperArmL], 0, 0, 1)); //ROTATE AROUND Z AXIS BY UPPERARML Degrees
upperArmL();
modelViewMatrix = mult(modelViewMatrix, translate(-UPPER_ARM_WIDTH, 0.0, 0.0));
modelViewMatrix = mult(modelViewMatrix, rotate(theta[LowerArmL], 0, 0, 1));
lowerArmL();
// modelViewMatrix = myStack.pop();
modelViewMatrix = myMVM;
modelViewMatrix = mult(modelViewMatrix, translate(0.5 * BASE_WIDTH, BASE_HEIGHT - 0.5 * UPPERR_ARM_HEIGHT, 0.0));
modelViewMatrix = mult(modelViewMatrix, rotate(theta[UpperArmR], 0, 0, 1));
upperArmR();
modelViewMatrix = mult(modelViewMatrix, translate(UPPERR_ARM_WIDTH, 0.0, 0.0));
modelViewMatrix = mult(modelViewMatrix, rotate(theta[LowerArmR], 0, 0, 1));
lowerArmR();
}
var render = function() {
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
drawRobot();
requestAnimFrame(render);
}
I can't add comments, and my answere will probably be rejectect since it don't directily resolve your problem, but I say what I think, because many people have similar problems than you for the exactly same reason: An unadapted approach of objects transformation hierarchy management.
As you noticed yourself, it is hard to know exactly where your problem come from, but since you say that manipulating sliders (so, force updating data) makes things to "appear", there is high probability that your problem is related to wrong values at initial state. Anyway, the way your program manage transformation matrices don't make things easy to debug and control, you will have hard time to tune that, this is because you don't use the good approach.
Unfortunately, almost no books nor tuturial give the correct way to manage transformation hierarchy. Instead, they give examples using this old pop / push matrix approach, because this is adapted to imperative programmation style, and quick to write. The good approache would requiere an entire chapter.
The transformation hierarchy principle is pretty simple: each object's "final matrix" is the result of the accumulated transformation of all its parents plus its own transformation. The proper way to manage transformation hierarchy is to reflect the logical structure of the hierarchy in your program structure, that is, by working with objects, so to say, to think in Object−Oriented programation paradigm.
To properly manage this, you have to create a Graph with nodes, where each node have parent and children, so to say: a Scene structure. Here is the fundamental object you need to implement:
function Node() {
this.parent = null;
this.childs = new Array();
this.matrix = new Float32Array(16);
this.worldMatrix = new Float32Array(16);
setIdentity(this.matrix);
setIdentity(this.worldMatrix);
}
MyNode.prototype = {
setParent(parent) {
// very simple parenting management
this.parent = parent;
parent.childs.psuh(this);
},
updateMatrix() {
// recursive matrix update (other methods are possible)
if(this.parent) {
this.parent.updateMatrix();
this.worldMatrix = multiply(this.matrix, this.parent.worldMatrix);
} else {
this.worldMatrix = this.matrix;
}
},
}
And here is how to use this:
let torso = new Node();
let upperArmR = new Node();
upperArmR.setParent(torso);
let lowerArmR = new Node();
lowerArmR.setParent(upperArmR);
let upperArmL = new Node();
upperArmL.setParent(torso);
let lowerArmL = new Node();
lowerArmL.setParent(upperArmL);
Once you have this, you have a hierarchical structure you can explores since each object have an identified parent, and children. You can control the local transformation of each object by its local matrix, update all hierarchy, and use the final world matrix to draw, like this:
// this is pseudocode..
rotate(upperArmR.matrix, upperArmRRotation);
rotate(lowerArmR.matrix, lowerArmRRotation);
upperArmR.updateMatrix();
lowerArmR.updateMatrix();
gl.uniformMatrix4fv(modelViewMatrixLoc, false, upperArmR.worldMatrix);
// draw
gl.uniformMatrix4fv(modelViewMatrixLoc, false, lowerArmR.worldMatrix);
// draw
Now, you have fine control on your scene hierarchy and transformation, you can debug each matrix independently to catch wrong transformation, and you can animate all this in easy way.
However notice that in my example, I use a recursive function to always recompute all matrices of the whole hierarchy tree, this induce waste of calculation, since in this case, for each children matrix update, the parent matrix will be recomputed again. To prevent that, you have several solution. One is to add a flag in your node to tell that the matrix is up to date and don't need to be recalculated until the next general update. Another is to do not use a recursive call, but to explores your graph in depth-first to update each node in the proper hierarchy order. I let you explore google using "Depth-First Traversal" or "Depth-First Search" as key words to found methods to achieve this.