I am working on a textured pyramid, but I got some warnings. I did it by step by step from the book "Beginning WebGL for HTML5" and it does not work.
Here is my code:
<!doctype html>
<html>
<head>
<title>Project 2</title>
<script type="text/javascript" src="gl-matrix-min.js"></script>
<style>
body{ background-color: grey; }
canvas{ background-color: white; }
</style>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec4 aVertexPosition;
attribute vec4 aVertexColor;
attribute vec2 aVertexTextureCoord;
varying highp vec2 vTextureCoord;
varying vec4 vColor;
/*
Couting On GPU
// Model matrix
uniform mat4 uMVMatrix;
// Projection matrix
uniform mat4 uPMatrix;
// View matrix
uniform mat4 uVMatrix;
*/
uniform mat4 uPVMatrix;
void main(void) {
vColor = aVertexColor;
gl_Position = uPVMatrix * aVertexPosition;
vTextureCoord = aVertexTextureCoord;
// gl_Position = uPMatrix * uVMatrix * uMVMatrix * aVertexPosition;
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec4 vColor;
varying highp vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = texture2D(uSampler, vTextureCoord);
}
</script>
<script>
var gl = null,
canvas = null,
glProgram = null,
fragmentShader = null,
vertexShader = null;
var coordinateArray = [],
triangleVerticeColors = [],
verticesArray = [],
verticesIndexArray = [],
triangleTexCoords = [];
var vertexPositionAttribute = null,
trianglesVerticeBuffer = null,
vertexColorAttribute = null,
trianglesColorBuffer = null,
triangleVerticesIndexBuffer = null,
vertexTexCoordAttribute = null,
trianglesTexCoordBuffer = null;
var P = mat4.create(),
V = mat4.create(),
M = mat4.create(),
VM = mat4.create(),
PVM = mat4.create();
var uPVMMatrix;
var texture;
var textureImage = null;
function initWebGL() {
canvas = document.getElementById("my-canvas");
try {
gl = canvas.getContext("webgl") ||
canvas.getContext("experimental-webgl");
}catch(e){ }
if(gl) {
setupWebGL();
initShaders();
setupTexture();
setupBuffers();
//getMatrixUniforms();
//setMatrixUniforms();
//animationLoop();
drawScene();
}else{
alert( "Error: Your browser does not appear to" + "support WebGL.");
}
}
function animationLoop() {
var R = mat4.create();
var angle = 0;
var i =0;
var loop = function() {
angle = performance.now() / 1000 / 6 * 2 * Math.PI;
i++;
mat4.rotate(PVM, R, angle, [0, 1, 0]);
gl.uniformMatrix4fv(uPVMMatrix, false, PVM);
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
drawScene();
requestAnimationFrame(loop);
};
requestAnimationFrame(loop);
}
function setupWebGL() {
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.frontFace(gl.CW);
gl.cullFace(gl.BACK);
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
console.log(P);
console.log(V);
console.log(M);
// mat4.identity(M);
mat4.lookAt(V, [5, 0, -5], [0, 0, 0], [0, 1, 0]);
mat4.perspective(P, glMatrix.toRadian(45), canvas.width / canvas.height, 0.1, 1000.0);
mat4.multiply(VM,V,M);
mat4.multiply(PVM,P,VM);
}
function initShaders() {
var fs_source = document.getElementById('shader-fs').innerHTML,
vs_source = document.getElementById('shader-vs').innerHTML;
vertexShader = makeShader(vs_source, gl.VERTEX_SHADER);
fragmentShader = makeShader(fs_source, gl.FRAGMENT_SHADER);
glProgram = gl.createProgram();
gl.attachShader(glProgram, vertexShader);
gl.attachShader(glProgram, fragmentShader);
gl.linkProgram(glProgram);
if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
alert("Unable to initialize the shader program.");
}
gl.useProgram(glProgram);
uPVMMatrix = gl.getUniformLocation(glProgram, "uPVMatrix");
gl.uniformMatrix4fv(uPVMMatrix, false, PVM);
}
function loadTexture() {
textureImage = $("#troll").get(0);
setupTexture();
}
function setupTexture() {
texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNISGNED_BYTE, textureImage);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
glProgram.sampleUniform = gl.getUniformLocation(glProgram, "uSampler");
gl.uniform1i(glProgram.sampleUniform, 0);
if(!gl.isTexture(texture)) {
console.log("Error : Texture is invalid");
}
}
function makeShader(src, type) {
var shader = gl.createShader(type);
gl.shaderSource(shader, src);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert("Error compiling shader: " + gl.getShaderInfoLog(shader));
}
return shader;
}
function setupBuffers() {
// n-sides polygon
var n = 6;
var radius = 1;
var angle = (Math.PI * 2) / n;
var xCoordinate = 0;
var yCoordinate = 0;
for(var i = 0 ; i < n ; i++) {
var a = angle * i;
var xNewCoordinate = xCoordinate + radius * Math.cos(a);
var yNewCoordinate = yCoordinate + radius * Math.sin(a);
var zNewCoordinate = 0;
coordinateArray.push(xNewCoordinate);
coordinateArray.push(yNewCoordinate);
coordinateArray.push(zNewCoordinate);
}
verticesArray = [
//Bottom Face
0.0, 0.0, 0.0,
0.0, 0.0, -1.0,
1.0, 0.0, -1.0,
0.0, 0.0, 0.0,
1.0, 0.0, -1.0,
1.0, 0.0, 0.0,
//Front Face
0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
0.5, 1.0, -0.5,
//Right Face
1.0, 0.0, 0.0,
1.0, 0.0, -1.0,
0.5, 1.0, -0.5,
//Back Face
1.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.5, 1.0, -0.5,
//Left Face
0.0, 0.0, -1.0,
0.0, 0.0, 0.0,
0.5, 1.0, -0.5,
];
trianglesVerticeBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticesArray), gl.STATIC_DRAW);
verticesIndexArray = [
0, 1, 2,
3, 4, 5,
6, 7, 8,
9, 10, 11,
12, 13, 14,
15, 16, 17,
];
triangleVerticesIndexBuffer = gl.createBuffer();
triangleVerticesIndexBuffer.number_vertext_points = verticesIndexArray.length;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, triangleVerticesIndexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(verticesIndexArray), gl.STATIC_DRAW);
triangleTexCoords = [
0.5000, 0.1910,
0.1910, 0.5000,
0.5000, 0.8090,
0.5000, 0.1910,
0.5000, 0.8090,
0.8090, 0.5000,
0.5000, 0.1910,
0.8090, 0.5000,
1.0000, 0.0000,
0.8090, 0.5000,
0.5000, 0.8090,
1.0000, 1.0000,
0.5000, 0.8090,
0.1910, 0.5000,
0.0000, 1.0000,
0.1910, 0.5000,
0.5000, 0.1910,
0.0000, 0.0000,
];
trianglesTexCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesTexCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleTexCoords), gl.STATIC_DRAW);
triangleVerticeColors = [
// Bottom quad
0.470, 0.796, 0.886,
0.470, 0.796, 0.886,
0.470, 0.796, 0.886,
0.470, 0.796, 0.886,
0.470, 0.796, 0.886,
0.470, 0.796, 0.886,
// Back triangle
0.772, 0.470, 0.886,
0.772, 0.470, 0.886,
0.772, 0.470, 0.886,
// Left triangle
0.886, 0.552, 0.470,
0.886, 0.552, 0.470,
0.886, 0.552, 0.470,
// Front triangle
0.886, 0.882, 0.470,
0.886, 0.882, 0.470,
0.886, 0.882, 0.470,
// Right triangle
0.470, 0.886, 0.505,
0.470, 0.886, 0.505,
0.470, 0.886, 0.505,
];
trianglesColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVerticeColors), gl.STATIC_DRAW);
}
// GPU
function getMatrixUniforms() {
glProgram.mvMatrixUniform = gl.getUniformLocation(glProgram, "uMVMatrix");
glProgram.pMatrixUniform = gl.getUniformLocation(glProgram, "uPMatrix");
glProgram.vMatrixUniform = gl.getUniformLocation(glProgram, "uVMatrix");
}
// GPU
function setMatrixUniforms() {
gl.uniformMatrix4fv(glProgram.mvMatrixUniform, false, M);
gl.uniformMatrix4fv(glProgram.pMatrixUniform, false, P);
gl.uniformMatrix4fv(glProgram.vMatrixUniform, false, V);
}
function drawScene() {
vertexPositionAttribute = gl.getAttribLocation(glProgram, "aVertexPosition");
gl.enableVertexAttribArray(vertexPositionAttribute);
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer);
gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
vertexTexCoordAttribute = gl.getAttribLocation(glProgram, "aVertexTexCoord");
gl.enableVertexAttribArray(vertexTexCoordAttribute);
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesTexCoordBuffer);
gl.vertexAttribPointer(vertexTexCoordAttribute, 2, gl.FLOAT, false, 0, 0);
/*vertexColorAttribute = gl.getAttribLocation(glProgram, "aVertexColor");
gl.enableVertexAttribArray(vertexColorAttribute);
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
gl.vertexAttribPointer(vertexColorAttribute, 3, gl.FLOAT, false, 0, 0);
*/
gl.drawElements(gl.TRIANGLE_STRIP, triangleVerticesIndexBuffer.number_vertext_points, gl.UNSIGNED_SHORT, 0);
}
</script>
</head>
<body onload="initWebGL()">
<canvas id="my-canvas" width="800" height="600">
Your browser does not support the HTML5 canvas element.
</canvas>
<img src="./trollface.png" id="troll" />
</body>
</html>
The texture coordinates I used looks like this:
Here is the texture:
The warnings are about out of range arrays and about the image not loading.
You have multiple errors in your code.
Your function loadTexture() is never called and so the texture is actually never loaded.
Replace setupTexture() with loadTexture() inside initWebGL().
You are also seem to be using jQuery to retrieve the image from DOM, but you didn't load the library.
Replace $("#troll").get(0) with document.getElementById("troll") inside loadTexture().
The dimensions of the texture needs to be a power of 2 (128x32, 256x256, 512x1024, ...)
You should resize your image to 256x256.
You made a typo with one of the parameters for texImage2D().
Replace gl.UNISGNED_BYTE with gl.UNSIGNED_BYTE inside your gl.texImage2D() call.
Your names for he texture coordinates attribute don't match between your gl.getAttribLocation() call and your vertex shader code.
Replace aVertexTexCoord with aVertexTextureCoord inside your gl.getAttribLocation() call.
If you are rendering individual triangles replace gl.TRIANGLE_STRIP with gl.TRIANGLES inside your gl.drawElements() call.
If you fix all those mistakes your code will run without errors.
Related
I'm trying to use normals for simple point lights on this simple scene, but I need the normals to modify correctly to the rotation of the cube.
Some notes for the code:
The reason it's so large is because it uses multiple files, which provides more organization.
The reasoning for the cube being rotated within the vertex shader but the cosine and sine operations being performed outside of it is due to performance improvements.
Instead of changing a buffer for, say, 100 cubes and rotating each and every one of them, in order to rotate the cube, we just need to input one buffer. If you just want to rotate the model view projection, that's fine, but if you want to have two cubes (side by side) rotating in different directions or have a first-person shooter with different rotating objects, that's nearly impossible.
// "shaders.js"
const vsSource = [
`attribute vec4 aVertexPosition;`,
`attribute vec3 aVertexNormal;`,
`uniform mat4 uModelViewMatrix;`,
`uniform mat4 uProjectionMatrix;`,
`uniform mat4 uNormalMatrix;`,
`uniform vec3 uTransform;`,
`uniform vec2 uRotationX;`,
`uniform vec2 uRotationY;`,
`uniform vec2 uRotationZ;`,
`varying highp vec3 vLighting;`,
`void main(void) {`,
` vec4 p = aVertexPosition;`,
` float n0x = p.x * uRotationX.y + p.y * uRotationX.x;`,
` float n0y = p.y * uRotationX.y - p.x * uRotationX.x;`,
` float n0z = p.z;`,
` float n1x = n0x;`,
` float n1y = n0y * uRotationY.y + n0z * uRotationY.x;`,
` float n1z = n0z * uRotationY.y - n0y * uRotationY.x;`,
` float n2x = n1x * uRotationZ.y - n1z * uRotationZ.x;`,
` float n2y = n1y;`,
` float n2z = n1z * uRotationZ.y + n1x * uRotationZ.x;`,
` gl_Position = uProjectionMatrix * uModelViewMatrix * (vec4(vec3(n2x, n2y, n2z) + uTransform, p.w));`,
` highp vec3 ambientLight = vec3(0.3, 0.3, 0.3);`,
` highp vec3 directionalLightColor = vec3(1.0, 1.0, 1.0);`,
` highp vec3 directionalVector = normalize(vec3(0.85, 0.8, 0.75));`,
` highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);`,
` highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);`,
` vLighting = ambientLight + (directionalLightColor * directional);`,
`}`
].join(`\n`);
const fsSource = [
`varying highp vec3 vLighting;`,
`void main(void) {`,
` gl_FragColor = vec4(vec3(1.0, 0.0, 0.0) * vLighting, 1.0);`,
`}`
].join(`\n`);
const initShaders = (gl) => {
const vertexShader = gl.createShader(gl.VERTEX_SHADER),
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertexShader, vsSource);
gl.shaderSource(fragmentShader, fsSource);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
alert(`An error occurred compiling the shaders: ${gl.getShaderInfoLog(vertexShader)}`);
gl.deleteShader(vertexShader);
return null;
};
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
alert(`An error occurred compiling the shaders: ${gl.getShaderInfoLog(fragmentShader)}`);
gl.deleteShader(fragmentShader);
return null;
};
return {
'vertex': vertexShader,
'fragment': fragmentShader
};
};
// "object.js"
class Obj {
#positions;
#index;
#normals;
get positions() {
return [...(this.#positions)];
};
get index() {
return [...(this.#index)];
};
get normals() {
return [...(this.#normals)];
};
constructor(positions, index, normals) {
if (typeof positions == `object` && typeof index == `object` && typeof normals == `object`) {
this.#positions = positions;
this.#index = index;
this.#normals = index;
} else {
console.error(`Need "object" type, got: "${typeof positions}", "${typeof index}"`)
};
return;
};
};
class Object {
static Cube = class Cube extends Obj {
constructor() {
super([-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0, -1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0, -1.0, -1.0, 1.0,
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0
], [
0, 1, 2, 0, 2, 3,
4, 5, 6, 4, 6, 7,
8, 9, 10, 8, 10, 11,
12, 13, 14, 12, 14, 15,
16, 17, 18, 16, 18, 19,
20, 21, 22, 20, 22, 23
], [
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0
]);
};
};
};
const getBuffers = (gl, clas) => {
if (typeof clas != `function`) {
console.error(`Need "function" type, got: "${typeof clas}"`);
return;
};
const classy = new clas();
var positions = classy.positions,
index = classy.index,
normals = classy.normals;
if (positions != undefined && positions != null && index != undefined && index != null && normals != undefined && normals != null) {
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const normalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(index), gl.STATIC_DRAW);
return {
'position': positionBuffer,
'index': indexBuffer,
'normal': normalBuffer
}
} else {
console.error(`Need any input type, got: "${typeof positions}", "${typeof index}", "${typeof normals}"`);
};
return;
};
// "draw.js"
var doDraw,
draw,
drawRad;
(() => {
const DTR = Math.PI / 180.0,
RTD = 180.0 / Math.PI;
var draws = [];
doDraw = (gl, aVertexPosition, aVertexNormal, uProjectionMatrix, uModelViewMatrix, uNormalMatrix, uTransform, uRotationX, uRotationY, uRotationZ, projectionMatrix, modelViewMatrix) => {
draws.forEach((e) => {
const normalMatrix = mat4.create();
mat4.invert(normalMatrix, normalMatrix);
mat4.transpose(normalMatrix, normalMatrix);
gl.bindBuffer(gl.ARRAY_BUFFER, e[`buffs`][`position`]);
gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aVertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, e[`buffs`][`normal`]);
gl.vertexAttribPointer(aVertexNormal, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aVertexNormal);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, e[`buffs`][`index`]);
gl.uniformMatrix4fv(uProjectionMatrix, false, projectionMatrix);
gl.uniformMatrix4fv(uModelViewMatrix, false, modelViewMatrix);
gl.uniformMatrix4fv(uNormalMatrix, false, normalMatrix);
gl.uniform3fv(uTransform, e[`transform`]);
gl.uniform2fv(uRotationX, e[`rotateX`]);
gl.uniform2fv(uRotationY, e[`rotateY`]);
gl.uniform2fv(uRotationZ, e[`rotateZ`]);
gl.drawElements(gl.TRIANGLES, e[`count`], gl.UNSIGNED_SHORT, 0); // LINE_LOOP, TRIANGLES
return;
});
draws = [];
return;
};
draw = (buffs, vertexCount, x, y, z, rx, ry, rz) => {
const rxr = rx * DTR,
ryr = ry * DTR,
rzr = rz * DTR;
draws.push({
'buffs': buffs,
'transform': [
x,
y,
z
],
'rotateX': [
Math.sin(rxr),
Math.cos(rxr)
],
'rotateY': [
Math.sin(ryr),
Math.cos(ryr)
],
'rotateZ': [
Math.sin(rzr),
Math.cos(rzr)
],
'rx': rxr,
'ry': ryr,
'rz': rzr,
'count': vertexCount
});
return;
};
drawRad = (buffs, vertexCount, x, y, z, rx, ry, rz) => {
draws.push({
'buffs': buffs,
'transform': [
x,
y,
z
],
'rotateX': [
Math.sin(rx),
Math.cos(rx)
],
'rotateY': [
Math.sin(ry),
Math.cos(ry)
],
'rotateZ': [
Math.sin(rz),
Math.cos(rz)
],
'rx': rx,
'ry': ry,
'rz': rz,
'count': vertexCount
});
return;
};
return;
})();
// "script.js"
(() => {
const DTR = Math.PI / 180.0,
RTD = 180.0 / Math.PI;
var gl,
ctx,
canvasgl,
canvasctx,
width = 0,
height = 0,
cubeBuffs,
shaderProgram,
vertexShader,
fragmentShader,
aVertexPosition,
aVertexNormal,
uProjectionMatrix,
uModelViewMatrix,
uNormalMatrix,
uTransform,
uRotationX,
uRotationY,
uRotationZ,
aProjectionMatrix,
aModelViewMatrix,
projectionMatrix,
modelViewMatrix,
cx = 0.0,
cy = 0.0,
cz = 0.0,
crx = 0.0,
cry = 0.0,
crz = 0.0;
var cubeTime = 0.0;
var updates = [],
updateTime = 0,
fpsupdate = 0.0,
fpsupdatemin = 0.0,
fpsupdatemax = 0.0;
const loop = (deltaTime) => {
cubeTime += deltaTime * 90;
updateTime += deltaTime;
updates.push(deltaTime);
if (updates.length > 60) {
var n = updates.shift();
};
var l = updates.length,
ftime = 0.0;
var max = 0.0,
min = 1000.0;
updates.forEach((e) => {
ftime += e;
if (min > e) {
min = e;
};
if (max < e) {
max = e;
};
return;
});
fpsupdatemin = min;
fpsupdatemax = max;
fpsupdate = ftime / l;
ctx.fillStyle = `#fff`;
ctx.font = `12px serif`;
var txt0 = ` 1 / deltaTime: [ FPS: ${(1 / deltaTime).toFixed(1)} ]`,
txt1 = ` Average / deltaTime: [ FPS: ${(1 / fpsupdate).toFixed(1)} ]`,
txt2 = ` Maximum / deltaTime: [ FPS: ${(1 / fpsupdatemin).toFixed(1)} ]`,
txt3 = ` Minimum / deltaTime: [ FPS: ${(1 / fpsupdatemax).toFixed(1)} ]`;
var metrics0 = ctx.measureText(` FPS:`),
metrics1 = ctx.measureText(txt0),
metrics2 = ctx.measureText(txt1),
metrics3 = ctx.measureText(txt2),
metrics4 = ctx.measureText(txt3);
var hmet0 = metrics0.actualBoundingBoxAscent + metrics0.actualBoundingBoxDescent + 2,
hmet1 = metrics1.actualBoundingBoxAscent + metrics1.actualBoundingBoxDescent + 2,
hmet2 = metrics2.actualBoundingBoxAscent + metrics2.actualBoundingBoxDescent + 2,
hmet3 = metrics3.actualBoundingBoxAscent + metrics3.actualBoundingBoxDescent + 2,
hmet4 = metrics4.actualBoundingBoxAscent + metrics4.actualBoundingBoxDescent + 2;
ctx.fillText(` FPS:`, 0, hmet0);
ctx.fillText(txt0, 0, hmet0 + hmet1);
ctx.fillText(txt1, 0, hmet0 + hmet1 + hmet2);
ctx.fillText(txt2, 0, hmet0 + hmet1 + hmet2 + hmet3);
ctx.fillText(txt3, 0, hmet0 + hmet1 + hmet2 + hmet3 + hmet4);
draw(cubeBuffs, 36, 0.0, 0.0, 0.0, cubeTime * 0.3, cubeTime * 0.7, cubeTime);
return;
};
var l,
then = 0;
l = (now) => {
requestAnimationFrame(l);
now *= 0.001;
const dT = now - then;
then = now;
mat4.copy(projectionMatrix, aProjectionMatrix);
mat4.copy(modelViewMatrix, aModelViewMatrix);
mat4.translate(modelViewMatrix, modelViewMatrix, [
cx, -cy,
cz
]);
mat4.rotate(projectionMatrix, projectionMatrix, (-crx) * DTR, [
1,
0,
0
]);
mat4.rotate(projectionMatrix, projectionMatrix, cry * DTR, [
0,
1,
0
]);
mat4.rotate(projectionMatrix, projectionMatrix, crz * DTR, [
0,
0,
1
]);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clearDepth(1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
ctx.clearRect(0, 0, width, height);
loop(dT);
doDraw(gl, aVertexPosition, aVertexNormal, uProjectionMatrix, uModelViewMatrix, uNormalMatrix, uTransform, uRotationX, uRotationY, uRotationZ, projectionMatrix, modelViewMatrix);
return;
};
const init = () => {
cubeBuffs = getBuffers(gl, Object.Cube);
cx = -6.0;
cy = 6.0;
cz = -6.0;
crx = -45.0;
cry = -45.0;
return false;
};
const resize = () => {
height = document.body.clientHeight;
width = document.body.clientWidth;
canvasctx.style.height = `${height}px`;
canvasctx.style.width = `${width}px`;
canvasctx.height = height;
canvasctx.width = width;
canvasgl.style.height = `${height}px`;
canvasgl.style.width = `${width}px`;
canvasgl.height = height;
canvasgl.width = width;
mat4.perspective(aProjectionMatrix, (45.0 * Math.PI) / 180.0, width / height, 0.0, 1000.0);
gl.viewport(0, 0, width, height);
return;
};
const ini = () => {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
const shaders = initShaders(gl);
vertexShader = shaders[`vertex`];
fragmentShader = shaders[`fragment`];
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert(`Unable to initialize the shader program: ${gl.getProgramInfoLog(shaderProgram)}`);
return true;
};
gl.useProgram(shaderProgram);
aVertexPosition = gl.getAttribLocation(shaderProgram, `aVertexPosition`);
aVertexNormal = gl.getAttribLocation(shaderProgram, `aVertexNormal`);
uProjectionMatrix = gl.getUniformLocation(shaderProgram, `uProjectionMatrix`);
uModelViewMatrix = gl.getUniformLocation(shaderProgram, `uModelViewMatrix`);
uNormalMatrix = gl.getUniformLocation(shaderProgram, `uNormalMatrix`);
uTransform = gl.getUniformLocation(shaderProgram, `uTransform`);
uRotationX = gl.getUniformLocation(shaderProgram, `uRotationX`);
uRotationY = gl.getUniformLocation(shaderProgram, `uRotationY`);
uRotationZ = gl.getUniformLocation(shaderProgram, `uRotationZ`);
gl.disable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.CULL_FACE);
gl.cullFace(gl.BACK);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
return init();
};
window.addEventListener(`load`, () => {
canvasctx = document.createElement(`canvas`);
canvasgl = document.createElement(`canvas`);
canvasctx.style.imageRendering = `pixelated`;
canvasctx.style.position = `fixed`;
canvasctx.style.zIndex = `999`;
canvasctx.style.left = `0px`;
canvasctx.style.top = `0px`;
canvasgl.style.position = `fixed`;
canvasgl.style.zIndex = `989`;
canvasgl.style.left = `0px`;
canvasgl.style.top = `0px`;
document.body.appendChild(canvasctx);
document.body.appendChild(canvasgl);
projectionMatrix = mat4.create();
modelViewMatrix = mat4.create();
aProjectionMatrix = mat4.create();
aModelViewMatrix = mat4.create();
ctx = canvasctx.getContext(`2d`);
gl = canvasgl.getContext(`webgl2`, {
'powerPreference': `high-performance`
});
if (ctx == null || typeof ctx == `undefined`) {
console.error(`Unable to get 2D context`);
alert(`Unable to get 2D context`);
return;
};
if (gl == null || typeof gl == `undefined`) {
console.error(`Unable to get WebGL2 context`);
alert(`Unable to get WebGL2 context`);
return;
};
resize();
var cb;
window.addEventListener(`resize`, () => {
clearTimeout(cb);
cb = setTimeout(resize, 150);
return;
});
if (ini() == false) {
then = performance.now() * 0.001;
requestAnimationFrame(l);
};
return;
});
return;
})();
* {
padding: 0px;
margin: 0px;
}
html,
body {
height: 100%;
width: 100%;
}
<script src="https://intre-webgl-rendering-engine.804kn.repl.co/gl-matrix-min.js"></script>
<!-- Modified version of gl-matrix as to not include imports -->
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.
I am creating a simple WebGL program that creates a cube rotating around the Z axis. The problem is that when its rotating some sides of it override the others and you don't see each individual side of the cube. I looked for a solution online but it makes it worse. They enable the face culling and for them, it seems to work but for me, unfortunately, it doesn't. Can anyone tell me what do I need to add into my code in order to fix the face overriding?
Full Source Code:
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");
var a = 24;
var positions = [
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.5, 0.5, 0.0,
-0.5, 0.5, 0.0,
-0.5, -0.5, 0.5,
0.5, -0.5, 0.5,
0.5, 0.5, 0.5,
-0.5, 0.5, 0.5,
//0.5, 0.5, 1.0,
];
var indices = [
0, 1, 2, 0, 2, 3, // Front
0, 4, 7, 0, 3, 7, // Side 1
1, 5, 6, 1, 2, 6, // Side 2
4, 5, 6, 6, 7, 4 // Back
];
var rotation_angle = 1;
var radians = (rotation_angle * Math.PI)/180;
var rotation = [Math.sin(radians), 0.0, Math.cos(radians)];
var _buffer = gl.createBuffer();
var i_buffer = gl.createBuffer();
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, `
precision mediump float;
attribute vec3 position;
uniform vec3 rotation;
varying vec3 f_col;
void main(){
vec2 newPos = vec2(
position.x * rotation.x - position.z * rotation.z,
position.x * rotation.z + position.z * rotation.x
);
gl_Position = vec4(newPos.x, position.y, newPos.y, 1.0);
f_col = position;
}
`);
gl.compileShader(vertexShader);
// Check if it compiled
var success2 = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS);
if (!success2) {
// Something went wrong during compilation; get the error
throw "could not compile shader:" + gl.getShaderInfoLog(vertexShader);
}
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, `
precision mediump float;
varying vec3 f_col;
void main() {
gl_FragColor = vec4(f_col.x, 0.2, f_col.z, 1.0);
}
`);
gl.compileShader(fragmentShader);
var success1 = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS);
if (!success1) {
// Something went wrong during compilation; get the error
throw "could not compile shader:" + gl.getShaderInfoLog(fragmentShader);
}
var program = gl.createProgram();
// Attach pre-existing shaders
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
var attributeLoc = gl.getAttribLocation(program, "position");
gl.bindBuffer(gl.ARRAY_BUFFER, _buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions),
gl.STATIC_DRAW);
gl.vertexAttribPointer(attributeLoc, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(attributeLoc);
gl.useProgram(program);
var rotation_location = gl.getUniformLocation(program, "rotation");
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, i_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices),
gl.STATIC_DRAW);
function loop() {
gl.clearColor(0.75, 0.85, 0.8, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//gl.drawArrays(gl.TRIANGLE_FAN, 0, 8);
gl.drawElements(gl.TRIANGLES, a, gl.UNSIGNED_SHORT, 0);
//gl.drawArrays(gl.TRIANGLE_STRIP, 1, 3);
rotation_angle++;
var radians = (rotation_angle * Math.PI)/180;
var rotation = [Math.sin(radians), 0.0, Math.cos(radians)];
gl.uniform3fv(rotation_location, rotation);
requestAnimationFrame(loop);
}
loop();
<canvas id="canvas" width="500" height="500"></canvas>
I have created a basic scene consisting of a floor(plane), table, and a cube. I now want to move onto texturing the floor with a wooden texture image Click to see the wooden texture. I know very little about texturing and fairly new to WebGL.
I have some idea of having to load the image from my directory, but not sure on how to apply it to the floor. In addition to this, I am unsure on the texture vertex coordinates needed for the plane(floor).
I am also aware I will need to add new attributes to allow texturing. Would you need to change the overall layout of the object for the texture to take place?
Would appreciate any advice on where to start and how I can go about this task.
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Drawing In 3D </title>
<meta charset="utf-8">
<script src="glMatrix.js"></script>
<script src="webgl-debug.js"></script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec4 vColor;
void main() {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = aVertexColor;
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec4 vColor;
void main() {
gl_FragColor = vColor;
}
</script>
<script type="text/javascript">
var gl;
var canvas;
var shaderProgram;
var floorVertexPositionBuffer;
var floorVertexIndexBuffer;
var cubeVertexPositionBuffer;
var cubeVertexIndexBuffer;
var modelViewMatrix;
var projectionMatrix;
var modelViewMatrixStack;
function createGLContext(canvas) {
var names = ["webgl", "experimental-webgl"];
var context = null;
for (var i = 0; i < names.length; i++) {
try {
context = canvas.getContext(names[i]);
} catch (e) { }
if (context) {
break;
}
}
if (context) {
context.viewportWidth = canvas.width;
context.viewportHeight = canvas.height;
} else {
alert("Failed to create WebGL context!");
}
return context;
}
function loadShaderFromDOM(id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var shaderSource = "";
var currentChild = shaderScript.firstChild;
while (currentChild) {
if (currentChild.nodeType == 3) { // 3 corresponds to TEXT_NODE
shaderSource += currentChild.textContent;
}
currentChild = currentChild.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
function setupShaders() {
var vertexShader = loadShaderFromDOM("shader-vs");
var fragmentShader = loadShaderFromDOM("shader-fs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Failed to setup shaders");
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
shaderProgram.uniformMVMatrix = gl.getUniformLocation(shaderProgram, "uMVMatrix");
shaderProgram.uniformProjMatrix = gl.getUniformLocation(shaderProgram, "uPMatrix");
// Initialise the matrices
modelViewMatrix = mat4.create();
projectionMatrix = mat4.create();
modelViewMatrixStack = [];
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
}
function pushModelViewMatrix() {
var copyToPush = mat4.create(modelViewMatrix);
modelViewMatrixStack.push(copyToPush);
}
function popModelViewMatrix() {
if (modelViewMatrixStack.length == 0) {
throw "Error popModelViewMatrix() - Stack was empty ";
}
modelViewMatrix = modelViewMatrixStack.pop();
}
function setupFloorBuffers() {
floorVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, floorVertexPositionBuffer);
var floorVertexPosition = [
// Plane in y=0
5.0, 0.0, 5.0, //v0
5.0, 0.0, -5.0, //v1
-5.0, 0.0, -5.0, //v2
-5.0, 0.0, 5.0]; //v3
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(floorVertexPosition), gl.STATIC_DRAW);
floorVertexPositionBuffer.itemSize = 3;
floorVertexPositionBuffer.numberOfItems = 4;
floorVertexIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, floorVertexIndexBuffer);
var floorVertexIndices = [0, 1, 2, 3];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(floorVertexIndices), gl.STATIC_DRAW);
floorVertexIndexBuffer.itemSize = 1;
floorVertexIndexBuffer.numberOfItems = 4;
}
function setupCubeBuffers() {
cubeVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
var cubeVertexPosition = [
1.0, 1.0, 1.0, //v0
-1.0, 1.0, 1.0, //v1
-1.0, -1.0, 1.0, //v2
1.0, -1.0, 1.0, //v3
1.0, 1.0, -1.0, //v4
-1.0, 1.0, -1.0, //v5
-1.0, -1.0, -1.0, //v6
1.0, -1.0, -1.0, //v7
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeVertexPosition), gl.STATIC_DRAW);
cubeVertexPositionBuffer.itemSize = 3;
cubeVertexPositionBuffer.numberOfItems = 8;
cubeVertexIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
var cubeVertexIndices = [
0, 1, 2, 0, 2, 3, // Front face
4, 6, 5, 4, 7, 6, // Back face
1, 5, 6, 1, 6, 2, //left
0, 3, 7, 0, 7, 4, //right
0, 5, 1, 0, 4, 5, //top
3, 2, 6, 3, 6, 7 //bottom
];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
cubeVertexIndexBuffer.itemSize = 1;
cubeVertexIndexBuffer.numberOfItems = 36;
}
function setupBuffers() {
setupFloorBuffers();
setupCubeBuffers();
}
function uploadModelViewMatrixToShader() {
gl.uniformMatrix4fv(shaderProgram.uniformMVMatrix, false, modelViewMatrix);
}
function uploadProjectionMatrixToShader() {
gl.uniformMatrix4fv(shaderProgram.uniformProjMatrix, false, projectionMatrix);
}
function drawFloor(r, g, b, a) {
// Disable vertex attrib array and use constant color for the floor.
gl.disableVertexAttribArray(shaderProgram.vertexColorAttribute);
// Set colour
gl.vertexAttrib4f(shaderProgram.vertexColorAttribute, r, g, b, a);
// Draw the floor
gl.bindBuffer(gl.ARRAY_BUFFER, floorVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, floorVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, floorVertexIndexBuffer);
gl.drawElements(gl.TRIANGLE_FAN, floorVertexIndexBuffer.numberOfItems, gl.UNSIGNED_SHORT, 0);
}
function drawCube(r, g, b, a) {
// Disable vertex attrib array and use constant color for the cube.
gl.disableVertexAttribArray(shaderProgram.vertexColorAttribute);
// Set color
gl.vertexAttrib4f(shaderProgram.vertexColorAttribute, r, g, b, a);
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numberOfItems, gl.UNSIGNED_SHORT, 0);
}
function drawTable() {
// Draw table top
pushModelViewMatrix();
mat4.translate(modelViewMatrix, [0.0, 1.0, 0.0], modelViewMatrix);
mat4.scale(modelViewMatrix, [2.0, 0.1, 2.0], modelViewMatrix);
uploadModelViewMatrixToShader();
// Draw the scaled cube
drawCube(0.72, 0.53, 0.04, 1.0); // brown color
popModelViewMatrix();
// Draw table legs
for (var i = -1; i <= 1; i += 2) {
for (var j = -1; j <= 1; j += 2) {
pushModelViewMatrix();
mat4.translate(modelViewMatrix, [i * 1.9, -0.1, j * 1.9], modelViewMatrix);
mat4.scale(modelViewMatrix, [0.1, 1.0, 0.1], modelViewMatrix);
uploadModelViewMatrixToShader();
drawCube(0.72, 0.53, 0.04, 1.0); // argument sets brown color
popModelViewMatrix();
}
}
}
function draw() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(60, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, projectionMatrix);
mat4.identity(modelViewMatrix);
mat4.lookAt([8, 5, -10], [0, 0, 0], [0, 1, 0], modelViewMatrix);
uploadModelViewMatrixToShader();
uploadProjectionMatrixToShader();
// Draw floor in red color
drawFloor(1.0, 0.0, 0.0, 1.0);
// Draw table
pushModelViewMatrix();
mat4.translate(modelViewMatrix, [0.0, 1.1, 0.0], modelViewMatrix);
uploadModelViewMatrixToShader();
drawTable(); //Call drawTable() function
popModelViewMatrix();
// Draw box on top of the table
pushModelViewMatrix();
mat4.translate(modelViewMatrix, [0.0, 2.7, 0.0], modelViewMatrix);
mat4.scale(modelViewMatrix, [0.5, 0.5, 0.5], modelViewMatrix);
uploadModelViewMatrixToShader();
drawCube(0.0, 0.0, 1.0, 1.0);
popModelViewMatrix()
}
function startup() {
canvas = document.getElementById("myGLCanvas");
gl = WebGLDebugUtils.makeDebugContext(createGLContext(canvas));
setupShaders();
setupBuffers();
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.enable(gl.DEPTH_TEST);
draw();
}
</script>
</head>
<body onload="startup();">
<canvas id="myGLCanvas" width="500" height="500"></canvas>
</body>
</html>
You can use loadTexture() method to load textures in WebGL project.
The loadTexture() routine starts by creating a WebGL texture object
texture by calling the WebGL createTexture() function. It then uploads
a single blue pixel using texImage2D(). This makes the texture
immediately usable as a solid blue color even though it may take a few
moments for our image to download.
To load the texture from the image file, it then creates an Image
object and assigned the src to the URL for our image we wish to use as
our texture. The function we assign to image.onload will be called
once the image has finished downloading. At that point, we again call
texImage2D() this time using the image as the source of the texture.
After that we setup filtering and wrapping for the texture based on
whether or not the image we download was a power of 2 in both
dimensions or not.
function loadTexture(gl, url) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// Because images have to be download over the internet
// they might take a moment until they are ready.
// Until then put a single pixel in the texture so we can
// use it immediately. When the image has finished downloading
// we'll update the texture with the contents of the image.
const level = 0;
const internalFormat = gl.RGBA;
const width = 1;
const height = 1;
const border = 0;
const srcFormat = gl.RGBA;
const srcType = gl.UNSIGNED_BYTE;
const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
width, height, border, srcFormat, srcType,
pixel);
const image = new Image();
image.onload = function() {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
srcFormat, srcType, image);
// WebGL1 has different requirements for power of 2 images
// vs non power of 2 images so check if the image is a
// power of 2 in both dimensions.
if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
// Yes, it's a power of 2. Generate mips.
gl.generateMipmap(gl.TEXTURE_2D);
} else {
// No, it's not a power of 2. Turn of mips and set
// wrapping to clamp to edge
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
}
};
image.src = url;
return texture;
}
Or have a look at this cube with texture WebGL tutorial on git hub.
I'm trying to follow WebGLFundamentals.org and LearningWebGL tutorials and I reached the projection part.
I create my scene something like LearningWebGL Tutorial 01 (with only the square):
var canvas;
var gl;
var shaderProgram;
// Vertex Shader
var positionLocation;
var uvMatrixLocation;
var pMatrixLocation;
var uvMatrix = mat4.create();
var pMatrix = mat4.create();
// Fragment Shader
var colorLocation;
var buffer = [];
function initGL() {
canvas = document.getElementById("webgl-canvas");
gl = WebGLUtils.setupWebGL(canvas);
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
}
function createShader(gl, id, type) {
var shader;
var shaderSrc = document.getElementById(id);
if (type == "fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (type == "vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, shaderSrc.text);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
function initShaders() {
var fragmentShader = createShader(gl, "fshader", "fragment");
var vertexShader = createShader(gl, "vshader", "vertex");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
// Linka os parametros do shader
positionLocation = gl.getAttribLocation(shaderProgram, "a_position");
uvMatrixLocation = gl.getUniformLocation(shaderProgram, "uvMatrix");
pMatrixLocation = gl.getUniformLocation(shaderProgram, "pMatrix");
gl.enableVertexAttribArray(positionLocation);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert("Não foi possível inicializar os shaders"); }
}
function initBuffers() {
createPoly([
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
]);
}
function draw() {
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(shaderProgram);
mat4.perspective(pMatrix, Math.PI/3, 1, -10, 10);
gl.uniformMatrix4fv(pMatrixLocation, false, pMatrix);
gl.uniformMatrix4fv(uvMatrixLocation, false, uvMatrix);
buffer.forEach(function(e) {
gl.bindBuffer(gl.ARRAY_BUFFER, e.buffer);
gl.vertexAttribPointer(positionLocation, e.vertSize, gl.FLOAT, false, 0, 0);
gl.drawArrays(e.primtype, 0, e.nVerts());
});
}
window.onload = function() {
initGL();
initShaders();
initBuffers();
draw();
}
// ---------------------------------------------------------------
// --------------------------- Utils -----------------------------
// ---------------------------------------------------------------
function createPoly(vertices) {
var vertexBuffer;
vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
var poly = {
buffer: vertexBuffer,
vertSize: 3,
nVerts: function() { return vertices.length/this.vertSize; },
primtype: gl.TRIANGLE_STRIP
};
buffer.push(poly);
}
<script src="https://www.khronos.org/registry/webgl/sdk/demos/common/webgl-utils.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.3.2/gl-matrix-min.js"></script>
<script id="vshader" type="x-shader/x-vertex">
attribute vec3 a_position;
uniform mat4 uvMatrix;
uniform mat4 pMatrix;
varying vec4 v_color;
void main() {
gl_Position = pMatrix * uvMatrix * vec4(a_position, 1);
v_color = gl_Position;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 v_color;
void main(void) { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }
</script>
<canvas id="webgl-canvas" width="800" height="600"></canvas>
Then I set the projection on line 85:
Using orthogonal projection mat4.ortho(pMatrix, -5, 5, -5, 5, -5, 5); the square appears on my canvas
when I use perspective mat4.perspective(pMatrix, Math.PI/3, 1, -10, 10); it won't work
I've already tried several parameters
First off normally you'd make zNear and zFar positive numbers. They represent how the area in front of the camera that will be visible. Second is because your uvMatrix is the identity matrix your object as at the origin. The view is also at the origin (see cameras and perspective)
That means in order to view the object you either need to move the object away from the camera or add in a view matrix (which also effectively moves the object away from the origin)
I changed the code to this and it worked
// set zNear to 0.1
mat4.perspective(pMatrix, Math.PI/3, 1, 0.1, 10);
// move the object out from the camera
mat4.translate(uvMatrix, uvMatrix, [0, 0, -5]);
var canvas;
var gl;
var shaderProgram;
// Vertex Shader
var positionLocation;
var uvMatrixLocation;
var pMatrixLocation;
var uvMatrix = mat4.create();
var pMatrix = mat4.create();
// Fragment Shader
var colorLocation;
var buffer = [];
function initGL() {
canvas = document.getElementById("webgl-canvas");
gl = WebGLUtils.setupWebGL(canvas);
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
}
function createShader(gl, id, type) {
var shader;
var shaderSrc = document.getElementById(id);
if (type == "fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (type == "vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, shaderSrc.text);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
function initShaders() {
var fragmentShader = createShader(gl, "fshader", "fragment");
var vertexShader = createShader(gl, "vshader", "vertex");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
// Linka os parametros do shader
positionLocation = gl.getAttribLocation(shaderProgram, "a_position");
uvMatrixLocation = gl.getUniformLocation(shaderProgram, "uvMatrix");
pMatrixLocation = gl.getUniformLocation(shaderProgram, "pMatrix");
gl.enableVertexAttribArray(positionLocation);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert("Não foi possível inicializar os shaders"); }
}
function initBuffers() {
createPoly([
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
]);
}
function draw() {
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(shaderProgram);
mat4.perspective(pMatrix, Math.PI/3, 1, 0.1, 10);
mat4.translate(uvMatrix, uvMatrix, [0, 0, -5]);
gl.uniformMatrix4fv(pMatrixLocation, false, pMatrix);
gl.uniformMatrix4fv(uvMatrixLocation, false, uvMatrix);
buffer.forEach(function(e) {
gl.bindBuffer(gl.ARRAY_BUFFER, e.buffer);
gl.vertexAttribPointer(positionLocation, e.vertSize, gl.FLOAT, false, 0, 0);
gl.drawArrays(e.primtype, 0, e.nVerts());
});
}
window.onload = function() {
initGL();
initShaders();
initBuffers();
draw();
}
// ---------------------------------------------------------------
// --------------------------- Utils -----------------------------
// ---------------------------------------------------------------
function createPoly(vertices) {
var vertexBuffer;
vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
var poly = {
buffer: vertexBuffer,
vertSize: 3,
nVerts: function() { return vertices.length/this.vertSize; },
primtype: gl.TRIANGLE_STRIP
};
buffer.push(poly);
}
<script src="https://www.khronos.org/registry/webgl/sdk/demos/common/webgl-utils.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.3.2/gl-matrix-min.js"></script>
<script id="vshader" type="x-shader/x-vertex">
attribute vec3 a_position;
uniform mat4 uvMatrix;
uniform mat4 pMatrix;
varying vec4 v_color;
void main() {
gl_Position = pMatrix * uvMatrix * vec4(a_position, 1);
v_color = gl_Position;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 v_color;
void main(void) { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }
</script>
<canvas id="webgl-canvas" width="800" height="600"></canvas>
Change zNear to a small, positive number.