There are many multitexturing effects you can achieve with the fixed function pipeline, but things start getting really cool when you add shaders. These are programs that take over the tasks of transforming vertices and calculating pixel colours in arbitrary ways, allowing techniques such as bump mapping, environment mapping, blurs, bloom and more. Shaders and multitexturing go hand in hand so I'll tackle them both in one post. Source is available as Tutorial 4
Following on from the simple texturing tutorial, we'll make some minor changes. Starting at the beginning:
GLHelper is a utility class to hide some of the complexity of loading a shader. Then we ask for 2 texture handles. We then bind them in turn and fill them with data. This all goes on in texture unit zero, as we don't need to render them in parallel yet.public void init(GL gl) {
GLHelper glh = new GLHelper();
try {
shader = glh.LoadShaderProgram(gl, "/tutorial4/vertex.shader", "/tutorial4/fragment.shader");
} catch (IOException ex) {
Logger.getLogger(TutorialObject.class.getName()).log(Level.SEVERE, null, ex);
} catch (GLHelperException ex) {
Logger.getLogger(TutorialObject.class.getName()).log(Level.SEVERE, null, ex);
}
gl.glGenTextures(2, textures, 0);
gl.glBindTexture(GL.GL_TEXTURE_2D, textures[0]);
ByteBuffer b = genTexture(32);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA8, 32, 32, 0, GL.GL_RGB, GL.GL_BYTE, b);
gl.glBindTexture(GL.GL_TEXTURE_2D, textures[1]);
b = genTexture(32);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA8, 32, 32, 0, GL.GL_RGB, GL.GL_BYTE, b);
}
Then when we draw -
The first block checks to see if the shader program is active, and if not, activates it.
public void display(GL gl, float time) {
int[] i = new int[1];
gl.glGetIntegerv(GL.GL_CURRENT_PROGRAM, i, 0);
if (i[0] != shader) {
gl.glUseProgram(shader);
}
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glActiveTexture(GL.GL_TEXTURE0);
gl.glBindTexture(GL.GL_TEXTURE_2D, textures[0]);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glActiveTexture(GL.GL_TEXTURE1);
gl.glBindTexture(GL.GL_TEXTURE_2D, textures[1]);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glUniform2f(gl.glGetUniformLocation(shader, "offset"), time, time);
gl.glUniform1i(gl.glGetUniformLocation(shader, "tex1"), 0);
gl.glUniform1i(gl.glGetUniformLocation(shader, "tex2"), 1);
gl.glUniform1f(gl.glGetUniformLocation(shader, "r"), time);
gl.glBegin(GL.GL_TRIANGLES);
{
gl.glVertex3f(0, 1, -3);
gl.glVertex3f(-1, -1, -3);
gl.glVertex3f(1, -1, -3);
}
gl.glEnd();
}
The second block enables texturing and binds the textures to the first two units. It also sets up bilinear filtering.
The third block sets some variables that are used by the shaders themselves. These are all uniform variables - they cannot be changed between a glBegin/glEnd pair, but there are also attribute variables that can be applied per vertex. Lighthouse 3d has some good background info.
The actual drawing is actually simpler than the last tutorial - just three vertices. That's possible because the vertex shader calculates the texture coordinates from the vertex coordinates, so they don't have to be specified. Obviously this won't work for every situation, but it's a good example of how the whole fixed function pipeline has been replaced. Those shaders in full:
Vertex:
Fragment:uniform float r;
void main(void)
{
vec4 v = gl_Vertex;
v.y += 0.3*cos(r+v.x);
gl_Position = gl_ModelViewProjectionMatrix * v;
gl_TexCoord[0].xy = gl_Vertex.xy;
gl_TexCoord[1].xy = gl_Vertex.xy;
}
The vertex shader applies a cosine wave to the y coordinate of each vertex - and the fragment shader blends two textures and applies an offset. The overall effect is a wavy, shimmering triangle. You'll have to run this one to see it in motion, I think!uniform sampler2D tex1;
uniform sampler2D tex2;
uniform vec2 offset;
void main(void)
{
vec4 c;
c = texture2D(tex1, gl_TexCoord[0].st);
c+= texture2D(tex2, offset+gl_TexCoord[1].st);
gl_FragColor = c / 2.0 ;
}
No comments:
Post a Comment