c - 使用 OpenGL 进行多纹理绘图?

标签 c opengl

我正在尝试使用 OpenGL 绘制一些具有 2 个或更多不同纹理的对象。例如来自 3 个不同 spritesheet 的 3 个 Sprite 。 你可以看到 here 我所期望的和我所拥有的 我现在遇到的问题是所有 Sprite 都来自 1 个 Sprite 表。 让我们看一下,首先在初始化中我加载了 3 个图像 img0、img1、img2

img0 = loadSurface2D("image0.png");
img1 = loadSurface2D("image1.png");
img2 = loadSurface2D("image2.png");

然后在我的绘制循环中有点像 SDL2:

BKP_Rec dest,src;                                                                                                                    
g2D_renderSurface(img0,NULL,NULL);//will draw all the sprite sheet a (0,0)

src.x = 0;
src.y = 4;
src.w = 64;
src.h = 64;
dest.x = 512;
dest.y = 300;
dest.w = 128;
dest.h = 128;
g2D_renderSurface(img1,&dest,&src);//draw sprite(0,4) 

src.x = 1;
src.y = 2;
dest.x = 562;
dest.y = 300;

g2D_renderSurface(img2,&dest,&src);//draw img 2 sprite(1,2) 

让我们看看 loadSurface2D

Surface2D * loadSurface2D(const char * file)
{
    unsigned  int width, height;
    unsigned char * image = image_loadPNG(file,&width,&height);
    //...all test & flip image are done here, removed it for lisibility
    Surface2D * s = NULL;
    ALLOC_L(Surface2D, s, 1);

    s->data = image;

    s->point[0]  = 0; s->point[1] = 0 ; s->point[2] = 0; s->point[3] = 1;
    s->point[4]  = 0; s->point[5] = -nh; s->point[6] = 0; s->point[7] = 1;
    s->point[8]  = nw; s->point[9] = -nh ; s->point[10] = 0; s->point[11] = 1;
    s->point[12] = nw; s->point[13] = 0 ; s->point[14] = 0; s->point[15] = 1;

    s->texture[0]   = 0.0f; s->texture[1]  = 1.0f ;
    s->texture[2]   = 0.0f; s->texture[3]  = 0.0f;
    s->texture[4]   = 1.0f; s->texture[5]  = 0.0f ;
    s->texture[6]   = 1.0f; s->texture[7]  = 1.0f ;

    s->w = (GLfloat) width;
    s->h = (GLfloat) height;

    bkp_numcal_setIdentity4(s->Mtx_translate);
    bkp_numcal_setIdentity4(s->Mtx_scale);
    bkp_numcal_setIdentity4(s->Mtx_rotate);
    bkp_numcal_setIdentity4(s->Mtx_i);
    bkp_numcal_setIdentity4(s->Mtx);

    GLuint point_vbo = 0;
    glGenBuffers(1,&point_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, point_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(s->point),s->point,GL_STATIC_DRAW);

    GLuint tex_vbo = 1;
    glGenBuffers(1,&tex_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, tex_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(s->texture),s->texture,GL_STATIC_DRAW);

    GLuint vao = stc_2d->vao_num;
    stc_2d->vao_num += 1;
    glGenVertexArrays(1,&vao);
    glBindVertexArray(vao);

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, point_vbo);
    glVertexAttribPointer(0,4,GL_FLOAT,GL_FALSE,0,NULL);

    GLuint dimension = 2;
    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, tex_vbo);
    glVertexAttribPointer(1,dimension,GL_FLOAT,GL_FALSE,0,NULL);

    s->sampler_loc = glGetUniformLocation(stc_2d->sh_sprite, "basic_texture");
    s->texunit_id = GL_TEXTURE0 + stc_2d->texunit_id;
    stc_2d->texunit_id += 1; // initialized at 0, every function call it increments

    GLuint tex = stc_2d->tex_num;
    ++stc_2d->tex_num;  // same here, another global at 0 when initialized
    glGenTextures(1, &tex);

    glBindTexture(GL_TEXTURE_2D, tex);
    glUseProgram(stc_2d->sprite); // EDITED
    glUniform1i(s->sampler_loc, s->texunit_id);

    glTexImage2D(GL_TEXTURE_2D, 0,
        GL_RGBA, width, height, 0, GL_RGBA,
        GL_UNSIGNED_BYTE, image);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    int st_offset_loc = glGetUniformLocation(stc_2d->sh_sprite, "vt_");
    glUniformMatrix2fv(st_offset_loc, 1,GL_FALSE, s->vt_);
    s->st_offset = st_offset_loc;

    s->vt_[0] = 0.0;
    s->vt_[1] = 0.0;
    s->vt_[2] = 0.0;
    s->vt_[3] = 0.0;

    s->vao = vao;
    s->texid = tex;
    s->tex_vbo = tex_vbo;
    s->point_vbo = point_vbo;
    return s;
}

