Lighthouse3d - OpenGL相关学习(一)

本文详细介绍了一个OpenGL应用程序的骨架,包括使用freeGLUT和GLEW初始化OpenGL上下文,设置着色器,初始化缓冲区和顶点数组对象。此外,还介绍了如何通过VSL库简化着色器设置和矩阵操作。
摘要由CSDN通过智能技术生成

GLSL教程 - OpenGL骨架 :

在我们开始介绍OpenGL着色器之前,我们将通过我们将使用的OpenGL应用程序,至少在第一个着色器中。为了弥补OpenGL核心版本中一些丢失的功能,并防止代码过于夸张,我们将使用两个非常简单的库:数学着色器

那么让我们来看看OpenGL应用程序中的一些相关位。

主功能

让我们从主要功能开始。要创建OpenGL上下文并提供窗口界面,我们将使用freeGLUT。要访问扩展和OpenGL功能,我们将采用GLEW。初始化过程涉及要求GLUT创建上下文,如GLUT教程的初始化部分所述。

int main(int argc, char **argv) {
 
//  GLUT initialization
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGBA|GLUT_MULTISAMPLE);
 
    glutInitContextVersion (3, 3);
    glutInitContextProfile (GLUT_CORE_PROFILE );
    glutInitContextFlags(GLUT_DEBUG);
 
    glutInitWindowPosition(100,100);
    glutInitWindowSize(512,512);
    glutCreateWindow("Lighthouse3D - Simple Shader Demo");

然后我们继续进行回调注册,也在GLUT教程中详细说明。

  ...
//  Callback Registration
    glutDisplayFunc(renderScene);
    glutReshapeFunc(changeSize);
    glutIdleFunc(renderScene);
 
//  Mouse and Keyboard Callbacks
    glutKeyboardFunc(processKeys);
    glutMouseFunc(processMouseButtons);
    glutMotionFunc(processMouseMotion);
 
    glutMouseWheelFunc ( mouseWheel ) ;
    ...

继续,我们初始化GLEW并打印一些有关我们创建的OpenGL上下文的信息。

    ...
//  Init GLEW
    glewExperimental = GL_TRUE;
    glewInit();
 
// print context information
    printf ("Vendor: %s\n", glGetString (GL_VENDOR));
    printf ("Renderer: %s\n", glGetString (GL_RENDERER));
    printf ("Version: %s\n", glGetString (GL_VERSION));
    printf ("GLSL: %s\n", glGetString (GL_SHADING_LANGUAGE_VERSION));
    ...

到目前为止,它们或多或少是标准的东西,我们会一遍又一遍地看到。现在我们已经准备好开始做我们的事了。我们打算调用设置功能。一个用于着色器,一个用于初始化缓冲区和一些OpenGL设置,最后一个函数用于初始化我们正在使用的VSL库。然后我们打电话glutMainLoop

  ...
    if (!setupShaders())
        return(1);
    initOpenGL()
    initVSL();
 
    //  GLUT main loop
    glutMainLoop();
 
    return(0);
}

这就是我们的主要功能。

设置着色器

在我们的示例中设置着色器将使用VSShaderLib来完成,以简化代码。代码首先加载和编译顶点和片段着色器的每个源代码文件。然后,它设置着色器中出现的变量的语义,请参阅Hello World示例。

调用prepareProgram链接程序,如果成功,它将检索有关着色器中存在的统一变量使用的所有信息。稍后这将有用于设置这些变量。

然后,我们显示各个着色器和程序的infoLog,如果我们有一个有效的程序,则返回一个值指示。

该函数的代码如下:

GLuint setupShaders() {
 
    // Shader for drawing the cube
    shader.init();
    shader.loadShader(VSShaderLib::VERTEX_SHADER, "shaders/helloWorld.vert");
    shader.loadShader(VSShaderLib::FRAGMENT_SHADER, "shaders/helloWorld.frag");
 
    // set semantics for the shader variables
    shader.setProgramOutput(0,"outputF");
    shader.setVertexAttribName(VSShaderLib::VERTEX_COORD_ATTRIB, "position");
 
    shader.prepareProgram();
 
    printf("InfoLog for Hello World Shader\n%s\n\n", shader.getAllInfoLogs().c_str());
     
    return(shader.isProgramValid());
}

OpenGL和缓冲区初始化

在这个函数中,我们正在执行我们的应用程序所需的更多初始化。这包括基于球面坐标,一些OpenGL设置和顶点阵列对象(VAO)创建来计算初始相机位置。

