Make 3DSierpinskiTriangle spin - javascript

How to make 3DSierpinskiTriangle Spin. I have provided with html and JavaScript code below. You need to add this common folder and it .js files to make it work. It would be very help you anyone can solve this.
....................................................................................................................................................
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>3D Sierpinski Gasket</title>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec3 vPosition;
attribute vec3 vColor;
varying vec4 color;
void
main()
{
gl_Position = vec4(vPosition, 1.0);
color = vec4(vColor, 1.0);
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 color;
void
main()
{
gl_FragColor = color;
}
</script>
<script type="text/javascript" src="Common/webgl-utils.js"></script>
<script type="text/javascript" src="Common/initShaders.js"></script>
<script type="text/javascript" src="Common/MV.js"></script>
<script type="text/javascript" src="3DSierpinskiTriangle.js"></script>
</head>
<body>
<canvas id="gl-canvas" width="512" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>
"use strict";
var canvas;
var gl;
var points = [];
var colors = [];
var NumTimesToSubdivide = 3;
window.onload = function init() {
canvas = document.getElementById("gl-canvas");
gl = WebGLUtils.setupWebGL(canvas);
if (!gl) { alert("WebGL isn't available"); }
//
// Initialize our data for the Sierpinski Gasket
//
// First, initialize the vertices of our 3D gasket
// Four vertices on unit circle
// Intial tetrahedron with equal length sides
var vertices = [
vec3(0.0000, 0.0000, -1.0000),
vec3(0.0000, 0.9428, 0.3333),
vec3(-0.8165, -0.4714, 0.3333),
vec3(0.8165, -0.4714, 0.3333)
];
divideTetra(vertices[0], vertices[1], vertices[2], vertices[3],
NumTimesToSubdivide);
//
// Configure WebGL
//
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
// enable hidden-surface removal
gl.enable(gl.DEPTH_TEST);
// Load shaders and initialize attribute buffers
var program = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(program);
// Create a buffer object, initialize it, and associate it with the
// associated attribute variable in our vertex shader
var cBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW);
var vColor = gl.getAttribLocation(program, "vColor");
gl.vertexAttribPointer(vColor, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vColor);
var vBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW);
var vPosition = gl.getAttribLocation(program, "vPosition");
gl.vertexAttribPointer(vPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
render();
};
function triangle(a, b, c, color) {
// add colors and vertices for one triangle
var baseColors = [
vec3(1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 0.0, 1.0),
vec3(0.0, 0.0, 0.0)
];
colors.push(baseColors[color]);
points.push(a);
colors.push(baseColors[color]);
points.push(b);
colors.push(baseColors[color]);
points.push(c);
}
function tetra(a, b, c, d) {
// tetrahedron with each side using
// a different color
triangle(a, c, b, 0);
triangle(a, c, d, 1);
triangle(a, b, d, 2);
triangle(b, c, d, 3);
}
function divideTetra(a, b, c, d, count) {
// check for end of recursion
if (count === 0) {
tetra(a, b, c, d);
}
// find midpoints of sides
// divide four smaller tetrahedra
else {
var ab = mix(a, b, 0.5);
var ac = mix(a, c, 0.5);
var ad = mix(a, d, 0.5);
var bc = mix(b, c, 0.5);
var bd = mix(b, d, 0.5);
var cd = mix(c, d, 0.5);
--count;
divideTetra(a, ab, ac, ad, count);
divideTetra(ab, b, bc, bd, count);
divideTetra(ac, bc, c, cd, count);
divideTetra(ad, bd, cd, d, count);
}
}
function render() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, points.length);
}

function setup() { createCanvas(windowWidth, windowHeight); background(0); } function draw() { fill("#0002") noStroke() rect(0,0,width,height) recursivePyramid() } function dot(x, y) { this.x = x this.y = y this.plot = function() { fill("white") rect(this.x-1, this.y-1, 2, 2) } } function lineDot(from, to) { stroke("#fff5") strokeWeight(2) line(from.x,from.y, to.x, to.y) } function pyramid(x, y, rot, size) { down = [] down[0] = new dot(2,0) down[1] = new dot(10,1) down[2] = new dot(50,2) up = new dot(250,3) middle = new dot(31250,4) middle.plot() this.center = new dot(6250,5) this.center.plot() y = y + size/3*1 down[0].x = sin(2/3 * PI + rot) * size + x down[0].y = cos(2/3 * PI + rot) * size/4 + y down[1].x = sin(2 * 2/3 * PI + rot) * size + x down[1].y = cos(2 * 2/3 * PI + rot) * size/4 + y down[2].x = sin(3 * 2/3 * PI + rot) * size + x down[2].y = cos(3 * 2/3 * PI + rot) * size/4 + y up.x = x up.y = y - size down[0].plot() down[1].plot() down[2].plot() up.plot() lineDot(down[0], up) lineDot(down[1], up) lineDot(down[2], up) lineDot(down[1], down[0]) lineDot(down[2], down[1]) lineDot(down[0], down[2]) } function recursivePyramid(x = width/2, y = height/2, rot = frameCount/70, size = 250) { if (size > 10) { pyramid(x, y, rot, size) recursivePyramid(x, y - size/2, rot*2, size/2) recursivePyramid(x + size, y + size/2, rot+size*sin(rot/10)/99, size/2) recursivePyramid(x - size, y + size/2, rot+size*sin(rot/10)/99, size/2) } }

