WebGL not drawing lines - javascript

I want to draw a line in WebGL context but it isn't working. I can clear the canvas color so I know the program is compiled, but not sure where is the error.
The main part of the code is
let canvas = document.getElementById("gl-canvas");
let gl = WebGLUtils.setupWebGL(canvas);
if (!gl) {
alert("WebGL isn't available");
}
let program = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(program);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0, 0, 0, 0.5);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
let color = gl.getAttribLocation(program, "color");
let colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1,0,0,1, 1,0,0,1]), gl.STATIC_DRAW);
gl.vertexAttribPointer(color, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(color);
let vPosition = gl.getAttribLocation(program, "vPosition");
let positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1,1,1,1, -1,-1,-1,1]), gl.STATIC_DRAW);
gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
gl.drawArrays(gl.LINES, 0, 1);
The full code can be found here

The problem is your drawArrays call:
count
Specifies the number of indices to be rendered.
Every line needs two indices: starting point and end point:
gl.drawArrays(gl.LINES, 0, 2);

Related

how do I readPixels() an R32F texture in webgl2?

I am using WebGL2 to render 32-bit floating point values into a 2D texture with only one channel (red). After the draw call, I want to read those values in JavaScript.
The following gives GL_INVALID_OPERATION: Invalid format and type combination. because of that last gl.readPixels line.
const gl = document.createElement("canvas").getContext("webgl2");
if(!gl.getExtension("EXT_color_buffer_float")) {
throw "float";
}
// ... compile program ...
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-1, -1,
1, -1,
1, 1,
-1, -1,
-1, 1,
1, 1,
]), gl.STATIC_DRAW);
const texture = gl.createTexture();
const framebuffer = gl.createFramebuffer();
gl.viewport(0, 0, width, height);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, width, height, 0, gl.RED, gl.FLOAT, null);
gl.useProgram(program);
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
const pixels = new Float32Array(width * height);
gl.readPixels(0, 0, width, height, gl.RED, gl.FLOAT, pixels);
How do I read from an R32F texture?

How do you render to an integer renderbuffer in webgl?

