Issue with webgl coloring - webgl

I'll start off by saying that I'm new to webgl, only picked it up a few days ago for a computer graphics class and I'm having a problem with an application using dat.gui. What it's supposed to do is draw a rectangle with 2 clicks and color it with the color selected with the dat.gui controller, but the color that I get is a sort of a mix going from green, yellow, red and left bottom corner is black. If I comment the gl.enableVertexAttribArray(_color); line the rectangles are all black, so all I can think of is I'm not storing the color information correctly. I would very much appreciate it if someone could point me towards a solution or at least towards the problem. `
<html>
<body>
<canvas width="570" height="570" id="my_Canvas"></canvas>
<script src="../lib/dat.gui.js"></script>
<script>
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
var vertCode =
'attribute vec3 coordinates;' +
'varying vec3 vColor;' +
'attribute vec3 color;' +
'void main(void){' +
' gl_Position=vec4(coordinates, 1.0);' +
'vColor=color;' +
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragCode =
'precision highp float;' +
'varying vec3 vColor;' +
'void main(void){' +
' gl_FragColor=vec4(vColor, 1.0);' +
'}';
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
console.log(gl.getShaderInfoLog(vertShader));
console.log(gl.getProgramInfoLog(shaderProgram));
var gui = new dat.GUI();
var colore = {
colorv: [200, 200, 0]
};
gui.addColor(colore, 'colorv');
gl.clearColor(0.5, 0.5, 0.5, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
var g_indices = [0, 1, 2, 0, 1, 3];
var colors = [];
var p_counter = 0; //this counter is used to detect if the point clicked is the 2nd point
var g_counter = 0; //this is a global counter, used as a multiplier for g_points
var quad_g_counter;
var dodeca_g_counter;
var g_points = []; // the array for mousepress
var indices = [];
var vertex_buffer = gl.createBuffer();
var Index_Buffer = gl.createBuffer();
var color_Buffer = gl.createBuffer();
function click(ev, gl, canvas) {
var x = ev.clientX;
var y = ev.clientY;
var rect = ev.target.getBoundingClientRect();
x = ((x - rect.left) - canvas.height / 2) / (canvas.height / 2);
y = (canvas.width / 2 - (y - rect.top)) / (canvas.width / 2);
//store the coords in g_points array
g_points.push(x);
g_points.push(y);
g_points.push(0);
// clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
p_counter += 1;
if (p_counter == 2) {
//g_points
dodeca_g_counter = g_counter * 12;
g_points.push(g_points[dodeca_g_counter + 3]);
g_points.push(g_points[dodeca_g_counter + 1]);
g_points.push(0);
g_points.push(g_points[dodeca_g_counter]);
g_points.push(g_points[dodeca_g_counter + 4]);
g_points.push(0);
//indices
quad_g_counter = g_counter * 4;
indices.push(g_indices[0] + quad_g_counter);
indices.push(g_indices[1] + quad_g_counter);
indices.push(g_indices[2] + quad_g_counter);
indices.push(g_indices[3] + quad_g_counter);
indices.push(g_indices[4] + quad_g_counter);
indices.push(g_indices[5] + quad_g_counter);
//colors
for (var i = 0; i < 4; i += 1) {
colors.push(colore.colorv[0] / 255);
colors.push(colore.colorv[1] / 255);
colors.push(colore.colorv[2] / 255);
}
p_counter = 0;
g_counter += 1;
}
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(g_points), gl.STATIC_DRAW);
//gl.bindBuffer(gl.ARRAY_BUFFER, null);
//gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
//gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, color_Buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
draw();
}
canvas.onmousedown = function(ev) {
click(ev, gl, canvas);
}
function draw() {
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coord);
var _color = gl.getAttribLocation(shaderProgram, "color");
gl.vertexAttribPointer(_color, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(_color);
gl.useProgram(shaderProgram);
gl.enable(gl.DEPTH_TEST);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
}
</script>
</body>
</html>

