0

我已经实现了一个简单的(慢速)方法,它可以模仿 OpenGL 即时模式来绘制线条。每一帧,我添加一对顶点,表示向量结构的线,以及添加一些指定或默认颜色到另一个向量结构。

void WindowsGraphicsManager::vertex(float x, float y, float z) {
vertices_.push_back(x);
vertices_.push_back(y);
vertices_.push_back(z);
colors_.push_back(vertexColor_.getR());
colors_.push_back(vertexColor_.getG());
colors_.push_back(vertexColor_.getB());
colors_.push_back(vertexColor_.getA());
}

在每一帧结束时,我清除这些向量。我的渲染代码如下所示:

void WindowsGraphicsManager::renderVertices(Mat4 mat) {
if (vertices_.size() == 0) {
    return;
}
static Shader* shader = (Shader*) services_->getRM()->get(
    Resource::SHADER, "openglimmediate");
glUseProgram(shader->getId());
shader->setMatrix4(Shader::WVP, mat);
glEnableVertexAttribArray(shader->getHandle(Shader::POS));
glVertexAttribPointer(shader->getHandle(Shader::POS),
    3, GL_FLOAT, GL_FALSE, 0, &vertices_[0]);
glEnableVertexAttribArray(shader->getHandle(Shader::COL));
glVertexAttribPointer(shader->getHandle(Shader::COL),
    4, GL_FLOAT, GL_FALSE, 0, &colors_[0]);
//LOGI("Before crash.");
//LOGI("Vertices size: %d", vertices_.size());
//LOGI("Colors size: %d", colors_.size());
//INFO: Vertices size: 607590
//INFO: Colors size: 810120
glDrawArrays(GL_LINES, 0, vertices_.size() / 3);
CHECK_GL_ERROR("Rendering lines.");
//LOGI("After crash.");
glDisableVertexAttribArray(shader->getHandle(Shader::COL));
glDisableVertexAttribArray(shader->getHandle(Shader::POS));
vertices_.clear();
colors_.clear();

}

当我将 607590 个浮点数(顶点除以 3)添加到顶点向量时,使用 glDrawArrays 函数在线渲染崩溃。奇怪的是,当我第一次最大化窗口并渲染时,它适用于具有 607590 个浮点数的模型,尽管对于具有 ~800k 个浮点数的模型它仍然崩溃。

这可能是什么原因造成的?

[编辑] 在渲染顶点之前,我调用了另一种方法。删除它后,渲染停止崩溃,所以我想我在这里做错了。

