With the texture sitting in VRAM and the 3D model equipped texture coordinates, you are itching to put the texels on the triangles. A good first step, however, is to visually confirm that the texture coordinates are what you think they should be.
In your vertex shader, you receive the texture coordinates as an attribute and send them along for interpolation:
// ...
in vec2 texPosition;
out vec2 mixTexPosition;
void main() {
// ...
mixTexPosition = texPosition;
}
In the fragment shader, you color the model using the texture coordinates:
in vec2 mixTexPosition;
out vec4 fragmentColor;
void main() {
fragmentColor = vec4(mixTexPosition, 0.0, 1.0);
}
The red intensity comes from the x-coordinate, and the green intensity from the y-coordinate. Since the texture coordinates are in [0, 1] and so are color intensities, the texture coordinates can be interpreted as colors. The texture coordinates are in a 2-vector, so you need a third intensity to make an RGB color. 0 is a reasonable choice for the blue intensity. The renderer should reveal a mixture of black, green, red, and yellow, as you see here:
Try dragging the unwrapped vertices around to see the fully saturated red, green, yellow, and black corners.
Once the texture coordinates check out, you are ready to use them in the fragment shader to look up the fragment's texel. The fragment needs to know what texture unit has the texture, so you declare it as a uniform of the type sampler2D
:
uniform sampler2D crateTexture;
In JavaScript, you must set this uniform to the number of the texture unit. If the crate has been bound to texture unit 0, then you'd write this code:
shaderProgram.bind();
shaderProgram.setUniform1i('crateTexture', 0);
shaderProgram.unbind();
The texture unit number is an integer, so setUniform1i
is used instead of setUniform1f
. If the unit numbers do not change as your application runs, consider setting them once in your initialization routine and never thinking about them again.
The final step is to use the texture
function to pull out the color as a 4-vector and assign it to the fragment's color:
uniform sampler2D crateTexture;
in vec2 mixTexPosition;
out vec4 fragmentColor;
void main() {
fragmentColor = texture(crateTexture, mixTexPosition);
}
Lighting could be added to this shader, with the texture providing each fragment's albedo. That's what's done in this renderer that shows a full rotating crate:
All six faces of the box are unwrapped so that they overlap on the crate texture. The light source is up and to the right of the eye. As you turn the crate, you see the faces pointing away from the light darken.