Related

Make triangle rotate/animate with radio button

I've been working on a WebGl animation program where there are buttons that you can choose to alter a triangle vertice location based on where you click on the screen as well as a slider that runs a recursive function that divides the triangle based on the input. The part i'm stuck on is my last radio button that is supposed to constantly rotate my triangle including the edits to whatever previous changed were made to the triangle with the buttons.
Every time I run my application it gives me a warning pointing to javascript line 149 my render2 function: gl.uniform1f(thetaLoc, theta); saying: sierpinski-extended.js:149 WebGL: INVALID_OPERATION: uniform1f: location not for current program.
The code below isn't going to work because I need to add external libraries and i'm not sure how to. Though I have uploaded my project on my website: https://www.cis.gvsu.edu/~nunezjo/labs/sierpinski-extended/sierpinski-extended.html
Here's an example of my working rotation with no other attributes or buttons added to the mix.
https://www.cis.gvsu.edu/~nunezjo/labs/triangle-rotate/triangle-rotate.html
You can inspect element there if needed. Any help would be awesome! I'm so stuck.
JAVASCRIPT
"use strict";
var canvas;
var gl;
var points = [];
var numTimesToSubdivide = 0;
var theta = 0.0;
var thetaLoc;
var x1 = -1;
var y1 = -1;
var x2 = 0;
var y2 = 1;
var x3 = 1;
var y3 = -1;
function init() {
canvas = document.getElementById("gl-canvas");
gl = WebGLUtils.setupWebGL(canvas);
if (!gl) {
alert("WebGL isn't available");
}
//
// Initialize our data for the Sierpinski Gasket
//
// First, initialize the corners of our gasket with three points.
var vertices = [
vec2(x1, y1),
vec2(x2, y2),
vec2(x3, y3)
];
divideTriangle(vertices[0], vertices[1], vertices[2],
numTimesToSubdivide);
//
// Configure WebGL
//
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
// Load shaders and initialize attribute buffers
var program = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(program);
// Load the data into the GPU
var bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER, 50000, gl.STATIC_DRAW);
gl.bufferSubData(gl.ARRAY_BUFFER, 0, flatten(points));
// Associate out shader variables with our data buffer
var vPosition = gl.getAttribLocation(program, "vPosition");
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
document.getElementById("slider").onchange = function(event) {
numTimesToSubdivide = parseInt(event.target.value);
};
canvas.addEventListener("mouseup", function(event) {
var rect = gl.canvas.getBoundingClientRect();
var newx = (event.clientX - rect.left) / canvas.width * 2 - 1;
var newy = (event.clientY - rect.top) / canvas.height * -2 + 1;
console.log(newx, newy);
var vertex_id = document.querySelector('input[name="vertex"]:checked').value;
if (vertex_id == 0) {
x1 = newx;
y1 = newy;
} else if (vertex_id == 1) {
x2 = newx;
y2 = newy;
} else if (vertex_id == 2) {
x3 = newx;
y3 = newy;
} else {
thetaLoc = gl.getUniformLocation(program, "theta");
render2(vertex_id);
}
});
render1();
};
function triangle(a, b, c) {
points.push(a, b, c);
}
function divideTriangle(a, b, c, count) {
// check for end of recursion
if (count === 0) {
triangle(a, b, c);
} else {
//bisect the sides
var ab = mix(a, b, 0.5);
var ac = mix(a, c, 0.5);
var bc = mix(b, c, 0.5);
--count;
// three new triangles
divideTriangle(a, ab, ac, count);
divideTriangle(c, ac, bc, count);
divideTriangle(b, bc, ab, count);
}
}
window.onload = init;
function render1() {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, points.length);
points = [];
requestAnimFrame(init);
}
function render2(button_id) {
gl.clear(gl.COLOR_BUFFER_BIT);
theta += 0.092;// this is the amount that will be rotating the object the bigger the number the faster.
gl.uniform1f(thetaLoc, theta);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, points.length);
while (button_id == 3) { // while rotate button is pressed run loop on render 2 else call init
init(); // running init first so it can keep track if the button_id changes.
requestAnimFrame(render2);
}
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title> Sierpinski Extended</title>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition; uniform float theta; void main() { gl_Position = vPosition; float s = sin( theta ); float c = cos( theta ); gl_Position.x = -s * vPosition.y + c * vPosition.x; gl_Position.y = s * vPosition.x + c * vPosition.y; gl_Position.z
= 0.0; gl_Position.w = 1.0; }
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float; void main() { gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 ); }
</script>
<script type="text/javascript" src="../Common/webgl-utils.js"></script>
<script type="text/javascript" src="../Common/initShaders.js"></script>
<script type="text/javascript" src="../Common/MV.js"></script>
<script type="text/javascript" src="sierpinski-extended.js"></script>
</head>
<body>
<div>
recursive steps 0 <input id="slider" type="range" min="0" max="6" step="1" value="0" /> 6
</div>
<div>
Vertex:
<input type="radio" name="vertex" value="0" checked> 0
<input type="radio" name="vertex" value="1"> 1
<input type="radio" name="vertex" value="2"> 2
<input type="radio" name="vertex" value="3"> rotate
</div>
<canvas id="gl-canvas" width="512" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>

How can I delete a specific object in Webgl (Without library)

