I'm learning webgl and trying to drop different objects from top of the canvas. Every time an object reaches the bottom a new object drops from the top.
This is working, but I wanna keep the object on the bottom. Every time a new obect drops from the dop the previous object disappears.
How can I solve this?
function initWebGL() {
canvas = document.getElementById("my-canvas");
gl = WebGLUtils.setupWebGL(canvas);
document.addEventListener("keydown", keyDown, false);
if(gl) {
setupWebGL();
initShaders();
setupBuffers();
getMatrixUniforms();
tick();
}
else{
alert( "Error: Your browser does not appear to support WebGL.");
}
function tick() {
requestAnimFrame(tick);
drawScene();
animate();
}
function setupBuffers() {
l_VerticeBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, l_VerticeBuffer);
var l_Vertices =
[-0.2 ,0.6,0.0,
-0.2,-0.6,0.0,
0.2 ,-0.6,0.0,
0.6 ,-0.6,0.0,
0.6,-0.2,0.0,
0.2,-0.2,0.0,
0.2,0.6,0.0];
l_VerticeBuffer.itemSize = 3;
l_VerticeBuffer.numItems = 7;
gl.bufferData(gl.ARRAY_BUFFER, new float32Array(l_Vertices), gl.DYNAMIC_DRAW);
L_IndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, L_IndexBuffer);
indices = [0,1,2,0,2,6,4,3,2,4,2,5,];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
}
function drawScene(){
gl.viewport(0, 0, canvas.width, canvas.height); //das sind die dinge die i in setupwebgl hab
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(45, canvas.width / canvas.height, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
mvPushMatrix();
mat4.translate(mvMatrix, [move, up_down, -7.0]);
mat4.rotateZ(mvMatrix, y_rot* Math.PI /40.0);
gl.bindBuffer(gl.ARRAY_BUFFER, mirrorLVerticeBuffer); //passt
gl.vertexAttribPointer(vertexPositionAttribute, mirrorLVerticeBuffer.itemSize, gl.FLOAT, false, 0, 0);//passt
gl.bindBuffer(gl.ARRAY_BUFFER, lColorBuffer);
gl.vertexAttribPointer(vertexColorAttribute, lColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mirrorLIndexBuffer);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, indicesL.length, gl.UNSIGNED_SHORT,0);
mvPopMatrix();
}
var lastTime = 0;
function animate() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;
if (up_down > GROUND_Y) {
up_down -= (10 * elapsed) / 1000.0;
}
}
lastTime = timeNow;
}
For every L object you want to draw in the scene you'll need to have a different set of coordinates that says where that specific L object is. In your code you set the x position and y position of the L object with the move and up_down variables.
So create an array of objects where each element represents the coordinates of an L object:
var lObjects = [
{
move: 0,
up_down: 3
}
];
The above array has only one element (so one L shape) to begin with. Also I wasn't sure what your starting values for move and up_down were so I just gave them whatever value I wanted.
Now in your drawScene() loop through the lObjects and draw an L object for every element in lObjects (using the move and up_down values of each element).
function drawScene(){
gl.viewport(0, 0, canvas.width, canvas.height); //das sind die dinge die i in setupwebgl hab
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(45, canvas.width / canvas.height, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
for(var i = 0; i < lObjects.length; i++) {
mvPushMatrix();
mat4.translate(mvMatrix, [lObjects[i].move, lObjects[i].up_down, -7.0]);
mat4.rotateZ(mvMatrix, y_rot* Math.PI /40.0);
gl.bindBuffer(gl.ARRAY_BUFFER, mirrorLVerticeBuffer); //passt
gl.vertexAttribPointer(vertexPositionAttribute, mirrorLVerticeBuffer.itemSize, gl.FLOAT, false, 0, 0);//passt
gl.bindBuffer(gl.ARRAY_BUFFER, lColorBuffer);
gl.vertexAttribPointer(vertexColorAttribute, lColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mirrorLIndexBuffer);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, indicesL.length, gl.UNSIGNED_SHORT,0);
mvPopMatrix();
}
}
Finally update your animate() to use the new lObjects array. Here is a modified version of your animate() that will only update the up_down of the newest L and whenever the newest L reaches the bottom it will add a new L to lObjects (so it will make an infinite amount of Ls).
function animate() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var newestL = lObjects[lObjects.length - 1];
var elapsed = timeNow - lastTime;
if (newestL.up_down > GROUND_Y) {
newestL.up_down -= (10 * elapsed) / 10000.0;
} else {
lObjects.push( { move: 0, up_down: 3 } );
}
}
lastTime = timeNow;
}
Again watch out for the constants I used, you probably don't want to use them, but I wasn't sure what values you were using. I also slowed down the speed at which the Ls fell because it worked better with my constants.
Related
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);
} ```
I started from an example WebGL program that shows a single cube on the page. The example code does not use classes.
I want to be able to draw multiple cubes that can move independently. So I added a "Cube" class. Each instance of this class uses its own "program". I create two objects, but I draw only the first one. Unfortunately the later instantiated object is shown instead. E.g. in the code below "ground" is shown instead of "cube1".
Relevant parts of the code is below. Can you see any problem with it? How can I fix it?
...
////
class Cube {
constructor(gl, color) {
this.gl = gl;
this.program = initShaders(gl, "vertex-shader", "fragment-shader");
//// Model buffers and attributes
[this.pointsArray, this.colorsArray] = cubePointsAndColors(color);
this.numVertices = 36;
this.initAttributeBuffers();
//// Camera Related Uniforms Matrices
this.modelViewMatrixLoc = gl.getUniformLocation(
this.program,
"modelViewMatrix"
);
this.projectionMatrixLoc = gl.getUniformLocation(
this.program,
"projectionMatrix"
);
}
draw() {
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.numVertices);
}
initAttributeBuffers() {
// arrange cube color data stuff
var cBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, cBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.colorsArray),
this.gl.STATIC_DRAW
);
var vColor = this.gl.getAttribLocation(this.program, "vColor");
this.gl.vertexAttribPointer(vColor, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(vColor);
// arrange cube vertex data stuff
var vBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.pointsArray),
this.gl.STATIC_DRAW
);
var vPosition = this.gl.getAttribLocation(this.program, "vPosition");
this.gl.vertexAttribPointer(vPosition, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(vPosition);
}
}
window.onload = function init() {
//// initialize WebGl System
const canvas = document.getElementById("gl-canvas");
const gl = WebGLUtils.setupWebGL(canvas);
if (!gl) {
alert("WebGL isn't available");
}
gl.viewport(0, 0, canvas.width, canvas.height);
aspect = canvas.width / canvas.height;
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.enable(gl.DEPTH_TEST);
//// Initialize game objects
var cube1 = new Cube(gl, vec4(1.0, 0.0, 0.0, 1.0));
var ground = new Cube(gl, vec4(0.0, 1.0, 0.0, 1.0));
let gameObjects = [cube1];
// sliders for viewing parameters
readGUI();
render(gl, gameObjects);
};
////
var render = function(gl, gameObjects) {
//// clear the background
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//// camera settings
eye = vec3(
radius * Math.sin(theta) * Math.cos(phi),
radius * Math.sin(theta) * Math.sin(phi),
radius * Math.cos(theta)
);
modelViewMatrix = lookAt(eye, at, up);
projectionMatrix = perspective(fovy, aspect, near, far);
//// draw all objects
for (let objectI = 0; objectI < gameObjects.length; objectI++) {
const gameObject = gameObjects[objectI];
gl.useProgram(gameObject.program);
gl.uniformMatrix4fv(
gameObject.modelViewMatrixLoc,
false,
flatten(modelViewMatrix)
);
gl.uniformMatrix4fv(
gameObject.projectionMatrixLoc,
false,
flatten(projectionMatrix)
);
gameObject.draw();
}
requestAnimFrame(() => render(gl, gameObjects));
};
...
In WebGL 1.0 drawArrays, uses the vertices which are currently specified by vertexAttribPointer and enabled by enableVertexAttribArray.
Use properties to store the buffer objects (this.cBuffer, this.vBuffer) and attribute indices (this.vColor, this.vPosition):
initAttributeBuffers() {
// arrange cube color data stuff
this.cBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.colorsArray),
this.gl.STATIC_DRAW
);
this.vColor = this.gl.getAttribLocation(this.program, "vColor");
// arrange cube vertex data stuff
this.vBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.pointsArray),
this.gl.STATIC_DRAW
);
this.vPosition = this.gl.getAttribLocation(this.program, "vPosition");
}
Specify and enable the arrays of generic vertex attribute data right before the draw call:
draw() {
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cBuffer);
this.gl.vertexAttribPointer(this.vColor, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(this.vColor);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vBuffer);
this.gl.vertexAttribPointer(this.vPosition, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(this.vPosition);
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.numVertices);
}
In WebGL 2.0 (or by the use of the extension OES_vertex_array_object), that can be simplified by the use of WebGLVertexArrayObjects.
The vertex specification is stated in the vertex array object:
initAttributeBuffers() {
// create vertex array object
this.vao = this.gl.createVertexArray();
this.gl.bindVertexArray(this.vao);
// arrange cube color data stuff
var cBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, cBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.colorsArray),
this.gl.STATIC_DRAW
);
var vColor = this.gl.getAttribLocation(this.program, "vColor");
this.gl.vertexAttribPointer(vColor, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(vColor);
// arrange cube vertex data stuff
var vBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vBuffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
flatten(this.pointsArray),
this.gl.STATIC_DRAW
);
var vPosition = this.gl.getAttribLocation(this.program, "vPosition");
this.gl.vertexAttribPointer(vPosition, 4, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(vPosition);
}
It is sufficient to bind the vertex array before the draw call:
draw() {
this.gl.bindVertexArray(this.vao);
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.numVertices);
}
I am trying to draw two hollow circles that are surrounding a cube which is located at the 0, 0, 0 position..
so far I've implemented the cube and the two circles here is what I get.
there are two strange things happening here.
One is that I want to draw the circles but I can see the lines radiating from the origin.
and two is that interpolated colors, even though I set just one color for the fragment shader.
here is you can see clearly those lines with interpolated color...
here is my vertex shader code and the fragment shader code
"use strict";
const loc_aPosition = 1;
const loc_aColor = 2;
const loc_UVCoord = 3;
const VSHADER_SOURCE =
`#version 300 es
layout(location=${loc_aPosition}) in vec4 aPosition;
layout(location=${loc_aColor}) in vec4 aColor;
layout(location=${loc_UVCoord}) in vec2 UVCoord;
out vec4 vColor;
out vec2 vUVCoord;
uniform mat4 uMVP;
void main()
{
gl_Position = uMVP * aPosition;
vColor = aColor;
vUVCoord = UVCoord;
}`;
const FSHADER_SOURCE =
`#version 300 es
precision mediump float;
in vec4 vColor;
out vec4 fColor;
void main()
{
fColor = vColor;
}`;
and the initilize functions for the two circles and there is the only difference is the target plane.
function init_equator(gl)
{
let vertices = []; // for the vertices
let color = [1, 0, 0]; // red color
for(var i = 0; i <= 360; i+=10)
{
let j = i * Math.PI/180;
let vert = [R * Math.cos(j), 0, R * Math.sin(j)]; // drawing a circle at the XZ plane since it has to be an equator for the cube...
vertices.push( vert[0], vert[1], vert[2] ); // push the vertices
vertices.push( color[0], color[1], color[2]); // set the color
}
const SZ = vertices.BYTES_PER_ELEMENT;
let vao = gl.createVertexArray();
gl.bindVertexArray(vao);
let vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(loc_aPosition, 3, gl.FLOAT, false, SZ * 6, 0); // stride is 6, 3 for positions and 3 for the color
gl.enableVertexAttribArray(loc_aPosition);
gl.vertexAttribPointer(loc_aColor, 3, gl.FLOAT, false, SZ * 6, SZ * 3); // stride is 6, offset is this is because 3 color elements are located after 3 position elements..
gl.enableVertexAttribArray(loc_aColor);
gl.bindVertexArray(null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return { vao, n : vertices.length / 3 }; // since it has three coordinates so devide by 3
}
function init_latitude(gl)
{
let vertices = []; // for the vertices
let color = [1, 0, 0]; // supposed to be the red
for(var i = 0; i <= 360; i+=10)
{
let j = i * Math.PI/180;
let vert = [0, R * Math.cos(j), R * Math.sin(j)]; // drawing a circle on the YZ plane
vertices.push( vert[0], vert[1], vert[2] );
vertices.push( color[0], color[1], color[2]);
}
const SZ = vertices.BYTES_PER_ELEMENT;
let vao = gl.createVertexArray();
gl.bindVertexArray(vao);
let vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(loc_aPosition, 3, gl.FLOAT, false, SZ * 6, 0); // stride is 6, 3 for positions and 3 for the color
gl.enableVertexAttribArray(loc_aPosition);
gl.vertexAttribPointer(loc_aColor, 3, gl.FLOAT, false, SZ * 6, SZ * 3); // stride is 6, offset is this is because 3 color elements are located after 3 position elements..
gl.enableVertexAttribArray(loc_aColor);
gl.bindVertexArray(null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return { vao, n : vertices.length / 3 }; // since it has three coordinates so devide by 3
}
I refer these drawing fucntions from here drawing circle
in the main function I called the draw function like this..
........
MVP.setOrtho(LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR); // setting MVP matrix to orthographic mode
MVP.lookAt(FIXED_X, FIXED_Y, FIXED_Z, 0,0,0, 0,1,0); // Eye position x, y, z Look at position 0, 0, 0 Up vector 0, 1, 0
gl.uniformMatrix4fv(loc_MVP, false, MVP.elements);
gl.bindVertexArray(cube.vao);
gl.drawElements(gl.TRIANGLES, cube.n, gl.UNSIGNED_BYTE, 0)
gl.bindVertexArray(null);
gl.bindVertexArray(equator.vao);
gl.drawArrays(gl.LINE_LOOP, 0, equator.n);
gl.bindVertexArray(null);
gl.bindVertexArray(latitudeCircle.vao);
gl.drawArrays(gl.LINE_LOOP, 0, latitudeCircle.n);
gl.bindVertexArray(null);
I have no ideas why the lines are radiating from the origin and the mixed color...
could somebody help me?
this line, which appears twice in the code you posted
const SZ = vertices.BYTES_PER_ELEMENT;
is SZ will be undefined. vertices is a native JavaScript array, not a typedarray array like Float32Array. After that every calculation with SZ will be 0 or NaN
In other words these lines
gl.vertexAttribPointer(loc_aPosition, 3, gl.FLOAT, false, SZ * 6, 0);
gl.vertexAttribPointer(loc_aColor, 3, gl.FLOAT, false, SZ * 6, SZ * 3);
Will be
gl.vertexAttribPointer(loc_aPosition, 3, gl.FLOAT, false, 0, 0);
gl.vertexAttribPointer(loc_aColor, 3, gl.FLOAT, false, 0, 0);
Which means every other position is a color, and every other color is a position which explains why lines go to the center and why colors are interpolated.
Note that if you had stepped through the code in the debugger you'd have probably seen this issue so it would be good to learn how to use the debugger.
Also FYI unrelated to your issue you don't need to call gl.bindVertexArray twice in a row, once with null and once with the next thing you want to draw with.
this
gl.bindVertexArray(cube.vao);
gl.drawElements(gl.TRIANGLES, cube.n, gl.UNSIGNED_BYTE, 0)
gl.bindVertexArray(null);
gl.bindVertexArray(equator.vao);
gl.drawArrays(gl.LINE_LOOP, 0, equator.n);
gl.bindVertexArray(null);
gl.bindVertexArray(latitudeCircle.vao);
gl.drawArrays(gl.LINE_LOOP, 0, latitudeCircle.n);
gl.bindVertexArray(null);
can just be this
gl.bindVertexArray(cube.vao);
gl.drawElements(gl.TRIANGLES, cube.n, gl.UNSIGNED_BYTE, 0)
gl.bindVertexArray(equator.vao);
gl.drawArrays(gl.LINE_LOOP, 0, equator.n);
gl.bindVertexArray(latitudeCircle.vao);
gl.drawArrays(gl.LINE_LOOP, 0, latitudeCircle.n);
gl.bindVertexArray(null); // this is also not technically needed
Also also, you can use the spread operator.
This
vertices.push( vert[0], vert[1], vert[2] ); // push the vertices
vertices.push( color[0], color[1], color[2]); // set the color
can be this
vertices.push( ...vert ); // push the vertices
vertices.push( ...color ); // set the color
Also you might find these tutorials useful.
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>
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...