inline void WindowsGraphicsManager::renderNode(
Node* node, Mat4 mat, bool ortho)
{
if (!node->getState(Node::RENDERABLE)) {
    return;
}

// Retrieve model data.
Renderable* renderable = 0;
Resource* resource = 0;
if (node->hasResource(Resource::SPRITE)) {
    resource = node->getResource(Resource::SPRITE);
    renderable = dynamic_cast<Renderable*>(resource);
}
else if (node->hasResource(Resource::STATIC_OBJECT)) {
    resource = node->getResource(Resource::STATIC_OBJECT);
    renderable = dynamic_cast<Renderable*>(resource);
    StaticObject* so = static_cast<StaticObject*>(resource);
    // Check for frustum culling.
    if (so->getBoundingVolume() != 0
        && so->getBoundingVolume()->isInFrustum(
        services_->getCamera(), node->getPos())
        == BoundingVolume::OUTSIDE)
    {
        return;
    }
}
else if (node->hasResource(Resource::DYNAMIC_OBJECT)) {
    resource = node->getResource(Resource::DYNAMIC_OBJECT);
    renderable = dynamic_cast<Renderable*>(resource);
}

if (renderable == 0) {
    LOGW("Renderable with name \"%s\" is null.",
        node->getName().c_str());
    return;
}

// Retrieve node shader or use default.
Shader* shader = static_cast<Shader*>(
    node->getResource(Resource::SHADER));
if (shader == 0) {
    LOGW("Unable to retrieve shader for node: %s.",
        node->getName().c_str());
    return;
}
int shaderId = shader->getId();

// Select shader program to use.
glUseProgram(shaderId);
CHECK_GL_ERROR("glUseProgram");

Mat4 res;
if (!ortho) {
    Matrix::multiply(mat, node->getMatrix(), res);
}
else {
    Mat4 tmp;
    Mat4 pos;
    Mat4 rot;
    Mat4 scale;
    Vec3 p = node->getPos();
    Vec3 r = node->getRot();
    Vec3 s = node->getScale();
    float width = s.getX();
    float height = s.getY();
    float x = p.getX();
    float y = p.getY();
    Matrix::translate(pos, x, y, p.getZ());
    Matrix::rotateXYZ(rot, r.getX(), r.getY(), r.getZ());
    Matrix::scale(scale, width, height, 1.0f);
    Matrix::multiply(mat, pos, res);
    Matrix::multiply(res, rot, tmp);
    Matrix::multiply(tmp, scale, res);
}
// World * View * Projection matrix.
shader->setMatrix4(Shader::WVP, res);
// World matrix.
shader->setMatrix4(Shader::W, node->getMatrix());
// Normal matrix.
if (shader->hasHandle(Shader::N)) {
    Mat3 normalMatrix;
    Matrix::toMat3(node->getMatrix(), normalMatrix);
    shader->setMatrix3(Shader::N, normalMatrix);
}
// Light position.
float* lightPos = new float[lights_.size() * 3];
if (lights_.size() > 0 && shader->hasHandle(Shader::LIGHT_POS)) {
    for (UINT i = 0; i < lights_.size(); i++) {
        Vec3& pos = lights_[i]->getPos();
        lightPos[i * 3 + 0] = pos.getX();
        lightPos[i * 3 + 1] = pos.getY();
        lightPos[i * 3 + 2] = pos.getZ();
    }
    shader->setVector3(Shader::LIGHT_POS, lightPos, lights_.size());
}
delete lightPos;
// Light count.
shader->setInt(Shader::LIGHT_COUNT, lights_.size());
//shader->setVector3(Shader::LIGHT_POS,
//  services_->getEnv()->getSunPos()->toArray());
// Eye position.
shader->setVector3(Shader::EYE_POS,
    services_->getCamera()->getPos().toArray());
// Fog color.
if (shader->hasHandle(Shader::FOG_COLOR)) {
    shader->setVector3(Shader::FOG_COLOR,
        services_->getEnv()->getFogColor());
}
// Fog density.
shader->setFloat(Shader::FOG_DENSITY, services_->getEnv()->getFogDensity());
// Timer.
shader->setFloat(Shader::TIMER,
    (float) services_->getSystem()->getTimeElapsed());
// Bind combined buffer object.
if (renderable->getCBO() > 0) {
    int stride = renderable->getVertexStride();
    glBindBuffer(GL_ARRAY_BUFFER, renderable->getCBO());
    if (shader->hasHandle(Shader::POS)) {
        glEnableVertexAttribArray(shader->getHandle(Shader::POS));
        glVertexAttribPointer(
            shader->getHandle(Shader::POS), 3, GL_FLOAT, GL_FALSE,
            stride, ((char*) 0) + renderable->getPosOffset());
    }
    if (renderable->getNormalOffset() != -1
        && shader->hasHandle(Shader::NORMAL)) {
        glEnableVertexAttribArray(shader->getHandle(Shader::NORMAL));
        glVertexAttribPointer(
            shader->getHandle(Shader::NORMAL), 3, GL_FLOAT, GL_FALSE,
            stride, ((char*) 0) + renderable->getNormalOffset());
    }
    if (renderable->getUVOffset() != -1 && shader->hasHandle(Shader::UV)) {
        glEnableVertexAttribArray(shader->getHandle(Shader::UV));
        glVertexAttribPointer(
            shader->getHandle(Shader::UV), 2, GL_FLOAT, GL_FALSE,
            stride, ((char*) 0) + renderable->getUVOffset());

    }
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else {
    return;
}
// Bind cube map.
if (node->hasResource(Resource::CUBE_MAP)
    && shader->hasHandle(Shader::CUBE_MAP)) {
    glActiveTexture(GL_TEXTURE0);
    CHECK_GL_ERROR("glActiveTexture");
    CubeMap* t = static_cast<CubeMap*>(
        node->getResource(Resource::CUBE_MAP));
    glBindTexture(GL_TEXTURE_CUBE_MAP, t->getId());
    CHECK_GL_ERROR("glBindTexture");
    glUniform1i(shader->getHandle(Shader::CUBE_MAP), 0);
    CHECK_GL_ERROR("glUniform1i");
}

int hTextures[8];
hTextures[0] = glGetUniformLocation(shader->getId(),
    SHADER_MAIN_TEXTURE);
// Bind the texture.
vector<Resource*> textures = node->getResources(Resource::TEXTURE_2D);
UINT size = textures.size() < 8 ? textures.size() : 7;
UINT texture = 0;
for (UINT i = 0; i < size; i++) {
    texture = i + 1;
    const string& name = textures[i]->getName();
    Texture2D* tex = static_cast<Texture2D*>(textures[i]);
    string textName = name.substr(0, name.length() - 4);

    hTextures[texture] = glGetUniformLocation(shader->getId(),
        textName.c_str());
    if (hTextures[texture] == -1) {
        continue;
    }
    glActiveTexture(GL_TEXTURE0 + i + 1);
    CHECK_GL_ERROR("glActiveTexture");
    glBindTexture(GL_TEXTURE_2D, tex->getId());
    CHECK_GL_ERROR("glBindTexture");
    glUniform1i(hTextures[texture], texture);
    CHECK_GL_ERROR("glUniform1i");
}

// Render node.
//      BoundingVolume* volume = (*model->getBoundingVolumes())[i];
//      if (model->hasBoundingVolumes()) {
//          if (volume->isInFrustum(services_->getCamera(), node)
//              == BoundingVolume::OUTSIDE) {
//              continue;
//          }
//      }

int renderType;
switch (renderable->getRenderType()) {
    case Renderable::RENDER_TYPE_POINTS:
        renderType = GL_POINTS;
        //glPointSize(renderable->getPointSize());
    break;
    case Renderable::RENDER_TYPE_LINES:
        renderType = GL_LINES;
        glLineWidth(renderable->getLineWidth());
    break;
    case Renderable::RENDER_TYPE_TRIANGLE_FAN:
        renderType = GL_TRIANGLE_FAN;
    break;
    case Renderable::RENDER_TYPE_TRIANGLE_STRIP:
        renderType = GL_TRIANGLE_STRIP;
    break;
    default:
        renderType = GL_TRIANGLES;
    break;
}

if (renderable->getWindingType() == Renderable::WINDING_TYPE_CCW) {
    glFrontFace(GL_CCW);
}
else {
    glFrontFace(GL_CW);
}

if (renderable->getCullFace()) {
    glEnable(GL_CULL_FACE);
}
else {
    glDisable(GL_CULL_FACE);
}
UINT renderCount = renderable->getRenderCount();
int lastTexture = 0;
for (UINT i = 0; i < renderable->getRenderCount(); i++) {
    renderable->setRenderable(i);
    // Ambient material color.
    if (shader->hasHandle(Shader::AMBIENT)) {
        shader->setVector3(Shader::AMBIENT,
            renderable->getAmbient().toArray());
    }
    // Diffuse material color.
    if (shader->hasHandle(Shader::DIFFUSE)) {
        shader->setVector3(Shader::DIFFUSE,
            renderable->getDiffuse().toArray());
    }
    // Specular material color.
    if (shader->hasHandle(Shader::SPECULAR)) {
        shader->setVector3(Shader::SPECULAR,
            renderable->getSpecular().toArray());
    }
    // Specular material color intensity.
    shader->setFloat(Shader::SPECULARITY, renderable->getSpecularity());
    // Model transparency.
    shader->setFloat(Shader::TRANSPARENCY, renderable->getTransparency());
    // Bind main texture.
    if (renderable->getTexture() != lastTexture
        && hTextures[0] != -1) {
        lastTexture = renderable->getTexture();
        if (shader->hasHandle(Shader::MAIN_TEXTURE)) {
            if (lastTexture == 0) {
                shader->setFloat(Shader::MAIN_TEXTURE, 0.0f);
            }
            else {
                shader->setFloat(Shader::MAIN_TEXTURE, 1.0f);
            }
        }
        glActiveTexture(GL_TEXTURE0);
        CHECK_GL_ERROR("glActiveTexture");
        glBindTexture(GL_TEXTURE_2D, renderable->getTexture());
        CHECK_GL_ERROR("glBindTexture");
        glUniform1i(hTextures[0], 0);
        CHECK_GL_ERROR("glUniform1i");
    }
    if (renderable->getIBO() > 0) {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
            renderable->getIBO());
        if (renderable->getIndexType() ==
            Renderable::INDEX_TYPE_USHORT) {
            glDrawElements(renderType,
                renderable->getIndexCount(),
                GL_UNSIGNED_SHORT,
                0);
            CHECK_GL_ERROR("glDrawElements");
        }
        else {
            glDrawElements(renderType,
                renderable->getIndexCount(),
                GL_UNSIGNED_INT,
                0);
            CHECK_GL_ERROR("glDrawElementsInt");
        }
    }
    else {
        glDrawArrays(renderType, 0, renderable->getVertexCount() / 3);
        CHECK_GL_ERROR("glDrawArrays");
    }
}
//// Unbind the cube map.
//if (node->hasResource(Resource::CUBE_MAP)) {
//  glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
//}
//// Unbind the textures.
//for (UINT i = 0; i < 8; i++) {
//  glActiveTexture(GL_TEXTURE0 + i);
//  CHECK_GL_ERROR("glActiveTexture");
//  glBindTexture(GL_TEXTURE_2D, 0);
//}
}
4

