Kamouth
Kamouth

Reputation: 134

Rendering to texture in webgl

I'm trying to render my scene (a cube) on a texture. Then I'd like to render the same cube with this texture. (see edit at the end) I'm new to webgl and javascript. I used this webpage as a start. I also read and use this.

The texture seems to be created properly (no errors or warnings) but the result is not the one I expected.

good image bad image

The first picture is the cube with it's "real" texture. The second picture is the cube rendered with the created texture. (both images rendered without errors or warnings)

For some reason I can't call gl.viewport without getting a warning (nothing displayed) :

  RENDER WARNING: texture bound to texture unit 0 is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete'

My issue might be related to this but I got no idea how to fix this.

Important parts of the code:

function drawScene() { 
  gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
  drawOnCube();
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
  [...]
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, rttTexture);    //rttTexture is the created texure
  gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0);
  [...]
}

rq: draw scene is the same as drawOnCube except for the 3 first lines and for the texture used.

function drawOnCube(){

  //gl.viewport(0, 0, rttFramebuffer.width, rttFramebuffer.height);  //
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  perspectiveMatrix = makePerspective(45, rttFramebuffer.width/rttFramebuffer.height, 0.1, 300.0);
  loadIdentity();
  mvTranslate([-0.0, 0.0, -6.0]);
  mvPushMatrix();
  mvRotate(cubeRotation, [1, 0, 1]);

  // Draw the cube by binding the array buffer to the cube's vertices
  // array, setting attributes, and pushing it to GL.

  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);
  gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);
  gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);

  // Specify the texture to map onto the faces.

  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
  gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0);

  // Draw the cube.

  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);
  setMatrixUniforms();
  gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
}

The function which creates the frameBuffer, the renderBuffer:

function initTextureFramebuffer(){
  rttFramebuffer = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
  rttFramebuffer.width = 256;
  rttFramebuffer.height = 256;

  rttTexture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, rttTexture);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, rttFramebuffer.width, rttFramebuffer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  gl.generateMipmap(gl.TEXTURE_2D);

  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);
}

EDIT: I replaced gl.viewportWidth and gl.viewportHeight by hardcoded values. I still got the warning but the cube is displayed. The texture seems to be used on one face at a time and is "incomplete" in most cases (when the cube is rotating). Pictures. I checked my TextCoordBuffer, it looks okay. I tried to render only 1 face of the cube but I still got the issue.

Upvotes: 2

Views: 2837

Answers (1)

user128511
user128511

Reputation:

I see several possible issues.

1) Where is cubeTexture defined? I only see rttTexture

2) rttTexture require mip maps because of setting gl.TEXTURE_MIN_FILTER to gl. LINEAR_MIPMAP_NEAREST but after it's been rendered to it will only have the cube in the first mip (level 0). You either need to turn off mips by setting gl.TEXTURE_MIN_FILTER to gl.LINEAR or gl.NEAREST or you need to call gl.generateMipmap after rendering to rttTexture.

3) You need to set the viewport to match the size of the renderbuffer. You have that line commented out.

Other minor issues.

4) Assigning properties to WebGL objects (eg rttFramebuffer.width) If you ever decide to handle WebGLContextLost events you'll have to fix that code because when the context is lost the gl.create functions will return null and your code that's trying to add a property to null will crash

5) There's no such property as gl.viewportWidth and gl.viewportHeight. I'm sure those are set up somewhere but why make a fake property when a live ones actually exist? Use gl.drawingBufferWidth and gl.drawinBufferHeight or gl.canvas.width and gl.canvas.height. Those are live

6) Looking up uniform and attribute locations is slow so you should only look them up once. As it is now they're being looked up every frame in line

 gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0);

Upvotes: 3

Related Questions