I have a simple WebGL application.
It has canvas and a pair of simple shaders:
<canvas id="render" width="320" height="240">
<div id="vertexShader" class="shader">
attribute vec4 position;
void main()
{
gl_Position = position;
}
</div>
<div id="fragmentShader" class="shader">
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}
</div>
The application code looks like this:
function getContext() {
var canvas = document.getElementById("render");
return canvas.getContext("webgl");
}
function initContext(context) {
context.clearColor(0.0, 0.0, 0.0, 1.0);
context.clear(context.COLOR_BUFFER_BIT);
}
function getShader(shaderId, type, context) {
var shaderSource = document.getElementById(shaderId).innerHTML;
var shader = context.createShader(type);
context.shaderSource(shader, shaderSource);
context.compileShader(shader);
if (!context.getShaderParameter(shader, context.COMPILE_STATUS)) {
console.log(context.getShaderInfoLog(shader));
return null;
}
return shader;
}
function initShaders(context) {
var program = context.createProgram();
context.attachShader(program, getShader("vertexShader", context.VERTEX_SHADER, context));
context.attachShader(program, getShader("fragmentShader", context.FRAGMENT_SHADER, context));
context.linkProgram(program);
if (!context.getProgramParameter(program, context.LINK_STATUS)) {
console.log("Could not initialise shaders");
}
return program;
}
function renderTile(context, program) {
var tileBuffer = context.createBuffer();
var tile = [
1.0, 1.0, 0, 1.0,
-1.0, 0, 0, 1.0,
1.0, -1.0, 0, 1.0
];
context.bindBuffer(context.ARRAY_BUFFER, tileBuffer);
context.bufferData(context.ARRAY_BUFFER, new Float32Array(tile), context.STATIC_DRAW);
positionLocation = context.getAttribLocation(program, "position");
context.enableVertexAttribArray(positionLocation);
context.vertexAttribPointer(positionLocation, 4, context.FLOAT, false, 0, 0);
context.drawArrays(context.TRIANGLES, 0, 3);
}
var context = getContext();
initContext(context);
var program = initShaders(context);
context.useProgram(program);
setTimeout(function() {
renderTile(context, program);
}, 100);
It renders a simple triangle on a canvas.
The problem is that it sometimes renders a triangle on a white background although clear color is set to non-transparent black. (in latest Google Chrome, Firefox is ok)
While debugging I found that white background is rendered when drawArrays method is called.
But I can't understand why it is not black.
Here is a jsFiddle for your convenience.
In your example you just have to clear your color buffer every "frame". Your background is black at first, then gets "overwritten" by your triangle (that vertices buffer), like you mentioned.
You actually just do one clear in your init function at startup.
function initContext(context) {
context.clearColor(0.0, 0.0, 0.0, 1.0);
context.clear(context.COLOR_BUFFER_BIT);
}
Just add context.clear(context.COLOR_BUFFER_BIT); to your update function, for example:
setInterval(function() {
context.clear(context.COLOR_BUFFER_BIT);
renderTile(context, program);
}, 100);
See this updated jsFiddle.
Related
I am trying to get a square drawn on to a html canvas using GLSL and I am actually having a hard time understanding the errors. Here is my code for defining vertex and fragment shaders.Also Don't forget to leave a comment about the question
<script type="x-shader/x-vertex" id="VertexShader">
attribute vec3 aSquareVertexPosition;
void(main){
gl_Position = vec4(aSquareVertexPosition, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="FragmentShader">
void(main){
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
</script>
And here is my code for loading and compiling above glsl code.
var gSimpleShader = null;
var gShaderVertexPositionAttribute = null;
function loadAndCompile(id, shaderType) {
var shaderText, shaderSource, compiledShader;
shaderText = document.getElementById(id);
shaderSource = shaderText.firstChild.textContent;
compiledShader = gGL.createShader(shaderType);
gGL.shaderSource(compiledShader, shaderSource);
gGL.compileShader(compiledShader);
var errorOrNot = gGL.getShaderParameter(compiledShader, gGL.COMPILE_STATUS);
if (!errorOrNot){
console.error(gGL.getShaderInfoLog(compiledShader));
}
return compiledShader;
}
function initSimpleShader(vertexShaderID, fragmentShaderID) {
var vertexShader = loadAndCompile(vertexShaderID, gGL.VERTEX_SHADER);
var fragmentShader = loadAndCompile(fragmentShaderID, gGL.FRAGMENT_SHADER);
gSimpleShader = gGL.createProgram();
gGL.attachShader(gSimpleShader, vertexShader);
gGL.attachShader(gSimpleShader, fragmentShader);
gGL.linkProgram(gSimpleShader);
var errorOrNot = gGL.getProgramParameter(gSimpleShader, gGL.LINK_STATUS);
if (!errorOrNot){
console.error(gGL.getProgramInfoLog(gSimpleShader));
}
gShaderVertexPositionAttribute = gGL.getAttribLocation(gSimpleShader, "aSquareVertexPosition");
gGL.bindBuffer(gGL.ARRAY_BUFFER, gSquareVertexBuffer);
gGL.vertexAttribPointer(gShaderVertexPositionAttribute, 3, gGL.FLOAT, false, 0, 0);
}
this is where the gSquareVertexBuffer variable from above code is defined.
"use strict";
var gSquareVertexBuffer = null;
function initSquareBuffer() {
var verticesOfSquare =
[
0.5, 0.5, 0.0,
-0.5, 0.5, 0.0,
0.5, -0.5, 0.0,
-0.5, -0.5, 0.0,
];
gSquareVertexBuffer = gGL.createBuffer();
gGL.bindBuffer(gGL.ARRAY_BUFFER, gSquareVertexBuffer);
gGL.bufferData(gGL.ARRAY_BUFFER, new Float32Array(verticesOfSquare), gGL.STATIC_DRAW);
}
And I call these functions in another file as below.
"use strict";
var gGL = null;
function initializeGL()
{
var canvas = document.getElementById("GLCanvas");
gGL = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if (gGL != null){
gGL.clearColor(0.0, 0.0, 1.0, 1.0);
initSquareBuffer();
initSimpleShader("VertexShader", "FragmentShader");
}else{
document.write("<br><b>WebGL is not supported</b>");
}
}
function drawSquare()
{
gGL.clear(gGL.COLOR_BUFFER_BIT);
gGL.useProgram(gSimpleShader);
gGL.enableVertexAttribArray(gShaderVertexPositionAttribute);
gGL.drawArrays(gGL.TRANGLE_STRIP, 0, 4);
}
function doGLDraw()
{
initializeGL();
drawSquare();
}
After I open the index.html file in the browser I can only see the canvas and I get the following errors in the console.
Must have a compiled vertex shader attached: SHADER_INFO_LOG: ERROR: 0:3: '(' : syntax error
And also these WebGL warnings
WebGL warning: linkProgram: Must have a compiled vertex shader attached: SHADER_INFO_LOG: ERROR: 0:3: '(' : syntax error
WebGL warning: vertexAttribI?Pointer: index (4294967295) must be < MAX_VERTEX_ATTRIBS.
WebGL warning: useProgram: Program must be linked successfully.
WebGL warning: enableVertexAttribArray: -1 is not a valid index. This value probably comes from a getAttribLocation() call, where this return value -1 means that the passed name didn't correspond to an active attribute in the specified program.
WebGL warning: drawArraysInstanced: The current program is not linked.
I am new to WebGL and javaScript so don't forget to leave a comment.
There is a syntax error in the vertex shader and in the fragment shader. void is the return type. The name of the main function is main:
void(main){
void main(){
// [...]
}
Furthermore, it is TRIANGLE_STRIP not TRANGLE_STRIP
gGL.drawArrays(gGL.TRANGLE_STRIP, 0, 4);
gGL.drawArrays(gGL.TRIANGLE_STRIP, 0, 4);
var gSimpleShader = null;
var gShaderVertexPositionAttribute = null;
function loadAndCompile(id, shaderType) {
var shaderText, shaderSource, compiledShader;
shaderText = document.getElementById(id);
shaderSource = shaderText.firstChild.textContent;
compiledShader = gGL.createShader(shaderType);
gGL.shaderSource(compiledShader, shaderSource);
gGL.compileShader(compiledShader);
var errorOrNot = gGL.getShaderParameter(compiledShader, gGL.COMPILE_STATUS);
if (!errorOrNot){
console.error(gGL.getShaderInfoLog(compiledShader));
}
return compiledShader;
}
function initSimpleShader(vertexShaderID, fragmentShaderID) {
var vertexShader = loadAndCompile(vertexShaderID, gGL.VERTEX_SHADER);
var fragmentShader = loadAndCompile(fragmentShaderID, gGL.FRAGMENT_SHADER);
gSimpleShader = gGL.createProgram();
gGL.attachShader(gSimpleShader, vertexShader);
gGL.attachShader(gSimpleShader, fragmentShader);
gGL.linkProgram(gSimpleShader);
var errorOrNot = gGL.getProgramParameter(gSimpleShader, gGL.LINK_STATUS);
if (!errorOrNot){
console.error(gGL.getProgramInfoLog(gSimpleShader));
}
gShaderVertexPositionAttribute = gGL.getAttribLocation(gSimpleShader, "aSquareVertexPosition");
gGL.bindBuffer(gGL.ARRAY_BUFFER, gSquareVertexBuffer);
gGL.vertexAttribPointer(gShaderVertexPositionAttribute, 3, gGL.FLOAT, false, 0, 0);
}
var gSquareVertexBuffer = null;
function initSquareBuffer() {
var verticesOfSquare =
[
0.5, 0.5, 0.0,
-0.5, 0.5, 0.0,
0.5, -0.5, 0.0,
-0.5, -0.5, 0.0,
];
gSquareVertexBuffer = gGL.createBuffer();
gGL.bindBuffer(gGL.ARRAY_BUFFER, gSquareVertexBuffer);
gGL.bufferData(gGL.ARRAY_BUFFER, new Float32Array(verticesOfSquare), gGL.STATIC_DRAW);
}
var gGL = null;
function initializeGL()
{
var canvas = document.getElementById("GLCanvas");
gGL = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if (gGL != null){
gGL.clearColor(0.0, 0.0, 1.0, 1.0);
initSquareBuffer();
initSimpleShader("VertexShader", "FragmentShader");
}else{
document.write("<br><b>WebGL is not supported</b>");
}
}
function drawSquare()
{
gGL.clear(gGL.COLOR_BUFFER_BIT);
gGL.useProgram(gSimpleShader);
gGL.enableVertexAttribArray(gShaderVertexPositionAttribute);
gGL.drawArrays(gGL.TRIANGLE_STRIP, 0, 4);
requestAnimationFrame(drawSquare);
}
function doGLDraw()
{
initializeGL();
drawSquare();
}
doGLDraw()
<script type="x-shader/x-vertex" id="VertexShader">
attribute vec3 aSquareVertexPosition;
void main(){
gl_Position = vec4(aSquareVertexPosition, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="FragmentShader">
void main(){
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
</script>
<canvas id="GLCanvas"></canvas>
I am trying to write a function to draw a triangle (it's in main() now). everything works - everything is cool, but I added the execution of two functions for drawing point ( drawPoint()) and the point that is drawn after the triangle is displayed in the wrong place, why?
index.html :
<!DOCTYPE html>
<html>
<head>
<title>
the rgb
</title>
</head>
<body onload="main()">
<canvas id="webgl" width="400" height="400">
PLZ USE BROWSER SUPPORTING CANVAS
</canvas>
<script src="../lib/webgl-utils.js"></script>
<script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></script>
<script src="thergb.js"></script>
</body>
</html>
thergb.js:
var canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
function main()
{
clearCanvas('green');
drawPoint(0.3,0.0,50.0,'blue'); //draw point before triangle
//draw triangle
var VSHADER_SOURCE=
'attribute vec4 a_Position;\n'+
'void main() {\n' +
' gl_Position = a_Position;\n'+
'}\n';
var FSHADER_SOURCE=
'void main() {\n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n'+
'}\n';
if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE))
{
return;
}
var n = initVertexBuffers(gl);
gl.drawArrays(gl.TRIANGLES, 0, n);
drawPoint(0.4,0.0,50.0,'red'); //draw point after triangle
}
function initVertexBuffers(gl) {
var vertices = new Float32Array([
0, 0.5, -0.5, -0.5, 0.5, -0.5
]);
var n = 3; // The number of vertices
// Create a buffer object
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create the buffer object');
return -1;
}
// Bind the buffer object to target
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// Write date into the buffer object
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return -1;
}
// Assign the buffer object to a_Position variable
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
// Enable the assignment to a_Position variable
gl.enableVertexAttribArray(a_Position);
return n;
}
function drawPoint(x,y,size,color)
{
var VSHADER_SOURCE=
'attribute vec4 a_Position;\n'+
'attribute float a_PointSize;\n'+
'void main() {\n' +
' gl_Position = a_Position;\n'+
' gl_PointSize = a_PointSize;\n'+
'}\n';
if (color == 'red')
{
var FSHADER_SOURCE=
'void main() {\n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n'+
'}\n';
}
if (color == 'green')
{
var FSHADER_SOURCE=
'void main() {\n' +
' gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n'+
'}\n';
}
if (color == 'blue')
{
var FSHADER_SOURCE=
'void main() {\n' +
' gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n'+
'}\n';
}
if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE))
{
return;
}
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
gl.vertexAttrib3f(a_Position,x,y,0.0);
gl.vertexAttrib1f(a_PointSize, size);
gl.drawArrays(gl.POINTS, 0,1);
}
function clearCanvas(color)
{
if (color == 'red')
{
gl.clearColor( 1.0, 0.0, 0.0, 1.0);
}
if (color == 'green')
{
gl.clearColor( 0.0, 1.0, 0.0, 1.0);
}
if (color == 'blue')
{
gl.clearColor( 0.0, 0.0, 1.0, 1.0);
}
gl.clear(gl.COLOR_BUFFER_BIT);
}
additional libraries are on my github: https://github.com/bazylevnik0/thergb
The reason the point after the triangle shows up in the wrong place is that when the triangle is drawn it enables the attributes with gl.enableVertexAttribArray
An enabled attribute gets its values from a buffer assigned when calling gl.vertexAttribPointer
A disabled attribute gets its value from a constant set by gl.vertexAttrib???
In drawPoint, the gl.vertexAttrib3f functions, they set the constant for that attribute, but when it comes time to draw the second point the attributes are enabled which means it's looking in the buffers assigned when the triangle was drawn not the constant.
If you add
gl.disableVertexAttribArray(a_Position);
gl.disableVertexAttribArray(a_PointSize);
in drawPoint before drawing it should work.
You might find this state diagram helpful in understanding what is being set by the various functions
I am seeing very odd behavior where polygonOffset initially works, but if I re-render it stops working.
I made a simple example to illustrate it. I started with the z-fighting example from Ch7 of the WebGL Programming Guide (https://sites.google.com/site/webglbook/). I then separated out just the rendering portion and wrapped it in a function. I then hooked up an HTML button to call the render() function when clicked. On the first click, the triangles render correctly with no issues. On the second click, it is like polygonOffset is turned off again.
I've tried a number of different variations, including re-enabling every time, disabling and re-enabling, changing the offsets, but I keep getting the same behavior. Any ideas?
I'm including the code, though the snippet doesn't run for me won't run without the book's libraries.
// Zfighting.js (c) 2012 matsuda
// Vertex shader program
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec4 a_Color;\n' +
'uniform mat4 u_ViewProjMatrix;\n' +
'varying vec4 v_Color;\n' +
'void main() {\n' +
' gl_Position = u_ViewProjMatrix * a_Position;\n' +
' v_Color = a_Color;\n' +
'}\n';
// Fragment shader program
var FSHADER_SOURCE =
'#ifdef GL_ES\n' +
'precision mediump float;\n' +
'#endif\n' +
'varying vec4 v_Color;\n' +
'void main() {\n' +
' gl_FragColor = v_Color;\n' +
'}\n';
function main() {
// Retrieve <canvas> element
var canvas = document.getElementById('webgl');
// Get the rendering context for WebGL
var gl = getWebGLContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
// Initialize shaders
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('Failed to intialize shaders.');
return;
}
// Set the vertex coordinates and color (the blue triangle is in the front)
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('Failed to set the vertex information');
return;
}
//Set clear color and enable the hidden surface removal function
gl.clearColor(0, 0, 0, 1);
gl.enable(gl.DEPTH_TEST);
// Get the storage locations of u_ViewProjMatrix
var u_ViewProjMatrix = gl.getUniformLocation(gl.program, 'u_ViewProjMatrix');
if (!u_ViewProjMatrix) {
console.log('Failed to get the storage locations of u_ViewProjMatrix');
return;
}
var viewProjMatrix = new Matrix4();
// Set the eye point, look-at point, and up vector.
viewProjMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100);
viewProjMatrix.lookAt(3.06, 2.5, 10.0, 0, 0, -2, 0, 1, 0);
// Pass the view projection matrix to u_ViewProjMatrix
gl.uniformMatrix4fv(u_ViewProjMatrix, false, viewProjMatrix.elements);
// Enable the polygon offset function
gl.enable(gl.POLYGON_OFFSET_FILL);
function render() {
// Clear color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Draw the triangles
gl.drawArrays(gl.TRIANGLES, 0, n/2); // The green triangle
gl.polygonOffset(1.0, 1.0); // Set the polygon offset
gl.drawArrays(gl.TRIANGLES, n/2, n/2); // The yellow triangle
}
document.getElementById("button").onclick = render;
}
function initVertexBuffers(gl) {
var verticesColors = new Float32Array([
// Vertex coordinates and color
0.0, 2.5, -5.0, 0.4, 1.0, 0.4, // The green triangle
-2.5, -2.5, -5.0, 0.4, 1.0, 0.4,
2.5, -2.5, -5.0, 1.0, 0.4, 0.4,
0.0, 3.0, -5.0, 1.0, 0.4, 0.4, // The yellow triagle
-3.0, -3.0, -5.0, 1.0, 1.0, 0.4,
3.0, -3.0, -5.0, 1.0, 1.0, 0.4,
]);
var n = 6;
// Create a buffer object
var vertexColorbuffer = gl.createBuffer();
if (!vertexColorbuffer) {
console.log('Failed to create the buffer object');
return -1;
}
// Write the vertex coordinates and color to the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var FSIZE = verticesColors.BYTES_PER_ELEMENT;
// Assign the buffer object to a_Position and enable the assignment
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if(a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return -1;
}
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
// Assign the buffer object to a_Color and enable the assignment
var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
if(a_Color < 0) {
console.log('Failed to get the storage location of a_Color');
return -1;
}
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
return n;
}
<canvas id="webgl" width="400" height="400">
Please use a browser that supports "canvas"
</canvas>
<input type="button" id="button" />
You need to reset PolygonOffset or disable/reenable it, otherwise both triangles are offset by the same amount.
GPUs are state machines, you're in charge of managing the state(variables):
function render() {
// Clear color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Draw the triangles
gl.polygonOffset(0.0, 0.0); // Reset the polygon offset
gl.drawArrays(gl.TRIANGLES, 0, n/2); // The green triangle
gl.polygonOffset(1.0, 1.0); // Set the polygon offset
gl.drawArrays(gl.TRIANGLES, n/2, n/2); // The yellow triangle
}
I am currently learning webgl and have a question.
I am trying to make a triangle and passing the color info into fragment shader from js file. The following is my js code:
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n'+
'attribute vec4 a_Color;\n'+
'varying vec4 v_Color;\n'+
'void main(){\n'+
'gl_Position = a_Position;\n'+
'v_Color = a_Color;\n'+
'}\n';
var FSHADER_SOURCE =
'precision highp float;\n'+
'varying vec4 v_Color;\n'+
'void main() {\n'+
'gl_FragColor = v_Color;\n'+
'}\n';
function main(){
var canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if(!gl){
console.log('Error!');
return;
}
//Init shaders.
if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)){
console.log('Error!');
return;
}
var vertices = new Float32Array([-0.8, -0.8, 0.8, -0.8, 0.0, 0.8]);
var color = new Float32Array([0.0, 0.0, 1.0, 1.0]);
var buffer_object = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer_object);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
var color_object = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, color_object);
gl.bufferData(gl.ARRAY_BUFFER, color, gl.STATIC_DRAW);
var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Color);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
return 0;
}
This have to create a blue triangle but the only thing I see is a canvas filled with black color. Can anyone tell me what's missing?? I created two buffer objects and used one for vertex and the other for color.
There's a lot of issues with your example but... specific problems.
You're only supplying colors for the first vertex.
You have 3 vertices but only 1 color. You should be getting an error for that.
Did you check the JavaScript Console for errors?
You have 3 options to fix that
Provide a color for each vertex
new Float32Array([
0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 1.0, 1.0,
]);
Turn off the a_Color attribute and supply a constant value
gl.disableVertexAtttibArray(a_Color);
gl.vertexAttrib4f(a_Color, 0, 0, 1, 1);
Use a uniform instead of an attribute + varying
remove all references of a_Color and v_color and instead have your
fragment shader be
precision highp float;
uniform vec4 u_Color;
void main() {
gl_FragColor = u_Color;
}
Now you'd set the color with
At Init time
// Lookup the location
var u_colorLocation = gl.getUniformLocation(program, "u_Color");
At render time
// Set the uniform
gl.uniform4f(u_colorLocation, 0, 0, 1, 1);
If you choose #2 you'll likely run into another issue that you'll get a warning that attirbute 0 is not enabled because, at least on my computer, a_Color is assigned to attribute 0. Turning it off means it has to be emulated which is slow. The solution is to make sure a_Position is in attribute 0 by calling gl.bindAttribLocation before linking the program.
Other issues:
Your initShader function is apparently creating a program and attaching it to the WebGLRenderContext (gl.program). Most WebGL projects have many shader programs so it would probably be best to just return the program. In other words, instead of
initShader(...);
gl.getAttribLocation(gl.program, ...)
You probably want
var program = initShader(...);
gl.getAttribLocation(program, ...)
You'll need to fix initShader so it returns the program that was created rather than hacking it on to the WebGLRenderingContext.
Also you're using precision highp float. That won't work on many phones. Unless you're sure you need highp it's better to use mediump.
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.