1 回答 1

0

所以问题是在这部分代码之后调用 glBindBuffer() :

// Bind combined buffer object.
if (renderable->getCBO() > 0) {
    int stride = renderable->getVertexStride();
    glBindBuffer(GL_ARRAY_BUFFER, renderable->getCBO());
    if (shader->hasHandle(Shader::POS)) {
        glEnableVertexAttribArray(shader->getHandle(Shader::POS));
        glVertexAttribPointer(
            shader->getHandle(Shader::POS), 3, GL_FLOAT, GL_FALSE,
            stride, ((char*) 0) + renderable->getPosOffset());
    }
    if (renderable->getNormalOffset() != -1
        && shader->hasHandle(Shader::NORMAL)) {
        glEnableVertexAttribArray(shader->getHandle(Shader::NORMAL));
        glVertexAttribPointer(
            shader->getHandle(Shader::NORMAL), 3, GL_FLOAT, GL_FALSE,
            stride, ((char*) 0) + renderable->getNormalOffset());
    }
    if (renderable->getUVOffset() != -1 && shader->hasHandle(Shader::UV)) {
        glEnableVertexAttribArray(shader->getHandle(Shader::UV));
        glVertexAttribPointer(
            shader->getHandle(Shader::UV), 2, GL_FLOAT, GL_FALSE,
            stride, ((char*) 0) + renderable->getUVOffset());
}
glBindBuffer(GL_ARRAY_BUFFER, 0);

我不得不将 glBindBuffer() 移到同一方法的末尾,并且我还为位置、正常和 UV 缓冲区编写了 glDisableVertexAttribArray。这解决了问题,但我不知道为什么。我认为没有必要为 VBO 调用 glDisableVertexAttribArray。我认为这个问题是 NVIDIA 驱动程序特有的,并为 nvoglv32.dll 提供了第一次机会异常。

于 2013-03-07T10:14:01.933 回答