-
Notifications
You must be signed in to change notification settings - Fork 0
Textures
Last chapter we talked about simple shapes with only onw color. But what if you want just load the pixel data from a .png and throw it on your shape ? As you can guess in the title we are now talking about Textures !. So how do these work in Zap ?
This is the code we will talk about:
#include <Zap.h>
#include <Graphics.h>
#include <vector>
const char* vertexCameraShaderSource = R"glsl(#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
TexCoord = aTexCoord;
}
)glsl";
const char* fragmentCameraShaderSource = R"glsl(#version 330
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
})glsl";
int main()
{
zap::Init();
zap::Window window(1920, 1080, "Hello Window");
zap::InitGlad();
std::vector<float> vertices =
{
// positions // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left
};
std::vector<unsigned int> indices =
{
0, 1, 3,
1, 2, 3
};
zap::Mesh mesh (vertices, indices);
mesh.SetVertexShaderSource(vertexCameraShaderSource);
mesh.SetFragmentShaderSource(fragmentCameraShaderSource);
mesh.SetAttribPointer(0, 3, 5, 0);
mesh.SetAttribPointer(1, 2, 5, 3);
unsigned int texture0Id = mesh.AddTextureFromPath(0, "path/to/your/texture.png", zap::TextureFilter::NEAREST, zap::MipmapSetting::LINEAR_MIPMAP_LINEAR, zap::TextureWrapping::CLAMP_TO_BORDER).getHash();
mesh.Finish();
mesh.UseProgram();
mesh.ActivateTexture(texture0Id, "texture1");
window.UpdateViewport(true);
while (window.Open())
{
glClear(GL_COLOR_BUFFER_BIT);
mesh.BindTextureByHash(texture0Id);
mesh.Bind();
mesh.Draw();
window.Update();
window.Draw();
}
zap::Delete();
}std::vector<float> vertices =
{
// positions // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left
};Before we can start we first have to map the texture to our shape. We simply do that with texture coords which represent a point in your texture so it can be mapped on your shape. We can read the from our vertices and then export them in the fragment shader. The texture coordinates reach from 0 to 1. Each point has a x and a y coordinate. A point in your texture with the coordinates 0,0 would be in the top left corner of your texture. I the coordinates are 1, 1 it would be in the bottom right of your texture. So if x increases you go to the right and if y increases you go down in your texture.
Let's have a look at our vertex shader:
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
TexCoord = aTexCoord;
}As you can see we read the data from our vertices and then export it the fragment shader with out vec2 TexCoord. "out" simply means that we want to export this variable to the fragment shader.
Because we are reading additional data we have to write new attribute pointer:
mesh.SetAttribPointer(0, 3, 5, 0);
mesh.SetAttribPointer(1, 2, 5, 3);Now we take a look at our fragment shader:
#version 330
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
}We recieve our exported variable TexCoord and combine it with a uniform sampler variable to create a texture which then determines our final pixel color.
unsigned int texture0Id = mesh.AddTextureFromPath(0, "path/to/your/texture.png", zap::TextureFilter::NEAREST, zap::MipmapSetting::LINEAR_MIPMAP_LINEAR, zap::TextureWrapping::CLAMP_TO_BORDER).getHash();You first have to load the texture from a file with mesh.AddTextureFromPath. It returns a reference to the texture class. But you'll probably only need its id so we call .getHash(). Now to the parameters. The first one is your hash. You can also call the function without this parameter and it will be autogenerated. Next is your path to your texture. The 3rd parameter is your texture filter. You can choose between linear and nearest filtering. If you want every pixel value as it is you use nearest. If you choose linear, the pixel values of your texture will be smoothed. Teh next one is your mipmap settings. Because your texture isn't always the same size as the original smaller version of your textures will be created. These versions are called mipmaps. You can set the filtering between these with this parameter. Lastly you are able to specify how your texture behaves if it can't fit in your shape. I wont go over them in detail. If you want to see the differences you can visit the OpenGL website: https://learnopengl.com/Getting-started/Textures
Next we have to activate our texture. We do that by first using our shader program and then calling mesh.ActivateTexture(). We first specify the hash and then the name of our uniform sample variable we want to activate.
mesh.UseProgram();
mesh.ActivateTexture(texture0Id, "texture1");In our case that's the id we got from the loading function abd the name we specified in the fragment shader.
In the update loop you only need to call mesh.BindTextureByHash(texture0Id); . Again you have to specify the id of your texture.
If you haven't got any texture you can grab one from the resource/textures folder from the repository.