如何在OpenGL中将多个纹理绑定到多个对象

时间:2015-09-20 22:23:19

标签: c++ opengl

我想绘制一个立方体和一个球体,并为每个球体应用不同的纹理。

我使用blender创建场景,然后导出到obj文件,然后包含两个对象的顶点,法线,uv和面以及纹理。

我创建了一个例程来加载obj文件中的所有数据。这一切都有效,因为我可以加载对象并显示它们等但只有一个纹理。正如我所说,我已经浏览了代码和帖子的页面和页面,99%只处理1个纹理到1个对象,处理多个纹理的对象只处理一个对象或处于非常旧的openGL版本。

我还没有尝试过的一件事是片段着色器中的均匀sample2D数组,但我没有找到解释,所以没试过。

我的代码如下:

ObjLoader *obj = new ObjLoader();
string _filepath = "objects\\" + _filename;
//bool res = obj->loadObjWithStaticColor(_filepath.c_str(), _vertices, _normals, vertex_colors, _colors, 1.0);
bool res = obj->loadObjWithTextures(_filepath.c_str(), _objects, _textures);

program = InitShader("shaders\\vshader.glsl", "shaders\\fshader.glsl");
glUseProgram(program);

GLuint vao_world_objects;
glGenVertexArrays(1, &vao_world_objects);
glBindVertexArray(vao_world_objects);

//GLuint vbo_world_objects;
//glGenBuffers(1, &vbo_world_objects);
//glBindBuffer(GL_ARRAY_BUFFER, vbo_world_objects);

NumVertices = _objects[_objects.size() - 1]._stop + 1;
for (size_t i = 0; i < _objects.size(); i++)
{
    _vertices.insert(_vertices.end(), _objects[i]._vertices.begin(), _objects[i]._vertices.end());      
    _normals.insert(_normals.end(), _objects[i]._normals.begin(), _objects[i]._normals.end());
    _uvs.insert(_uvs.end(), _objects[i]._uvs.begin(), _objects[i]._uvs.end());
}

GLuint _vSize = _vertices.size() * sizeof(point4);
GLuint _nSize = _normals.size() * sizeof(point4);
GLuint _uSize = _uvs.size() * sizeof(point2);
GLuint _totalSize = _vSize + _uSize; // normals + vertices + uvs

GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, _vSize, &_vertices[0], GL_STATIC_DRAW);

GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, _uSize, &_uvs[0], GL_STATIC_DRAW);

TextureID = glGetUniformLocation(program, "myTextureSampler");

TextureObjects = new GLuint[_textures.size()];
glGenTextures(_textures.size(), TextureObjects);

for (size_t i = 0; i < _textures.size(); i++)
{
    // "Bind" the newly created texture : all future texture functions will modify this texture
    glBindTexture(GL_TEXTURE_2D, TextureObjects[i]);

    // Give the image to OpenGL
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _textures[i].width, _textures[i].height, 0, GL_BGR, GL_UNSIGNED_BYTE, _textures[i]._tex_data);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}



for (size_t i = 0; i < _objects.size(); i++)
{
    if (i == 0)
    {
        glActiveTexture(GL_TEXTURE0);
    }
    else
    {
        glActiveTexture(GL_TEXTURE1);
    }

    glBindTexture(GL_TEXTURE_2D, TextureObjects[i]);

    GLuint _v_size = _objects[i]._vertices.size() * sizeof(point4);
    GLuint _u_size = _objects[i]._uvs.size() * sizeof(point2);

    GLuint vPosition = glGetAttribLocation(program, "vPosition");
    glEnableVertexAttribArray(vPosition);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    if (i == 0)
    {
        glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    }
    else
    {
        glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(_v_size));
    }

    GLuint vUV = glGetAttribLocation(program, "vUV");
    glEnableVertexAttribArray(vUV);
    glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
    if (i == 0)
    {
        glVertexAttribPointer(vUV, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    }
    else
    {
        glVertexAttribPointer(vUV, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(_u_size));
    }

    if (i == 0)
    {
        glUniform1i(TextureID, 0);
    }
    else
    {
        glUniform1i(TextureID, 1);
    }

}

_scale = Scale(zoom, zoom, zoom);
_projection = Perspective(45.0, 4.0 / 3.0, 0.1, 100.0);
_view = LookAt(point4(Camera.x, Camera.y, Camera.z, 0), point4(0, 0, 0, 0), point4(0, 1, 0, 0));
_model = mat4(1.0); // identity matrix
_mvp = _projection * _view * _model;

MVP = glGetUniformLocation(program, "MVP");
theta = glGetUniformLocation(program, "theta");
Zoom = glGetUniformLocation(program, "Zoom");

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE);
glClearColor(1.0, 1.0, 1.0, 1.0);

我知道在绘制对象时我必须在活动纹理之间切换,但我无法弄清楚如何。

更新

@immibis好的我昨天试着这样做,但它没有用,但已经很晚了,我非常沮丧。为了让我的想法正确,我每次都要创建一个缓冲区(glGenBuffer)然后填充它,激活纹理然后glDrawArrays或者我只是创建缓冲区然后每次用不同的vetices和uvs填充它对于每个对象,设置偏移量,然后为每个对象调用glDrawArray?

当我最初尝试这个时我不知道在哪里 glGetAttribLocation / glEnableVertexAttribArray / glBindBuffer 应该去。因此,如果我每次进行转换时都能正确理解,例如围绕x轴旋转,则必须填充缓冲区等,因此代码需要进入显示功能。这是对的吗?

解决 好吧,对于immibus的评论,它让我看向不同的方向。我一直盯着数据如何被抽入数组,我从来没有看过glDrawArrays。我再次在网上搜索,我在教程中遇到了一段代码,这个人解释了glDrawArrays,我看到你可以告诉它要画什么。

那么这就变得容易了,正如我原先认为的那样。我将代码更改回缓冲区中的所有内容,因为我的加载器返回的对象上有一个start和stop属性,所以很容易告诉glDrawArrays该做什么。

谢谢。

0 个答案:

没有答案