I'm having trouble using webgl2 to render to an integer renderbuffer. Using the example code at the bottom, I get all zeros in the pixels array and the following error on Firefox:
WebGL warning: readPixels: Format and type RGBA_INTEGER/<enum 0x1400> incompatible with this RGBA8I attachment. This framebuffer requires either RGBA_INTEGER/INT or getParameter(IMPLEMENTATION_COLOR_READ_FORMAT/_TYPE) RGBA_INTEGER/INT.
When I substitute:
gl.readPixels(
0, 0, 256, 256,
gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT),
gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE),
pixels
);
for
gl.readPixels(0, 0, 256, 256, gl.RGBA_INTEGER, gl.BYTE, pixels);
The error becomes:
WebGL warning: readPixels: `pixels` type does not match `type`.
(On Firefox, gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE) returns gl.INT instead of gl.BYTE.)
I've tried changing the TypedArray for pixels between Uint8Array and Int8Array, but none options works. I should note that the provided example does work on Chrome. Is there a way to render to int buffer on Firefox or is it entirely bugged?
const gl = document.getElementById('target').getContext('webgl2', { preserveDrawingBuffer: true });
const prog = gl.createProgram()
const vert = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vert, `#version 300 es
in vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0., 1.);
}`);
gl.compileShader(vert);
gl.attachShader(prog, vert);
const frag = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(frag, `#version 300 es
precision highp isampler2D;
out ivec4 color;
void main() {
color = ivec4(255, 0, 0, 255);
}`);
gl.compileShader(frag);
gl.attachShader(prog, frag);
gl.linkProgram(prog);
const vao = gl.createVertexArray();
gl.bindVertexArray(vao)
const buff = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buff);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([-1,-1, -1,1, 1,-1, 1,1, -1,1, 1,-1]),
gl.STATIC_DRAW
);
const pos = gl.getAttribLocation(prog, 'a_position');
gl.enableVertexAttribArray(pos);
gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0)
const rbo = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8I, 256, 256);
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferRenderbuffer(
gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.RENDERBUFFER, rbo
);
gl.viewport(0, 0, 256, 256);
gl.clearColor(0,0,0,0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.disable(gl.DEPTH_TEST);
gl.useProgram(prog);
gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
gl.drawArrays(gl.TRIANGLES, 0, 6);
gl.readBuffer(gl.COLOR_ATTACHMENT0);
const pixels = new Int8Array(256 ** 2 * 4);
gl.readPixels(0, 0, 256, 256, gl.RGBA_INTEGER, gl.BYTE, pixels);
console.log(pixels);
Figured it out. For whatever reason, Firefox wants gl.INT and Int32Array to be passed to readPixels. Note that this is not to spec and fails on Chrome.

WebGL render loop performance

I've just started learning WebGL.
I am rendering multiple spheres but I'm not sure about the "bindBuffer" and "bufferData" calls inside the render loops.
I can render a single sphere with 2 million vertices no problem. But once I try to render 3 spheres with 100k vertices each (300k total, 85% less vertices), the performance starts to go down.
I want to know exactly what needs to remain inside the render loop and what doesn't. And if there is something else I am missing.
Here is my Sphere "class":
function Sphere (resolution, gl, vertex, fragment) {
const {positions, indexes} = createPositionsAndIndexes(resolution);
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertex);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragment);
const program = createProgram(gl, vertexShader, fragmentShader);
this.x = 0;
this.y = 0;
this.z = -6;
this.angle = {x:0,y:0,z:0};
const positionBuffer = gl.createBuffer();
const indexBuffer = gl.createBuffer();
const positionLocation = gl.getAttribLocation(program, "position");
const viewLocation = gl.getUniformLocation(program, "view");
const projectionLocation = gl.getUniformLocation(program, "projection");
this.render = () => {
gl.useProgram(program);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(indexes), gl.STATIC_DRAW);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionLocation);
const viewMatrix = glMatrix.mat4.create();
glMatrix.mat4.translate(viewMatrix, viewMatrix, [this.x, this.y, this.z]);
glMatrix.mat4.rotateX(viewMatrix, viewMatrix, this.angle.x);
glMatrix.mat4.rotateY(viewMatrix, viewMatrix, this.angle.y);
glMatrix.mat4.rotateZ(viewMatrix, viewMatrix, this.angle.z);
gl.uniformMatrix4fv(viewLocation, false, viewMatrix);
const projectionMatrix = glMatrix.mat4.create();
glMatrix.mat4.perspective(projectionMatrix, 45 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.1, 100.0);
gl.uniformMatrix4fv(projectionLocation, false, projectionMatrix);
gl.drawElements(gl.TRIANGLES, indexes.length, gl.UNSIGNED_INT, 0);
};
}
And here is the main "class":
document.addEventListener("DOMContentLoaded", () => {
const canvas = document.querySelector("canvas");
const width = canvas.width = canvas.clientWidth;
const height = canvas.height = canvas.clientHeight;
const gl = canvas.getContext("webgl2");
const sphere1 = new Sphere(300, gl, vertexShaderSource, fragmentShaderSource);
sphere1.x = -0.5;
const sphere2 = new Sphere(300, gl, vertexShaderSource, fragmentShaderSource);
sphere2.x = 0.0;
const sphere3 = new Sphere(300, gl, vertexShaderSource, fragmentShaderSource);
sphere3.x = +0.5;
const render = () => {
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
gl.clearDepth(1.0);
gl.depthFunc(gl.LEQUAL);
sphere1.angle.y -= 0.01;
sphere1.render();
sphere2.angle.y -= 0.01;
sphere2.render();
sphere3.angle.y -= 0.005;
sphere3.render();
window.requestAnimationFrame(render);
};
render();
});
You shouldn't call bufferData at render time unless you're changing the data in the buffer.
unction Sphere (resolution, gl, vertex, fragment) {
const {positions, indexes} = createPositionsAndIndexes(resolution);
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertex);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragment);
const program = createProgram(gl, vertexShader, fragmentShader);
this.x = 0;
this.y = 0;
this.z = -6;
this.angle = {x:0,y:0,z:0};
const positionBuffer = gl.createBuffer();
const indexBuffer = gl.createBuffer();
const positionLocation = gl.getAttribLocation(program, "position");
const viewLocation = gl.getUniformLocation(program, "view");
const projectionLocation = gl.getUniformLocation(program, "projection");
// create buffers and put data in them
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(indexes), gl.STATIC_DRAW);
this.render = () => {
gl.useProgram(program);
// bind the position buffer to the attribute
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionLocation);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
const viewMatrix = glMatrix.mat4.create();
glMatrix.mat4.translate(viewMatrix, viewMatrix, [this.x, this.y, this.z]);
glMatrix.mat4.rotateX(viewMatrix, viewMatrix, this.angle.x);
glMatrix.mat4.rotateY(viewMatrix, viewMatrix, this.angle.y);
glMatrix.mat4.rotateZ(viewMatrix, viewMatrix, this.angle.z);
gl.uniformMatrix4fv(viewLocation, false, viewMatrix);
const projectionMatrix = glMatrix.mat4.create();
glMatrix.mat4.perspective(projectionMatrix, 45 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.1, 100.0);
gl.uniformMatrix4fv(projectionLocation, false, projectionMatrix);
gl.drawElements(gl.TRIANGLES, indexes.length, gl.UNSIGNED_INT, 0);
};
}
you might find these articles and in particular this one
The problem in your code is that you are trying to do way too much in your render method. You generally don't want to send any buffer data to GPU in render loop as it is quite expensive.
In your case, you are also "overusing" uniforms. It is great that you are using MVP but whey are you generating it every frame for every object? View and projection are seldom object-specific as they relate to camera and window projections. You are also compiling shader for every sphere which isn't really needed either.
Optimizing the code could look like this:
function Sphere (resolution, gl, shaderProgram) {
const {positions, indexes} = createPositionsAndIndexes(resolution);
// bind shader program so you can retrieve attribute locations later on (when you use WebGL2, you can define location directly in shader files)
gl.useProgram(shaderProgram);
// create vao - this will enable you to bind vbo and ibo to one WebGL "object" which makes your life so much easier..
const vertexArrayObject = gl.createVertexArray();
gl.bindVertexArray(vertexArrayObject);
// create vbo
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
// create ibo
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(indexes), gl.STATIC_DRAW);
// define attribute locations
const positionAttributeLocation = gl.getAttribLocation(program, "position");
gl.vertexAttribPointer(positionAttributeLocation , 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionAttributeLocation );
// unbind vao as it is not needed for now
gl.bindVertexArray(null);
// great! your geometry is ready, now prepare mvp matrix
// the sphere only cares about the model uniform
const modelLocation = gl.getUniformLocation(program, "model");
const modelMatrix = glMatrix.mat4.create();
// helper methods to avoid re-generating model matrix
this.rotate = (valueInRadians, axis) => {
glMatrix.mat4.fromRotation(modelMatrix, valueInRadians, axis);
}
this.translate = (vector) => {
glMatrix.mat4.fromTranslation(modelMatrix, vector);
}
// set initial rotation/translation
this.translate([0, 0, -6]);
// time to render
this.render = () => {
// bind shader as per usual
gl.useProgram(program);
// instead of binding all buffers, bind VAO
gl.bindVertexArray(vertexArrayObject);
// bind model uniform
gl.uniformMatrix4fv(modelLocation, false, modelMatrix );
// draw elements
gl.drawElements(gl.TRIANGLES, indexes.length, gl.UNSIGNED_INT, 0);
// don't forget to unbind VAO after
gl.bindVertexArray(null);
};
}
After changes, the main program would look like this
document.addEventListener("DOMContentLoaded", () => {
const canvas = document.querySelector("canvas");
const width = canvas.width = canvas.clientWidth;
const height = canvas.height = canvas.clientHeight;
const gl = canvas.getContext("webgl2");
// prepare shader
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertex);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragment);
const shaderProgram = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(shaderProgram);
// prepare uniforms for view and projection
const viewLocation = gl.getUniformLocation(shaderProgram, "view");
const projectionLocation = gl.getUniformLocation(shaderProgram, "projection");
// prepare view matrix with initial rotations/translations
const viewMatrix = glMatrix.mat4.create();
glMatrix.mat4.translate(viewMatrix, viewMatrix, [this.x, this.y, this.z]);
glMatrix.mat4.rotateX(viewMatrix, viewMatrix, this.angle.x);
glMatrix.mat4.rotateY(viewMatrix, viewMatrix, this.angle.y);
glMatrix.mat4.rotateZ(viewMatrix, viewMatrix, this.angle.z);
// prepare projection matrix with perspective projection
const projectionMatrix = glMatrix.mat4.create();
glMatrix.mat4.perspective(projectionMatrix, 45 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.1, 100.0);
// create objects
const sphere1 = new Sphere(300, gl, shaderProgram);
const sphere2 = new Sphere(300, gl, shaderProgram);
const sphere3 = new Sphere(300, gl, shaderProgram);
sphere1.translate([-0.5, 0, 0]);
// finally, define render method
const render = () => {
// reset viewport
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
gl.clearDepth(1.0);
gl.depthFunc(gl.LEQUAL);
// update objects
sphere1.rotate(-0.01, [0, 1, 0]);
sphere1.rotate(-0.01, [0, 1, 0]);
sphere1.rotate(-0.005, [0, 1, 0]);
// bind view and projection uniforms
gl.uniformMatrix4fv(viewLocation, false, viewMatrix);
gl.uniformMatrix4fv(projectionLocation, false, projectionMatrix);
// render individual spheres
sphere1.render();
sphere2.render();
sphere3.render();
window.requestAnimationFrame(render);
};
render();
});

