1

I'm trying to create sprite animation with texture array. Right now I have follow code:

int width, height, depth;
stbi_set_flip_vertically_on_load(true);
byte_t* buffer = stbi_load(R"(.\fire.jpg)",
                                   &width, &height, &depth, STBI_rgb_alpha);
if (buffer == nullptr) {
    std::cerr << "Could not read texture" << std::endl;
    return EXIT_FAILURE;
}
GLuint texture_id;
const GLenum target = GL_TEXTURE_2D_ARRAY;
SAFE_CALL(glGenTextures(1, &texture_id));
SAFE_CALL(glBindTexture(target, texture_id));
SAFE_CALL(glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0));
SAFE_CALL(glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 1));
SAFE_CALL(glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
SAFE_CALL(glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
SAFE_CALL(glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
SAFE_CALL(glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));

const GLsizei tile_w_count = 6, tile_h_count = 6;
const GLsizei total_tiles = tile_w_count * tile_h_count;
const GLsizei tile_w = width / tile_w_count,
              tile_h = height / tile_h_count;
std::cout << "Texture WxH: " << width << "x" << height;
std::cout << ", Tile WxH: " << tile_w << "x" << tile_h << std::endl;
SAFE_CALL(glTexStorage3D(target, 1, GL_RGBA8, tile_w, tile_h,
                         total_tiles));

SAFE_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, width));
SAFE_CALL(glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, height));
for (GLsizei i = 0; i < total_tiles; ++i) {
    SAFE_CALL(glTexSubImage3D(
        GL_TEXTURE_2D_ARRAY,
        0,
        0, 0, i,
        tile_w, tile_h, 1,
        GL_RGBA,
        GL_UNSIGNED_BYTE,
        buffer + (i * tile_w * tile_h * depth)
    ));
}

Fragment shader:

#version 460 core

in vec2 tex_coords;
out vec4 frag_color;

uniform sampler2DArray texture_0;

uniform int current_frame;
uniform int total_frames;

float actual_layer() {
    return max(0, min(total_frames - 1,
                      floor(current_frame + 0.5)));
}

void main() {
    frag_color = texture(texture_0, vec3(tex_coords, actual_layer()));
}

And seems like I incorrectly crop source texture, because when I run my program in Nsight debugger I saw follow:

Texture array:

texture array

Original image:

Original image

Is it issue with cropping source image, or issue with fragment shader? How to make sprite animation correctly?

genpfault
  • 51,148
  • 11
  • 85
  • 139
oiushder
  • 11
  • 1

1 Answers1

1

You calculate the data offset incorrectly. The correct way would be:

Convert i to a 2-d index of the tile:

int ix = i % tile_w_count;
int iy = i / tile_w_count;

The x and y coordinates of its top-left pixel would be at

int x = ix*tile_w;
int y = iy*tile_h;

The offset can be calculated then by:

buffer + 4*(y*width + x)

Note that you shall use 4 instead of depth because stb returns the number of channels that was found in the file rather the number of the channels returned.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • yes, thanks. Also I changed (y * width + x)*depth to (y * width + x)*4. I guess stbi wrote 3, although I opened image with STBI_rgb_alpha, to depth because jpg format doen't support transparent pixels, isn't it? (y * width + x) * depth Does it mean that tile in buffer stores like: tile_r_00, tile_g_00, tile_b_00, tile_r_10, ..., -> image_width tile_r_01, tile_g_01, tile_b_01, tile_r_11 ..., -> image_width – oiushder Aug 30 '22 at 19:31
  • @oiushder oh good catch; stb returns the number of channels found in the file rather than the number of the channels requested. Doesn't have to be a JPG. Even a grayscale PNG, if you request four channels, you will get four channels, but depth will be set to 1 to reflect the data in the file. This is a documented behavior. I don't understand the rest of what you're saying. – Yakov Galka Aug 30 '22 at 22:00