After drawing a simple triangle in webgl, I've decided to start to learn how to do transformations. So basically I'm thinking that the simplest thing I can do is to write an identity matrix and multiply it for the vertex positions.
So I've added to the code the identity matrix as
var identityMatrix = [1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1];
Then I've added to the shader the mat4 variable as
'uniform mat4 id_matrix;'
And multiplied it for the position (so I'm expecting no changes in the transformations at all, since I multiply everything by 1)
gl_Position = id_matrix * vec4 (a_position,1);
Finally I retrieve the location of the matrix in the shader and fill it with my data
var shaderIdentityMatrix = gl.getUniformLocation(program, "id_matrix");
gl.uniformMatrix4fv(shaderIdentityMatrix,false,new Float32Array(identityMatrix));
But after those changes, nothing appears on screen. Am I doing wrong assumptions?
Here's the full code
<!DOCTYPE HTML>
<html>
<canvas id = "can" width="400" height="400">
</canvas>
<script>
var webgl_canvas = document.getElementById('can');
var gl = webgl_canvas.getContext('experimental-webgl');
var triangles = [-0.8,-0.8,0,0.8,-0.8,0,0,0.8,0];
var identityMatrix = [1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1];
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(triangles), gl.STATIC_DRAW);
vertexBuffer.itemSize = 3;
vertexBuffer.numItems = 3;
var vertexShader_source = 'attribute vec3 a_position;' + 'uniform mat4 id_matrix;' + 'void main() { gl_Position = id_matrix * vec4 (a_position,1); }';
var fragmentShader_source = 'precision mediump float;' + 'void main() { gl_FragColor = vec4 (0.9,0,0.1,1); }';
//Compile shaders
var buildShader = function (shaderSource, typeOfShader) {
var shader = gl.createShader(typeOfShader);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert (gl.getShaderInfoLog(shader));
}
return shader;
}
var compiledVertexShader = buildShader (vertexShader_source, gl.VERTEX_SHADER);
var compiledFragmentShader = buildShader (fragmentShader_source, gl.FRAGMENT_SHADER);
//setup GLSL program
program = gl.createProgram();
gl.attachShader(program,compiledVertexShader);
gl.attachShader(program,compiledFragmentShader);
gl.linkProgram(program);
//Draw
var shaderIdentityMatrix = gl.getUniformLocation(program, "id_matrix");
gl.uniformMatrix4fv(shaderIdentityMatrix,false,new Float32Array(identityMatrix));
var positionLocation = gl.getAttribLocation(program,"a_position");
gl.enableVertexAttribArray(positionLocation);
gl.useProgram(program);
gl.vertexAttribPointer(positionLocation, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.drawArrays (gl.TRIANGLES, 0, vertexBuffer.numItems);
</script>
</html>
gl.uniformMatrix4fv
always operates on the currently used shader program. Since there is no shader program activated when you call this function, nothing is set. Calling
gl.useProgram(program);
directly before the uniformMatrix4fv statement should fix your problem.
Hint: Always check the javascript error console. At least for me (Chrome) it tells me that
WebGL: INVALID_OPERATION: uniformMatrix4fv: location is not from current program
which is a good indicator for where to search for the problem.
Related
I've recently started learning Javascript/ WebGL and I've learned enough to put together a simple Mandelbrot fractal renderer. The program works fine but for some reason it won't let me zoom in more than about 20 times, and it starts looking pixellated if I zoom in more. I've had this problem before in other fractal drawing programs I've made, but it usually doesn't become noticeable until about 2^45 zoom. I was thinking maybe it has to do with the max float size in GLSL, but I'm really not sure what the problem is or even how to go about finding the problem. I was just wondering if anyone knows what the cause of this zoom limit is and if there's any way I can increase it? Here's my HTML/ GLSL code:
<html>
<head>
<title>Mandelbrot Set</title>
<style>
body {
margin = 0;
padding = 0;
}
</style>
</head>
<body>
<h3>Click on the fractal to zoom in.</h3>
<canvas id = "canvas" width = "500" height = "500" onclick = "drawFractal();">
Sorry, your browser does not support HTML5.
</canvas>
<script id = "vertexshader" type = "vertexshader">
attribute vec2 a_position;
void main(){
gl_Position = vec4(a_position, 0, 0);
}
</script>
<script id = "fragmentshader" type = "fragmentshader">
precision mediump float;
uniform vec2 u_resolution;
uniform vec2 u_zoomCenter;
uniform float u_zoom;
uniform int u_maxIterations;
uniform float u_colorDiversity;
vec2 f(vec2 z, vec2 c)
{
return vec2(z.x*z.x - z.y*z.y, z.x*z.y*2.0) + c;
}
// Credit to hughsk on GitHub for this hsv to rgb converter
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main(){
vec2 zeroToOne = gl_FragCoord.xy / u_resolution;
vec2 c = u_zoomCenter + (zeroToOne * 4.0 - vec2(2.0)) / u_zoom;
vec2 z = vec2(0.0);
bool escaped = false;
float iterations = 0.0;
for (int i = 0; i < 100000; i++)
{
if (i > u_maxIterations) break;
z = f(z, c);
if (length(z) > 2.0)
{
escaped = true;
iterations = float(i);
break;
}
}
gl_FragColor = escaped ? vec4(hsv2rgb(vec3(iterations * u_colorDiversity, 1.0, 1.0)), 1.0) : vec4(vec3(0.0), 1.0);
}
</script>
<script src = "webgl.js"></script>
</body>
</html>
Here's my "webgl.js" file:
// Compile and link shaders and create program
function createShader(gl, type, source){
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader;
console.log(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
alert("Error: failed to create shader. Check the console for more information.");
}
function createProgram(gl, vertexShader, fragmentShader){
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (gl.getProgramParameter(program, gl.LINK_STATUS)) return program;
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
alert("Error: failed to create program. Check the console for more information.");
}
// WebGL setup
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");
if (!gl){
var gl = canvas.getContext("experimental-webgl");
console.log("WebGL not supported, falling back on experimental WebGL.");
}
if (!gl){
console.log("Experimental WebGL not supported.");
alert("Your browser does not support WebGL. Check the console for more information.");
}
// Create shaders and program
var vertexShaderSource = document.getElementById("vertexshader").text;
var fragmentShaderSource = document.getElementById("fragmentshader").text;
var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
var program = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(program);
// Set up position buffer
var screen = new Float32Array([
-1, -1,
1, -1,
1, 1,
1, 1,
-1, 1,
-1, -1]);
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, screen, gl.STATIC_DRAW);
// Set up position attribute in vertex shader
var a_positionLocation = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(a_positionLocation);
gl.vertexAttribPointer(a_positionLocation, 2, gl.FLOAT, false, 0, 0);
// Set up WebGL window
gl.viewport(0, 0, 500, 500);
gl.clearColor(0, 0, 0, 0);
// Set up uniforms in fragment shader
var u_resolutionLocation = gl.getUniformLocation(program, "u_resolution");
var u_zoomCenterLocation = gl.getUniformLocation(program, "u_zoomCenter");
var u_zoomLocation = gl.getUniformLocation(program, "u_zoom");
var u_maxIterationsLocation = gl.getUniformLocation(program, "u_maxIterations");
var u_colorDiversityLocation = gl.getUniformLocation(program, "u_colorDiversity");
gl.uniform2f(u_resolutionLocation, 500, 500);
// Set up some global variables
var offset_x = 0;
var offset_y = 0;
var zoom = 1;
var iterations = 10000;
var colorDiversity = 0.01;
// Update uniforms based on global variables
function updateUniforms()
{
gl.uniform2f(u_zoomCenterLocation, offset_x, offset_y);
gl.uniform1f(u_zoomLocation, zoom);
gl.uniform1i(u_maxIterationsLocation, iterations);
gl.uniform1f(u_colorDiversityLocation, colorDiversity);
}
// Get mouse position
function getMousePos() {
var rect = canvas.getBoundingClientRect();
return [(event.clientX - rect.left - 250) / 125, (event.clientY - rect.top - 250) / 125];
}
// Draw the fractal
function drawFractal() {
mousePos = getMousePos();
offset_x += mousePos[0] / zoom;
offset_y -= mousePos[1] / zoom;
zoom *= 2;
updateUniforms();
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
// Draw fractal when the page loads
updateUniforms();
gl.drawArrays(gl.TRIANGLES, 0, 6);
Maximal possible zoom depends on the precision of the floating point number you use and your algorithm.
You can increase precision using arbitrary precision numbers, for example mpfr, mpc or arb library
I'm attempting to animate a projectile's trajectory (in the form of a cannon ball) given an angle and initial velocity. I've built the "cannon" in the form of a line and the target I'm aiming for in the form of a box, which I know is elementary but I just want to get the projectile motion down for now. Currently, I'm messing around with hardcoded angles and velocity, but eventually would like to input the angle and velocity and have the cannon shoot following the input. The target is parallel to the launch point, so I know that the x value of the cannon will be (initialVelocity)cos(angle)(time), and the y will be (initialVelocity)sin(angle)(time) - (g*t^2)/2, where g is the length or distance. Currently what I have is a cannon ball moving linearly across the screen, and it doesn't even start in the right spot.
I'm not asking for code to be written for me, I'd just like a starting point as to how to get the cannon to move from the right spot, and to know where I'm going completely wrong. I'm confident I can get it to hit the target if I'm taught how to manipulate the shaders correctly.
Shaders:
<script id="vertex-shader" type="x-shader/x-vertex">
precision mediump float;
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
uniform float time;
void main()
{
/*old code from manipulating clock hands*/
/* fColor = vColor;
float length = sqrt(vPosition.x*vPosition.x + vPosition.y * vPosition.y);
gl_Position.x = length*cos(theta);
gl_Position.y = length*sin(theta);
gl_Position.z = 0.0;
gl_Position.w = 1.0; */
fColor = vColor;
gl_Position = vPosition;
}
</script>
<script id="background-vertex-shader" type="x-shader/x-vertex">
precision mediump float;
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
void main()
{
fColor = vColor;
gl_Position = vPosition;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 fColor;
void main()
{
gl_FragColor = fColor;
}
</script>
WebGL code:
var gl;
var points = [];
var colors = [];
var cannonpoints = [];
var circlepoints;
var squarepoints;
var baseColors = [
vec3(1.0,0.0,0.0),
vec3(0.0,1.0,0.0),
vec3(0.0,0.0,1.0),
vec3(1.0,1.0,1.0),
vec3(0.0,0.0,0.0)
];
var program;
var backgroundprogram;
var Time;
var thetaLoc;
var angle;
var initialVel;
var vx;
var vy;
var ballX = -0.5;
var ballY = -0.5;
window.onload = function init(){
var canvas = document.getElementById("gl-canvas");
gl = WebGLUtils.setupWebGL(canvas);
if(!gl) {
alert("webGL isn't available");
}
// configuring WebGL
gl.viewport(0,0,
canvas.width,canvas.height);
gl.clearColor(0.0,0.0,1.0,1.0); // set background color to black.
// load the shaders and initialize
// the attrbibute buffers.
program = initShaders(gl, "vertex-shader", "fragment-shader");
backgroundprogram = initShaders(gl, "background-vertex-shader", "fragment- shader");
document.getElementById("shoot").onclick = function() {
velocity = document.getElementById("velocity").value;
angle = document.getElementById("angle").value;
console.log("angle="+angle);
vx = (Math.cos(angle*(Math.PI/180))*velocity);
console.log("vx="+vx);
vy = (Math.sin(angle*(Math.PI/180))*velocity);
console.log("vy="+vy);
}
Time = 0.0;
thetaLoc = gl.getUniformLocation(program,"time");
initBackground();
/******************
initBall(Time,1);
*******************/
initBall(Time);
//render();
setInterval(render, 100);
};
function render(){
gl.clear(gl.COLOR_BUFFER_BIT);
/* draw the circle */
gl.drawArrays(gl.TRIANGLE_FAN,0,circlepoints);
/* draw the square(s) */
gl.drawArrays(gl.TRIANGLES,circlepoints,squarepoints);
//draw the cannon
gl.drawArrays(gl.LINES,circlepoints+squarepoints,2);
//draw the cannon ball
//starting index is the amount of points already drawn
//amount of points for circle + amount of points for square + amount of points for line
var start = circlepoints + squarepoints + 2;
Time += 0.01;
initBall(Time); //,1);
gl.uniform1f(thetaLoc,Time);
//amount of points to draw is length of points array minus the start index
gl.drawArrays(gl.TRIANGLE_FAN,start,points.length-start);
}
function initBall(Time) { //,r){
gl.useProgram(program);
/*******************************************************
filled_circle(vec2(r*Math.cos(Time),r*Math.sin(Time)),0.05,4);*/
vx= (Math.cos(60*(Math.PI/180))*1);
vy= (Math.sin(60*(Math.PI/180))*1);
filled_circle(vec2(-0.8+(vx*Time),-0.3+(vy*Time)),0.05,4);
// Load the data into the GPU
var bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER,
flatten(points),
gl.STATIC_DRAW);
// Associate our shader variables with
// the data buffer.
var vPosition = gl.getAttribLocation(program,"vPosition");
gl.vertexAttribPointer(vPosition,2,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(vPosition);
// load color data to the gpu
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);
}
I think the easiest way to do it is give your projectile a starting position, velocity and acceleration. Then the position of the projectile at any time is position + velocity * time + acceleration * time * time. The angle of the projectile would just be the angle of the projectile's current velocity.
If you want to eventually adding other stuff like collisions then its probably a good idea to make the projectile track its current velocity and acceleration; and on each frame the position and velocity changes based on the elapsed time between each frame. Like so:
Projectile.prototype.update = function(dt){
this.velocity += this.acceleration * dt;
this.position += this.velocity * dt;
this.angle = getAngle(this.velocity);
};
And on each frame, call projectile.update(dt) where dt = currentFrameTime - lastFrameTime.
I am under a situation that i have two canvas, and i want to display the same object in both canvas (in fact i have to display different objects in each canvas, but i want to start by showing same object in both), but i am not able to do this,
could some one please hlep me in doing this ?
My try to do it is: (i have two canvas (canvas ans canvas2) in grey and it display mutiple square in both, but it is displayed in only one), how to display in both.
My code to try is :
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<script class="WebGL">
var gl,gl2;
function createProgram(gl, vertexShader, fragmentShader)
{
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, vertexShader);
gl.compileShader(vs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
alert(gl.getShaderInfoLog(vs));
//////
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, fragmentShader);
gl.compileShader(fs);
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
alert(gl.getShaderInfoLog(fs));
program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS))
alert(gl.getProgramInfoLog(program));
return program;
}
function createShaderFromScriptElement(gl , shaderName)
{
var Shader = document.getElementById(shaderName).firstChild.nodeValue;
return Shader;
}
function start()
{
var canvas = document.getElementById("canvas");
canvas2 = document.getElementById("canvas2");
gl = canvas.getContext("experimental-webgl");
gl2 = canvas2.getContext("experimental-webgl");
if (!gl) { alert("error while GL load"); }
if (!gl2) { alert("error while GL load"); }
// var vertexShader2 = createShaderFromScriptElement(gl, "2d-vertex-shader");
// var fragmentShader2 = createShaderFromScriptElement(gl, "2d-fragment-shader");
var vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader");
var fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader");
var program = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(program);
var positionLocation = gl.getAttribLocation(program, "a_position");
var colorLocation = gl.getUniformLocation(program, "u_color");
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.uniform2f(resolutionLocation, 200, 200);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
for (var ii = 0; ii < 5005; ++ii)
{
// Setup a random rectangle
setRectangle(gl, randomInt(300), randomInt(300), 50, 50);
// Set a random color.
gl.uniform4f(colorLocation, Math.random(), Math.random(), Math.random(), 1);
// Draw the rectangle.
gl.drawArrays(gl.TRIANGLES, 0, 3);
gl2.drawArrays(gl2.TRIANGLES, 0, 3);
}
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;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x1, -y1,
-x1, y1,
]), gl.STATIC_DRAW);
}
}
</script>
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
// convert the rectangle 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>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_color;
void main()
{
gl_FragColor = u_color; // green
}
</script>
</head>
<body onload="start()">
<div style="text-align: center">
</div>
<table style="width:100%; height: 10%;">
<tr>
<td style="width:200px; max-width:200px; background-color:gray ">
<canvas id="canvas" width="300" height="300"></canvas>
</td>
<td style="width:200px; max-width:200px; background-color:gray; ">
<canvas id="canvas2" width="300" height="300"></canvas>
</td>
</tr>
</table>
</body>
</html>
No, unfortunately you can not share WebGL objects across canvases in WebGL 1.0
What are you trying to accomplish?
Some solutions:
Split 1 canvas
If you need multiple views like many 3D modeling programs you can split a single canvas using gl.enable(gl.SCISSOR_TEST), gl.scissor and gl.viewport. Here's one example
Draw to one canvas, then copy to other canvases
In this case you render to an offscreen canvas with WebGL then
use multiple visible canvas 2d canvases to display by using
drawImage.
gl = offscreenCanvas.getContext("webgl");
ctx1 = onscreenCanvas1.getContext("2d");
ctx2 = onscreenCanvas2.getContext("2d");
// render whatever you want to appear in onscreenCanvas1
renderScene(scene1Settings, gl);
// copy the result to offscreenCanvas1
ctx1.drawImage(gl.canvas, ...);
// render whatever you want to appear in onscreenCanvas2
renderScene(scene2Settings, gl);
// copy the result to offsceenCanvas2
ctx2.drawImage(gl,canvas, ...);
Make 1 canvas the size of the window, put it in the background, use the first technique (scissor, viewport) and getBoundingClientRect to render exactly where some other element is.
In this case you make a single WebGL canvas the size of the window
and using CSS put it in the background. Then you create a placeholder
<div> or other element to represent where you want a canvas to
appear.
You can then ask the browser exactly where that element appears and
use that info to set the viewport and scissor and then render to
that area to make it appear like it's a canvas
Example1,
Example2
var canvas = document.getElementById("canvas"),
canvas2 = document.getElementById("canvas2");
gl = canvas.getContext("experimental-webgl");
gl2 = canvas.getContext("experimental-webgl");
I think you missed the reference to the second canvas element
I have to draw sphere using multiple squares(i am also allowed to use triangles even, but i found some existing code for help in square, so i used it). I have successfully drawn multiple squares (5000).But i don't have to use any inbuit function to create sphere . My code is below :
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<script class="WebGL">
var gl;
function createProgram(gl, vertexShader, fragmentShader)
{
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, vertexShader);
gl.compileShader(vs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
alert(gl.getShaderInfoLog(vs));
//////
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, fragmentShader);
gl.compileShader(fs);
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
alert(gl.getShaderInfoLog(fs));
program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS))
alert(gl.getProgramInfoLog(program));
return program;
}
function createShaderFromScriptElement(gl , shaderName)
{
var Shader = document.getElementById(shaderName).firstChild.nodeValue;
return Shader;
}
function start()
{
var canvas = document.getElementById("canvas");
gl = canvas.getContext("experimental-webgl");
if (!gl) { alert("error while GL load"); }
var vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader");
var fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader");
var program = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(program);
var positionLocation = gl.getAttribLocation(program, "a_position");
var colorLocation = gl.getUniformLocation(program, "u_color");
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.uniform2f(resolutionLocation, 200, 200);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
for (var ii = 0; ii < 5000; ++ii)
{
// Setup a random rectangle
setRectangle(gl, randomInt(300), randomInt(300), 10, 10);
// Set a random color.
gl.uniform4f(colorLocation, Math.random(), Math.random(), Math.random(), 1);
// Draw the rectangle.
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
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;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2]), gl.STATIC_DRAW);
}
}
</script>
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
// convert the rectangle 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>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_color;
void main()
{
gl_FragColor = u_color; // green
}
</script>
</head>
<body onload="start()">
<div style="text-align: center">
<canvas id="canvas" width="1000" height="800"></canvas>
</div>
</body>
</html>
What i am asked is to draw sphere using multiple objects which i have no idea how to do.And my try was first to draw the multiple objects (5000 in my case) and then try for drawing sphere using it(i mean using these 5000 squares, my next step is to create sphere).
But i don't know how to proceed further to draw sphere using these squares ?
Which i am not able to understand how to do. Could some one please help me ?
One of approaches is constructing sphere from rectangular tiles in vertex shader.
Generally, the thing is to cover [0, 2*M_PI] x [0, M_PI] region with tiles. Say, you have N tiles where N = m*k, m is amount of tiles in a row and k is amount of tiles in column.
You can create N unit squares and assign to each of them its unique position in m * k matrix. Then pass these positions and width/height of tiles (2*M_PI / m and M_PI / k) as uniforms to vertex shader (or as attributes).
In vertex shader knowing position of tile and its width/height compute vertice's coords on [0, 2*M_PI] x [0, M_PI] (they would be phi and ksi). And then compute actual vertex position on sphere:
coord.x = sin(ksi) * cos(phi);
coord.y = sin(ksi) * sin(phi);
coord.z = cos(ksi);
Also note you should set up perspective projection for this.
Choosing m and k is up to you. I recommend to start with square tiles. Here is the picture of result i got this way:
I am webGL beginner and i have to display animated multiple objects. I have written the code. It runs without error. I mean it prints all the alert test cases in start() function until alert("I am executed6"); but still it displays nothing in browser.
What i want is to display rectangles using two triangle with animation. But it not at all display the rectangles.
My full code is :
var gl;
function initGL()
{
// Get A WebGL context
var canvas = document.getElementById("canvas");
gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if (!gl)
{
return;
}
}
var positionLocation;
var resolutionLocation;
var colorLocation;
var translationLocation;
var rotationLocation;
var translation = [50, 50];
var rotation = [0, 1];
var angle = 0;
function initShaders()
{
// setup GLSL program
vertexShader = document.getElementById("2d-vertex-shader").firstChild.nodeValue;
// vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader");
fragmentShader = document.getElementById("2d-fragment-shader").firstChild.nodeValue;
// fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader");
program = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(program);
// look up where the vertex data needs to go.
positionLocation = gl.getAttribLocation(program, "a_position");
// lookup uniforms
resolutionLocation = gl.getUniformLocation(program, "u_resolution");
colorLocation = gl.getUniformLocation(program, "u_color");
translationLocation = gl.getUniformLocation(program, "u_translation");
rotationLocation = gl.getUniformLocation(program, "u_rotation");
// set the resolution
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
}
function createProgram(gl,vertexShader, fragmentShader)
{
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, vertexShader);
gl.compileShader(vs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
alert(gl.getShaderInfoLog(vs));
//////
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, fragmentShader);
gl.compileShader(fs);
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
alert(gl.getShaderInfoLog(fs));
program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS))
alert(gl.getProgramInfoLog(program));
}
function initBuffers()
{
// Create a buffer.
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// Set Geometry.
setGeometry(gl);
}
function setColor(red, green, blue)
{
gl.uniform4f(colorLocation, red, green, blue, 1);
}
// Draw the scene.
function drawScene()
{
// Clear the canvas.
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the translation.
gl.uniform2fv(translationLocation, translation);
// Set the rotation.
gl.uniform2fv(rotationLocation, rotation);
// Draw the geometry.
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
// Fill the buffer with the values that define a letter 'F'.
function setGeometry(gl)
{
var size1 = 0.5;
/*Assume size1 is declared*/
var vertices = [
-size1 / 2, -size1 / 2,
-size1 / 2, size1 / 2,
size1 / 2, size1 / 2,
size1 / 2, size1 / 2,
size1 / 2, -size1 / 2,
-size1 / 2, -size1 / 2];
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(vertices),
gl.STATIC_DRAW);
}
function animate()
{
translation[0] += 0.01;
translation[1] += 0.01;
angle += 0.01;
rotation[0] = Math.cos(angle);
rotation[1] = Math.sin(angle);
}
function tick()
{
// requestAnimFrame(tick);
drawScene();
animate();
}
function start()
{
alert("I am executed1");
initGL();
alert("I am executed2");
initShaders();
alert("I am executed3");
initBuffers();
alert("I am executed4");
setColor(0.2, 0.5, 0.5);
alert("I am executed5");
tick();
alert("I am executed6"); //All are executed, so no error in code
}
start();
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
uniform vec2 u_translation;
uniform vec2 u_rotation;
void main()
{
vec2 rotatedPosition = vec2(
a_position.x * u_rotation.y + a_position.y * u_rotation.x,
a_position.y * u_rotation.y - a_position.x * u_rotation.x);
// Add in the translation.
vec2 position = rotatedPosition + u_translation;
// convert the position from pixels to 0.0 to 1.0
vec2 zeroToOne = 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, 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>
<div style="text-align: center">
<canvas id="canvas" width="512" height="512"></canvas>
</div>
What is the problem with this code ? Is there any logical error. How to display animated objects ?
So when I run your code and I check the Web Console/Error Console, whatever it's called in your browser of choice I get these errors
WebGL: INVALID_VALUE: getAttribLocation: no object or object deleted
WebGL: INVALID_VALUE: getUniformLocation: no object or object deleted
WebGL: INVALID_VALUE: getUniformLocation: no object or object deleted
WebGL: INVALID_VALUE: getUniformLocation: no object or object deleted
WebGL: INVALID_VALUE: getUniformLocation: no object or object deleted
WebGL: INVALID_VALUE: enableVertexAttribArray: index out of range
WebGL: INVALID_VALUE: vertexAttribPointer: index out of range
WebGL: INVALID_OPERATION: drawArrays: no valid shader program in use
Looking at the code the first problem I see is that you're using lots of global variables. The specific reason for all those errors is you have this line
program = createProgram(gl, vertexShader, fragmentShader);
But createProgram does not return anything so after that line program = undefined and all the parts of the code that use program fail.
So, adding
return program;
to the end of createProgram all the errors go away.
After that the size1 in setGeometry is set to 0.5 and is then divided by 2 so it's trying to draw a 1/2 a pixel. Changing it to
var size1 = 10;
and I see a 10 pixel bluish-green square get drawn.
Also note you might find using console.log(msg) better than alert(msg). You don't have to click to see each result but you do have to open the JavaScript Console/Web Console to see the messages. In Chrome that's View->Developer->JavaScript Console. In Firefox it's Tools->Web Developer->Web Console. In Safari you first after to enable the developer menu in Safari's preferences under Safari->Preferences->Advanced->Show Develop menu in menu Bar. Once you've done that it's Develop->Show Error Console