Texture in OpenTK

We drew a triangle in the previous post. Now, I want to add texture to the surface of the shape. So, I will try to add an image file as a texture to it. 

Firstly, we have to understand the texturing concept of OpenGL. The texture image should be handled by a coordinate system:
Texturing in Modern OpenGL

OpenGL makes transfers each pixel of the texture to each pixel of our shape. So our texture image is in below:
texturing in modern opengl

If you read the previous posts about usage OpenTK. I created a little system to manage development easily. So, I won't show directly how to use texture in simple code. I want to create Texture class which contains ID of texture. I created a file called Texture.cs:
    public class Texture
    {
        int textureId;

        public Texture(string imagePath)
        {
            SFML.Graphics.Image image = new SFML.Graphics.Image(imagePath);

            GL.GenTextures(1, out textureId);
            GL.BindTexture(TextureTarget.Texture2D, textureId);

            GL.TexImage2D(
                TextureTarget.Texture2D, 
                0, 
                PixelInternalFormat.Rgba, 
                (int)image.Size.X, (int)image.Size.Y, 
                0,
                OpenTK.Graphics.OpenGL.PixelFormat.Rgba,
                PixelType.UnsignedByte,
                image.Pixels
            );
            
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);   
        }

        public void BindTexture()
        {
            GL.ActiveTexture(TextureUnit.Texture0);
            GL.BindTexture(TextureTarget.Texture2D, textureId);
        }
    }
Let's examine above the code. Firstly, I need to integer id field called textureId which is keep pointer for the texture from GPU. I added constructor, and this constructor needs parameter called imagePath. I will pass the image path for the texture with this constructor. I used Image class of SFML for loading image. After that the texture is created with GenTextures(1, out textureId) method, and then we have to bound this texture with TextureTarget. We will load the image data via the TexImage2D method. After that we have to apply some settings via TexParameter. In here, I have some doubt that do we have to use TexParameter, because if I don't then the Texture cannot be shown on the shape(if I find the real answer, I will update here). There is a another method called BindTexture for activating the texture. We have to call this method before drawing the shape. Also, if you think you can confuse this function name with api method name which is BindTexture, you can named with different name.

The property name Texture is defined in GameObject class:
    public class GameObject
    {
        ObjectType objectType;

        public int VAO { get; set; }
        public int IndexCount { get; set; }
        public Texture? Texture { get; set; }
        ...
Also, the draw method changed like as follows:
        public void Draw()
        {
            GL.UseProgram(Shader!.ShaderProgram);

            if(Texture != null)
            {
                Texture.BindTexture();
            }

            GL.UniformMatrix4(0, true, ref Transformation);

            GL.BindVertexArray(VAO);
            GL.DrawElements(PrimitiveType.Triangles, IndexCount, DrawElementsType.UnsignedInt, 0);
            GL.BindVertexArray(0);
        }
It's time to make changes to our mesh class. Because OpenGL has to know texture coordinates from the VBO. The GenerateQuad method updated as follows:
                private void GenerateQuad()
        {   
            ...

            float[] vertices = 
            {
                // x, y, z, s, t
                -len,  len, 0f, 0f, 1f,
                 len,  len, 0f, 1f, 1f,  
                 len, -len, 0f, 1f, 0f,
                -len, -len, 0f, 0f, 0f
            };

            ...

            GenerateVAO(len, vertices, indices);
        }
We have to describe the data to OpenGL properly. So, I added new attribute pointer in the GenerateVAO method:
        private void GenerateVAO(float len, float[] vertices, int[] indices)
        {
            GL.GenVertexArrays(1, out vao);
            GL.BindVertexArray(vao);
            
            ...
            
            int attrPosition_Position = 0;
            GL.EnableVertexAttribArray(attrPosition_Position);
            GL.VertexAttribPointer(attrPosition_Position, 3, VertexAttribPointerType.Float, false, sizeof(float) * 5, 0);
            int attrPosition_TextureCoords = 1;
            GL.EnableVertexAttribArray(attrPosition_TextureCoords);
            GL.VertexAttribPointer(attrPosition_TextureCoords, 2, VertexAttribPointerType.Float, false, sizeof(float) * 5, sizeof(float) * 3);
            
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
            GL.BindVertexArray(0);
        }
I assume you have already knew how to use attribute pointer from the previous posts. We need to change the vertex shader and the fragment shader like below:
#version 330 core

layout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aTexCoord;

uniform mat4 uTransform;

out vec2 passTexCoord;

void main()
{
    gl_Position =  vec4(aPos, 1.0) * uTransform;
    passTexCoord = aTexCoord;
}
We created the empty texture with uniform and the pixel from the image pixels which is specified by passTexCoord is copied to the textureSampler via texture method:
#version 330 core

in vec2 passTexCoord;

out vec4 FragColor;

uniform sampler2D textureSampler;

void main()
{
    FragColor = texture(textureSampler, passTexCoord);
}
Finally, we can define texture for a game object. I created texture for the game object like in the code below:
        private void InitScene()
        {
            objectManager.AddObject(ObjectType.Quad2D);
            objectManager.gameObjects[0].Texture = new Texture("resources/images/image.png");
            ...
Let's see the result:
Texture in OpenTK

No comments:

Post a Comment