recently I have been suffering from unpack 6 images from single environment texture for rendering reflection pass.
SOURCE IMG
It turns out in webGl it is difficult to use texImage2D in this kind of job, since texImage2D doesn't provide xoffset, neither yoffset. Granted copyTexImage2D and texSubImage2D did provide offset parameters, however, by using those two functions never run for me
Finally, I found the solution by render the image into canvas then pass the canvas to texImage2D.
RENDER RESULT
But I got annoying texture seam on the screen. How did that happen and how can I fix it? Thanks guys.
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
var myCanvas = document.createElement("canvas");
myCanvas.width = 512;
myCanvas.height = 512;
var myCanvasContext = myCanvas.getContext("2d"); // Get canvas 2d context
myCanvasContext.drawImage(_this._data.image, 1024, 512, 512,512,0,0,512,512);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, myCanvas);
myCanvasContext.drawImage(_this._data.image, 0, 512, 512,512,0,0,512,512);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, myCanvas);
myCanvasContext.drawImage(_this._data.image, 512, 1024, 512,512,0,0,512,512);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, myCanvas);
myCanvasContext.drawImage(_this._data.image, 512,0, 512,512, 0,0,512,512);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, myCanvas);
myCanvasContext.drawImage(_this._data.image, 512, 512,512,512,0,0,512,512);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, myCanvas);
myCanvasContext.drawImage(_this._data.image, 1536, 512,512,512,0,0,512,512);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, myCanvas);
_this._data.image is the environment image; and each texture block is 512X512.
Related
i'm trying to load image on webgl by texture, the detail steps is:
after loaded image ,create positions and bind positionBuffer:
...
const positions = [ // here width is viewport width, and height calculted by height = naturalHeight / naturalWidth * width;
-width / 2, -height / 2, 0.0,
width / 2, -height / 2, 0.0,
width / 2, height / 2, 0.0,
-width / 2, height / 2, 0.0,
]
...
create textureCoordinates and bind textureCoordBuffer
create indices( define which vertexes combines a plane ) and bind indexBuffer
create projectionMatrix ,modelViewMatrix, pull out the positions from the positionbuffer into the vertexPosition attribute, pull out the texture coordinates from the texture coordinate buffer into the textureCoord attribute
pass projectionMatrix,modelViewMatrix by gl.uniformMatrix4fv
bindTexture:
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
const level = 0;
const internalFormat = gl.RGBA;
const srcFormat = gl.RGBA;
const srcType = gl.UNSIGNED_BYTE;
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, srcFormat, srcType, 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.LINEAR );
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,gl.LINEAR );
last step is active texture0,bindTexture,bound the texture to texture unit 0, and gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
After these steps, the result on the screen just looks compressed, the image becomes fuzzy and full of sawtooth.
What could i do to solve this problem ?
I run into this error when I set a non-power of to image on webGL:
Error: WebGL warning: drawArrays: TEXTURE_2D at unit 0 is incomplete:
Mipmapping requires power-of-two sizes.
Note, I am currently learning webGL. I have notice that when I use a Power-of-Two image every thing works fine.
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
All I want to do is learn to load all kinds of images on webgl
WebGL1 has limits on non-power-of-2 textures. They can't have mips and they can't repeat. So, to use a non-power-of-2 texture you have to set these texture parameters
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
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);
You can also use gl.NEAREST
Sometimes you can use code like this
...
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
// Check if the image is a power of 2 in both dimensions.
if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
// Yes, it's a power of 2. Generate mips.
gl.generateMipmap(gl.TEXTURE_2D);
} else {
// No, it's not a power of 2. Turn off mips and set wrapping to clamp to edge
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.LINEAR);
}
...
function isPowerOf2(value) {
return (value & (value - 1)) == 0;
}
See this article
I cant figure out why this is happening.
I draw a quad (of 2 triangles) with the following vertices
let data = [
-0.5, -0.5, 0,
0.5, -0.5, 0,
0.5, 0.5, 0,
-0.5, -0.5, 0,
0.5, 0.5, 0,
-0.5, 0.5, 0
]
And the following texture coordinates
let textureData = [0,0,1,0,1,1,0,1];
which gives me for this texture
this output
Another error is that the texture is not transparent, but i call
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
every frame i draw the texture.
So my Questions are, what are the right texture coordinates and how can draw a texutere with a transparent background.
Edit :
Loading Texture
this._image.onload = () => {
gl.bindTexture(gl.TEXTURE_2D, this._textureBuffer);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._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);
gl.bindTexture(gl.TEXTURE_2D, null);
};
Cant post more code but short summary
gl.bindBuffer(vbo)
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture()
gl.uniform1i(sampler2D,0)
draw stuff
Edit 2 (How i create Buffer that contains vertices)
this._vertexBufferObject= gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
this._textureBufferObject= gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this._textureBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureData), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
Edit 3: Draw-Method and applyTexture
draw(camera) {
let gl = Core.mGL;
// gl.enable(gl.BLEND);
// gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBufferObject);
this._shaderProgram.activateProgram(camera.vpMatrix);
gl.vertexAttribPointer(this._shaderProgram.vertexAttributeLocation, 3, gl.FLOAT, false, 0, 0);
gl.vertexAttribPointer(this._shaderProgram.textureAttributeLocation, 2, gl.FLOAT, false, 0, 0);
this._shaderProgram.loadTransformation(this._transformation.transform());
this._shaderProgram.applyTexture(this._textureBuffer, gl.TEXTURE_2D);
gl.drawArrays(gl.TRIANGLES, 0, this._data.length / 3);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
this._shaderProgram.deactivateProgram(gl.TEXTURE_2D);
}
applyTexture(id, type) {
this._gl.activeTexture(this._gl.TEXTURE0);
this._gl.bindTexture(type, id);
this._gl.uniform1i(this._mouseSamplerLocation, 0);
}
You need two more texture vertices
0,0, 1,0, 1,1, 0,1
to
0,0, 1,0, 1,1,
0,0, 1,1, 0,1
The correct texture coordinates depend on your position vertices so it seems fine.
And I guess your texture is not transparent. It might be just with white background.
#update1
Please do this
after glTexImage2D()
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
or just do
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
And don't do unbindtexture gl.bindTexture(gl.TEXTURE_2D, null);
#update2
this._shaderProgram.activateProgram(camera.vpMatrix);
gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBufferObject);
gl.vertexAttribPointer(this._shaderProgram.vertexAttributeLocation, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, this._textureBufferObject); // **missing**
gl.vertexAttribPointer(this._shaderProgram.textureAttributeLocation, 2, gl.FLOAT, false, 0, 0);
I am working on a WebGL project that requires blending of 100 pictures. However, there is significant data loss in this process.
What I mean by that is, for example, I did a test to draw the same picture 100 times with each of them setting alpha value 1/100. In principle I should have got the same picture as itself but I have not.
I suspect that has something to do with framebuffer which only supports 8 bit unsign int array thus each time the picture gets drawn, its alpha value is truncated. I was wondering if I can use floating point texture with OES-texture-float extension and rendering to texture to solve the issue.
First I set up a framebuffer to render my 100 pictures to (after enabling the "OES-texture-float" extension). In particular, texImage2D takes the parameter gl.FlOAT instead of gl.UNSIGNED_BYTE. Finally I draw rttTexture as the final result to the display.
The issue is that when I used gl.UNSIGNED_BYTE it outputs a compromised result as I described before. However, when I used gl.FlOAT it outputs nothing. Is this the right process for me to solve this issue? Where might the problem be? (I am sure that the extension is enabled)
rttFramebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
rttFramebuffer.width = 512;
rttFramebuffer.height = 512;
rttTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, rttTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
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.generateMipmap(gl.TEXTURE_2D);
//gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, rttFramebuffer.width rttFramebuffer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, rttFramebuffer.width, rttFramebuffer.height, 0, gl.RGBA, gl.FLOAT, null);
var renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, rttFramebuffer.width, rttFramebuffer.height);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, rttTexture, 0);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
drawScene();
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
drawFinalScene();
I have a one question about WebGLRenderingContext's texImage2D and texSubImage2D function.
What I trying to create is something similar like loading image by tile by tile.
Here is my first function. It's working properly while it's first load. But whenever loading second time using same function but tiled background.
It failed. Look at the code below
// This is first load code which is working fine
gl.bindTexture(gl.TEXTURE_2D, handle)
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null)
gl.bindTexture(gl.TEXTURE_2D, handle)
gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, gl.RGBA, gl.UNSIGNED_BYTE, image)
// This is second time using same but one different coding section [image data from canvas]. But it's not working.
gl.bindTexture(gl.TEXTURE_2D, handle)
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, [image data from canvas])
gl.bindTexture(gl.TEXTURE_2D, handle)
gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, gl.RGBA, gl.UNSIGNED_BYTE, image)
Have you ever face the problem similar like me. Then please guide me to the light. Much appreciate it.
UPD
on('start', function (data) {
gl.bindTexture(gl.TEXTURE_2D, handle)
// gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, data.width, data.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, myCanvasData)
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, data.width, data.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(myCanvasData.buffer))
}).on('progress', function (ev) {
var x = ev.position[0]
var y = texHeight - ev.position[1] - ev.image.height
// now blit the intermediate image
gl.bindTexture(gl.TEXTURE_2D, handle)
gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, gl.RGBA, gl.UNSIGNED_BYTE, ev.image)
}).on('complete', function () {
})
Console warning image
If I've understood your question correctly, you're probably using texImage2D wrong. The thing is, for ImageData signature of the function is a bit different (it's the same as for am image):
void texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, TexImageSource? source),
where TexImageSource can be an ImageData object. So you just need to pass it, without explicitly passing width and height of the image:
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
gl.RGBA,
gl.UNSIGNED_BYTE,
canvas.getImageData(/* ... */)
);
You need to use like texImage2D without explicitly passing width and height. Because i think texSubImage2D function width and height requires thought
on('start', function (data) {
gl.bindTexture(gl.TEXTURE_2D, handle)
// gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, data.width, data.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, myCanvasData)
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, data.width, data.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(myCanvasData.buffer))
}).on('progress', function (ev) {
var x = ev.position[0]
var y = texHeight - ev.position[1] - ev.image.height
// now blit the intermediate image
gl.bindTexture(gl.TEXTURE_2D, handle)
gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, gl.RGBA, gl.UNSIGNED_BYTE, ev.image)
}).on('complete', function () {
})
Console warning image