I'm studying webgl.
Now I spray the food to a random location on the canvas, and when the mouse pointer and the food collide, I try to delete the food.
(The collision implementation of the mouse cursor is another issue, but it is not necessary now.)
However, no matter how many times I looked for it, I could not find a way to erase a specific object even if I explained how to draw it. Is there a way to delete only certain objects from canvas without a library?
The full text of my code is as follows.
var gl;
var points;
window.onload = function init()
{
var canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
// Four Vertices
var vertices = [
vec2( -0.5, -0.5 ),
vec2( -0.5, 0.5 ),
vec2( 0.5, 0.5 ),
vec2( 0.5, -0.5)
];
//
// Configure WebGL
//
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
// Load shaders and initialize attribute buffers
var program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
// Load the data into the GPU
var bufferId = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, bufferId );
//gl.bufferData( gl.ARRAY_BUFFER, flatten(vertices), gl.STATIC_DRAW );
// Associate out shader variables with our data buffer
var foodX, foodY;
var foodSize = 20;
var foodNumber = 50;
var vPosition = gl.getAttribLocation( program, "vPosition" );
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 2; // 2 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer( vPosition, size, type, normalize, stride, offset);
gl.enableVertexAttribArray( vPosition );
// we added a uniform called vResolution.
var vResolution = gl.getUniformLocation(program, "vResolution");
var fColor = gl.getUniformLocation(program, "fColor");
// set the resolution
gl.uniform2f(vResolution, gl.canvas.width, gl.canvas.height);
// draw 50 random rectangles in random colors
while (foodNumber > 0) {
// Setup a random rectangle
// This will write to positionBuffer because
// its the last thing we bound on the ARRAY_BUFFER
// bind point
//food 좌표는 canvas width와 height 사이에 있도록 하며, canvas 밖으로 빠져나가지 않도록 조절한다.
foodX = randomInt(canvas.width - foodSize);
foodY = randomInt(canvas.height-foodSize);
setRectangle(gl, foodX, foodY, foodSize, foodSize);
foodNumber = foodNumber - 1;
// Set a random color.
gl.uniform4f(fColor, Math.random(), Math.random(), Math.random(), 1);
// Draw the rectangle.
var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = 6;
gl.drawArrays(primitiveType, offset, count);
}
};
// Returns a random integer from 0 to range - 1.
function randomInt(range) {
return Math.floor(Math.random() * range);
}
// Fills the buffer with the values that define a rectangle.
function setRectangle(gl, x, y, width, height) {
var x1 = x;
var x2 = x + width;
var y1 = y;
var y2 = y + height;
// NOTE: gl.bufferData(gl.ARRAY_BUFFER, ...) will affect
// whatever buffer is bound to the `ARRAY_BUFFER` bind point
// but so far we only have one buffer. If we had more than one
// buffer we'd want to bind that buffer to `ARRAY_BUFFER` first.
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2]), gl.STATIC_DRAW);
}
function pop(bufferName){
gl.deleteBuffer(bufferName)
}
<!DOCTYPE html>
<html>
<head>
<script id="vertex-shader" type="x-shader/x-vertex">
//attribute vec4 vPosition;
attribute vec2 vPosition;
uniform vec2 vResolution;
void
main()
{
// convert the position from pixels to 0.0 to 1.0
vec2 zeroToOne = vPosition / vResolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clip space)
vec2 clipSpace = zeroToTwo - 1.0;
//gl_Position = vec4(clipSpace, 0.0, 1.0);
// To get it to be the more traditional top left corner used for 2d graphics APIs we can just flip the clip space y coordinate.
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 fColor;
void
main()
{
gl_FragColor = fColor;
}
</script>
<script type="text/javascript" src="../Common/webgl-utils.js"></script>
<script type="text/javascript" src="../Common/initShaders.js"></script>
<script type="text/javascript" src="../Common/MV.js"></script>
<script type="text/javascript" src="snakeGame.js"></script>
</head>
<body>
<canvas id="gl-canvas" width="1024" height="800">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
<script>
var canvas =
</script>
</body>
</html>
There is no such thing as "deleting an object" at the webgl. WebGL is just an API that draws pixels into a canvas. "Objects" are a higher level concept that your code deals with.
You generally keep your own list of things to draw (whether that is the same as your list of objects or not is up to you)
Every "frame" you clear the canvas and then draw all things you want to draw
render function:
clear the canvas
for each thing to draw
draw thing
So "deleting" an object is a matter of not drawing it.
See this and this and this
As an example
const thingsToDraw = [
{ color: [1, 0, 0, 1], center: [0.2, 0.3], },
{ color: [0, 1, 0, 1], center: [0.0, 0.1], },
{ color: [0, 0, 1, 1], center: [-0.5, -0.4], },
{ color: [1, 0.5, 0, 1], center: [-0.2, 0.3], },
{ color: [0, 1, 1, 1], center: [0.7, -0.1], },
{ color: [1, 0, 1, 1], center: [-0.5, 0.4], },
];
const gl = document.querySelector('canvas').getContext('webgl');
const prg = twgl.createProgram(gl, [`
uniform vec4 position;
void main() {
gl_PointSize = 20.0;
gl_Position = position;
}`,`
precision mediump float;
uniform vec4 color;
void main() {
gl_FragColor = color;
}
`]);
const positionLoc = gl.getUniformLocation(prg, "position");
const colorLoc = gl.getUniformLocation(prg, "color");
function drawThing(color, position) {
gl.useProgram(prg);
gl.uniform4f(positionLoc, ...position, 0, 1);
gl.uniform4fv(colorLoc, color);
gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point
}
function render(time) {
time *= 0.001;
gl.clear(gl.COLOR_BUFFER_BIT);
thingsToDraw.forEach((thing, i) => {
const t = time * 10 + i;
const position = [
thing.center[0] + Math.cos(t) * 0.1,
thing.center[1] + Math.sin(t) * 0.1,
];
drawThing(thing.color, position);
});
requestAnimationFrame(render);
}
requestAnimationFrame(render);
document.querySelector('button').addEventListener('click', () => {
thingsToDraw.splice(0, 1);
});
canvas { border: 1px solid black; }
<canvas></canvas>
<button type="button">remove first thing</button>
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
How you decide to track and organize your "objects" or your "things to draw" is entirely up to you. Many 3D systems use a scene graph and then draw the entire graph every frame so 2 ways of not drawing something is to either remove it from the graph or else add some flag to each node whether or not to draw it.
In other systems the scene graph is separate from the list of things to draw.
For small programs people might just use an array (like the example above)