Multiple objects Glsl

I have some problems using Glsl while I'm searching to drawing two object independently. When I search to see the result of my code, the object considered by the compiler is the first texture while the texture is the second.Additionally, I don't understand how I can set the initial position of the object in independent way using the same shaders.
This is my code:
var program;
var gl;
var shaderDir;
var baseDir;
var missileModel;
var pigModel;
var missileStr = 'model/R73-Ready.obj';
var missileTexture = 'model/R73 Texture.png';
var modelStr = 'model/mount.obj';
var modelTexture = 'model/ground_grass_3264_4062_Small.jpg';
function main() {
var lastUpdateTime = (new Date).getTime();
var Rx = 0.0;
var Ry = 0.0;
var Rz = 0.0;
var S = 0.5;
utils.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0.85, 1.0, 0.85, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
//Here we extract the position of the vertices, the normals, the indices, and the uv coordinates
var missileVertices = missileModel.vertices;
var missileNormals = missileModel.vertexNormals;
var missileIndices = missileModel.indices;
var missileTexCoords = missileModel.textures;
var pigVertices = pigModel.vertices;
var pigNormals = pigModel.vertexNormals;
var pigIndices = pigModel.indices;
var pigTexCoords = pigModel.textures;
//###################################################################################
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
var uvAttributeLocation = gl.getAttribLocation(program, "a_uv");
var matrixLocation = gl.getUniformLocation(program, "matrix");
var textLocation = gl.getUniformLocation(program, "u_texture");
var perspectiveMatrix = utils.MakePerspective(120, gl.canvas.width/gl.canvas.height, 0.1, 100.0);
var viewMatrix = utils.MakeView(0, 0.0, 3.0, 0.0, 0.0);
//drawing land
var vao = gl.createVertexArray();
gl.bindVertexArray(vao);
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pigVertices), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);
var uvBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pigTexCoords), gl.STATIC_DRAW);
gl.enableVertexAttribArray(uvAttributeLocation);
gl.vertexAttribPointer(uvAttributeLocation, 2, gl.FLOAT, false, 0, 0);
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(pigIndices), gl.STATIC_DRAW);
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
var image = new Image();
image.src = baseDir+modelTexture;
image.onload= function() {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.generateMipmap(gl.TEXTURE_2D);
};
//drawing the missile
var missile = gl.createVertexArray();
gl.bindVertexArray(missile);
var misspositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, misspositionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(missileVertices), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);
var missileuvBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, missileuvBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(missileTexCoords), gl.STATIC_DRAW);
gl.enableVertexAttribArray(uvAttributeLocation);
gl.vertexAttribPointer(uvAttributeLocation, 2, gl.FLOAT, false, 0, 0);
var missindexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, missindexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(missileIndices), gl.STATIC_DRAW);
var misstexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, misstexture);
var missimage = new Image();
missimage.src = baseDir+missileTexture;
missimage.onload= function() {
gl.bindTexture(gl.TEXTURE_2D, misstexture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, missimage);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.generateMipmap(gl.TEXTURE_2D);
};
drawScene();
function animate(){
var currentTime = (new Date).getTime();
if(lastUpdateTime != null){
//var deltaC = 0; //(30 * (currentTime - lastUpdateTime)) / 1000.0;
Rx = 90;
Ry = 90;
Rz = 90;
}
worldMatrix = utils.MakeWorld(0.0, 0.0, 0.0, Rx, Ry, Rz, S);
lastUpdateTime = currentTime;
}
function drawScene() {
animate();
utils.resizeCanvasToDisplaySize(gl.canvas);
gl.clearColor(0.85, 0.85, 0.85, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
var viewWorldMatrix = utils.multiplyMatrices(viewMatrix, worldMatrix);
var projectionMatrix = utils.multiplyMatrices(perspectiveMatrix, viewWorldMatrix);
gl.uniformMatrix4fv(matrixLocation, gl.FALSE, utils.transposeMatrix(projectionMatrix));
gl.activeTexture(gl.TEXTURE0);
gl.uniform1i(textLocation, misstexture);
gl.bindVertexArray(missile);
gl.drawElements(gl.TRIANGLES, missileIndices.length, gl.UNSIGNED_SHORT, 0 );
gl.activeTexture(gl.TEXTURE0);
gl.uniform1i(textLocation, texture);
gl.bindVertexArray(vao);
gl.drawElements(gl.TRIANGLES, pigIndices.length, gl.UNSIGNED_SHORT, 0 );
window.requestAnimationFrame(drawScene);
}
}
async function init(){
var path = window.location.pathname;
var page = path.split("/").pop();
baseDir = window.location.href.replace(page, '');
shaderDir = baseDir+"shaders/";
var canvas = document.getElementById("c");
gl = canvas.getContext("webgl2");
if (!gl) {
document.write("GL context not opened");
return;
}
await utils.loadFiles([shaderDir + 'vs.glsl', shaderDir + 'fs.glsl'], function (shaderText) {
var vertexShader = utils.createShader(gl, gl.VERTEX_SHADER, shaderText[0]);
var fragmentShader = utils.createShader(gl, gl.FRAGMENT_SHADER, shaderText[1]);
program = utils.createProgram(gl, vertexShader, fragmentShader);
});
gl.useProgram(program);
//###################################################################################
//This loads the obj model in the pigModel variable
var pigObjStr = await utils.get_objstr(baseDir+ missileStr);
missileModel = new OBJ.Mesh(pigObjStr);
var pigObjStr1 = await utils.get_objstr(baseDir+ modelStr);
pigModel = new OBJ.Mesh(pigObjStr1);
main();
}
window.onload = init;
bindTexture binds a named texture to a texturing target and the current texture unit. The current texture unit is set by activeTexture.
The texture unit is the binding point between the named texture object and the texture sampler uniform. The sampler uniform has to be set by the texture unit, rather than the texture object name.
You have to assign the texture unit (index) to the texture sampler uniform, and you have to bind the texture to the texture unit before drawing the object:
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, misstexture);
gl.uniform1i(textLocation, 0); // 0 because 'misstexture' is bound to texture unit 0
gl.bindVertexArray(missile);
gl.drawElements(gl.TRIANGLES, missileIndices.length, gl.UNSIGNED_SHORT, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.uniform1i(textLocation, 0); // 0 because 'texture' is bound to texture unit 0
gl.bindVertexArray(vao);
gl.drawElements(gl.TRIANGLES, pigIndices.length, gl.UNSIGNED_SHORT, 0);
Of course it is possible to bind the textures to different texture units:
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, misstexture);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texture);
and to set the texture sampler uniform before drawing the object
gl.uniform1i(textLocation, 0); // 0 because 'misstexture' is bound to texture unit 0
gl.bindVertexArray(missile);
gl.drawElements(gl.TRIANGLES, missileIndices.length, gl.UNSIGNED_SHORT, 0);
gl.uniform1i(textLocation, 1); // 1 because 'texture' is bound to texture unit 1
gl.bindVertexArray(vao);
gl.drawElements(gl.TRIANGLES, pigIndices.length, gl.UNSIGNED_SHORT, 0);
As #Rabbid76 pointed out your calls to gl.uniform1i for textures are wrong. You need to pass in a texture unit index, not a WebGLTexture
As for positions you generally set the position of an object when rendering by passing in a matrix to the shader as a uniform
for each object
set vertex array
gl.useProgram(whateverProgramThisObjectNeeds)
bind textures to texture units
set uniforms to tell shader which texture units you bound the textures to
set uniforms for material settings (colors, etc..)
set uniforms for matrices (projection, view, model)
gl.drawArrays or gl.drawElements
you don't generally hard code positions into shaders. Setting "initial" positions is not part of WebGL. WebGL just draws points, lines, and triangles. Positions of objects are part of your code. Store them in an array, an map, a tree, a scene graph, a gameobject, something you makeup and then loop through the ones you want to draw, setting some uniforms to draw them in the correct places.