You have to bind the proper vertex buffer before you call gl.vertexAttribPointer:
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
var _color = gl.getAttribLocation(shaderProgram, "color");
.....
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coord);
gl.bindBuffer(gl.ARRAY_BUFFER, color_Buffer);
gl.vertexAttribPointer(_color, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(_color);
Note, gl.vertexAttribPointer define an array of generic vertex attribute data refering to the currently bound ARRAY_BUFFER. See gl.bindBuffer.
Before you specify the vertex attributes for "coordinates" you bind vertex_buffer. But you don't bind color_Buffer befor you specify the vertex attributes for "color".
Because of that the vertex coordinate buffer is used for the color attributes too. his causes colorful lines and areas, because the colors are interpolated from point to point.
See the snippet:
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
var vertCode=
'attribute vec3 coordinates;' +
'varying vec3 vColor;' +
'attribute vec3 color;' +
'void main(void){' +
' gl_Position=vec4(coordinates, 1.0);' +
'vColor=color;' +
'}';
var vertShader=gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragCode=
'precision highp float;' +
'varying vec3 vColor;' +
'void main(void){' +
' gl_FragColor=vec4(vColor, 1.0);' +
'}';
var fragShader=gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderProgram=gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
console.log(gl.getShaderInfoLog(vertShader));
console.log(gl.getProgramInfoLog(shaderProgram));
//var gui = new dat.GUI();
var colore={
colorv: [200,200,0]
};
//gui.addColor(colore, 'colorv');
gl.clearColor(0.5, 0.5, 0.5, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
var g_indices=[0,1,2,0,1,3];
var colors=[];
var p_counter=0; //this counter is used to detect if the point clicked is the 2nd point
var g_counter=0; //this is a global counter, used as a multiplier for g_points
var quad_g_counter;
var dodeca_g_counter;
var g_points = []; // the array for mousepress
var indices=[];
var vertex_buffer=gl.createBuffer();
var Index_Buffer=gl.createBuffer();
var color_Buffer=gl.createBuffer();
function click(ev,gl,canvas){
var x = ev.clientX;
var y = ev.clientY;
var rect = ev.target.getBoundingClientRect();
x = ((x - rect.left) - canvas.height/2)/(canvas.height/2);
y = (canvas.width/2 - (y - rect.top))/(canvas.width/2);
//store the coords in g_points array
g_points.push(x);g_points.push(y); g_points.push(0);
// clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
p_counter+=1;
if(p_counter==2){
//g_points
dodeca_g_counter=g_counter*12;
g_points.push(g_points[dodeca_g_counter+3]);g_points.push(g_points[dodeca_g_counter+1]);g_points.push(0);
g_points.push(g_points[dodeca_g_counter]);g_points.push(g_points[dodeca_g_counter+4]);g_points.push(0);
//indices
quad_g_counter=g_counter*4;
indices.push(g_indices[0]+quad_g_counter);indices.push(g_indices[1]+quad_g_counter);
indices.push(g_indices[2]+quad_g_counter);indices.push(g_indices[3]+quad_g_counter);
indices.push(g_indices[4]+quad_g_counter);indices.push(g_indices[5]+quad_g_counter);
//colors
for(var i=0; i<4; i+=1){
colors.push(colore.colorv[0]/255);colors.push(colore.colorv[1]/255);
colors.push(colore.colorv[2]/255);
}
p_counter=0;
g_counter+=1;
}
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(g_points), gl.STATIC_DRAW);
//gl.bindBuffer(gl.ARRAY_BUFFER, null);
//gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
//gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, color_Buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
draw();
}
canvas.onmousedown = function(ev) {click(ev,gl,canvas);}
function draw(){
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var coord=gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coord);
gl.bindBuffer(gl.ARRAY_BUFFER, color_Buffer);
var _color=gl.getAttribLocation(shaderProgram, "color");
gl.vertexAttribPointer(_color, 3, gl.FLOAT, false, 0,0);
gl.enableVertexAttribArray(_color);
gl.useProgram(shaderProgram);
gl.enable(gl.DEPTH_TEST);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
}
<canvas width="570" height="570" id="my_Canvas"></canvas>

Related

Webgl rotate two triangles using offset in vertex shader without using transformation matrix

