Welcome to Fractal Forums

Fractal Software => Programming => Topic started by: David Makin on January 30, 2011, 04:27:51 PM




Title: Shader 2 coding - render to a texture
Post by: David Makin on January 30, 2011, 04:27:51 PM
Hi all, just asking this question before I get around to the need to do it.

I have so far only coded shader 2 to render to a framebuffer that is then displayed but I understand from the OpenGL ES2 documentation that it is possible to render so that the target is a texture rather than a screen to be displayed i.e. so that the rendered texture can then be used as a source texture in a secondary shader program allowing multi-layering without having to put all the code in a single shader fragment *but* I can't make head or tail of how to do this, nor can I find any examples that do so.

Can anyone help ?

Here's an example of how I'm rendering to a framebuffer that is then displayed (old and not optimum code but I'm still a beginner as far as using shader 2 is concerned):

Code:
    glUseProgram(program);
if ((didAnimate)||([tfc colour]>149))
{
if (usesmallbail!=1e-3)
{
glUniform1f(uniforms[UNIFORM_SMALLBAIL], (GLfloat)1e-3);
usesmallbail=1e-3;
}
if (usemaxiter!=100)
{
glUniform1i(uniforms[UNIFORM_MAXITER], 100);
usemaxiter=100;
}
}
else
{
if (usesmallbail!=1e-6)
{
glUniform1f(uniforms[UNIFORM_SMALLBAIL], (GLfloat)1e-6);
usesmallbail=1e-6;
}
if (usemaxiter!=256)
{
glUniform1i(uniforms[UNIFORM_MAXITER], 256);
usemaxiter=256;
}
}
glUniform1f(uniforms[UNIFORM_OFFSET], (GLfloat)(offset/256.0));
glUniform1f(uniforms[UNIFORM_PAL], (GLfloat)(pal/256.0));
glUniform1f(uniforms[UNIFORM_CSCALE], cscale);
if ((colourCycle)&&(!useMap))
{
if ((manual)||(autoAnim))
{
offset = (offset+4)&255;
pal = (pal+4)&255;
}
else
{
offset = ((int)round(offset+8*ox))&255;
pal = ((int)round(pal+8*oy))&255;
}
}
if ((useposx!=posx)||(useposy!=posy))
{
glUniform2f(uniforms[UNIFORM_POS], (GLfloat)posx, (GLfloat)-posy);
useposx=posx;
useposy=posy;
}
if ((usetrapCentrex!=trapx)||(usetrapCentrey!=trapy))
{
glUniform2f(uniforms[UNIFORM_TRAP], (GLfloat)trapx, (GLfloat)trapy);
usetrapCentrex=trapx;
usetrapCentrey=trapy;
}
UInt32 u=0;
while (u<[extraUniforms count])
{
NSMutableDictionary *dic = [extraUniforms objectAtIndex:u];
switch ([[dic objectForKey:@"type"] intValue])
{
case 0:
glUniform1i(uniforms[NUM_UNIFORMS+u], (GLint)[[dic objectForKey:@"value"] intValue]);
break;
case 1:
glUniform1f(uniforms[NUM_UNIFORMS+u], (GLfloat)[[dic objectForKey:@"value"] floatValue]);
break;
case 2:
glUniform2f(uniforms[NUM_UNIFORMS+u], (GLfloat)[[dic objectForKey:@"value1"] floatValue], (GLfloat)[[dic objectForKey:@"value2"] floatValue]);
break;
}
++u;
}
numIter=256<<8;
// Update attribute values
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
//    glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, 1, 0, squareColors);
  //  glEnableVertexAttribArray(ATTRIB_COLOR);
    glVertexAttribPointer(ATTRIB_COORD, 2, GL_FLOAT, 0, 0, squareCoords);
    glEnableVertexAttribArray(ATTRIB_COORD);

oldScale=newScale;
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);*/
double tt = [[NSProcessInfo processInfo] systemUptime];
if (newScale>40.0)
{
if ((formula==3)&&(addRot>=4)&&(useposx*useposx+useposy*useposy<4.0f))
{
newScale=192.0f;
}
else if (useposx*useposx+useposy*useposy<1.0f)
{
newScale=192.0f;
}
else
{
newScale=384.0f;
}
glViewport(0, 0, newScale*backingWidth/384.0f, newScale*backingHeight/384.0f);
glBindFramebuffer(GL_FRAMEBUFFER, backgroundBuffer);
GLuint tx = glGetUniformLocation(program,"palettes");
glUniform1i(tx,1);
glActiveTexture(GL_TEXTURE1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
glActiveTexture(GL_TEXTURE0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, backTex, 0);
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_COORD, 2, GL_FLOAT, 0, 0, squareCoords);
glEnableVertexAttribArray(ATTRIB_COORD);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);/*
oldtime=1.0f;
if (tt<0.00033)
{
oldtime=tt;
newScale=384.0f;
}
else// if (tt<0.0008)
{
newScale=192.0f;
}
for (UInt32 i=0;i<8;i+=2)
{
if (squareVertices[i]<0.0f)
{
texVertices[i]=0.0f;
}
else
{
texVertices[i]=newScale*backingWidth/(512.0f*384.0f);
}
if (squareVertices[i+1]<0.0f)
{
texVertices[i+1]=0.0f;
}
else
{
texVertices[i+1]=newScale*backingHeight/(512.0f*384.0f);
}
}
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
glViewport(0, 0, backingWidth, backingHeight);
glUseProgram(program1);
GLuint tx1 = glGetUniformLocation(program1,"texture");
glUniform1i(tx1,0);
glVertexAttribPointer(ATTRIB_VERTEX1, 2, GL_FLOAT, 0, 0, squareVertices);
glEnableVertexAttribArray(ATTRIB_VERTEX1);
glVertexAttribPointer(ATTRIB_COORD1, 2, GL_FLOAT, 0, 0, texVertices);
glEnableVertexAttribArray(ATTRIB_COORD1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
else
{
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
glViewport(0, 0, backingWidth, backingHeight);
GLuint tx1 = glGetUniformLocation(program,"palettes");
glActiveTexture(GL_TEXTURE1);
glUniform1i(tx1,1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_COORD, 2, GL_FLOAT, 0, 0, squareCoords);
glEnableVertexAttribArray(ATTRIB_COORD);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
    // Draw
[context presentRenderbuffer:GL_RENDERBUFFER];
tt = [[NSProcessInfo processInfo] systemUptime] - tt;



Title: Re: Shader 2 coding - render to a texture
Post by: cbuchner1 on January 30, 2011, 08:12:08 PM
You will want to make use of the ARB framebuffer object extension. http://www.opengl.org/registry/specs/ARB/framebuffer_object.txt
This extension allows you to change the render target to an FBO, instead of rendering to screen. Later the FBO can be bound to a texture and used in another render pass.

On Win32 systems one can also render to PBuffers. http://www.opengl.org/registry/specs/ARB/wgl_pbuffer.txt  But that's not part of OpenGL ES 2.0 I presume.

Do you need more information how to set up an FBO?


Title: Re: Shader 2 coding - render to a texture
Post by: David Makin on January 31, 2011, 02:40:47 AM
Doh !!
I just looked through my own code again (as posted above) and realised that I was already rendering to a texture that gets re-used !
In this case rendering smaller-scale for speed then using that as source to smoothly blit re-scaled to screen size :)

Shows that:

1. As you get older things slip your mind !
2. I really should comment my code more !
3. Most important - I shouldn't leave fractal coding for such long periods :)


Title: Re: Shader 2 coding - render to a texture
Post by: marius on January 31, 2011, 03:09:43 AM
In this case rendering smaller-scale for speed then using that as source to smoothly blit re-scaled to screen size :)

Thinking about doing some GPU assisted DoF. Mostly to reduce shimmering in the distance.
Something like render to texture, mipmap and then 2nd ortho projected shader to pick from mipmap level depending on distance.
What'd be the best way to retain the zbuffer / read from zbuffer for the 2nd shader? I'd rather not re-raycast.

I guess I could have the 1st shader encode distance in the alpha channel, then have the 2nd pass use alpha to blend between two mipmaps. Suggestions?