readPixels function returns not modified texture

I'm trying draw an image (as a texture) to a framebuffer, apply sharpness filter (by dragging slider on UI), then read result from the framebuffer and copy data to a simple 2d canvas (not webgl) by calling readPixels with the binded framebuffer, getting array with pixels and copying them to ImageData.data, but the function returns original texture.
Maybe someone can explain this to me, because as I understand, the thing on a screen is actually a framebuffer's content.
Sorry for a lot of code, but I hope it can help to understand what I'm doing.
(function () {
var anotherContext = null;
var canvas = $("#canvas");
main();
setupCanvas();
function setupCanvas () {
anotherContext = document.getElementById("anothercanvas").getContext("2d");
}
function main () {
var image = new Image();
image.src = "http://localhost:9292/img/ava.jpg";
image.onload = function () {
render(image);
}
}
function render (image) {
//-----get contexts----
var canvas = document.getElementById('canvas');
var gl = canvas.getContext('experimental-webgl');
//----define shaders-----
var vs = document.getElementById('vshader').textContent;
var fs = document.getElementById('fshader').textContent;
//----create program-----
var program = createProgram(vs, fs);
gl.useProgram(program);
//----setup vertex data-----
var positionLocation = gl.getAttribLocation(program, "a_position");
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
//----setup texture-----
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
// Create a texture.
var texture = createAndSetupTexture();
// Upload the image into the texture.
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
//---framebuffer----
var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
var canRead = (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE);
console.log("Can read: ", canRead);
//----lookup uniforms and set the resolution-----
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
var textureSizeLocation = gl.getUniformLocation(program, "u_textureSize");
var kernelLocation = gl.getUniformLocation(program, "u_kernel[0]");
gl.uniform2f(textureSizeLocation, image.width, image.height);
//----kernels-----
var kernel = [
0, 0, 0,
0, 1, 0,
0, 0, 0
];
var sharpnessKernel = [
0,-1, 0,
-1, 5, -1,
0,-1, 0
];
//-----bind buffer------
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(program.vertexPosAttrib, 2, gl.FLOAT, false, 0, 0);
setRectangle(gl, 0, 0, image.width, image.height);
draw(kernel);
function draw (krn) {
// gl.bindTexture(gl.TEXTURE_2D, texture);
setFramebuffer(framebuffer);
drawWithKernel(krn);
copyImage();
// gl.bindTexture(gl.TEXTURE_2D, texture);
setFramebuffer(null);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
function setFramebuffer (fbuf) {
gl.bindFramebuffer(gl.FRAMEBUFFER, fbuf);
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
gl.viewport(0, 0, canvas.width, canvas.height);
}
function drawWithKernel (kernel) {
gl.uniform1fv(kernelLocation, kernel);
//---draw
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
function createAndSetupTexture () {
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// Set the parameters so we can render any size image.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
return texture;
}
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);
}
function createShader(str, type) {
var shader = gl.createShader(type);
gl.shaderSource(shader, str);
gl.compileShader(shader);
return shader;
}
function createProgram (vstr, fstr) {
var program = gl.createProgram();
var vshader = createShader(vstr, gl.VERTEX_SHADER);
var fshader = createShader(fstr, gl.FRAGMENT_SHADER);
gl.attachShader(program, vshader);
gl.attachShader(program, fshader);
gl.linkProgram(program);
return program;
}
function copyImage () {
var pixels = new Uint8Array(image.width * image.height * 4);
gl.readPixels(0, 0, image.width, image.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
var imageData = anotherContext.createImageData(image.width, image.height);
for (var i = pixels.length - 1; i >= 0; i--) {
imageData.data[i] = pixels[i];
};
// console.log(imageData.data);
anotherContext.putImageData(imageData, 0, 0);
}
$("#slider").slider({
min: 0,
max: 99,
slide: function (event, ui) {
var currentKernel = null;
//do not use any filtering if slider is on 0 position
if(ui.value == 0) {
currentKernel = kernel;
}
else {
currentKernel = sharpnessKernel.slice(0);
currentKernel[4] -= (ui.value / 100);
}
draw(currentKernel);
}
});
}
})()
Your current function and bracket setup is completely broken, which also suggests that you're not using firebug or any other web-console to debug your javascript.
For a start you should move some functions outside of the main one and get a modern editor as most of them have means of showing brackets which belong together.
EDIT: Looks similar to the code from WebGL fundamentals. To answer your question: you're drawing to screen only if the bound framebuffer is null (as you can read on that site).
Anyway, you might be helped with this one: Creating texture from getImageData (Javascript) or possibly fabric.js image filters

Categories

Resources