WebGL Renders pixelated lines

Im trying to render simple shapes ( circles, rectangles and triangles , however, they become very pixelated when WebGL Renders them.
Shader code:
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
// convert the rectangle points from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}
</script>
Here is my code for rendering the circle:
var WebGLRenderer = (function () {
function WebGLRenderer() {
this.canvas = document.getElementById('canvas')
this.gl = this.canvas.getContext('webgl') || this.canvas.getContext('experimental-webgl')
if (!this.gl) {
throw Error('Your browser does not support WebGL')
return
}
// Programs
this.rectangleProgram = webglUtils.createProgramFromScripts(this.gl, ['2d-vertex-shader', '2d-fragment-shader'])
// Locations
this.rectanglePoisitionLocation = this.gl.getAttribLocation(this.rectangleProgram, 'a_position')
// Uniforms
this.rectangleResolutionLocation = this.gl.getUniformLocation(this.rectangleProgram, 'u_resolution')
this.rectangleColorLocation = this.gl.getUniformLocation(this.rectangleProgram, 'u_color')
// this.positionBuffer = this.gl.createBuffer()
this.rectanglePositionBuffer = this.gl.createBuffer()
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer)
requestAnimationFrame(this.render.bind(this))
}
WebGLRenderer.prototype.clearCanvas = function (color) {
var rgba = color.getColor()
this.gl.clearColor(...rgba)
this.gl.clear(this.gl.COLOR_BUFFER_BIT)
}
WebGLRenderer.prototype.drawCircle = function (x, y, radius, color) {
// Render circle
// For now user rectangleProgram
this.gl.useProgram(this.rectangleProgram)
this.gl.enableVertexAttribArray(this.rectanglePoisitionLocation)
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer)
this.circleBuffer = this.gl.createBuffer()
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectanglePositionBuffer)
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.circleBuffer)
// Setup circle
var circleVertices = [x, y]
var numFans = 360
var anglePerFan = (2 * Math.PI) / numFans
for (var i = 0; i <= numFans; i++) {
var angle = anglePerFan * (i + 1)
var angledX = x + Math.cos(angle) * radius
var angledY = y + Math.sin(angle) * radius
circleVertices.push(angledX, angledY)
// circleVertices.push()
}
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(circleVertices), this.gl.DYNAMIC_DRAW)
// this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW)
var size = 2
var type = this.gl.FLOAT
var normalize = false
var stride = 0
var offset = 0
this.gl.vertexAttribPointer(this.rectanglePoisitionLocation, size, type, normalize, stride, offset)
this.gl.uniform2f(this.rectangleResolutionLocation, this.gl.canvas.width, this.gl.canvas.height)
// Color
var colorArray = color.getColor()
this.gl.uniform4fv(this.rectangleColorLocation, colorArray)
// Draw rectangle
var primitiveType = this.gl.TRIANGLE_FAN
// var primitiveType = this.gl.POINTS
var offset = 0
var count = circleVertices.length / size
// var count = positions.length / size
this.gl.drawArrays(primitiveType, offset, count)
}
WebGLRenderer.prototype.render = function (time) {
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height)
var delta = Math.sin(time / 1000) * 10
this.clearCanvas(new Color(0, 0, 0, 255))
var rectangleColor = new Color(0, 65, 255, 255)
var width = 50
var height = 50
var circleColor = new Color(0, 167, 255, 255)
this.drawCircle(10, 10, 10, circleColor)
requestAnimationFrame(this.render.bind(this))
}
return WebGLRenderer
})()
function Color(r, g, b, a) {
this.r = r
this.g = g
this.b = b
this.a = a
this.getColor = function () {
return [r / 255, g / 255, b / 255, a / 255]
}
}
var renderer = new WebGLRenderer()
Results: blurry circle (everything I render with WebGL is blurry)
See fiddle for results: https://jsfiddle.net/xLwmngav/1/
Expected results: a smooth round circle
Any help is appreciated. Thank you in advance.
As is pointed out in this article canvases have 2 sizes, their resolution (how many pixels are in them) and the size they are displayed.
Generally you want the resolution to match or exceed the size the canvas is displayed. The best way to do that is to to check, just before rendering, if the canvas's resolution matches the size it's displayed and if it's not to resize it with a function like this
function resize(canvas) {
// Lookup the size the browser is displaying the canvas.
const desiredWidth = canvas.clientWidth;
const desiredHeight = canvas.clientHeight;
// Check if the canvas is not the same size.
if (canvas.width !== desiredWidth ||
canvas.height !== desiredHeight) {
// Make the canvas the same size
canvas.width = desiredWidth;
canvas.height = desiredHeight;
}
}
And use it like this
function render() {
resize(canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
... draw here ...
...
example:
function resize(canvas) {
// Lookup the size the browser is displaying the canvas.
const desiredWidth = canvas.clientWidth;
const desiredHeight = canvas.clientHeight;
// Check if the canvas is not the same size.
if (canvas.width !== desiredWidth ||
canvas.height !== desiredHeight) {
// Make the canvas the same size
canvas.width = desiredWidth;
canvas.height = desiredHeight;
}
}
var WebGLRenderer = (function () {
function WebGLRenderer() {
this.canvas = document.getElementById('canvas')
this.gl = this.canvas.getContext('webgl') || this.canvas.getContext('experimental-webgl')
if (!this.gl) {
throw Error('Your browser does not support WebGL')
return
}
// Programs
this.rectangleProgram = webglUtils.createProgramFromScripts(this.gl, ['2d-vertex-shader', '2d-fragment-shader'])
// Locations
this.rectanglePoisitionLocation = this.gl.getAttribLocation(this.rectangleProgram, 'a_position')
// Uniforms
this.rectangleResolutionLocation = this.gl.getUniformLocation(this.rectangleProgram, 'u_resolution')
this.rectangleColorLocation = this.gl.getUniformLocation(this.rectangleProgram, 'u_color')
// this.positionBuffer = this.gl.createBuffer()
this.rectanglePositionBuffer = this.gl.createBuffer()
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer)
requestAnimationFrame(this.render.bind(this))
}
WebGLRenderer.prototype.clearCanvas = function (color) {
var rgba = color.getColor()
this.gl.clearColor(...rgba)
this.gl.clear(this.gl.COLOR_BUFFER_BIT)
}
WebGLRenderer.prototype.drawCircle = function (x, y, radius, color) {
// Render circle
// For now user rectangleProgram
this.gl.useProgram(this.rectangleProgram)
this.gl.enableVertexAttribArray(this.rectanglePoisitionLocation)
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer)
this.circleBuffer = this.gl.createBuffer()
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectanglePositionBuffer)
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.circleBuffer)
// Setup circle
var circleVertices = [x, y]
var numFans = 360
var anglePerFan = (2 * Math.PI) / numFans
for (var i = 0; i <= numFans; i++) {
var angle = anglePerFan * (i + 1)
var angledX = x + Math.cos(angle) * radius
var angledY = y + Math.sin(angle) * radius
circleVertices.push(angledX, angledY)
// circleVertices.push()
}
/*var circleVertices = [
x, y,
15, 18,
5, 18,
0, 10,
4, 1,
14, 1,
20, 9,
15, 18
]*/
// three 2d points
// TODO: Research static draw
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(circleVertices), this.gl.DYNAMIC_DRAW)
// this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW)
var size = 2
var type = this.gl.FLOAT
var normalize = false
var stride = 0
var offset = 0
this.gl.vertexAttribPointer(this.rectanglePoisitionLocation, size, type, normalize, stride, offset)
this.gl.uniform2f(this.rectangleResolutionLocation, this.gl.canvas.width, this.gl.canvas.height)
// Color
var colorArray = color.getColor()
this.gl.uniform4fv(this.rectangleColorLocation, colorArray)
// Draw rectangle
var primitiveType = this.gl.TRIANGLE_FAN
// var primitiveType = this.gl.POINTS
var offset = 0
var count = circleVertices.length / size
// var count = positions.length / size
this.gl.drawArrays(primitiveType, offset, count)
}
WebGLRenderer.prototype.render = function (time) {
resize(this.gl.canvas);
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height)
var delta = Math.sin(time / 1000) * 10
this.clearCanvas(new Color(0, 0, 0, 255))
var rectangleColor = new Color(0, 65, 255, 255)
var width = 50
var height = 50
var circleColor = new Color(0, 167, 255, 255)
this.drawCircle(10, 10, 10, circleColor)
requestAnimationFrame(this.render.bind(this))
}
return WebGLRenderer
})()
function Color(r, g, b, a) {
this.r = r
this.g = g
this.b = b
this.a = a
this.getColor = function () {
return [r / 255, g / 255, b / 255, a / 255]
}
}
var renderer = new WebGLRenderer()
window.WebGLRenderer = WebGLRenderer
body {
margin: 0;
}
#canvas {
display: block; /* prevents scrollbar */
width: 100vw;
height: 100vh;
}
<canvas id="canvas"></canvas>
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
// convert the rectangle points from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}
</script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/m3.js"></script>
The canvas defaults to a width and height of 300x150 pixels. These are attributes of the <canvas> element, not CSS properties. By scaling to 100vw by 100vh, you're just stretching those 300x150 pixels out to fill the screen.
To actually get a 1:1 mapping from canvas pixels to screen pixels, you need to set the width and height of the canvas to the size of the window:
this.canvas.width = window.innerWidth
this.canvas.height = window.innerHeight
You may also want to listen for the resize event on window and update the canvas size accordingly.
Fiddle: https://jsfiddle.net/kL1a2zpr/

