WebGL perspective projection matrix not working - javascript

Trying to write basic WebGL program, which draws a triangle to the screen. Without any projection matrix it works just right, as well as with identity matrix. But when it comes to perspective projection matrix it just shows nothing. Here is my code:
const canvas = document.getElementById("viewport");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const gl = canvas.getContext("webgl2");
gl.viewport(0, 0, window.innerWidth, window.innerHeight);
const vs = gl.createShader(gl.VERTEX_SHADER);
const fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vs, document.getElementById("vs").innerText);
gl.shaderSource(fs, document.getElementById("fs").innerText);
gl.compileShader(vs);
gl.compileShader(fs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)){
const info = gl.getShaderInfoLog(vs);
throw new Error("Error compiling vertex shader:\n\n" + info);
}
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)){
const info = gl.getShaderInfoLog(fs);
throw new Error("Error compiling fragment shader:\n\n" + info);
}
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
gl.validateProgram(program);
gl.useProgram(program);
const position = [
-0.5, -0.5, 0.0,
0.0, 0.5, 0.0,
0.5, -0.5, 0.0,
];
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(position), gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
const projectionMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
];
const FOV = 70;
const NEAR_PLANE = .1;
const FAR_PLANE = 1000;
const aspectRatio = canvas.width / canvas.height;
const yScale = (1.0 / Math.tan((FOV / 2.0) * (Math.PI / 180.0))) * aspectRatio;
const xScale = yScale / aspectRatio;
const frustumLength = FAR_PLANE - NEAR_PLANE;
projectionMatrix[0] = xScale;
projectionMatrix[5] = yScale;
projectionMatrix[10] = ((FAR_PLANE + NEAR_PLANE) / frustumLength) * -1.0;
projectionMatrix[11] = -1.0;
projectionMatrix[14] = ((2.0 * NEAR_PLANE * FAR_PLANE) / frustumLength) * -1;
projectionMatrix[15] = 0;
gl.uniformMatrix4fv(gl.getUniformLocation(program, "u_Projection"), false, projectionMatrix)
const loop = () => {
gl.clearColor(0.0, 0.0, 0.0, 0.8);
gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(loop);
}
loop();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
html, body {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script id="vs" type="x-shader/x-vertex">#version 300 es
precision highp float;
precision highp int;
layout(location=0) in vec3 a_Position;
out vec4 v_Position;
uniform mat4 u_Projection;
void main()
{
gl_Position = u_Projection * vec4(a_Position, 1.0);
v_Position = gl_Position;
}
</script>
<script id="fs" type="x-shader/x-fragment">#version 300 es
precision highp float;
precision highp int;
in vec4 v_Position;
out vec4 out_Color;
void main()
{
out_Color = v_Position;
}
</script>
<canvas id="viewport"></canvas>
<script src="main.js"></script>
</body>
</html>
I have also tried this solution, but id didn`t work either.

Have you tried moving the triangle back a bit? Based on your NEAR_PLAIN, the triangle is too close. Try:
const position = [
-0.5, -0.5, -1.0,
0.0, 0.5, -1.0,
0.5, -0.5, -1.0,
];
Just as an aside, I'm not sure I agree with the math that you're using to create your projection matrix. I think it would be worth comparing against https://glmatrix.net/docs/mat4.js.html#line1508, which I believe gives a different result.

Related

Why does this not get the corresponding pixel

After drawing a triangle, I want to use the readPixels method to get the pixel information, but I can't get it with the following code.
const gl = document.querySelector("canvas").getContext("webgl2", {
preserveDrawingBuffer: true
});
render();
read(); // read in other event
function render() {
const fragment_center = `#version 300 es
precision highp float;
in vec3 HSV;
out vec4 fragColor;
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main() {
vec3 color = hsv2rgb(HSV);
fragColor = vec4(color, 1.0);
}
`;
const vertex_center = `#version 300 es
precision highp float;
in vec2 position;
in vec2 offset;
in float hue;
out vec3 HSV;
void main() {
float x = offset.x + position.x + 0.15;
float y = offset.y + position.y + 0.3;
HSV = vec3(hue, y, x);
gl_Position = vec4(position, 1.0, 1.0);
}
`;
const program = initProgram(gl, vertex_center, fragment_center);
const radius = 1;
const x1 = Math.cos((30 / 180) * Math.PI) * radius;
const y1 = Math.sin((30 / 180) * Math.PI) * radius;
const v_triangle = new Float32Array([0, radius, x1, -y1, -x1, -y1]);
let buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, v_triangle, gl.STATIC_DRAW);
let gl_position = gl.getAttribLocation(program, "position");
gl.vertexAttribPointer(gl_position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(gl_position);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, v_triangle.length / 2);
}
function read() {
const pixel = new Uint8Array(4);
gl.readPixels(0, 0.5, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
log(pixel);
}
function log(...args) {
const elem = document.createElement("pre");
elem.textContent = [...args].join(" ");
document.body.appendChild(elem);
}
function initProgram(gl, v, f) {
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, v);
gl.compileShader(vertexShader);
let status = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS);
if (!status) alert(gl.getShaderInfoLog(vertexShader));
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, f);
gl.compileShader(fragmentShader);
status = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS);
if (!status) alert(gl.getShaderInfoLog(fragmentShader));
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
return program;
}
<canvas></canvas>
The above code does not get the corresponding pixels properly.
However, if I change the implementation to not use drawArrays and use a method like clearColor, I can get the pixels.
const gl = document.querySelector("canvas").getContext("webgl");
render();
read(); // read in same event
function render() {
gl.clearColor(.25, .5, .75, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
}
function read() {
const pixel = new Uint8Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
log(pixel);
}
function log(...args) {
const elem = document.createElement("pre");
elem.textContent = [...args].join(' ');
document.body.appendChild(elem);
}
<canvas></canvas>
The coordinates for gl.readPixels are window (frambuffer) coordinates. These coordinates are integral and the top left is (0, 0). You actually read the pixel from the top left corner of the framebuffer. This fragment is not changed when you draw the triangle and contains the clear color. Read a fragment from a different position:
gl.readPixels(0, 0.5, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
gl.readPixels(200, 100, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl2", {
preserveDrawingBuffer: true
});
render();
read(); // read in other event
function render() {
const fragment_center = `#version 300 es
precision highp float;
in vec3 HSV;
out vec4 fragColor;
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main() {
vec3 color = hsv2rgb(HSV);
fragColor = vec4(color, 1.0);
}
`;
const vertex_center = `#version 300 es
precision highp float;
in vec2 position;
in vec2 offset;
in float hue;
out vec3 HSV;
void main() {
float x = offset.x + position.x + 0.15;
float y = offset.y + position.y + 0.3;
HSV = vec3(hue, y, x);
gl_Position = vec4(position, 1.0, 1.0);
}
`;
const program = initProgram(gl, vertex_center, fragment_center);
const radius = 1;
const x1 = Math.cos((30 / 180) * Math.PI) * radius;
const y1 = Math.sin((30 / 180) * Math.PI) * radius;
const v_triangle = new Float32Array([0, radius, x1, -y1, -x1, -y1]);
let buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, v_triangle, gl.STATIC_DRAW);
let gl_position = gl.getAttribLocation(program, "position");
gl.vertexAttribPointer(gl_position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(gl_position);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, v_triangle.length / 2);
}
function read() {
const pixel = new Uint8Array(4);
const x = canvas.width/2;
const y = canvas.height/2;
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
log('(' + x + ', ' + y + '): ' + pixel);
}
function log(...args) {
const elem = document.createElement("pre");
elem.textContent = [...args].join(" ");
document.body.appendChild(elem);
}
function initProgram(gl, v, f) {
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, v);
gl.compileShader(vertexShader);
let status = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS);
if (!status) alert(gl.getShaderInfoLog(vertexShader));
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, f);
gl.compileShader(fragmentShader);
status = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS);
if (!status) alert(gl.getShaderInfoLog(fragmentShader));
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
return program;
}
<canvas></canvas>

WebGL vertices interpolation in shader with indexed drawElements, how to do it in GPU?

I have some streaming data, I want to draw interpolated vertices using gl.POINTS using WebGL2. I have smoothing function to produce circles and this is really what I need (I may want to interpolate twofold or threefold):
To illustrate problem:
To interpolate between vertices, here in JavaScript twofold:
var array = new Float32Array([-0.9, -0.9, 0.9, -0.9, 0.9, 0.9, -0.9, 0.9]);
var array2 = new Float32Array(array.length * 2 - 2);
/* init canvas */
var gl = document.getElementById('plot2').getContext('webgl2');
gl.canvas.width = gl.canvas.height = 128;
gl.viewportWidth = gl.canvas.width;
gl.viewportHeight = gl.canvas.height;
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
const fs_point = `#version 300 es
precision mediump float;
out vec4 color;
void main() {
color = vec4(0.5, 0., 0.5, 0.8);
}`;
const vs_points = `#version 300 es
precision mediump float;
in vec2 vPos;
void main() {
gl_Position = vec4(vPos.x, vPos.y, 0, 1.0);
gl_PointSize = 10.0;
}`;
const shaderProgram = gl.createProgram();
let shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, fs_point);
gl.compileShader(shader);
gl.attachShader(shaderProgram, shader);
shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(shader, vs_points);
gl.compileShader(shader);
gl.attachShader(shaderProgram, shader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.BLEND);
gl.disable(gl.DEPTH_TEST);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "vPos");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
const pointPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, pointPosBuffer);
gl.bufferData(gl.ARRAY_BUFFER, array2, gl.DYNAMIC_DRAW);
pointPosBuffer.itemSize = 2;
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, pointPosBuffer.itemSize, gl.FLOAT, false, 0, 0);
/* /init canvas */
/* loop */
gl.clear(gl.COLOR_BUFFER_BIT);
//array changes, manual interpolation
for(var i = 0; i < array.length; i += 2) {
array2[2 * i] = array[i];
array2[2 * i + 1] = array[i + 1];
}
//here starts interpolation
for(var i = 2; i < array2.length - 2; i += 4) {
array2[i] = (array2[i - 2] + array2[i + 2]) * 0.5;
array2[i + 1] = (array2[i - 1] + array2[i + 3]) * 0.5;
}
gl.bufferData(gl.ARRAY_BUFFER, array2, gl.DYNAMIC_DRAW); //array values changes
gl.drawArrays(gl.GL_POINTS, 0, 7);
/* /loop */
<canvas id="plot2"></canvas>
It is really really awkward to do it manually, so here is switch to shader:
var array = new Float32Array([-0.9, -0.9, 0.9, -0.9, 0.9, 0.9, -0.9, 0.9]),
gl = document.getElementById('plot3').getContext('webgl2');
gl.canvas.width = gl.canvas.height = 128;
gl.viewportWidth = gl.canvas.width;
gl.viewportHeight = gl.canvas.height;
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
const fs_point = `#version 300 es
precision mediump float;
out vec4 color;
void main() {
color = vec4(0.5, 0., 0.5, 0.8);
}`;
const vs_points = `#version 300 es
precision mediump float;
in vec4 vPos;
void main() {
switch (gl_VertexID % 3) {
case 0:
gl_Position = vec4(vPos.x, vPos.y, 0, 1.0);
break;
case 1:
gl_Position = vec4(0.5 * (vPos.x + vPos.z), 0.5 * (vPos.y + vPos.w), 0, 1.0);
break;
case 2:
gl_Position = vec4(vPos.z, vPos.w, 0, 1.0);
break;
}
gl_PointSize = 12.0;
}`;
const shaderProgram = gl.createProgram();
let shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, fs_point);
gl.compileShader(shader);
gl.attachShader(shaderProgram, shader);
shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(shader, vs_points);
gl.compileShader(shader);
gl.attachShader(shaderProgram, shader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.BLEND);
gl.disable(gl.DEPTH_TEST);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "vPos");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
const pointPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, pointPosBuffer);
gl.bufferData(gl.ARRAY_BUFFER, array, gl.DYNAMIC_DRAW);
pointPosBuffer.itemSize = 4;
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, pointPosBuffer.itemSize, gl.FLOAT, false, 8, 0);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
const indices = new Uint8Array([
0, 0, 0,
1, 1, 1,
2, 2, 2
]);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
/* /init canvas */
/* loop */
gl.clear(gl.COLOR_BUFFER_BIT);
//array changes, manual interpolation
gl.bufferData(gl.ARRAY_BUFFER, array, gl.DYNAMIC_DRAW); //array values changes
gl.drawElements(gl.GL_POINTS, 9, gl.UNSIGNED_BYTE, 0);
/* /loop */
<canvas id="plot3"></canvas>
Here, I want to use indices and supply two pairs of x, y coordinates to shader. I see only three dots. I think the code tells the indices, calls three times the same quad of vertices interpolating them according to index (which seems to fail), advances 8 bytes (2 Float coordinates) and draws again.
Is there easier way to interpolate between vertices?
Aren't gl_VertexID or gl_InstanceID (tried the same at instanced version) suppose to advance every index / vertex?
Is this due to index reuse?

Nothing is being rendered in canvas

This is my code:
I am just trying to render the triangle in webgl, but I am not able to.
There is no error or warning in console whereas there is nothing being rendered in the canvas.
`use strict`;
const vsTriangle = `#version 300 es
in vec3 a_position;
out vec3 varying_color;
uniform mat4 u_vpMatrix;
void main(){
gl_Position = u_vpMatrix*vec4(a_position, 1.0);
varying_color = a_position;
}
`;
const fsTriangle = `#version 300 es
precision mediump float;
in vec3 varying_color;
out vec4 outColor;
void main(){
outColor = vec4(1.0, 0.0, 0.0, 0.7);
}
`;
const up = [0, 1, 0];
let modelDegree = 0;
let cameraYposition = 2.0;
const positionTriangle = [0.0, 1.0, 0.0, 0.5, 0.5, 0.0, 1.0, 0.0, 0.0];
(function() {
const canvas = document.querySelector("#main-canvas");
let gl = canvas.getContext("webgl2");
if (!gl) {
console.log("webgl2 not found");
return;
}
var ext = gl.getExtension("OES_element_index_uint");
let programTriangle = webglUtils.createProgramFromSources(gl, [
vsTriangle,
fsTriangle,
]);
let vao = gl.createVertexArray();
gl.bindVertexArray(vao);
let position = gl.getAttribLocation(programTriangle, "a_position");
let modelMatrixLocation = gl.getUniformLocation(programTriangle, "u_vpMatrix");
let posTriangleBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, posTriangleBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(positionTriangle),
gl.STATIC_DRAW
);
let cameraDegree = 0;
function degToRadian(deg) {
return (Math.PI / 180) * deg;
}
function initialCameraSetup(cameraPosition, up) {
let cameraMatrix = m4.lookAt(cameraPosition, [1, 0, 0], up);
return cameraMatrix;
}
function drawScene() {
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0.5, 0.5, 0.5, 0.5);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.CULL_FACE);
gl.cullFace(gl.BACK);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.BLEND);
let cameraRadian = degToRadian(cameraDegree);
let cameraMatrix = m4.yRotation(cameraRadian);
cameraMatrix = m4.translate(cameraMatrix, 0.0, 0.0, 1.5);
cameraPosition = [cameraMatrix[12], cameraMatrix[13], cameraMatrix[14]];
cameraMatrix = initialCameraSetup(cameraPosition, up);
viewMatrix = m4.inverse(cameraMatrix);
let aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
let fieldofView = degToRadian(90);
let projectionMatrix = m4.perspective(fieldofView, aspect, 0.01, 1000);
let vProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);
gl.bindBuffer(gl.ARRAY_BUFFER, posTriangleBuffer);
gl.enableVertexAttribArray(position);
gl.vertexAttribPointer(
position,
3,
gl.FLOAT,
false,
0,
0
);
gl.useProgram(programTriangle);
gl.uniformMatrix4fv(
modelMatrixLocation,
false,
vProjectionMatrix
);
gl.drawArrays(gl.TRIANGLES, 0, 3);
window.requestAnimationFrame(drawScene);
}
requestAnimationFrame(drawScene);
})();
#main-canvas {
width: 720px;
height: 360px;
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>test !!!</title>
<link rel="stylesheet" href="./styles/main.css" />
</head>
<body>
<div class="canvas-container">
<canvas id="main-canvas"></canvas>
</div>
<script src="https://webglfundamentals.org/webgl/resources/m4.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script src="https://greggman.github.io/webgl-lint/webgl-lint.js"></script>
</body>
</html>
Your "triangle" is not a triangle but a straight line. Change the vertex coordinates:
const positionTriangle = [0.0, 1.0, 0.0, 0.5, 0.5, 0.0, 1.0, 0.0, 0.0];
const positionTriangle = [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0];
The default winding order of fron faces is counter-clockwise. Since Face Culling is enabled, you need to make sure your triangle has counter clockwise winding order. See Face Culling
`use strict`;
const vsTriangle = `#version 300 es
in vec3 a_position;
out vec3 varying_color;
uniform mat4 u_vpMatrix;
void main(){
gl_Position = u_vpMatrix*vec4(a_position, 1.0);
varying_color = a_position;
}
`;
const fsTriangle = `#version 300 es
precision mediump float;
in vec3 varying_color;
out vec4 outColor;
void main(){
outColor = vec4(1.0, 0.0, 0.0, 0.7);
}
`;
const up = [0, 1, 0];
let modelDegree = 0;
let cameraYposition = 2.0;
const positionTriangle = [0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0];
(function() {
const canvas = document.querySelector("#main-canvas");
let gl = canvas.getContext("webgl2");
if (!gl) {
console.log("webgl2 not found");
return;
}
var ext = gl.getExtension("OES_element_index_uint");
let programTriangle = webglUtils.createProgramFromSources(gl, [
vsTriangle,
fsTriangle,
]);
let vao = gl.createVertexArray();
gl.bindVertexArray(vao);
let position = gl.getAttribLocation(programTriangle, "a_position");
let modelMatrixLocation = gl.getUniformLocation(programTriangle, "u_vpMatrix");
let posTriangleBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, posTriangleBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(positionTriangle),
gl.STATIC_DRAW
);
let cameraDegree = 0;
function degToRadian(deg) {
return (Math.PI / 180) * deg;
}
function initialCameraSetup(cameraPosition, up) {
let cameraMatrix = m4.lookAt(cameraPosition, [1, 0, 0], up);
return cameraMatrix;
}
function drawScene() {
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0.5, 0.5, 0.5, 0.5);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.CULL_FACE);
gl.cullFace(gl.BACK);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.BLEND);
let cameraRadian = degToRadian(cameraDegree);
let cameraMatrix = m4.yRotation(cameraRadian);
cameraMatrix = m4.translate(cameraMatrix, 0.0, 0.0, 1.5);
cameraPosition = [cameraMatrix[12], cameraMatrix[13], cameraMatrix[14]];
cameraMatrix = initialCameraSetup(cameraPosition, up);
viewMatrix = m4.inverse(cameraMatrix);
let aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
let fieldofView = degToRadian(90);
let projectionMatrix = m4.perspective(fieldofView, aspect, 0.01, 1000);
let vProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);
gl.bindBuffer(gl.ARRAY_BUFFER, posTriangleBuffer);
gl.enableVertexAttribArray(position);
gl.vertexAttribPointer(
position,
3,
gl.FLOAT,
false,
0,
0
);
gl.useProgram(programTriangle);
gl.uniformMatrix4fv(
modelMatrixLocation,
false,
vProjectionMatrix
);
gl.drawArrays(gl.TRIANGLES, 0, 3);
window.requestAnimationFrame(drawScene);
}
requestAnimationFrame(drawScene);
})();
#main-canvas {
width: 720px;
height: 360px;
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>test !!!</title>
<link rel="stylesheet" href="./styles/main.css" />
</head>
<body>
<div class="canvas-container">
<canvas id="main-canvas"></canvas>
</div>
<script src="https://webglfundamentals.org/webgl/resources/m4.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script src="https://greggman.github.io/webgl-lint/webgl-lint.js"></script>
</body>
</html>

webgl trying to draw a triangle

I have been trying to draw a triangle but it is not showing up on the canvas
here is my draw function code:
function draw() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight)gl.clear(gl.COLOR_BUFFER_BIT)
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,
buffer.itemSize, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute)
  
//Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, buffer.numberOfItems)
}
here is the whole work:
const vertexShaderText = [
'attribute vec3 vertexPos;',
'',
'void main() {',
' gl_Position = vec4(vertexPos, 1.0);',
'}'
].join('\n')
const fragmentShaderText = [
'precision mediump float;',
'',
'void main() {',
' gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);',
'}'
].join('\n')
let gl, shaderProgram, buffer
function startup() {
const canvas = document.getElementById('myCanvas')
gl = canvas.getContext('webgl')
initShader()
initBuffer()
gl.clearColor(0.0, 0.0, 0.0, 1.0)
draw()
}
function initShader() {
// VERTEX SHADER
let vertexShader = gl.createShader(gl.VERTEX_SHADER)
gl.shaderSource(vertexShader, vertexShaderText)
gl.compileShader(vertexShader)
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
alert('vertex', gl.getShaderInfoLog(vertexShader))
return
}
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(fragmentShader, fragmentShaderText)
gl.compileShader(fragmentShader)
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
alert('fragment', gl.getShaderInfoLog(fragmentShader))
return
}
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.vertextPositionAttribute = gl.getAttribLocation(shaderProgram, 'vertexPos')
//gl.enableVertexAttribArray(shaderProgram.vertextPositionAttribute)
}
function initBuffer() {
buffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
const triangleVertices = [
0.0, 0, 5, 0.0, -0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW)
buffer.itemSize = 3
buffer.numberOfItems = 3
console.log(shaderProgram)
}
function draw() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight) 
gl.clear(gl.COLOR_BUFFER_BIT)
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,
buffer.itemSize, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute)  
//Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, buffer.numberOfItems)
}
startup()
<canvas id="myCanvas" width="500" height="500"></canvas>
There are some issues:
The properties gl.viewportWidth and gl.viewportHeight are never set:
gl = canvas.getContext('webgl')
gl.viewportWidth = canvas.clientWidth;
gl.viewportHeight = canvas.clientHeight;
In the array of vertex coordinates is a , instead of a .
const triangleVertices = [
0.0, 0,5, 0.0, // <---- this line
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
And there is a typo , you wrote vertextPositionAttribute instead of vertexPositionAttribute, when you get the attribute index:
shaderProgram.vertextPositionAttribute = // <--- typo
gl.getAttribLocation(shaderProgram, 'vertexPos')
But in general your code works:
const vertexShaderText = [
'attribute vec3 vertexPos;',
'',
'void main() {',
' gl_Position = vec4(vertexPos, 1.0);',
'}'
].join('\n')
const fragmentShaderText = [
'precision mediump float;',
'',
'void main() {',
' gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);',
'}'
].join('\n')
let gl, shaderProgram, buffer
function startup() {
const canvas = document.getElementById('myCanvas')
gl = canvas.getContext('webgl')
gl.viewportWidth = canvas.clientWidth;
gl.viewportHeight = canvas.clientHeight;
initShader()
initBuffer()
gl.clearColor(0.0, 0.0, 0.0, 1.0)
draw()
}
function initShader() {
// VERTEX SHADER
let vertexShader = gl.createShader(gl.VERTEX_SHADER)
gl.shaderSource(vertexShader, vertexShaderText)
gl.compileShader(vertexShader)
if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
alert('vertex', gl.getShaderInfoLog(vertexShader))
return
}
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(fragmentShader, fragmentShaderText)
gl.compileShader(fragmentShader)
if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
alert('fragment', gl.getShaderInfoLog(fragmentShader))
return
}
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, 'vertexPos')
//gl.enableVertexAttribArray(shaderProgram.vertextPositionAttribute)
}
function initBuffer() {
buffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
const triangleVertices = [
0.0, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW)
buffer.itemSize = 3
buffer.numberOfItems = 3
console.log(shaderProgram)
}
function draw() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,
buffer.itemSize, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
//Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, buffer.numberOfItems)
requestAnimationFrame(draw);
}
startup()
<canvas id="myCanvas" width="500" height="500"></canvas>
Some issues
There is no such thing as gl.viewportWidth and gl.viewportHeight
Use gl.canvas.width and gl.canvas.height.
There's a site out there that teaches using gl.viewportWidth and gl.viewportHeight. It is arguably an anti-pattern. Those variables are not part of WebGL. They are user variables being added by the example onto the WebGL context. There is absolutely zero reason to do that as they will always have to be manually updated and the actual width and height are always available.
Typo in triangleVertices
The second comma below should be a period
bad
const triangleVertices = [
0.0, 0, 5, 0.0, -0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
good
const triangleVertices = [
0.0, 0.5, 0.0, -0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
With that it runs but here's another typo
vertextPositionAttribute should be vertexPositionAttribute
shaderProgram.vertextPositionAttribute = gl.getAttribLocation(shaderProgram, 'vertexPos')
//gl.enableVertexAttribArray(shaderProgram.vertextPositionAttribute)
That said here's a bunch of suggestions.
Use multiline template literals for shaders
Instead of
const vertexShaderText = [
'attribute vec3 vertexPos;',
'',
'void main() {',
' gl_Position = vec4(vertexPos, 1.0);',
'}'
].join('\n')
do this
const vertexShaderText = `
attribute vec3 vertexPos;
void main() {
gl_Position = vec4(vertexPos, 1.0);
}
`;
So much easier! Use backticks instead of quotes for multi-line strings
Make initShader return a shader rather than assign a global
It's not common to have a single shader in WebGL so it's much more useful to have a function that creates shaders
Don't call gl.useProgram in initShader
Again it's not common to have a single shader. Calling gl.useProgram generally belongs in draw
Don't add attributes to browser objects, especially WebGL objects
bad
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, 'vertexPos');
good (one of many ways)
const shaderProgramInfo = {}
shaderProgramInfo.program = initShader(...)
shaderProgramInfo.vertexPositionAttribute =
gl.getAttribLocation(shaderProgramInfo.program, 'vertexPos');
This is because if initShader fails (for example the context is lost) your gl.createProgram will be null and trying to assign a property to null will cause your page to fail. The same issue with buffer
bad
const buffer = gl.createBuffer();
...
buffer.itemSize = 3
buffer.numberOfItems = 3
good (one of many ways)
const bufferInfo = {
buffer: gl.createBuffer(),
}
...
bufferInfo.itemSize = 3
bufferInfo.numberOfItems = 3
Call gl.bindBuffer before calling gl.vertexAttribPointer
Your code works because there is only one buffer. If there are 2 buffers it would likely stop working because gl.vertexAttribPointer references the currently bound buffer
Consider Reading better tutorials.
I'd recommend https://webglfundamentals.org
const vertexShaderText = `
attribute vec3 vertexPos;
void main() {
gl_Position = vec4(vertexPos, 1.0);
}
`;
const fragmentShaderText = `
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
`;
let gl, shaderProgramInfo, bufferInfo
function startup() {
const canvas = document.getElementById('myCanvas')
gl = canvas.getContext('webgl')
shaderProgramInfo = {
program: initShader(gl, vertexShaderText, fragmentShaderText),
};
shaderProgramInfo.vertexPositionAttribute = gl.getAttribLocation(shaderProgramInfo.program, 'vertexPos');
bufferInfo = initBuffer()
gl.clearColor(0.0, 0.0, 0.0, 1.0)
draw()
}
function initShader(gl, vertexShaderText, fragmentShaderText) {
// VERTEX SHADER
let vertexShader = gl.createShader(gl.VERTEX_SHADER)
gl.shaderSource(vertexShader, vertexShaderText)
gl.compileShader(vertexShader)
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
alert('vertex', gl.getShaderInfoLog(vertexShader))
return
}
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(fragmentShader, fragmentShaderText)
gl.compileShader(fragmentShader)
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
alert('fragment', gl.getShaderInfoLog(fragmentShader))
return
}
const 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')
}
return shaderProgram;
}
function initBuffer() {
buffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
const triangleVertices = [
0.0, 0.5, 0.0, -0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW)
return {
buffer,
itemSize: 3,
numberOfItems: 3,
};
}
function draw() {
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); 
gl.clear(gl.COLOR_BUFFER_BIT)
gl.useProgram(shaderProgramInfo.program)
gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.buffer);
gl.vertexAttribPointer(shaderProgramInfo.vertexPositionAttribute,
bufferInfo.itemSize, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaderProgramInfo.vertexPositionAttribute)  
//Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, bufferInfo.numberOfItems)
}
startup()
<canvas id="myCanvas" width="500" height="500"></canvas>

WebGL using gl-matrix library mat4.translate not running

I have this segment of code:
function setupWebGL() {
gl.clearColor(0.1, 0.5, 0.1, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0,0,400,300);
mat4.perspective(45, 400 / 300, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [0, 0, -2.0]);
}
And everything in the code runs except the very last line
mat4.translate(mvMatrix, [0, 0, -2.0]);
I know this because I put alert functions after every line until they failed to run (I need a better way of debugging in chrome, any suggestions?)
I'm using the gl-Matrix library found here https://github.com/toji/gl-matrix/blob/master/dist/gl-matrix-min.js
Any ideas on why that line is stopping the code execution?
Here is the full code:
<!doctype html>
<html>
<head>
<title>WebGL - Chapter One - Lol</title>
<style>
body{ background-color: grey; }
canvas{ background-color: white; }
</style>
<script src = "gl-matrix-min.js"></script>
<script src = "raf_polyfill.js"></script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec3 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying highp vec4 vColor;
void main(void){
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = vec4(aVertexColor, 1.0);
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
varying highp vec4 vColor;
void main(void){
gl_FragColor = vColor;
}
</script>
<script>
var gl = null,
canvas = null,
glProgram = null,
fragmentShader = null,
vertexShader = null;
var vertexPositionAttribute = null,
trianglesVerticeBuffer = null,
vertexColorAttribute = null,
trianglesColorBuffer = null;
var angle = 0.0;
var mvMatrix = mat4.create(),
pMatrix = mat4.create();
function initWebGL(){
var canvas = document.getElementById("my-canvas");
try{
gl = canvas.getContext("experimental-webgl");
}catch(e){}
if(gl){
initShaders();
setupBuffers();
getMatrixUniforms();
animLoop();
}else{
alert("Error: Your browser does not appear to support WebGL.");
}
}
function animLoop(){
setupWebGL();
setupDynamicBuffers();
setMatrixUniforms();
drawScene();
requestAnimationFrame(animLoop,canvas);
}
function setupWebGL() {
//sets the clear color to red lol
gl.clearColor(0.1, 0.5, 0.1, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0,0,400,300);
mat4.perspective(45, 400 / 300, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [0, 0, -2.0]);
}
function initShaders(){
var fs_source = document.getElementById("shader-fs").innerHTML;
var vs_source = document.getElementById("shader-vs").innerHTML;
//compile shaders
vertexShader = makeShader(vs_source, gl.VERTEX_SHADER);
fragmentShader = makeShader(fs_source, gl.FRAGMENT_SHADER);
//create program
glProgram = gl.createProgram();
//attach and link shaders to the program
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.");
}
//use program
gl.useProgram(glProgram);
}
function makeShader(src, type) {
//compile the vertex shader
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 getMatrixUniforms(){
glProgram.pMatrixUniform = gl.getUniformLocation(glProgram, "uPMatrix");
glProgram.mvMatrixUniform = gl.getUniformLocation(glProgram, "uMVMatrix");
}
function setMatrixUniforms(){
gl.unifromMatrix4fv(glProgram.pMatrixUniform, false, pMatrix);
gl.unifromMatrix4fv(glProgram.mvMatrixUniform, false, mvMatrix);
}
function setupBuffers() {
var triangleVerticeColors = [
1.0, 0.0, 0.0,
1.0, 1.0, 1.0,
1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
1.0, 1.0, 1.0,
0.0, 0.0, 1.0
];
trianglesColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVerticeColors), gl.STATIC_DRAW);
}
function setupDynamicBuffers(){
var xTran = Math.sin(angle)/2.0;
var triangleVertices = [
-0.5 + xTran, 0.5, -0.5,
0.0 + xTran, 0.0, -0.5,
-0.5 + xTran, -0.5, -0.5,
0.5 + xTran, 0.5, -0.5,
0.0 + xTran, 0.0, -0.5,
0.5 + xTran, -0.5, -0.5
];
angle += 0.05;
trianglesVerticeBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.DYNAMIC_DRAW);
}
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);
vertexColorAttribute = gl.getAttribLocation(glProgram, "aVertexColor");
gl.enableVertexAttribArray(vertexColorAttribute);
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
gl.vertexAttribPointer(vertexColorAttribute, 3, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
</script>
</head>
<body onload="initWebGL()">
<canvas id="my-canvas" width="400" height="300">
Your browser does not support the HTML5 canvas element.
</canvas>
</body>
</html>
Use the new API:
Old API
mat4.translate(mvMatrix, [0, 0, -2.0]);
New API
var translation = vec3.create();
vec3.set (translation, 0, 0, -2.0);
mat4.translate (mvMatrix, mvMatrix, translation);
You have a typo:
unifromMatrix4fv should be uniformMatrix4fv in function setMatrixUniforms.
I'm not sure if this fixes your problem or not, or why you thought your problem was with mat4.translate. You can always open the JavaScript console (F12 if you're running Chrome in Windows) and it'll tell you what the error is.

Categories