patterncMinor
2D OpenGL tile atlas fragment shader
Viewed 0 times
shaderatlasopenglfragmenttile
Problem
I am currently using the following glsl code to retrieve separate textures from a tile atlas:
The tile atlas is made up of: 88 sprites each with dimensions of: 1616 pixels
Is this the best method to use when carrying out this task and could my code be improved / made more efficient?
#version 330 core
in vec2 TexCoord;
out vec4 color;
uniform sampler2D image;
void main()
{
//width and height in tiles of atlas
int width = 8;
int height = 8;
//x and y position of a tile in the atlas
int x = 1;
int y = 4;
float scalarX = 1.0 / width;
float scalarY = 1.0 / height;
color = vec4(1.0) * texture(image, vec2((TexCoord.x + x) * scalarX, (TexCoord.y * scalarY) + y * scalarY));
}The tile atlas is made up of: 88 sprites each with dimensions of: 1616 pixels
Is this the best method to use when carrying out this task and could my code be improved / made more efficient?
Solution
Why don't you simply set the texture coordinates properly and have a "pass-thru" shader that just samples the texture and nothing else? For example, if you're using
This assumes your vertex shader has attribute 0 as position and attribute 1 as texture coordinates. Then your fragment shader just becomes:
NOTE: I may be off by 1 on the right and top side. You might need to subtract 1
glVertexAttribPointer() with an array of vertices and texture coords, make sure that the texture coordinates you send have the proper tile offset. Something like this:const int numXTiles = 8;
const int numYTiles = 8;
const int numXPixelsPerTile = 16;
const int numYPixelsPerTile = 16;
const int atlasWidth = numXTiles * numXPixelsPerTile;
const int atlasHeight = numYTiles * numYPixelsPerTile;
const double pixelXDelta = 1.0 / atlasWidth;
const double pixelYDelta = 1.0 / atlasHeight;
typedef struct vertex {
Point3D position;
Point2D texCoord;
} vertex;
// Assume you're drawing a square and want to texture it with tile 3,4
vertex square[] = {
{ {-1.0, -1.0, 0.0 }, { 3.0 * numXPixelsPerTile * pixelXDelta, 4.0 * numYPixelsPerTile * pixelYDelta } },
{ { 1.0, -1.0, 0.0 }, { 4.0 * numXPixelsPerTile * pixelXDelta, 4.0 * numYPixelPerTile * pixelYDelta } },
{ { 1.0, 1.0, 0.0 }, { 4.0 * numXPixelsPerTile * pixelXDelta, 5.0 * numYPixelPerTile * pixelYDelta } },
{ { -1.0, 1.0, 0.0 }, { 3.0 * numXPixelsPerTile * pixelXDelta, 5.0 * numYPixelPerTile * pixelYDelta } }
};
glBufferData(GL_ARRAY_BUFFER, 4, square, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, sizeof(vertex), 0); // Position
glVertexAttribPointer(1, 2, GL_FLOAT, sizeof(vertex), (GLvoid*)sizeof(Point3D)); // Texture CoordinateThis assumes your vertex shader has attribute 0 as position and attribute 1 as texture coordinates. Then your fragment shader just becomes:
#version 330 core
in vec2 TexCoord;
out vec4 color;
uniform sampler2D image;
void main()
{
color = texture(image, TexCoord);
}NOTE: I may be off by 1 on the right and top side. You might need to subtract 1
pixelXDelta and 1 pixelYDelta from those coordinates - I can never remember.Code Snippets
const int numXTiles = 8;
const int numYTiles = 8;
const int numXPixelsPerTile = 16;
const int numYPixelsPerTile = 16;
const int atlasWidth = numXTiles * numXPixelsPerTile;
const int atlasHeight = numYTiles * numYPixelsPerTile;
const double pixelXDelta = 1.0 / atlasWidth;
const double pixelYDelta = 1.0 / atlasHeight;
typedef struct vertex {
Point3D position;
Point2D texCoord;
} vertex;
// Assume you're drawing a square and want to texture it with tile 3,4
vertex square[] = {
{ {-1.0, -1.0, 0.0 }, { 3.0 * numXPixelsPerTile * pixelXDelta, 4.0 * numYPixelsPerTile * pixelYDelta } },
{ { 1.0, -1.0, 0.0 }, { 4.0 * numXPixelsPerTile * pixelXDelta, 4.0 * numYPixelPerTile * pixelYDelta } },
{ { 1.0, 1.0, 0.0 }, { 4.0 * numXPixelsPerTile * pixelXDelta, 5.0 * numYPixelPerTile * pixelYDelta } },
{ { -1.0, 1.0, 0.0 }, { 3.0 * numXPixelsPerTile * pixelXDelta, 5.0 * numYPixelPerTile * pixelYDelta } }
};
glBufferData(GL_ARRAY_BUFFER, 4, square, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, sizeof(vertex), 0); // Position
glVertexAttribPointer(1, 2, GL_FLOAT, sizeof(vertex), (GLvoid*)sizeof(Point3D)); // Texture Coordinate#version 330 core
in vec2 TexCoord;
out vec4 color;
uniform sampler2D image;
void main()
{
color = texture(image, TexCoord);
}Context
StackExchange Code Review Q#92156, answer score: 6
Revisions (0)
No revisions yet.