在OpenGL ES 2.0中独立转换对象

7
我看过的所有教程都是使用单个对象,例如三角形或立方体。但我不清楚如何独立地操作不同对象。我看到一些教程提到了固定函数管线并使用pushmatrix和popmatrix,但对于可编程管线,这些函数已经不存在了。以下是一个init函数和一个draw函数,它们在屏幕上绘制一个单独的三角形并将其绕Z轴旋转。有人可以展示给我代码,甚至是伪代码来添加第二个三角形并使其独立于其他三角形旋转吗?比如绕不同的轴或朝相反的方向旋转?
int Init(ESContext* esContext)
{
    UserData* userData = (UserData *)esContext->userData;
    const char *vShaderStr =
        "attribute vec4 vPosition;  \n"
        "uniform mat4 MVPMatrix;"
        "void main()                \n"
        "{                          \n"
        "   gl_Position = MVPMatrix * vPosition;\n"
        "}                          \n";

    const char *fShaderStr =
        "precision mediump float;   \n"
        "void main()                \n"
        "{                          \n"
        "   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n"
        "}                          \n";

    GLuint vertexShader;
    GLuint fragmentShader;
    GLuint programObject;
    GLint linked;
    GLfloat ratio = 320.0f/240.0f;

    vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr);
    fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr);

    programObject = glCreateProgram();

    if (programObject == 0)
        return 0;

    glAttachShader(programObject, vertexShader);
    glAttachShader(programObject, fragmentShader);

    glBindAttribLocation(programObject, 0, "vPosition");
    glLinkProgram(programObject);
    glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &linked);

    if (!linked)
    {
        GLint infoLen = 0;
        glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &infoLen);

        if (infoLen > 1)
        {
            char* infoLog = (char *)malloc(sizeof(char) * infoLen);
            glGetProgramInfoLog(programObject, infoLen, NULL, infoLog);

            free(infoLog);
        }

        glDeleteProgram(programObject);
        return FALSE;
    }

    userData->programObject = programObject;

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    glViewport(0, 0, esContext->width, esContext->height);
    glClear(GL_COLOR_BUFFER_BIT);


    glUseProgram(userData->programObject);

    userData->angle = 0.0f;
    userData->start = time(NULL);
    userData->ProjMatrix = PVRTMat4::Perspective(ratio*2.0f, 2.0f, 3.0f, 7.0f, PVRTMat4::eClipspace::OGL, false, false);
    userData->ViewMatrix = PVRTMat4::LookAtLH(PVRTVec3(0.0f, 0.0f, -3.0f), PVRTVec3(0.0f, 0.0f, 0.0f), PVRTVec3(0.0f, 1.0f, 0.0f));
    return TRUE;
}



void Draw(ESContext *esContext)
{
    GLfloat vVertices[] = {0.0f, 0.5f, 0.0f,
                          -0.5f, -0.5f, 0.0f,
                           0.5f, -0.5f, 0.0f};

    GLint MVPHandle;
    double timelapse;

    PVRTMat4 MVPMatrix = PVRTMat4::Identity();
    UserData* userData = (UserData *)esContext->userData;

    timelapse = difftime(time(NULL), userData->start) * 1000;
    if(timelapse > 16.0f) //Maintain approx 60FPS
    {
        if (userData->angle > 360.0f)
        {
            userData->angle = 0.0f;
        }
        else
        {
            userData->angle += 0.1f;
        }
    }

    userData->ModelMatrix = PVRTMat4::RotationZ(userData->angle);

    MVPMatrix = userData->ViewMatrix * userData->ModelMatrix;
    MVPMatrix = userData->ProjMatrix * MVPMatrix;

    MVPHandle = glGetUniformLocation(userData->programObject, "MVPMatrix");
    glUniformMatrix4fv(MVPHandle, 1, FALSE, MVPMatrix.ptr());

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices);
    glEnableVertexAttribArray(0);

    glClear(GL_COLOR_BUFFER_BIT);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface);
}
1个回答

5
在绘制第一个三角形后,使用您所需的新旋转/位置生成新的MVP矩阵,上传它,然后再次绘制三角形。您可以在场景中随意更改uniforms。
这类似于push和pop所做的事情,它们只是在绘制给定对象之前更改活动矩阵。
示例伪代码:
MMatrix = identity;
MVPMatrix = VPMatrix * MMatrix;
glUniformMatrix4fv(MVPHandle, 1, FALSE, MVPMatrix.ptr());
glDrawArrays(GL_TRIANGLES, 0, 3); //draw triangle at 0,0,0

MMatrix.translate(1,0,0);
MVPMatrix = VPMatrix * MMatrix;
glUniformMatrix4fv(MVPHandle, 1, FALSE, MVPMatrix.ptr());
glDrawArrays(GL_TRIANGLES, 0, 3); //draw triangle at 1,0,0

MMatrix.translate(1,0,0);
MVPMatrix = VPMatrix * MMatrix;
glUniformMatrix4fv(MVPHandle, 1, FALSE, MVPMatrix.ptr());
glDrawArrays(GL_TRIANGLES, 0, 3); //draw triangle at 2,0,0

..repeat for as many objects as you want..

这将留下三个三角形,分别位于(0,0,0)、(1,0,0)和(2,0,0)。

你能再明确一些吗?具体来说,如果我只是改变统一的MVPMatrix值以包括一个平移,它将如何知道在新位置绘制三角形的副本,而不仅仅是将现有的三角形移动到该位置? - Legion
1
一旦你通过glDrawArrays分派了一个三角形,它就完成了。任何变量的进一步更改都不会对其产生任何影响。一旦某物被渲染,它就无法“移动”,因此对任何uniforms的更改只会影响在更改后进行的绘制调用。我在我的答案中放了一些示例代码,以帮助您理解。 - Tim
完美!回想起来,我不敢相信它是如此简单。我的理解是,一旦从客户端加载顶点到GPU中,它们就会被缓存,所以我认为任何变换都会应用于已经发送过来的所有内容。 - Legion
@Legion,从技术上讲,它们被缓存起来,可能不会立即绘制,但GPU足够聪明,在调用时记住uniforms的状态,因此您作为设备程序员不必担心它。 - Tim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接