基本上我只是加载 png 创建纹理。有一些值 (stc_2D->*) 在启动时初始化为 0,在计数器 ex: stc_2D->vba_num 告诉当前要创建的 vba 编号。

现在要渲染的函数

void g2D_renderSurface(BKP_Surface2D * s,BKP_Rec * dest,BKP_Rec * src)
{
    glUseProgram(stc_2d->sh_sprite);
    glBindVertexArray(s->vao);

    glActiveTexture(s->texunit_id);
    glBindTexture(GL_TEXTURE_2D, s->texid);
    //glUniform1i(s->sampler_loc, s->texunit_id);

假设我没有评论这一行

    float xf,yf;

    if(dest != NULL)
    {
        xf = (dest->x / (float) stc_fb_width * 2 - 1) ;
        yf = - ((dest->y / (float) stc_fb_height * 2 - 1));
        bkp_numcal_setFreeScalMatrix4(s->Mtx_scale,dest->w /s->w, dest->h/ s->h, 1.0f);
    }
    else
    {
        xf =  - 1 ;
        yf =   1;
        bkp_numcal_setIdentity4(s->Mtx_scale);
    }

    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    if(src != NULL)
    {
        s->vt_[0] =(float)(src->x * src->w) / s->w;
        s->vt_[1] = (float) src->w / s->w;
        s->vt_[2] =(s->h - (float)((1 + src->y) * src->h) )/ s->h;
        s->vt_[3] = (float) src->h / s->h;
    }
    else
    {
        s->vt_[0] = 0.0;
        s->vt_[1] = (float) s->w / s->w;
        s->vt_[2] = 0.0;
        s->vt_[3] = (float) s->h / s->h;
    }

    glUniform4fv(s->st_offset,1,s->vt_);

    bkp_numcal_translate4(s->Mtx_translate, xf, yf, 0);
    bkp_numcal_multMat4Mat4(s->Mtx,s->Mtx_scale,s->Mtx_translate);
    glUniformMatrix4fv(stc_2d->mtx_location, 1,GL_FALSE, s->Mtx);
    return;
}

现在到了着色器的最后。

顶点:

#version 410\n
in vec3 vertex_position;uniform mat4 matrix;
in vec2 vt_loc;
varying vec2 v_uv;
uniform vec4 vt_;
void main() 
{
    v_uv.x = (vt_loc.x * vt_[1]) + vt_[0];
    v_uv.y = (vt_loc.y * vt_[3]) + (vt_[2]);

    gl_Position = matrix * vec4(vertex_position, 1.0);
 }

片段:

#version 410
out vec4 frag_colour;
uniform sampler2D basic_texture;
varying vec2 v_uv;
void main() 
{
    vec4 texel = texture(basic_texture, v_uv);
    frag_colour = texel; 
}

我认为它们可能是我不明白的东西,因为我不明白为什么它会绘制 3 个我想要的大小、我想要的位置但具有唯一相同纹理的对象。我在想我覆盖了相同的纹理,但它是第一个显示的纹理,而不是最后一个加载的纹理。

最佳答案

glUniform*指定当前程序对象的统一变量值。
glUseProgram安装程序对象作为当前呈现状态的一部分。

存储由 glUniform* 设置的最后一个值。从 loadSurface2D 中删除统一值的所有设置。在 glUseProgram(stc_2d->sh_sprite); 之后立即在 g2D_renderSurface 中执行统一值的所有设置。

进一步注意,您必须分配给纹理采样器统一 basic_texture 的值是,不是纹理单元枚举常量(不是 GL_TEXTURE0 , GL_TEXTURE1, ...).
它必须是纹理单元的编号(0、1、2...)

这是错误的:

s->texunit_id = GL_TEXTURE0 + stc_2d->texunit_id;
glUniform1i(s->sampler_loc, s->texunit_id);

它必须是:

s->texunit_id = stc_2d->texunit_id;

.....

glUseProgram(stc_2d->sh_sprite);

glActiveTexture(s->texunit_id + GL_TEXTURE0); // GL_TEXTURE0, GL_TEXTURE1, GL_TEXTURE2, ....
glBindTexture(GL_TEXTURE_2D, s->texid);
glUniform1i(s->sampler_loc, s->texunit_id);   // 0, 1, 2, ....

关于c - 使用 OpenGL 进行多纹理绘图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48742558/

相关文章:

c - STM32,读取ADC值并使用UART传输(HAL库)

c - 我的程序收到错误 'stray '\16 0' in program '

c - 如何在linux中打印进程的pgd和stack_start值?

c++ - 未定义对 Main::playerX 的引用

c++ - 在 OpenGL Win32 上激活多重采样

c++ - openGl 对象在某些 zCoord 处消失

c++ - Ubuntu 上的 Eclipse 和 OpenGL 设置

c - 如何反转字节顺序?

C指针故障: it loses address information when returned from a function

amazon-web-services - 在 AWS EC2 上运行 OpenGL + SDL2