WebGL Resetting vertex positions

I am creating a simple webgl program that puts 3 random vertices on the canvas and connects them into a triangle. I tried to add translation to move the triangle to the right (increase the X value of each vertex), but of course if it goes forever, the triangle will go out of the canvas. Does anyone know how to detect if the vertex has an x value above 1 and if yes, reset the position of the given vertex because my solution doesnt seem to do anything, its like it doesnt even trigger
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");
gl.clearColor(0.1, 0.2, 0.2, 1.0);
gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
var indices = [0, 0, 0, 0, 0, 0];
for (var points = 0; points < 6; points++) {
indices[points] = (Math.random() * 2) - 1;
//indices[points + 1] = Math.random() < 0.5 ? -1 : 1;
}
var buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(indices),
gl.STATIC_DRAW);
var vert = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vert, `
precision mediump float;
attribute vec2 position;
uniform vec2 translation;
void main(){
gl_Position = vec4(position + translation, 0.0, 1.0);
}
`);
gl.compileShader(vert);
var success1 = gl.getShaderParameter(vert, gl.COMPILE_STATUS);
if (!success1) {
// Something went wrong during compilation; get the error
throw gl.getShaderInfoLog(vert);
}
var frag = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(frag, `
precision mediump float;
void main(){
gl_FragColor = vec4(0.3, 0.6, 0.4, 1.0);
}
`);
gl.compileShader(frag);
var success2 = gl.getShaderParameter(frag, gl.COMPILE_STATUS);
if (!success2) {
// Something went wrong during compilation; get the error
throw gl.getShaderInfoLog(frag);
}
var program = gl.createProgram();
gl.attachShader(program, vert);
gl.attachShader(program, frag);
gl.linkProgram(program);
var vertLoc = gl.getAttribLocation(program, "position");
gl.vertexAttribPointer(vertLoc, 2, gl.FLOAT, gl.FALSE, 0, 0);
gl.enableVertexAttribArray(vertLoc);
gl.useProgram(program);
var trans = gl.getUniformLocation(program, "translation");
var translation = [0.0, 0.0];
gl.uniform2fv(trans, translation);
gl.drawArrays(gl.TRIANGLES, 0, 3);
function loop() {
gl.clearColor(0.1, 0.2, 0.2, 1.0);
gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
translation[0] += 0.01;
gl.uniform2fv(trans, translation);
gl.drawArrays(gl.TRIANGLES, 0, 3);
for (var points = 0; points < 6; points++) {
if (indices[points] % 2 == 0) {
if (indices[points] + translation[0] > 1) {
indices[points] = (Math.random() * 2) - 1;
}
}
//indices[points + 1] = Math.random() < 0.5 ? -1 : 1;
}
requestAnimationFrame(loop);
}
loop();
<canvas id="canvas"></canvas>
To achieve this, consider making the following changes to your code:
remove placement of vertices by translation in your vertex shader to give you "per-vertex" control over placement of the geometry (the translation effectivly means "object-level" placement which isn't what your want here)
when you iterate over the points in your loop(), you checking modulo over the vertex coordinate. You should be performing that check on the iteration index like this: if (points % 2 == 0)
now that the translation concept is gone, update the position of the vertex coordinate, rather the translation array after the modulo check: indices[points] += 0.01;
finally, seeing you're updating the indices vertex data, you'll need to update the webgl buf to ensure your changes are reflected when the next frame is rendered:
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(indices), gl.STATIC_DRAW);
Here's the updated script in full:
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");
gl.clearColor(0.1, 0.2, 0.2, 1.0);
gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
var indices = [0, 0, 0, 0, 0, 0];
for (var points = 0; points < 6; points++) {
indices[points] = (Math.random() * 2) - 1;
}
var buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(indices),
gl.STATIC_DRAW);
var vert = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vert, `
precision mediump float;
attribute vec2 position;
void main(){
gl_Position = vec4(position, 0.0, 1.0);
}
`);
gl.compileShader(vert);
var success1 = gl.getShaderParameter(vert, gl.COMPILE_STATUS);
if (!success1) {
throw gl.getShaderInfoLog(vert);
}
var frag = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(frag, `
precision mediump float;
void main(){
gl_FragColor = vec4(0.3, 0.6, 0.4, 1.0);
}
`);
gl.compileShader(frag);
var success2 = gl.getShaderParameter(frag, gl.COMPILE_STATUS);
if (!success2) {
throw gl.getShaderInfoLog(frag);
}
var program = gl.createProgram();
gl.attachShader(program, vert);
gl.attachShader(program, frag);
gl.linkProgram(program);
var vertLoc = gl.getAttribLocation(program, "position");
gl.vertexAttribPointer(vertLoc, 2, gl.FLOAT, gl.FALSE, 0, 0);
gl.enableVertexAttribArray(vertLoc);
gl.useProgram(program);
gl.drawArrays(gl.TRIANGLES, 0, 3);
function loop() {
gl.clearColor(0.1, 0.2, 0.2, 1.0);
gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
// Update the vertex data, causing the vertex x coordinate to increase per-frame
for (var points = 0; points < 6; points++) {
// Only process x coordinate
if (points % 2 == 0) {
// Increase x coordinate per-frame
indices[points] += 0.01;
// If x position > 1 reset it to a new random value
if (indices[points] > 1) {
indices[points] = (Math.random() * 2) - 1;
}
}
}
// Update webgl vertex buffer so that updated indices data is rendered
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(indices), gl.STATIC_DRAW);
requestAnimationFrame(loop);
}
loop();
<canvas id="canvas"><canvas>

