I'm trying to generate a random color everytime the code executes and passing it to the fragment shader(to draw a triangle).
Reading other posts, I've decided that the most effective solutions seems to be:
set a uniform variable in the fragment shader
link it to a javascript variable
write to the fragment shader with uniform4f providing the data
Trying to structure this, my snippet doesn't display the triangle but only the background. If I take
away all the lines that deal with the color, the triangle appears again.
var can = document.getElementById('cont');
var gl = can.getContext('experimental-webgl');
gl.clearColor(0.0, 0.1, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
red = Math.random();
green = Math.random();
blue = Math.random();
alpha = Math.random();
var vertices = [-1,-1,1,-1,0,0.5];
var colorData = [red,green,blue,alpha];
//Create color buffer
var cbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,cbo);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(colorData),gl.STATIC_DRAW);
//Create vertex buffer
var vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vbo);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(vertices),gl.STATIC_DRAW);
//Shaders
var vshaderCode = 'attribute vec2 pos;' + 'void main() {gl_Position = vec4 (pos,0.,1.);}';
var fshaderCode = 'precision mediump float;' + 'uniform vec4 uColor' + 'void main() {gl_FragColor = uColor;}';
function getShader(shaderSource,type) {
var shad = gl.createShader(type);
gl.shaderSource(shad,shaderSource);
gl.compileShader(shad);
return shad;
}
var vertexShader = getShader (vshaderCode,gl.VERTEX_SHADER);
var fragmentShader = getShader (fshaderCode,gl.FRAGMENT_SHADER);
//Create the program to link shaders
var prog = gl.createProgram();
gl.attachShader(prog,vertexShader);
gl.attachShader(prog,fragmentShader);
gl.linkProgram(prog);
var _position = gl.getAttribLocation(prog, "pos");
var u_ColorLocation = gl.getUniformLocation(prog, "uColor");
//Draw
gl.enableVertexAttribArray(_position);
gl.useProgram(prog);
gl.vertexAttribPointer(_position, 2, gl.FLOAT, false, 0,0);
gl.uniform4f(u_ColorLocation, colorData);
gl.drawArrays(gl.TRIANGLES, 0, 3);
The console says that gl.uniform4f(u_ColorLocation, colorData); wants five arguments. That point is not clear to me.
Even if I change that line to something like gl.uniform4f(u_colorLocation, 0, 0, 1, 1); the program doesn't link.
How do I pass then my values from javascript to the fragment on the gpu so that my triangle has only one color, driven by javascript variables?
You were missing a ; on your fshaderCode shader so it wasn't compiling.
Reading the COMPILE_STATUS of the shader can help you work out if your have any syntax problems.
if (!gl.getShaderParameter(shad, gl.COMPILE_STATUS)) {
console.log("COMPILE_STATUS", gl.getShaderInfoLog(shad));
}
Updated code to show random colour triangle
var can = document.getElementById('cont');
var gl = can.getContext('experimental-webgl');
gl.clearColor(0.0, 0.1, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
red = Math.random();
green = Math.random();
blue = Math.random();
alpha = Math.random();
var vertices = [-1,-1,1,-1,0,0.5];
var colorData = [red,green,blue,alpha];
//Create color buffer
var cbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,cbo);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(colorData),gl.STATIC_DRAW);
//Create vertex buffer
var vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vbo);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(vertices),gl.STATIC_DRAW);
//Shaders
var vshaderCode = 'attribute vec2 pos;' + 'void main()' + '{gl_Position = vec4 (pos,0.,1.);' + '}';
var fshaderCode = 'precision mediump float;' + 'uniform vec4 uColor;' + 'void main() {gl_FragColor = uColor;}';
function getShader(shaderSource,type) {
var shad = gl.createShader(type);
gl.shaderSource(shad,shaderSource);
gl.compileShader(shad);
if (!gl.getShaderParameter(shad, gl.COMPILE_STATUS)) {
console.log("COMPILE_STATUS", gl.getShaderInfoLog(shad));
}
return shad;
}
var vertexShader = getShader (vshaderCode,gl.VERTEX_SHADER);
var fragmentShader = getShader (fshaderCode,gl.FRAGMENT_SHADER);
//Create the program to link shaders
var prog = gl.createProgram();
gl.attachShader(prog,vertexShader);
gl.attachShader(prog,fragmentShader);
gl.linkProgram(prog);
var _position = gl.getAttribLocation(prog, "pos");
var u_ColorLocation = gl.getUniformLocation(prog, "uColor");
//Draw
var r = Math.random(), g= Math.random(), b = Math.random();
gl.enableVertexAttribArray(_position);
gl.useProgram(prog);
gl.vertexAttribPointer(_position, 2, gl.FLOAT, false, 0,0);
gl.uniform4f(u_ColorLocation, r, g, b, 1.0);
gl.drawArrays(gl.TRIANGLES, 0, 3);
<canvas id="cont"></canvas>
In your fragmentshader you're missing a colon behind your uniform declaration:
var fshaderCode = 'precision mediump float;' + 'uniform vec4 uColor;' + 'void main() {gl_FragColor = uColor;}';
As mentioned in the answer below checking the compile status is helpful here, as writing shaders in its own files is.
As to setting uniforms there are uniformXX(ie. uniform4f) and uniformXXv(ie. uniform4fv) variants. the v stands for vector and needs to be used when you provide a vector of data like your color.
So you want to change this to uniform4fv too.
var can = document.getElementById('cont');
var gl = can.getContext('experimental-webgl');
gl.clearColor(0.0, 0.1, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
red = Math.random();
green = Math.random();
blue = Math.random();
alpha = Math.random();
var vertices = [-1,-1,1,-1,0,0.5];
var colorData = [red,green,blue,alpha];
//Create color buffer
var cbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,cbo);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(colorData),gl.STATIC_DRAW);
//Create vertex buffer
var vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vbo);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(vertices),gl.STATIC_DRAW);
//Shaders
var vshaderCode = 'attribute vec2 pos;' + 'void main() {gl_Position = vec4 (pos,0.,1.);}';
var fshaderCode = 'precision mediump float;' + 'uniform vec4 uColor;' + 'void main() {gl_FragColor = uColor;}';
function getShader(shaderSource,type) {
var shad = gl.createShader(type);
gl.shaderSource(shad,shaderSource);
gl.compileShader(shad);
return shad;
}
var vertexShader = getShader (vshaderCode,gl.VERTEX_SHADER);
var fragmentShader = getShader (fshaderCode,gl.FRAGMENT_SHADER);
//Create the program to link shaders
var prog = gl.createProgram();
gl.attachShader(prog,vertexShader);
gl.attachShader(prog,fragmentShader);
gl.linkProgram(prog);
var _position = gl.getAttribLocation(prog, "pos");
var u_ColorLocation = gl.getUniformLocation(prog, "uColor");
//Draw
gl.enableVertexAttribArray(_position);
gl.useProgram(prog);
gl.vertexAttribPointer(_position, 2, gl.FLOAT, false, 0,0);
gl.uniform4fv(u_ColorLocation, colorData);
gl.drawArrays(gl.TRIANGLES, 0, 3);
<canvas id="cont"></canvas>
Related
The goal is a textured open cylinder. I believe the issue is with the setCamera() function. I havent made any changes from when I used the function as it is previously. Running on an http-server localhost in firefox(javascript is enabled). I would really appreciate a solution on how to make this work as well as any tips.
"glmatrix" is a Javascript Matrix and Vector library.
Here is the code:
var mat4 = glMatrix.mat4;
var segments = 64;
var cylVertices=[]; //sidevertices
var positionAttribLocation = null;
var gl = null;
var program = null;
var cylVertexBufferObject = null;
var matWorldUniformLocation =null;
var matViewUniformLocation =null;
var matProjectionUniformLocation =null;
var worldMatrix = null;
var viewMatrix = null;
var projectionMatrix = null;
var canvas = null;
var vertexShaderText =
[
'precision mediump float;',
'',
'attribute vec3 vertPosition;',
'attribute vec2 vertTexCoord;',
'varying vec2 fragTexCoord;',
'uniform mat4 mWorld;',
'uniform mat4 mView;',
'uniform mat4 mProjection;',
'',
'void main()',
'{',
' fragTexCoord = vertTexCoord;',
' gl_Position = mProjection * mView * mWorld * vec4(vertPosition, 1.0);',
'}'
].join('\n');
var fragmentTexShaderText =
[
'precision mediump float;',
'',
'varying vec2 fragTexCoord;',
'uniform sampler2D sampler;',
'void main()',
'{',
' gl_FragColor = texture2D(sampler,fragTexCoord);',
'}'
].join('\n');
var initDemo = function () {
console.log('This is working');
canvas = document.getElementById('game-surface');
gl = canvas.getContext('webgl');
if (!gl) {
console.log('WebGL not supported, falling back on experimental-webgl');
gl = canvas.getContext('experimental-webgl');
}
if (!gl) {
alert('Your browser does not support WebGL');
}
clear();
gl.enable(gl.DEPTH_TEST);//enable drawing over if closer to the virtual camera
//
//Create Shaders
//
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertexShader,vertexShaderText);
gl.shaderSource(fragmentShader,fragmentTexShaderText);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader,gl.COMPILE_STATUS)){
console.error('ERROR compiling vertex shader!', gl.getShaderInfoLog(vertexShader));
return;
}
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader,gl.COMPILE_STATUS)){
console.error('ERROR compiling fragment shader!', gl.getShaderInfoLog(fragmentShader));
return;
}
program = gl.createProgram();
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader)
gl.linkProgram(program);
if (!gl.getProgramParameter(program,gl.LINK_STATUS)){
console.error('ERROR linking program!', gl.getProgramInfoLog(program));
return;
}
a=0, b=0, y=0, u=0, v=0, s=0, t=0; //The origin
r=1.0,g=0.4,b=0.6;
theta = (Math.PI/180) * (360);
//theta = (Math.PI/180) * (360/(segments)); //Degrees = radians * (180 / )
for (i =0;i<=(segments);i++){
x = i*Math.cos(theta);
z = i*Math.sin(theta);
s=(theta+180)/360;
cylVertices.push(x, y, z, s,0); //Sidevertices along the bottom
cylVertices.push(x, y+2, z, s,2); //Sidevertices along the top
}
cylArray = new Float32Array(cylVertices); //sidearray
//
//------MAIN RENDER LOOP-------
//
var angle = 0;
var loop = function (){
setCamera();
angle = performance.now() / 1000 / 6 * 2 * Math.PI;
mat4.rotate(xRotationMatrix,identityMatrix, angle, [0,1,0]);//x rotation
gl.uniformMatrix4fv(matWorldUniformLocation, gl.FALSE, xRotationMatrix);
clear();
theVertexBufferObject = gl.createBuffer();
drawCylSide();
requestAnimationFrame(loop);
};
requestAnimationFrame(loop);
};
//
// --------------------functions--------------------
//
function drawCylSide(){
gl.bindBuffer(gl.ARRAY_BUFFER,theVertexBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cylArray),gl.STATIC_DRAW);
setPointer(5);
var texCoordAttribLocation = gl.getAttribLocation(program,'vertTexCoord');
gl.vertexAttribPointer(
texCoordAttribLocation, //Attribute location
2, //Number of vertix elements
gl.FLOAT, //Type of elements
gl.FALSE, //Normalised
5 * Float32Array.BYTES_PER_ELEMENT, //Size of individual vertex
3 * Float32Array.BYTES_PER_ELEMENT, //Offset
);
gl.enableVertexAttribArray(positionAttribLocation);
gl.enableVertexAttribArray(texCoordAttribLocation);
var boxTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, boxTexture);
gl.texParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);
gl.texParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);
gl.texParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,gl.LINEAR);
gl.texParameter(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,gl.LINEAR);
gl.texImage2D(
gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,
gl.UNSIGNED_BYTE,
document.getElementById('wall-img')
);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.useProgram(program);
gl.bindTexture(gl.TEXTURE_2D, boxTexture);
gl.activeTexture(gl.TEXTURE0);
gl.drawArrays(gl.TRIANGLE_STRIP,0, segments);
};
function setPointer(n){
positionAttribLocation = gl.getAttribLocation(program,'vertPosition');
gl.vertexAttribPointer(
positionAttribLocation, //Attribute location
3, //Number of vertix elements
gl.FLOAT, //Type of elements
gl.FALSE, //Normalised
n * Float32Array.BYTES_PER_ELEMENT, //Size of individual vertex
0 //Offset
);
};
function clear(){
gl.clearColor(0.75, 0.85, 0.8, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
};
function setCamera(){
mat4.identity(worldMatrix);
mat4.lookAt(viewMatrix,[0,1,-8],[0,0,0],[0,10,0]);
mat4.perspective(projectionMatrix,glMatrix.glMatrix.toRadian(45),canvas.width/canvas.height,0.1,1000.0);
gl.uniformMatrix4fv(matWorldUniformLocation,gl.FALSE,worldMatrix);
gl.uniformMatrix4fv(matViewUniformLocation,gl.FALSE,viewMatrix);
gl.uniformMatrix4fv(matProjectionUniformLocation,gl.FALSE,projectionMatrix);
};
You need to initialize vectors and matrices using the respective create function of glMatrix.
var worldMatrix = mat4.create();
var viewMatrix = mat4.create();
var projectionMatrix = mat4.create();
Try to use createVertices() to move the coords attribute: Plunkr live code:
Question: how can I move my gl_Position with an attribute?
It works when I manually set the vec4 value:
let gl;
let shaderProgram;
initGl();
createShaders();
draw();
function initGl() {
const canvas = document.getElementById('canvas');
gl = canvas.getContext('webgl');
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1, 0, 1, 1);
}
function createShaders() {
// Think of this as a point in 3d space.
const vs = `
void main(void) {
gl_Position = vec4(0.5, 0, 0, 1.0);
gl_PointSize = 10.0;
}
`; // !!!!!!!!!! this will offset the pixel by
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vs);
gl.compileShader(vertexShader);
// Think of this as a fragment.
const fs = `
void main(void) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
`;
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs);
gl.compileShader(fragmentShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function draw() {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 1);
}
But when I add an attribute
function createVertices() {
const coords = gl.getAttribLocation(shaderProgram, "coords");
gl.vertexAttrib3f(coords, 0.5, 0, 0); // will not work
const pointSize = gl.getAttribLocation(shaderProgram, "pointSize");
gl.vertexAttrib1f(pointSize, 100); // works
}
const vs = `
attribute vec4 coords;
attribute float pointSize;
void main(void) {
gl_Position = coords;
gl_PointSize = pointSize;
}
`;
Please review Plunkr live code to see complete working code.
You have to disableVertexAttribArray. enableVertexAttribArray enable or a generic vertex attribute array and disableVertexAttribArray disables a generic vertex attribute array.
You have no vertex attrute array, but you have a constant attribute.
const coords = gl.getAttribLocation(shaderProgram, "coords");
const pointSize = gl.getAttribLocation(shaderProgram, "pointSize");
gl.disableVertexAttribArray(coords);
gl.disableVertexAttribArray(pointSize);
gl.vertexAttrib3f(coords, 0.5, 0, 0);
gl.vertexAttrib1f(pointSize, 100);
See also:
Khronos WebGL specification - Enabled Vertex Attributes and Range Checking
WebGL - which API to use?
Is it important to call glDisableVertexAttribArray()?
When should I enable/disable vertex position attributes in WebGL/OpenGL?
Example:
var gl,
shaderProgram;
initGL();
createShaders();
createVertices();
draw();
function initGL() {
var canvas = document.getElementById("canvas");
console.log(canvas);
gl = canvas.getContext("experimental-webgl");
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1, 1, 1, 1);
}
function createShaders() {
var vs = "";
vs += "attribute vec4 coords;";
vs += "attribute float pointSize;";
vs += "void main(void) {";
vs += " gl_Position = coords;";
vs += " gl_PointSize = pointSize;";
vs += "}";
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vs);
gl.compileShader(vertexShader);
var fs = "";
fs += "precision mediump float;";
fs += "uniform vec4 color;";
fs += "void main(void) {";
fs += " gl_FragColor = color;";
fs += "}";
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fs);
gl.compileShader(fragmentShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function createVertices() {
var coords = gl.getAttribLocation(shaderProgram, "coords");
var pointSize = gl.getAttribLocation(shaderProgram, "pointSize");
gl.disableVertexAttribArray(coords);
gl.disableVertexAttribArray(pointSize);
gl.vertexAttrib3f(coords, 0.0, 0.0, 0.0);
gl.vertexAttrib1f(pointSize, 100);
var color = gl.getUniformLocation(shaderProgram, "color");
gl.uniform4f(color, 1, 0, 1, 1);
}
function draw() {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 1);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<canvas id="canvas" width="200" height="200"></canvas>
<script src="lib/script.js"></script>
</body>
</html>
Very new to WebGL and attempting to port some 2D image processing shaders in order to get a handle on things. I initially was misled by the MDN tutorials into thinking WebGL was like OpenGL desktop, but then found these tutorials, which I found much more true to form as well as my purposes. However, I'm still having some trouble in formatting a render loop so I can pass a continually updating texture for processing. In cases where it does render, I just get a muddy mess and in cases where the vertex shader isn't a simple pass through I get nothing. I understand GLSL and the basics of how buffers work, but clearly am doing something very wrong here... Any help would be greatly appreciated. Thanks!
class GL {
constructor(canvas){
this.gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if (!this.gl) {
alert("Unable to initialize WebGL. Your browser may not support it.");
this.gl = null;
}
//init shaders
var fragmentShader = getShader(this.gl, "fshader");
var vertexShader = getShader(this.gl, "vshader");
var shaderProgram = this.gl.createProgram();
this.gl.attachShader(shaderProgram, vertexShader);
this.gl.attachShader(shaderProgram, fragmentShader);
this.gl.linkProgram(shaderProgram);
this.gl.useProgram(shaderProgram);
this.positionLocation = this.gl.getAttribLocation(shaderProgram, "position");
this.texCoordLocation = this.gl.getAttribLocation(shaderProgram, "texcoord");
var resolutionLocation = this.gl.getUniformLocation(shaderProgram, "resolution");
this.width = this.gl.getUniformLocation(shaderProgram, "width");
//set resolution
this.gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
function getShader(gl, id) {
var shaderScript, theSource, currentChild, shader;
shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
theSource = "";
currentChild = shaderScript.firstChild;
while(currentChild) {
if (currentChild.nodeType == currentChild.TEXT_NODE) {
theSource += currentChild.textContent;
}
currentChild = currentChild.nextSibling;
}
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 {
// Unknown shader type
return null;
}
gl.shaderSource(shader, theSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));
return null;
}
return shader;
};
};
render(bufferCanvas, x, y) {
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
//texture coordinates
var texCoordBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
this.gl.enableVertexAttribArray(this.texCoordLocation);
this.gl.vertexAttribPointer(this.texCoordLocation, 2, this.gl.FLOAT, false, 8, 0);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
new Float32Array([
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0]),
this.gl.STATIC_DRAW);
//create texture
var texture = this.gl.createTexture();
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
//normalize image to powers of two
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
//load texture from 2d canvas
this.gl.texImage2D(this.gl.TEXTURE_2D,
0,
this.gl.RGBA,
this.gl.RGBA,
this.gl.UNSIGNED_BYTE,
bufferCanvas);
//load buffer
var buffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
this.gl.enableVertexAttribArray(this.positionLocation);
this.gl.vertexAttribPointer(this.positionLocation, 2, this.gl.FLOAT, false, 12, 0);
//draw size and position
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([
x, y,
x + bufferCanvas.width, y,
x, y + bufferCanvas.height,
x, y + bufferCanvas.height,
x+ bufferCanvas.width, y,
x+ bufferCanvas.width, y + bufferCanvas.height]), this.gl.STATIC_DRAW);
//blur width
this.gl.enableVertexAttribArray(this.width);
this.gl.vertexAttribPointer(this.width, 1, this.gl.FLOAT, false, 12, 8);
//draw
this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
};
};
var canvas2d = document.getElementById('buffer-canvas');
var context2d = canvas2d.getContext("2d");
var canvasGL = new GL(document.getElementById('main-canvas'));
canvasGL.width = 5.0;
for(var i=0; i<10; i++) {
var r = Math.floor(Math.random() * 255);
var g = Math.floor(Math.random() * 255);
var b = Math.floor(Math.random() * 255);
var a = Math.floor(Math.random() * 255);
context2d.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a + ")";
var x = Math.random() * canvas2d.width;
var y = Math.random() * canvas2d.height;
var width = canvas2d.width - (Math.random() * canvas2d.width);
var height = canvas2d.height - (Math.random() * canvas2d.height);
context2d.fillRect(x, y, width , height);
canvasGL.render(canvas2d, canvas2d.getBoundingClientRect("left"), canvas2d.getBoundingClientRect("top"));
}
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sylvester/0.1.3/sylvester.min.js"></script>
<script src="https://github.com/mdn/webgl-examples/blob/gh-pages/tutorial/glUtils.js"></script>
<script id="vshader" type="x-shader/x-vertex">
precision mediump float;
attribute vec2 position;
attribute vec2 texcoord;
uniform vec2 resolution;
uniform float width;
varying vec2 texcoord11;
varying vec2 texcoord00;
varying vec2 texcoord02;
varying vec2 texcoord20;
varying vec2 texcoord22;
void main()
{
gl_Position = vec4(((position / resolution) * 2.0 - 1.0) * vec2(1, -1), 0, 1);
// get texcoords
texcoord11 = texcoord;
texcoord00 = texcoord + vec2(-width, -width);
texcoord02 = texcoord + vec2( width, -width);
texcoord20 = texcoord + vec2( width, width);
texcoord22 = texcoord + vec2(-width, width);
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D image;
varying vec2 texcoord11;
varying vec2 texcoord00;
varying vec2 texcoord02;
varying vec2 texcoord20;
varying vec2 texcoord22;
void main()
{
vec4 blur;
blur = texture2D(image, texcoord11);
blur += texture2D(image, texcoord00);
blur += texture2D(image, texcoord02);
blur += texture2D(image, texcoord20);
blur += texture2D(image, texcoord22);
gl_FragColor = 0.2 * blur;
}
</script>
</head>
<body>
<canvas id="main-canvas" width="400" height="300" style="border:1px solid black;"></canvas>
<canvas id="buffer-canvas" width="400" height="300" style="visibility:hidden;"></canvas>
</body>
There's several issues with the code
neither of the script tags seem to be needed
You assign this.width to a uniform location
this.width = this.gl.getUniformLocation(shaderProgram, "width");
But then later destroy that with
canvasGL.width = 5.0
width is a uniform but you're trying to set it as an attribute
wrong
this.gl.enableVertexAttribArray(this.width);
this.gl.vertexAttribPointer(this.width, 1, this.gl.FLOAT, false, 12, 8);
right
this.gl.uniform1f(this.width, whateverYouWantedWidthToBe);
You've got unneeded strides on all your attributes
wrong
this.gl.vertexAttribPointer(this.texCoordLocation, 2, this.gl.FLOAT, false, 8, 0);
this.gl.vertexAttribPointer(this.positionLocation, 2, this.gl.FLOAT, false, 12, 0);
right
this.gl.vertexAttribPointer(this.texCoordLocation, 2, this.gl.FLOAT, false, 0, 0);
this.gl.vertexAttribPointer(this.positionLocation, 2, this.gl.FLOAT, false, 0, 0);
Well I suppose the texcoord one is not wrong if you want to set strides but the position one is wrong since you're using 2 floats per position not 3. Why not just set them to 0?
You're assigning the texCoordLocation to a var but then using it as a property on this
wrong
var texCoordBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
right?
this.texCoordBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
On top of that the structure of the code is probably not what you intended.
In WebGL you don't generally call gl.createXXX functions in your render function. You'd call gl.createXXX functions those during initialization. See here for a more typical structure.
It's not clear at all what this line is trying to do
canvasGL.render(canvas2d, canvas2d.getBoundingClientRect("left"),
canvas2d.getBoundingClientRect("top"))
What do you think canvas2d.getBoundingClientRect() is going to return that's useful for rendering? Also that's not how getBoundingClientRect works. It returns a rect, it doesn't take any arguments.
Once you have all that fixed it's not clear what you want width to be. I'm assuming you want it to be pixels but in that case it needs to be 1 / canvas2D.width and you need a separate value for height in your shader since you'll need different values to move up and down a certain number of pixels vs left and right.
other suggestions
Pull gl into a local variable. Then you don't have to do this.gl everywhere. Less typing, shorter, and faster
You can get the contents of script tag with just this
var theSource = shaderScript.text;
You're checking for shader compile errors but not link errors.
visibility: hidden; doesn't do what I think you think it does. You probably want display: none;.
Here's one version that does something.
class GL {
constructor(canvas){
var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if (!gl) {
alert("Unable to initialize WebGL. Your browser may not support it.");
return;
}
this.gl = gl;
//init shaders
var fragmentShader = getShader(gl, "fshader");
var vertexShader = getShader(gl, "vshader");
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("An error occurred linking the shaders: " + gl.getProgramInfoLog(shaderProgram));
return;
}
this.shaderProgram = shaderProgram;
this.positionLocation = gl.getAttribLocation(shaderProgram, "position");
this.texCoordLocation = gl.getAttribLocation(shaderProgram, "texcoord");
this.resolutionLocation = gl.getUniformLocation(shaderProgram, "resolution");
this.blurOffsetLocation = gl.getUniformLocation(shaderProgram, "blurOffset");
// init texture coordinates
this.texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0]),
gl.STATIC_DRAW);
// create position buffer
this.positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
//create texture
this.texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, this.texture);
//normalize image to powers of two
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.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
function getShader(gl, id) {
var shaderScript, theSource, currentChild, shader;
shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var theSource = shaderScript.text;
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 {
// Unknown shader type
return null;
}
gl.shaderSource(shader, theSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));
return null;
}
return shader;
};
};
render(bufferCanvas, x, y, blurAmount) {
var gl = this.gl;
gl.clear(this.gl.COLOR_BUFFER_BIT);
gl.useProgram(this.shaderProgram);
// setup buffers and attributes
gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);
gl.enableVertexAttribArray(this.texCoordLocation);
gl.vertexAttribPointer(this.texCoordLocation, 2, gl.FLOAT, false, 0, 0);
//load buffer
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
gl.enableVertexAttribArray(this.positionLocation);
gl.vertexAttribPointer(this.positionLocation, 2, gl.FLOAT, false, 0, 0);
//draw size and position
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x, y,
x + bufferCanvas.width, y,
x, y + bufferCanvas.height,
x, y + bufferCanvas.height,
x+ bufferCanvas.width, y,
x+ bufferCanvas.width, y + bufferCanvas.height]), gl.STATIC_DRAW);
//load texture from 2d canvas
gl.bindTexture(gl.TEXTURE_2D, this.texture);
gl.texImage2D(gl.TEXTURE_2D,
0,
gl.RGBA,
gl.RGBA,
gl.UNSIGNED_BYTE,
bufferCanvas);
//blur width
gl.uniform2f(this.blurOffsetLocation,
blurAmount / bufferCanvas.width,
blurAmount / bufferCanvas.height);
//set resolution
gl.uniform2f(this.resolutionLocation,
gl.canvas.width,
gl.canvas.height);
//draw
gl.drawArrays(gl.TRIANGLES, 0, 6);
};
};
var canvas2d = document.getElementById('buffer-canvas');
var context2d = canvas2d.getContext("2d");
var canvasGL = new GL(document.getElementById('main-canvas'));
function render(time) {
time *= 0.001;
var r = Math.floor(Math.random() * 255);
var g = Math.floor(Math.random() * 255);
var b = Math.floor(Math.random() * 255);
var a = Math.floor(Math.random() * 255);
context2d.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a + ")";
var x = Math.random() * canvas2d.width;
var y = Math.random() * canvas2d.height;
var width = canvas2d.width - (Math.random() * canvas2d.width);
var height = canvas2d.height - (Math.random() * canvas2d.height);
context2d.fillRect(x, y, width , height);
canvasGL.render(canvas2d, 0, 0, Math.sin(time) * 5);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
<script id="vshader" type="x-shader/x-vertex">
precision mediump float;
attribute vec2 position;
attribute vec2 texcoord;
uniform vec2 resolution;
uniform vec2 blurOffset;
varying vec2 texcoord11;
varying vec2 texcoord00;
varying vec2 texcoord02;
varying vec2 texcoord20;
varying vec2 texcoord22;
void main()
{
gl_Position = vec4(((position / resolution) * 2.0 - 1.0) * vec2(1, -1), 0, 1);
// get texcoords
texcoord11 = texcoord;
texcoord00 = texcoord + blurOffset * vec2(-1, -1);
texcoord02 = texcoord + blurOffset * vec2( 1, -1);
texcoord20 = texcoord + blurOffset * vec2( 1, 1);
texcoord22 = texcoord + blurOffset * vec2(-1, 1);
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D image;
varying vec2 texcoord11;
varying vec2 texcoord00;
varying vec2 texcoord02;
varying vec2 texcoord20;
varying vec2 texcoord22;
void main()
{
vec4 blur;
blur = texture2D(image, texcoord11);
blur += texture2D(image, texcoord00);
blur += texture2D(image, texcoord02);
blur += texture2D(image, texcoord20);
blur += texture2D(image, texcoord22);
// do you really want to blend the alpha?
gl_FragColor = 0.2 * blur;
}
</script>
<canvas id="main-canvas" width="400" height="300" style="border:1px solid black;"></canvas>
<canvas id="buffer-canvas" width="400" height="300" style="display: none;"></canvas>
<!doctype html>
<html>
<body>
<canvas id ="ctx" width = "300" height = "300"></canvas>
<script>
//Getting Webgl Context
var ctx = document.getElementById("ctx");
var webgl = ctx.getContext("experimental-webgl");
/*Creating Shader*/
//Vertex Code
var vertexCode =
'attribute vec3 coordinates;'+
'attribute vec3 color;'+
'varying vec3 vColor;'+
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;'+
'}';
//Creating Shader Object
var vertexShader = webgl.createShader(webgl.VERTEX_SHADER);
//Assigning the Source
webgl.shaderSource(vertexShader, vertexCode);
//Compiling the Source
webgl.compileShader(vertexShader);
//Fragment Shader Code
var fragmentCode ='precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
//Creating Shader Object
var fragmentShader = webgl.createShader(webgl.FRAGMENT_SHADER);
//Assigning the Source
webgl.shaderSource(fragmentShader, fragmentCode);
//Compiling the Source
webgl.compileShader(fragmentShader);
//Creating Program to store Shader
var shaderProgram = webgl.createProgram();
//Attaching the shaders
webgl.attachShader(shaderProgram, vertexShader);
webgl.attachShader(shaderProgram, fragmentShader);
//linking the Program
webgl.linkProgram(shaderProgram);
//using the Program
webgl.useProgram(shaderProgram);
//Defining geometry
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
var colors = [0,0,1, 1,0,0, 0,1,0, 1,0,1,];
indices = [3,2,1,3,1,0];
//Creating a Buffer
var VextexBuffer = webgl.createBuffer();
var IndexBuffer = webgl.createBuffer();
var colorBuffer = webgl.createBuffer();
//Binding the Buffer
webgl.bindBuffer(webgl.ARRAY_BUFFER, VextexBuffer);
webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER, IndexBuffer);
webgl.bindBuffer(webgl.ARRAY_BUFFER, colorBuffer);
//Buffer Data
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(vertices), webgl.STATIC_DRAW);
webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), webgl.STATIC_DRAW);
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(colors), webgl.STATIC_DRAW);
/*Associating the shaders to bufferObject*/
//Getting attribute location
var coord = webgl.getAttribLocation(shaderProgram,"coordinates");
var color = webgl.getAttribLocation(shaderProgram, "color");
//pointing an attribute to the currently bound VBO
webgl.vertexAttribPointer(coord, 3, webgl.FLOAT, false ,0,0);
webgl.vertexAttribPointer(color, 3, webgl.FLOAT, false ,0,0);
//enabling the attributes
webgl.enableVertexAttribArray(coord);
webgl.enableVertexAttribArray(color);
//Unbind Array
/*Drawing the Triangle*/
//Clearing the Colour
webgl.clearColor(.5,.5,.5,1);
//Enabling the depth test
webgl.enable(webgl.DEPTH_TEST);
//Clearing colour nuffer bit
webgl.clear(webgl.COLOR_BUFFER_BIT);
//Setting a viewport
webgl.viewport(0,0,ctx.width,ctx.height);
//Draw the triangle
webgl.drawElements(webgl.TRIANGLES,indices.length,webgl.UNSIGNED_SHORT,0);
</script>
</body>
</html>
If I remove colour buffer and everything related to it, the code runs but with colour buffer, I only see gray canvas, nothing else.
Also Chrome console doesn't show any errors or warnings.
Please help me.
Here's the working fiddle.
The biggest mistake in your code is the use of the bindBuffer method. A WebGL context can bind a buffer at a time. Binding two or more buffers at a time results in binding only the last one.
When you have to copy data to a buffer, you need to bind it and then call bufferData function.
Same applies to the vertexAttribPointer function. First bind the buffer you want the attribute to bind to, then call vertexAttribPointer, and so on with the other buffer.
//Getting Webgl Context
var ctx = document.getElementById("ctx");
var webgl = ctx.getContext("experimental-webgl");
/*Creating Shader*/
//Vertex Code
var vertexCode =
'attribute vec3 coordinates;' +
'attribute vec3 color;' +
'varying vec3 vColor;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;' +
'}';
//Creating Shader Object
var vertexShader = webgl.createShader(webgl.VERTEX_SHADER);
//Assigning the Source
webgl.shaderSource(vertexShader, vertexCode);
//Compiling the Source
webgl.compileShader(vertexShader);
//Fragment Shader Code
var fragmentCode = 'precision mediump float;' +
'varying vec3 vColor;' +
'void main(void) {' +
'gl_FragColor = vec4(vColor, 1.);' +
'}';
//Creating Shader Object
var fragmentShader = webgl.createShader(webgl.FRAGMENT_SHADER);
//Assigning the Source
webgl.shaderSource(fragmentShader, fragmentCode);
//Compiling the Source
webgl.compileShader(fragmentShader);
//Creating Program to store Shader
var shaderProgram = webgl.createProgram();
//Attaching the shaders
webgl.attachShader(shaderProgram, vertexShader);
webgl.attachShader(shaderProgram, fragmentShader);
//linking the Program
webgl.linkProgram(shaderProgram);
//using the Program
webgl.useProgram(shaderProgram);
//Defining geometry
var vertices = [
-0.5, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.5, 0.5, 0.0
];
var colors = [0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, ];
indices = [3, 2, 1, 3, 1, 0];
var coord = webgl.getAttribLocation(shaderProgram, "coordinates");
var color = webgl.getAttribLocation(shaderProgram, "color");
webgl.enableVertexAttribArray(coord);
webgl.enableVertexAttribArray(color);
//Creating a Buffer
var VextexBuffer = webgl.createBuffer();
var IndexBuffer = webgl.createBuffer();
var colorBuffer = webgl.createBuffer();
//Binding the Buffer
webgl.bindBuffer(webgl.ARRAY_BUFFER, VextexBuffer);
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(vertices), webgl.STATIC_DRAW);
webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER, IndexBuffer);
webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), webgl.STATIC_DRAW);
webgl.bindBuffer(webgl.ARRAY_BUFFER, colorBuffer);
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(colors), webgl.STATIC_DRAW);
webgl.bindBuffer(webgl.ARRAY_BUFFER, VextexBuffer);
webgl.vertexAttribPointer(coord, 3, webgl.FLOAT, false, 0, 0);
webgl.bindBuffer(webgl.ARRAY_BUFFER, colorBuffer);
webgl.vertexAttribPointer(color, 3, webgl.FLOAT, false, 0, 0);
/*Drawing the Triangle*/
//Clearing the Colour
webgl.clearColor(.5, .5, .5, 1);
//Enabling the depth test
webgl.enable(webgl.DEPTH_TEST);
//Clearing colour nuffer bit
webgl.clear(webgl.COLOR_BUFFER_BIT);
//Setting a viewport
webgl.viewport(0, 0, ctx.width, ctx.height);
//Draw the triangle
webgl.drawElements(webgl.TRIANGLES, indices.length, webgl.UNSIGNED_SHORT, 0);
<canvas id ="ctx" width = "300" height = "300"></canvas>
You're overwriting your vertex positions with your colors:
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(vertices), webgl.STATIC_DRAW);
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(colors), webgl.STATIC_DRAW);
At any given time there can only be one buffer bound for each type (ARRAY_BUFFER and ELEMENT_ARRAY_BUFFER), so
the flow is to bind a buffer and set its data followed by setting up the vertex attribute pointers for that specific buffer, then proceed to the next buffer:
// setup positions
var VextexBuffer = webgl.createBuffer();
webgl.bindBuffer(webgl.ARRAY_BUFFER, VextexBuffer);
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(vertices), webgl.STATIC_DRAW);
var coord = webgl.getAttribLocation(shaderProgram,"coordinates");
webgl.vertexAttribPointer(coord, 3, webgl.FLOAT, false ,0,0);
// setup indices
var IndexBuffer = webgl.createBuffer();
webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER, IndexBuffer);
webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), webgl.STATIC_DRAW);
// setup colors
var colorBuffer = webgl.createBuffer();
webgl.bindBuffer(webgl.ARRAY_BUFFER, colorBuffer);
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(colors), webgl.STATIC_DRAW);
var color = webgl.getAttribLocation(shaderProgram, "color");
webgl.vertexAttribPointer(color, 3, webgl.FLOAT, false ,0,0);
For applications that work with multiple different buffers and intend to be realtime the flow is to create and set the buffers during initialization phase to then only bind the buffer and set the vertex attribute pointers during the animation loop.
<!doctype html>
<html>
<body>
<canvas id ="ctx" width = "300" height = "300"></canvas>
<script>
//Getting Webgl Context
var ctx = document.getElementById("ctx");
var webgl = ctx.getContext("experimental-webgl");
/*Creating Shader*/
//Vertex Code
var vertexCode =
'attribute vec3 coordinates;'+
'attribute vec3 color;'+
'varying vec3 vColor;'+
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;'+
'}';
//Creating Shader Object
var vertexShader = webgl.createShader(webgl.VERTEX_SHADER);
//Assigning the Source
webgl.shaderSource(vertexShader, vertexCode);
//Compiling the Source
webgl.compileShader(vertexShader);
//Fragment Shader Code
var fragmentCode ='precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
//Creating Shader Object
var fragmentShader = webgl.createShader(webgl.FRAGMENT_SHADER);
//Assigning the Source
webgl.shaderSource(fragmentShader, fragmentCode);
//Compiling the Source
webgl.compileShader(fragmentShader);
//Creating Program to store Shader
var shaderProgram = webgl.createProgram();
//Attaching the shaders
webgl.attachShader(shaderProgram, vertexShader);
webgl.attachShader(shaderProgram, fragmentShader);
//linking the Program
webgl.linkProgram(shaderProgram);
//using the Program
webgl.useProgram(shaderProgram);
//Defining geometry
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
var colors = [0,0,1, 1,0,0, 0,1,0, 1,0,1,];
indices = [3,2,1,3,1,0];
// setup positions
var VextexBuffer = webgl.createBuffer();
webgl.bindBuffer(webgl.ARRAY_BUFFER, VextexBuffer);
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(vertices), webgl.STATIC_DRAW);
var coord = webgl.getAttribLocation(shaderProgram,"coordinates");
webgl.vertexAttribPointer(coord, 3, webgl.FLOAT, false ,0,0);
// setup indices
var IndexBuffer = webgl.createBuffer();
webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER, IndexBuffer);
webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), webgl.STATIC_DRAW);
// setup colors
var colorBuffer = webgl.createBuffer();
webgl.bindBuffer(webgl.ARRAY_BUFFER, colorBuffer);
webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(colors), webgl.STATIC_DRAW);
var color = webgl.getAttribLocation(shaderProgram, "color");
webgl.vertexAttribPointer(color, 3, webgl.FLOAT, false ,0,0);
//enabling the attributes
webgl.enableVertexAttribArray(coord);
webgl.enableVertexAttribArray(color);
//Unbind Array
/*Drawing the Triangle*/
//Clearing the Colour
webgl.clearColor(.5,.5,.5,1);
//Enabling the depth test
webgl.enable(webgl.DEPTH_TEST);
//Clearing colour nuffer bit
webgl.clear(webgl.COLOR_BUFFER_BIT);
//Setting a viewport
webgl.viewport(0,0,ctx.width,ctx.height);
//Draw the triangle
webgl.drawElements(webgl.TRIANGLES,indices.length,webgl.UNSIGNED_SHORT,0);
</script>
</body>
</html>
I'm want my javascript program to be shifting a triangle to the right.
What I'm focusing on right now are matrices and draw loops. I've never done such a thing so I may be off road but what I'm attempting to do, for study purposes is this:
-Setup the webgl pipeline so I display correctly a triangle (OK)
-Write a function with a matrix that allows me to pass in the values of translation (seems ok but I'm not sure)
var translation_prototype = [1,0,0,0,
0,1,0,0,
0,0,1,0,
tx,ty,0,1];
Leaving out for the moment rotation a scaling and modelview, since I'm perfectly happy(just for the sake of an exercise) with the orthographic view webgl provides.
-Setup a loop that cycles through the drawArrays (even here I'm not sure if the loop starts and ends in the correct place)
I suspect I'm really close, but the triangle doesn't move (tx remains constant).
Here's the code(I think I don't even need to clear the color and depth buffer since I'm only translating on x axis)
<!DOCTYPE HTML>
<html>
<canvas id = "can" width="400" height="400">
</canvas>
<script>
var webgl_canvas = document.getElementById('can');
var gl = webgl_canvas.getContext('experimental-webgl');
var triangles = [-0.8,-0.8,0,0.8,-0.8,0,0,0.8,0];
var vertexBuffer = gl.createBuffer();
var tx = 0.1;
var ty = 0;
var translation_prototype = [1,0,0,0,
0,1,0,0,
0,0,1,0,
tx,ty,0,1];
var vertexShader_source = 'attribute vec3 a_position;' + 'uniform vec4 u_translation;' + 'void main() { gl_Position = u_translation * vec4 (a_position,1);}';
var fragmentShader_source = 'precision mediump float;' + 'void main() { gl_FragColor = vec4 (0.9,0,0.1,1); }';
function getTimeInSeconds () {
return Date.now() * 0.001;
}
function makeTranslation (tx, ty) {
return translation_prototype;
}
//Compile shaders
var buildShader = function (shaderSource, typeOfShader) {
var shader = gl.createShader(typeOfShader);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert (gl.getShaderInfoLog(shader));
}
return shader;
}
var compiledVertexShader = buildShader (vertexShader_source, gl.VERTEX_SHADER);
var compiledFragmentShader = buildShader (fragmentShader_source, gl.FRAGMENT_SHADER);
//setup GLSL program
program = gl.createProgram();
gl.attachShader(program,compiledVertexShader);
gl.attachShader(program,compiledFragmentShader);
gl.linkProgram(program);
//Fill the buffer with vertex data
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(triangles), gl.STATIC_DRAW);
vertexBuffer.itemSize = 3;
vertexBuffer.numItems = 3;
gl.clear(gl.COLOR_BUFFER_BIT);
var positionLocation = gl.getAttribLocation(program,"a_position");
gl.enableVertexAttribArray(positionLocation);
gl.useProgram(program);
var shaderTranlsationMatrix = gl.getUniformLocation(program, "u_translation");
gl.uniformMatrix4fv(shaderTranlsationMatrix,false,new Float32Array(translation_prototype));
gl.vertexAttribPointer(positionLocation, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
var startTime = 0;
function animate (time) {
//Draw loop
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
var deltaTime = (time - startTime);
makeTranslation((tx*deltaTime),(ty*deltaTime));
console.log(tx,ty,deltaTime);
gl.drawArrays (gl.TRIANGLES, 0, vertexBuffer.numItems);
startTime = time;
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</html>
<!-- start last edited snippet -->
<!DOCTYPE HTML>
<html>
<canvas id = "can" width="400" height="400">
</canvas>
<script>
var webgl_canvas = document.getElementById('can');
var gl = webgl_canvas.getContext('experimental-webgl');
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,0,1,-1,0,0,1,0]), gl.STATIC_DRAW);
vertexBuffer.itemSize = 3;
vertexBuffer.numItems = 3;
var identityMatrix = [1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1];
function translation (tx,ty,tz) {
return [1,0,0,0,
0,1,0,0,
0,0,1,0,
tx,ty,tz,1]
}
var vertexShader_source = 'attribute vec3 a_position;' + 'uniform mat4 u_move;' + 'void main() { gl_Position = u_move * vec4 (a_position,1); }';
var fragmentShader_source = 'precision mediump float;' + 'void main() { gl_FragColor = vec4 (0.9,0,0.1,1); }';
//Compile shaders
var buildShader = function (shaderSource, typeOfShader) {
var shader = gl.createShader(typeOfShader);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert (gl.getShaderInfoLog(shader));
}
return shader;
}
var compiledVertexShader = buildShader (vertexShader_source, gl.VERTEX_SHADER);
var compiledFragmentShader = buildShader (fragmentShader_source, gl.FRAGMENT_SHADER);
//setup GLSL program
program = gl.createProgram();
gl.attachShader(program,compiledVertexShader);
gl.attachShader(program,compiledFragmentShader);
gl.linkProgram(program);
var positionLocation = gl.getAttribLocation(program,"a_position");
gl.enableVertexAttribArray(positionLocation);
gl.useProgram(program);
var tx = 0, ty = 0, tz = 0;
var translate = gl.getUniformLocation (program, "u_move");
gl.uniformMatrix4fv(translate,false,new Float32Array(identityMatrix));
gl.vertexAttribPointer(positionLocation, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
//Draw
var start_time =0;
var animate=function(time) {
var dt= time-start_time;
tx+=0.5;
translation((dt*tx),0,0);
console.log(dt);
console.log(tx);
start_time=time;
gl.drawArrays (gl.TRIANGLES, 0, vertexBuffer.numItems);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</html>
<!-- end last edited snippet -->
Here is the working snippet
JSFIDDLE
Your vertex shader should look like this:
attribute vec3 a_position;' + 'uniform mat4 u_translation;' + 'void main() { gl_Position = u_translation*vec4 (a_position,1);}
In order to make objects move in space you have to multiply all your vectors and matrices with the position vector to get the result. Tranlation Wiki
You have to update your translation_prototype variable every loop cycle:
deltaTime += 0.005;
makeTranslation(tx+deltaTime,ty+deltaTime);
the deltaTime was declared outside the loop and incremented every cycle
Also your makeTranslation function should look like this:
function makeTranslation (x, y) {
translation_prototype =
[1,0,0,0,
0,1,0,0,
0,0,1,0,
x,y,0,1]
return translation_prototype;
}
(you can get rid of the return statement if you are using global variables, though is recommended to use local variables)
(I had to try this new snippet feature :D)
var webgl_canvas = document.getElementById('can');
var gl = webgl_canvas.getContext('experimental-webgl');
var triangles = [-0.5,-0.5,0,0.5,-0.5,0,0,0.5,0];
var vertexBuffer = gl.createBuffer();
var tx = 0;
var ty = 0;
var translation_prototype = [1,0,0,0,
- 0,1,0,0,
0,0,1,0,
0,0,0,1];
var vertexShader_source = 'attribute vec3 a_position;' + 'uniform mat4 u_translation;' + 'void main() { gl_Position = u_translation*vec4 (a_position,1);}';
var fragmentShader_source = 'precision mediump float;' + 'void main() { gl_FragColor = vec4 (0.9,0,0.1,1); }';
function getTimeInSeconds () {
return Date.now() * 0.001;
}
function makeTranslation (x, y) {
translation_prototype =
[1,0,0,0,
0,1,0,0,
0,0,1,0,
x,y,0,1]
return translation_prototype;
}
//Compile shaders
var buildShader = function (shaderSource, typeOfShader) {
var shader = gl.createShader(typeOfShader);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert (gl.getShaderInfoLog(shader));
}
return shader;
}
var compiledVertexShader = buildShader (vertexShader_source, gl.VERTEX_SHADER);
var compiledFragmentShader = buildShader (fragmentShader_source, gl.FRAGMENT_SHADER);
//setup GLSL program
program = gl.createProgram();
gl.attachShader(program,compiledVertexShader);
gl.attachShader(program,compiledFragmentShader);
gl.linkProgram(program);
//Fill the buffer with vertex data
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(triangles), gl.STATIC_DRAW);
vertexBuffer.itemSize = 3;
vertexBuffer.numItems = 3;
gl.clear(gl.COLOR_BUFFER_BIT);
var positionLocation = gl.getAttribLocation(program,"a_position");
gl.enableVertexAttribArray(positionLocation);
gl.useProgram(program);
var shaderTranlsationMatrix = gl.getUniformLocation(program, "u_translation");
gl.uniformMatrix4fv(shaderTranlsationMatrix,false,new Float32Array(translation_prototype));
gl.vertexAttribPointer(positionLocation, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
var startTime = 0;
var deltaTime = 0;
function animate (time) {
//Draw loop
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
deltaTime += 0.005;
makeTranslation(tx+deltaTime,ty+deltaTime);
gl.useProgram(program);
var shaderTranlsationMatrix = gl.getUniformLocation(program, "u_translation");
gl.uniformMatrix4fv(shaderTranlsationMatrix,false,new Float32Array(translation_prototype));
gl.vertexAttribPointer(positionLocation, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.drawArrays (gl.TRIANGLES, 0, vertexBuffer.numItems);
startTime = time;
window.requestAnimationFrame(animate);
}
animate(0);
<canvas id = "can" width="300" height="300">
</canvas>