摄像机位置放置在以原点为中心的球体中,半径为r。它由球面坐标(alpha,beta,r),所有全局变量定义,鼠标控制这些变量。在我们在渲染功能中设置相机之前,我们需要将它们转换为笛卡尔坐标。每次相机移动时都必须这样做,这里,在初始化时获取初始笛卡尔值。

然后,我们继续进行一些常见的OpenGL初始化,例如启用剔除,多重采样和深度测试。

最后一步是设置包含几何体的顶点数组对象,在这种情况下是一个立方体,其数据在头文件中定义。我们开始生成VAO并绑定它。然后我们创建四个缓冲区来保存数据,三个用于顶点属性,一个用于索引。

void initOpenGL()
{
    // set the camera position based on its spherical coordinates
    camX = r * sin(alpha * 3.14f / 180.0f) * cos(beta * 3.14f / 180.0f);
    camZ = r * cos(alpha * 3.14f / 180.0f) * cos(beta * 3.14f / 180.0f);
    camY = r *                               sin(beta * 3.14f / 180.0f);
 
    // some GL settings
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glEnable(GL_MULTISAMPLE);
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
 
    // create the VAO
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
 
    // create buffers for our vertex data
    GLuint buffers[4];
    glGenBuffers(4, buffers);
 
    //vertex coordinates buffer
    glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(VSShaderLib::VERTEX_COORD_ATTRIB);
    glVertexAttribPointer(VSShaderLib::VERTEX_COORD_ATTRIB, 4, GL_FLOAT, 0, 0, 0);
 
    //texture coordinates buffer
    glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW);
    glEnableVertexAttribArray(VSShaderLib::TEXTURE_COORD_ATTRIB);
    glVertexAttribPointer(VSShaderLib::TEXTURE_COORD_ATTRIB, 2, GL_FLOAT, 0, 0, 0);
 
    //normals buffer
    glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(normals), normals, GL_STATIC_DRAW);
    glEnableVertexAttribArray(VSShaderLib::NORMAL_ATTRIB);
    glVertexAttribPointer(VSShaderLib::NORMAL_ATTRIB, 3, GL_FLOAT, 0, 0, 0);
 
    //index buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[3]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(faceIndex), faceIndex, GL_STATIC_DRAW);
 
    // unbind the VAO
    glBindVertexArray(0);
}

VSL初始化

VSL,特别是数学库,需要进行少量初始化以便于与着色器进行通信。设置我们将要使用的矩阵的制服是通过单个函数调用完成的,我们将在渲染函数中看到,但为了做到这一点,我们需要为着色器中定义的统一变量定义一些语义。在这里,我们假设我们的着色器将在名为Matrices 的内定义所有矩阵制服。

void initVSL() {
    vsml = VSMathLib::getInstance();
    // tell VSL the uniform block name
    vsml->setUniformBlockName("Matrices");
    // set semantics for the matrix variables
    vsml->setUniformName(VSMathLib::PROJ_VIEW_MODEL, "pvm");
    vsml->setUniformName(VSMathLib::NORMAL, "normal");
    vsml->setUniformName(VSMathLib::VIEW_MODEL, "viewModel");
    vsml->setUniformName(VSMathLib::VIEW, "view");
}

changeSize函数

视口设置为整个窗口。然后该函数使用math lib来设置投影矩阵。这个lib的功能与不推荐使用的OpenGL和GLU中的功能非常相似。有关详细信息,请参阅文档

void changeSize(int w, int h) {
 
    float ratio;
    // prevent a divide by zero, when window is zero height
    if(h == 0)
        h = 1;
    // set the viewport to be the entire window
    glViewport(0, 0, w, h);
    // set the projection matrix
    ratio = (1.0f * w) / h;
    vsml->loadIdentity(VSMathLib::PROJECTION);
    vsml->perspective(53.13f, ratio, 0.1f, 1000.0f);
}

渲染功能

此功能首先清除颜色和深度缓冲区,在模型上加载单位矩阵并查看矩阵,设置摄像机,要求数学库使着色器可以访问矩阵,然后绑定并渲染我们的VAO。

void renderScene(void) {
 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // load identity matrices
    vsml->loadIdentity(VSMathLib::VIEW);
    vsml->loadIdentity(VSMathLib::MODEL);
    // set the camera
    vsml->lookAt(camX, camY, camZ, 0,0,0, 0,1,0);
    // use our shader
    glUseProgram(shader.getProgramIndex());
    // send the matrices to the uniform buffer
    vsml->matricesToGL();
    // draw VAO
    glBindVertexArray(vao);
    glDrawElements(GL_TRIANGLES, faceCount*3, GL_UNSIGNED_INT, 0);
     //swap buffers
    glutSwapBuffers();
}

就是这样!转到下一部分以查看第一个着色器示例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值