Why doesn't my sphere render complete?

I'm trying to render a sphere in webgl, im using a method from webglfundamentals but somehow in my programm the sphere is just rendered to 20%. In chrome i get this error: L ERROR :GL_INVALID_OPERATION : glDrawArrays: attempt to access out of range vertices in attribute 1
var canvas;
var gl;
var index = 0;
var pointsArray = [];
var normalsArray = [];
var indexArray = [];
var colorArray = [];
var near = -10;
var far = 10;
var radius = 1.5;
var theta = 0.0;
var phi = 0.0;
var dr = 5.0 * Math.PI/180.0;
var left = -3.0;
var right = 3.0;
var ytop =3.0;
var bottom = -3.0;
var va = vec4(0.0, 0.0, -1.0,1);
var vb = vec4(0.0, 0.942809, 0.333333, 1);
var vc = vec4(-0.816497, -0.471405, 0.333333, 1);
var vd = vec4(0.816497, -0.471405, 0.333333,1);
var lightPosition = vec4(0.0, 1.0, 1.0, 0.0 );
var lightAmbient = vec4(0.2, 0.2, 0.2, 1.0 );
var lightDiffuse = vec4( 1.0, 1.0, 1.0, 1.0 );
var lightSpecular = vec4( 1.0, 1.0, 1.0, 1.0 );
var materialAmbient = vec4( 1.0, 0.0, 1.0, 1.0 );
var materialDiffuse = vec4( 1.0, 0.0, 0.0, 1.0 );
var materialSpecular = vec4( 1.0, 0.8, 0.0, 1.0 );
var materialShininess = 100.0;
var ctm;
var ambientColor, diffuseColor, specularColor;
var texture;
var modelViewMatrix, projectionMatrix;
var modelViewMatrixLoc, projectionMatrixLoc;
var eye;
var at = vec3(0.0, 0.0, 0.0);
var up = vec3(0.0, 1.0, 0.0);
var iBuffer;
function createSphereVertices(
radius,
subdivisionsAxis,
subdivisionsHeight,
opt_startLatitudeInRadians,
opt_endLatitudeInRadians,
opt_startLongitudeInRadians,
opt_endLongitudeInRadians) {
if (subdivisionsAxis <= 0 || subdivisionsHeight <= 0) {
throw Error('subdivisionAxis and subdivisionHeight must be > 0');
}
opt_startLatitudeInRadians = opt_startLatitudeInRadians || 0;
opt_endLatitudeInRadians = opt_endLatitudeInRadians || Math.PI;
opt_startLongitudeInRadians = opt_startLongitudeInRadians || 0;
opt_endLongitudeInRadians = opt_endLongitudeInRadians || (Math.PI * 2);
var latRange = opt_endLatitudeInRadians - opt_startLatitudeInRadians;
var longRange = opt_endLongitudeInRadians - opt_startLongitudeInRadians;
// We are going to generate our sphere by iterating through its
// spherical coordinates and generating 2 triangles for each quad on a
// ring of the sphere.
// var numVertices = (subdivisionsAxis + 1) * (subdivisionsHeight + 1);
var positions = [];
// var normals = webglUtils.createAugmentedTypedArray(3, numVertices);
// var texCoords = webglUtils.createAugmentedTypedArray(2 , numVertices);
// Generate the individual vertices in our vertex buffer.
for (var y = 0; y <= subdivisionsHeight; y++) {
for (var x = 0; x <= subdivisionsAxis; x++) {
// Generate a vertex based on its spherical coordinates
var u = x / subdivisionsAxis;
var v = y / subdivisionsHeight;
var theta = longRange * u;
var phi = latRange * v;
var sinTheta = Math.sin(theta);
var cosTheta = Math.cos(theta);
var sinPhi = Math.sin(phi);
var cosPhi = Math.cos(phi);
var ux = cosTheta * sinPhi;
var uy = cosPhi;
var uz = sinTheta * sinPhi;
positions.push(vec4(radius * ux, radius * uy, radius * uz,1.0));
normalsArray.push(vec4(ux, uy, uz,1.0));
// texCoords.push(1 - u, v);
}
}
var numVertsAround = subdivisionsAxis + 1;
// var indices = webglUtils.createAugmentedTypedArray(3, subdivisionsAxis * subdivisionsHeight * 2, Uint16Array);
for (var x = 0; x < subdivisionsAxis; x++) {
for (var y = 0; y < subdivisionsHeight; y++) {
// Make triangle 1 of quad.
pointsArray.push(positions[(y + 0) * numVertsAround + x]);
pointsArray.push(positions[(y + 0) * numVertsAround + x + 1]);
pointsArray.push(positions[(y + 1) * numVertsAround + x]);
// Make triangle 2 of quad.
pointsArray.push(positions[(y + 1) * numVertsAround + x]);
pointsArray.push(positions[(y + 0) * numVertsAround + x + 1]);
pointsArray.push(positions[(y + 1) * numVertsAround + x + 1]);
index +=6;
}
}
}
window.onload = function init() {
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if ( !gl ) { alert( "WebGL isn't available" ); }
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
gl.enable(gl.DEPTH_TEST);
//
// Load shaders and initialize attribute buffers
//
var program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
createSphereVertices(1,12,12);
ambientProduct = mult(lightAmbient, materialAmbient);
diffuseProduct = mult(lightDiffuse, materialDiffuse);
specularProduct = mult(lightSpecular, materialSpecular);
var nBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, nBuffer);
gl.bufferData( gl.ARRAY_BUFFER, flatten(normalsArray), gl.STATIC_DRAW );
var vNormal = gl.getAttribLocation( program, "vNormal" );
gl.vertexAttribPointer( vNormal, 4, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vNormal);
var vBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW);
var vPosition = gl.getAttribLocation( program, "vPosition");
gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
modelViewMatrixLoc = gl.getUniformLocation( program, "modelViewMatrix" );
projectionMatrixLoc = gl.getUniformLocation( program, "projectionMatrix" );
gl.uniform4fv( gl.getUniformLocation(program,
"ambientProduct"),flatten(ambientProduct) );
gl.uniform4fv( gl.getUniformLocation(program,
"diffuseProduct"),flatten(diffuseProduct) );
gl.uniform4fv( gl.getUniformLocation(program,
"specularProduct"),flatten(specularProduct) );
gl.uniform4fv( gl.getUniformLocation(program,
"lightPosition"),flatten(lightPosition) );
gl.uniform1f( gl.getUniformLocation(program,
"shininess"),materialShininess );
render();
}
function render() {
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
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 = ortho(left, right, bottom, ytop, near, far);
gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix) );
gl.uniformMatrix4fv(projectionMatrixLoc, false, flatten(projectionMatrix) );
for( var i=0; i<index; i+=3)
gl.drawArrays( gl.TRIANGLES, i, 3);
window.requestAnimFrame(render);
}
project1.html
<!DOCTYPE html>
<html>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vNormal;
varying vec3 N, L, E;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform vec4 lightPosition;
void main()
{
vec3 pos = -(modelViewMatrix * vPosition).xyz;
vec3 light = lightPosition.xyz;
L = normalize( light - pos );
E = -pos;
N = normalize( (modelViewMatrix*vNormal).xyz);
gl_Position = projectionMatrix * modelViewMatrix * vPosition;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 ambientProduct;
uniform vec4 diffuseProduct;
uniform vec4 specularProduct;
uniform float shininess;
varying vec3 N, L, E;
void main()
{
vec4 fColor;
vec3 H = normalize( L + E );
vec4 ambient = ambientProduct;
float Kd = max( dot(L, N), 0.0 );
vec4 diffuse = Kd*diffuseProduct;
float Ks = pow( max(dot(N, H), 0.0), shininess );
vec4 specular = Ks * specularProduct;
if( dot(L, N) < 0.0 ) specular = vec4(0.0, 0.0, 0.0, 1.0);
fColor = ambient + diffuse +specular;
fColor.a = 1.0;
gl_FragColor = fColor;
}
</script>
<script type="text/javascript" src="./Common/webgl-utils.js"></script>
<script type="text/javascript" src="./Common/initShaders.js"></script>
<script type="text/javascript" src="./Common/MV.js"></script>
<script type="text/javascript" src="project1.js"></script>
<body>
<canvas id="gl-canvas" width="512" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>
This is what i get only a unfinished sphere:
I don't know this is actual correct answer since I didn't check this by running codes.
But, I just guess why this error occured.
Major reason of "out of range in attribute variable"
Basically, this will happen when the buffer you passed didn't have enough length.
Therefore, you need to check the count of buffer source you created.
And your error is ":GL_INVALID_OPERATION : glDrawArrays: attempt to access out of range vertices in attribute 1". In this case, attribute 1 in the error message means "vNormal" attribute in your GLSL code.
Because it is 2nd attribute variable in your GLSL code.
(If the error code says attribute 0, this problem should be made by vPosition)
As long as I saw your code, I think there is mismatch of length with normal buffer and position buffer.
Surface count in your code : Subdivision Height * Subdivision Axis * 2
Position element count in your code:Subdivision Height * Subdivision Axis *6
Normal element count in your code: Subdivision Height * Subdivision Axis * 4
I guess this is the reason of the problem.
Each vertex must have position and normal in this case, so your normal element count must be Subdivision Height * Subdivision Axis * 6
2nd argument in gl.vertexAttribPointer
I think you have mistake about 2nd argument in gl.vertexAttribPointer.
This is the count which means how many float elements needs to be passed each vertex.
In this case, you pushed 3 float elements for each vertex. So, you needs to specify 3 as argument for vPosition even if you used vec4 in your GLSL code.
By this argument, GPU can split these buffers for each vertex and pass them into vertex shader parallely.
4th element in vector
This is not strongly related to your question.But I found the code can be a reason of bug.
positions.push(vec4(radius * ux, radius * uy, radius * uz,1.0));
normalsArray.push(vec4(ux, uy, uz,1.0));
You need to understand what the meaning of 4th element in vec4. When this vector means coordinates, 4th element must be 1.However, when this vector means directions, 4th element must be 0.
Because, if this means directions, direction can not be affected by translation transform. ( I suggest you to learn affine transform to understand this)
So, you need to rewrite that code like this.
positions.push(vec4(radius * ux, radius * uy, radius * uz,1.0));
normalsArray.push(vec4(ux, uy, uz,0));
I hope this answer could help you...

Categories