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
Related
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)
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 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:
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.