The goal of this task is to display two triangles on the canvas using the same vertex data and an offset to display the triangles and have them rotated in the vertex shader. I can get two triangles to display (comment out the window.requestAnimFrame(render, canvas); in my render function) how ever when trying to animate this code only one of the triangles displays, is there something really obvious I'm missing? Code below.
canvas display with requestAnimFrame commented out
canvas display after trying to animate the triangles
var fRotation;
var uOffset;
window.onload = function init()
{
canvas = document.getElementById("gl-canvas");
gl = WebGLUtils.setupWebGL(canvas);
if (!gl) {alter("WebGL is not available.");}
fRotation = 1;
gl.viewport(0, 0, 512, 512);
gl.clearColor(0, 0, 0, 1);
points = [
vec2(-1, 0),
vec2(1, 0),
vec2(0, 1)
];
colors = [
vec3(0, 1, 0),
vec3(1, 0, 0),
vec3(0, 0, 1)
];
var program = initShaders(gl, vBasicShaderCode, fBasicShaderCode);
gl.useProgram(program);
var posBufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, posBufferId);
gl.bufferData(gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW);
var vPos = gl.getAttribLocation(program, "aPosition");
console.log("position data loaded");
// load the data into GPU
var colBufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colBufferId);
gl.bufferData(gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW);
// Associate shader variables with data buffer
var vCol = gl.getAttribLocation(program, "aColour");
gl.vertexAttribPointer(vCol, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vCol);
console.log("color data loaded");
render();
function drawtri(){
gl.enableVertexAttribArray(vPos);
gl.bindBuffer(gl.ARRAY_BUFFER, posBufferId);
gl.vertexAttribPointer(vPos, 2, gl.FLOAT, false, 0, 0);
fRotation += 0.1 / 144;
gl.uniform1f(gl.getUniformLocation(program, "fRotation"), fRotation );
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
function render(){
gl.clear(gl.COLOR_BUFFER_BIT);
drawtri();
var uOffset = gl.getUniformLocation(program, "uOffset"); // first need to get the location of the uniform variable
var offset = vec2(0.3, 0.1); // we define 'offset' which is a 2 dimensional vector
gl.uniform2fv(uOffset, offset); // we pass 'offset' to the variable in the Vertex Shader.
drawtri();
window.requestAnimFrame(render, canvas);
}
}
and the vertex shader
var vBasicShaderCode =`
attribute vec2 aPosition;
uniform vec2 uOffset;
attribute vec3 aColour;
uniform float fRotation;
varying vec3 vColour;
void
main()
{
vColour=aColour;
vec2 uPosition = vec2(0.0,0.0);
//translate
uPosition.x = aPosition.x;
uPosition.y = aPosition.y;
vec2 transformedVertexPosition = (aPosition + uOffset );
uPosition.x = (cos(fRotation)*transformedVertexPosition.x)-(sin(fRotation)*transformedVertexPosition.y);
uPosition.y = (cos(fRotation)*transformedVertexPosition.y)+(sin(fRotation)*transformedVertexPosition.x);
//gl_Position = vec4(transformedVertexPosition, 0.0, 1.0);
gl_Position = vec4(uPosition.x, uPosition.y, 0.0, 1.0);
}`;
any help would be greatly appreciated.
You need to set the uOffset for every draw.
The code is effectively doing this
uOffset = 0 // the default value
render
drawTri
uOffset = 0.3, 0.1
drawTri
requestAnimationFrame
render
drawTri // uOffset is still 0.3, 0.1 here. it doesn't magically go back to 0
uOffset = 0.3, 0.1
drawTri
Adding answer to show the code that fixed this issue, thanks to Gman for the advice.
gl.clear(gl.COLOR_BUFFER_BIT);
var uOffset = gl.getUniformLocation(program, "uOffset");
var offset = vec2(0.0, 0.0);
gl.uniform2fv(uOffset, offset);
drawtri();
var offset = vec2(0.3, 0.1);
gl.uniform2fv(uOffset, offset);
drawtri();
window.requestAnimFrame(render, canvas);
} ```

WebGL texture bound to texture unit 0 is not renderable error

I been getting a "texture bound to texture unit 0 is not renderable. It maybe non-power-of-2 and have incompatible texture filtering." error when loading a texture to an object in WebGL. I tried all of the suggestions on StackOverflow but none of them worked for me. I tried changing the image files to make the dimensions a power of 2 and tried different file formats (jpg, gif, png).
I can't tell if the image is the problem or something is happening in my code.
Fragment Shader:
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}
Vertex Shader:
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
}
initShaders()
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
//Create the program, then attach and link
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
//Check for linker errors.
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
//Attach shaderprogram to openGL context.
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
}
Texture Load:
var sunTexture;
function initTexture() {
sunTexture = gl.createTexture();
sunTexture.image = new Image();
sunTexture.image.onload = function() {
handleLoadedTexture(sunTexture)
}
sunTexture.image.src = "images/leaves.jpg";
}
function handleLoadedTexture(texture) {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
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_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.bindTexture(gl.TEXTURE_2D, null);
}
drawScene() - Render and draw the object
var mvMatrix = mat4.create();
var pMatrix = mat4.create();
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(pMatrix, 45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
// Render the Sun
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, mvMatrix, 0, 0, -7.0);
mat4.multiply(mvMatrix, mouseRotMatrix, mvMatrix);
gl.bindBuffer(gl.ARRAY_BUFFER, sunVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, sunVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, sunVertexTextureBuffer);
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, sunVertexTextureBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, sunTexture);
gl.uniform1i(shaderProgram.samplerUniform, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLE_STRIP, 0, sunVertexPositionBuffer.numItems);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}
initBuffers() - Set up the data for the position and texture buffer
var sunVertexPositionBuffer;
var sunVertexTextureBuffer;
function initBuffers() {
sunVertexPositionBuffer = gl.createBuffer();
sunVertexTextureBuffer = gl.createBuffer();
var sRadius = 4;
var slices = 25;
var stacks = 12;
var sVertices = [];
var count = 0;
for (t = 0 ; t < stacks ; t++ ) {
var phi1 = ((t)/stacks) * Math.PI;
var phi2 = ((t+1)/stacks) * Math.PI;
for (p = 0 ; p < slices + 1; p++) {
var theta = ((p)/slices ) * 2 * Math.PI ;
var xVal = sRadius * Math.cos(theta) * Math.sin(phi1);
var yVal = sRadius * Math.sin(theta) * Math.sin(phi1);
var zVal = sRadius * Math.cos(phi1);
sVertices = sVertices.concat([xVal, yVal, zVal]);
count++;
var xVal = sRadius * Math.cos(theta) * Math.sin(phi2);
var yVal = sRadius * Math.sin(theta) * Math.sin(phi2);
var zVal = sRadius * Math.cos(phi2);
sVertices = sVertices.concat([xVal, yVal, zVal]);
count++;
}
}
var textureCoords = [];
for (t = 0; t < stacks; t++) {
var phi1 = ((t)/stacks);
var phi2 = ((t+1)/stacks);
for (p = 0; p < slices + 1; p++) {
var theta = 1 - ( (p)/slices );
textureCoords = textureCoords.concat([theta, phi1]);
textureCoords = textureCoords.concat([theta, phi2]);
}
}
gl.bindBuffer(gl.ARRAY_BUFFER, sunVertexPositionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(sVertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, sunVertexTextureBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
sunVertexPositionBuffer.itemSize = 3;
sunVertexPositionBuffer.numItems = count
sunVertexTextureBuffer.itemSize = 2;
sunVertexTextureBuffer.numItems = stacks * (slices + 1) * 2;
gl.bindBuffer(gl.ARRAY_BUFFER, null);
}
The issue is likely that the code starts rendering before the images has loaded and until that time your texture is not-renderable.
My solution is always to start the texture with a single pixel so it's renderable immediately
sunTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, sunTexture);
gl.texImage2D(gl.TEXTURE_2D, 1, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
new Uint8Array([0, 0, 255, 255])); // blue
When the image finishes loading the code will update the texture but until then it's usable.
See these tutorials

Webgl Circle without using extrernal library

I am new to webgl and at this point I am able to create a triangle and square.
I am finding it difficult to understand how to create a circle with out any external scripts or libraries.
var vertexShaderText =
[
'uniform vec2 u_resolution;',
'',
'attribute vec2 a_position;',
'',
'void main()',
'{',
'',
'vec2 clipspace = a_position / u_resolution * 1.0 ;',
'',
'gl_Position = vec4(clipspace * vec2(2.5, 2.0), 0, 1);',
'}'
].join("\n");
var fragmentShaderText =
[
'precision mediump float;',
'',
'void main(void)',
'{',
'',
'gl_FragColor = vec4(0, 0, 0, 1.0);',
'',
'}'
].join("\n");
var uni = function(){
var canvas = document.getElementById("game-surface");
var gl = canvas.getContext("webgl");
console.log("This is working");
gl.clearColor(0.412,0.412,0.412,1);
gl.clear(gl.COLOR_BUFFER_BIT);
var vertextShader = gl.createShader(gl.VERTEX_SHADER);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertextShader,vertexShaderText);
gl.shaderSource(fragmentShader,fragmentShaderText);
gl.compileShader(vertextShader);
gl.compileShader(fragmentShader);
if(!gl.getShaderParameter(vertextShader,gl.COMPILE_STATUS)){
console.error("Error with vertexshader",gl.getShaderInfoLog(vertextShader));
return;
}
if(!gl.getShaderParameter(fragmentShader,gl.COMPILE_STATUS)){
console.error("Error with fragmentShader",gl.getShaderInfoLog(fragmentShader));
return;
}
var program =gl.createProgram();
gl.attachShader(program,vertextShader);
gl.attachShader(program,fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
if(!gl.getProgramParameter(program,gl.LINK_STATUS)){
console.error("Error linking program",gl.getProgramInfoLog(program));
return;
}
gl.validateProgram(program);
if(!gl.getProgramParameter(program,gl.VALIDATE_STATUS)){
console.error("Error validating",gl.getProgramInfoLog(program));
}
var circle = {x: 0, y:0, r: 75};
var ATTRIBUTES = 2;
var numFans = 64;
var degreePerFan = (2* Math.PI) / numFans;
var vertexData = [circle.x, circle.y];
for(var i = 0; i <= numFans; i++) {
var index = ATTRIBUTES * i + 2; // there is already 2 items in array
var angle = degreePerFan * (i+0.1);
vertexData[index] = circle.x + Math.cos(angle) * circle.r;
vertexData[index + 1] = circle.y + Math.sin(angle) * circle.r;
}
var vertexDataTyped = new Float32Array(vertexData);
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertexDataTyped, gl.STATIC_DRAW);
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
gl.enableVertexAttribArray(positionLocation);
var positionLocation = gl.getAttribLocation(program, "a_position");
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 0);
gl.drawArrays(gl.TRIANGLE_FAN, 0, vertexData.length/ATTRIBUTES);
};

Generate random shape along a point on circumference of circle

I am new to webgl ,i created a circle from vertices generated in a loop and i want a random shape(small circle) to be generated on some point along the circumference of the big circle.Can anyone provide me some info on how i can acheive this
Here is my code for the circle:
var vertexShaderText = [
'uniform vec2 u_resolution;',
'',
'attribute vec2 a_position;',
'',
'void main()',
'{',
'',
'vec2 clipspace = a_position / u_resolution * 1.0 ;',
'',
'gl_Position = vec4(clipspace * vec2(1, -1), 0, 1);',
'}'
].join("\n");
var fragmentShaderText = [
'precision mediump float;',
'',
'void main(void)',
'{',
'',
'gl_FragColor = vec4(0, 0, 0, 1.0);',
'',
'}'
].join("\n");
var uni = function(){
var canvas = document.getElementById("game-surface");
var gl = canvas.getContext("webgl",{antialias: true});
console.log("This is working");
gl.clearColor(0.412,0.412,0.412,1);
gl.clear(gl.COLOR_BUFFER_BIT);
var vertextShader = gl.createShader(gl.VERTEX_SHADER);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertextShader,vertexShaderText);
gl.shaderSource(fragmentShader,fragmentShaderText);
gl.compileShader(vertextShader);
gl.compileShader(fragmentShader);
if(!gl.getShaderParameter(vertextShader,gl.COMPILE_STATUS)){
console.error("Error with vertexshader",gl.getShaderInfoLog(vertextShader));
return;
}
if(!gl.getShaderParameter(fragmentShader,gl.COMPILE_STATUS)){
console.error("Error with fragmentShader",gl.getShaderInfoLog(fragmentShader));
return;
}
var program =gl.createProgram();
gl.attachShader(program,vertextShader);
gl.attachShader(program,fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
if(!gl.getProgramParameter(program,gl.LINK_STATUS)){
console.error("Error linking program",gl.getProgramInfoLog(program));
return;
}
gl.validateProgram(program);
if(!gl.getProgramParameter(program,gl.VALIDATE_STATUS)){
console.error("Error validating",gl.getProgramInfoLog(program));
}
var circle = {x: 0, y:0, r: 55};
var ATTRIBUTES = 2;
var numFans = 32;
var degreePerFan = (2* Math.PI) / numFans;
var vertexData = [circle.x, circle.y];
for(var i = 0; i <= numFans; i++) {
var index = ATTRIBUTES * i + 2; // there is already 2 items in array
var angle = degreePerFan * (i+0.1);
vertexData[index] = circle.x + Math.cos(angle) * circle.r;
vertexData[index + 1] = circle.y + Math.sin(angle) * circle.r;
}
console.log(vertexData);
var vertexDataTyped = new Float32Array(vertexData);
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertexDataTyped, gl.STATIC_DRAW);
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
gl.enableVertexAttribArray(positionLocation);
var positionLocation = gl.getAttribLocation(program, "a_position");
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 0);
gl.drawArrays(gl.TRIANGLE_FAN, 0, vertexData.length/ATTRIBUTES);
};
uni();
<canvas id="game-surface"></canvas>
It's hard to answer your question because WebGL is just a rasterization library so there's literally 1000s of ways to draw something somewhere.
So, you can
add more points
You generated the circle points. Generate some more for whatever else you want to draw.
draw the same circle multiple times in different places and sizes
Let's say you wanted to draw a small circle on the big circle. Compute a matrix to scale and reorient the big circle where you want it to be, update the matrix, draw the circle again.
draw more things
Just like you drew the circle, draw something else like a square and position it at the edge of the circle.
1000 more ways...

WebGL: Simple Texture Rendering Issue ("Drawing to a destination rect smaller than the viewport rect.")

I am currently trying to render a simple texture with WebGL.
This is basically a port from normal system OpenGL.
It doesn't seem to work and I seriously have no idea what's wrong as it also seems very difficult to debug these thing.
I am getting an error on Firefox though:
"Error: WebGL: drawElements: Drawing to a destination rect smaller than the viewport rect. (This warning will only be given once)"
The viewport / projection matrix / positions seem to be correct so why am I getting that error?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Test</title>
<style>
.canstyle {
width: 800px;
height: 600px;
}
</style>
</head>
<body>
<canvas id="canvas0" class="canstyle">
</canvas>
<script type='text/javascript'>
var vertexShaderSrc = `
precision mediump float;
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat3 projectionMatrix;
varying vec2 vTextureCoord;
void main() {
gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
vTextureCoord = aTextureCoord;
}
`;
var fragmentShaderSrc = `
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
void main() {
gl_FragColor = texture2D(uSampler, vTextureCoord);
}
`;
var img1 = new Image(); // HTML5 Constructor
img1.src = 'bunny.png';
img1.alt = 'alt';
img1.onload = function() {
render();
}
function render() {
var canvas = document.getElementById("canvas0");
var gl = canvas.getContext("webgl", {
alpha: false,
depth: false,
stencil: true,
premultipliedAlpha: false
});
var funcs = Object.getOwnPropertyNames(gl.__proto__).filter(function(p) {
return typeof gl[p] === 'function';
});
function HookFunction(func, callback) {
return function() {
var res = func.apply(this, arguments);
callback(arguments);
return res;
};
}
var endFrame = false;
var afterFrame = 8;
funcs.forEach(function(funcName) {
gl[funcName] = HookFunction(gl[funcName], function(args) {
if (endFrame) {
if (afterFrame == 0) {
return;
}
afterFrame -= 1;
}
if (funcName == "drawElements") {
endFrame = true;
}
var KK = [];
var dumpArr = [];
for (var item in args) {
var arg = args[item];
if (arg === null) {
KK.push("null");
} else if (arg instanceof ArrayBuffer || arg instanceof Float32Array || arg instanceof Uint8Array || arg instanceof Uint16Array) {
dumpArr.push(new Uint8Array(arg.buffer));
} else {
KK.push(arg);
}
}
console.log("WebGL Interceptor: ", funcName, "(", KK.join(', '), ")");
if (dumpArr.length) {
console.log(dumpArr);
}
});
});
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.CULL_FACE);
gl.disable(gl.STENCIL_TEST);
gl.enable(gl.BLEND);
gl.enable(gl.SCISSOR_TEST);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, 800, 600);
gl.scissor(0, 0, 800, 600);
gl.clearColor(0.06274509803921569, 0.6, 0.7333333333333333, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
var vertexDataCount = 4;
var vertexByteSize = vertexDataCount * 4;
var BatchSize = 2000;
var totalIndices = BatchSize * 6;
var vertices = new ArrayBuffer(BatchSize * vertexByteSize * 4);
var indices = new ArrayBuffer(totalIndices * 2);
var indicesUint16View = new Uint16Array(indices);
var verticesFloat32View = new Float32Array(vertices);
var j = 0;
for (var i = 0; i < totalIndices; i += 6, j += 4) {
indicesUint16View[i + 0] = j + 0;
indicesUint16View[i + 1] = j + 1;
indicesUint16View[i + 2] = j + 2;
indicesUint16View[i + 3] = j + 0;
indicesUint16View[i + 4] = j + 2;
indicesUint16View[i + 5] = j + 3;
}
var indexBuffer = gl.createBuffer();
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indicesUint16View, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesFloat32View, gl.DYNAMIC_DRAW);
function compileShader(shaderSource, shaderType) {
var shader = gl.createShader(shaderType);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!success) {
throw "could not compile shader:" + gl.getShaderInfoLog(shader);
}
return shader;
}
function createProgram(vertexShader, fragmentShader) {
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
var success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!success) {
throw ("program filed to link:" + gl.getProgramInfoLog(program));
}
return program;
}
var vertexShad = compileShader(vertexShaderSrc, gl.VERTEX_SHADER);
var fragShad = compileShader(fragmentShaderSrc, gl.FRAGMENT_SHADER);
var shaderProg = createProgram(vertexShad, fragShad);
gl.useProgram(shaderProg);
var vertLoc = gl.getAttribLocation(shaderProg, "aVertexPosition");
var texCoordLoc = gl.getAttribLocation(shaderProg, "aTextureCoord");
gl.enableVertexAttribArray(vertLoc);
gl.enableVertexAttribArray(texCoordLoc);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.vertexAttribPointer(vertLoc, 2, gl.FLOAT, false, vertexByteSize, 0);
gl.vertexAttribPointer(texCoordLoc, 2, gl.FLOAT, false, vertexByteSize, 2 * 4);
var currIndex = 0;
verticesFloat32View[currIndex++] = 174; // pos
verticesFloat32View[currIndex++] = 113; // pos
verticesFloat32View[currIndex++] = 0; // UV
verticesFloat32View[currIndex++] = 0; // UV
verticesFloat32View[currIndex++] = 226; // pos
verticesFloat32View[currIndex++] = 113; // pos
verticesFloat32View[currIndex++] = 1; // UV
verticesFloat32View[currIndex++] = 0; // UV
verticesFloat32View[currIndex++] = 226; // pos
verticesFloat32View[currIndex++] = 187; // pos
verticesFloat32View[currIndex++] = 1; // UV
verticesFloat32View[currIndex++] = 1; // UV
verticesFloat32View[currIndex++] = 174; // pos
verticesFloat32View[currIndex++] = 187; // pos
verticesFloat32View[currIndex++] = 0; // UV
verticesFloat32View[currIndex++] = 1; // UV
gl.bufferSubData(gl.ARRAY_BUFFER, 0, verticesFloat32View);
// | 2 / Width | 0 | -1
// | 0 | 2 / Height | -1
// | 0 | 0 | 1
var rawProjectionMat = new Float32Array([
0.00249999994, 0, 0, 0, -0.00333333341, 0, -1, 1, 1
]);
gl.uniformMatrix3fv(gl.getUniformLocation(shaderProg, "projectionMatrix"), false, rawProjectionMat);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
gl.activeTexture(gl.TEXTURE0);
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img1);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
}
</script>
</body>
</html>
EDIT:
I am using the following image:
https://raw.githubusercontent.com/pixijs/examples/gh-pages/_assets/bunny.png
I'm just guessing the issue is no where did you set the size of your canvas element's content.
The number of actual pixels in the canvas element defaults to 300x150. you can set that in HTML with
<canvas width="800" height="600"></canvas>
or you can set it in JavaScript with
someCanvasElement.width = 800;
someCanvasElement.height = 600;
Firefox is warning you that you set the viewport to 800x600 but it's larger than your canvas (300x150) which is very unusual and the warning was to help you notice the issue.
FYI: gl.viewport only does 2 things. It sets the conversion from clip space to screen space (or in this case canvas space) and it sets the clipping region for vertices. 'clipping vertices' means it does not clip pixels so drawing a gl_PointSize = 10.0 point at the edge of the viewport setting will draw outside the viewport setting.
To clip pixels use the scissor test. I see you're setting up a scissor test but since you apparently want to draw to the edge of the canvas you don't need to setup the scissor at all.

Resources