GLSL(6)分别使用可编程渲染管线编程和固定渲染管线编程来画点(理解VAO&VBO)

因为之前在用c++写ray tracing(在CPU上跑),后来因为在CPU上跑太慢了,于是又上cuda,但是用cuda实现完成到30%,各种不能理解的错误,我这个cuda新手也是被折腾的惨,代码调试也很苦难。于是打算后面用compute shader来实现ray tracing。所以最近在狂学opengl和glsl。目前是glsl新手,希望各位多多指教。

不得不承认opengl的API设计比较复杂,至少我是这么感觉,花了一些时间来理它的脉络。

一定要清楚的一点是,在opengl中,可编程渲染管线的编程结构和固定渲染管线方式下的code结构其实差别蛮大的。

假设我们要使用glsl,也就是要使用可编程渲染管线来实现如下效果:

使用可编程渲染管线的coding方式,应该怎么做呢?

首先,我们要知道,可编程,主要是指,我们可以编写自己的顶点着色器和片段着色器,而这两个着色器是分别对应着渲染管线中的两个阶段,我们现在可以操纵这两个阶段,所以叫做可编程渲染管线。OK。

顶点着色器里面可以定义很多的顶点属性,比如顶点的坐标、颜色、法线等等,这些属性下的数据叫做vertex attribute data.这个很重要。和vertex attribute data挂钩的又出现了传说中的VAO、VBO。

哇,要理解好多东西!确实如此!

这两个又是什么鬼??-_-....

VAO:vertex array object.

VBO:vertex buffer object.

这两个有啥区别?分别是干嘛的?

首先要明确的是,VAO,VBO都和vertex shader有关系,你如果要在opengl中使用glsl来实现你想要的效果,那么你必定会接触到这两个东西,也就是说,你要使用和VAO,VBO相关的函数。而在固定渲染管线中不会用到这些函数,这里就是一个界限!这一点很重要。

要在opengl中使用glsl来画图,需要这样来组织代码(理解并记住这个结构很重要):

initialization:

for each batch:

generate,store,and bind a VAO,

bind all the buffers needed for a draw call.

unbind the VAO.

main loop/whenever you render:

for each batch

bind VAO

glDrawArrays(...);or gl DrawElements(...);

unbind VAO.

问:VAO、VBO和shader的关系是啥?

答:VAO stores data about vertex attribute locations。很好理解,VAO保存的是数据的location。当你调用glVertexAttribPointer(...)的时候,VAO就记住了当前VBO绑定的是啥东西,当在执行渲染的时候,VAO就会从VBO中获取 vertex attribute data。即便当前VBO没被绑定!

其实,当我们在调用glUseProgram()这个函数的时候,就表明告诉opengl,我现在已经从固定渲染管线切换到可编程渲染管线了,我要用glsl来搞事情。不能同时既搞fixed又搞programable。

还要注意的是,一次只能将一个target绑定到VAO!你要使用谁,你就绑定谁,把它调到前台来drawarray。

关于VBO。

VBO是一个buffer object。它作为vertex attribute data的数据来源。我们可以通过以下方法来让一个VBO做为vertex attribute data的数据源:

首先,一定要将这个VBO绑定到GL_ARRAY_BUFFER上,然后,调用glVertexAttribPointer(index,....)(如果对这些函数不理解,可以看我之前的文章,调用这个函数,就指定,vertex shader中layout 中index索引处的data的数据来自绑定到GL_ARRAY_BUFFER上的VBO。当这个函数被调用的时候,这个关系就被确定下来了.。假设在这句函数后面再调用glBindBuffer(0),这时是不是我们的数据源就被切断了呢(因为之前是glBindBuffer(VBO),现在这个VBO变成0了)?不是得,源头还是不变!要改变这个,必须要调用glVertexAttribPointer(index,....),理解这个很重要。

VAO和VBO的区别:VAO stores all of the state needed to supply data.VBO才是真正的存储着数据。

好了,按照上面结构,我们用glsl实现上图的效果,代码如下:

void InitGL(int argc,char* argv[])
{


    glutInit(&argc,argv);      
    glEnable(GL_DEBUG_OUTPUT);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE ); //设置显示方式,RGB、双缓冲
    glutInitWindowPosition(100,100);   //位置
    glutInitWindowSize(WIN_WIDTH,WIN_HEIGHT);//窗口大小
    glutCreateWindow("GLSL FUN!");  //创建窗口,设置标题
    glutDisplayFunc(renderScene);  // 当绘制窗口时调用myDisplay
    glutIdleFunc(renderScene);
    glutReshapeFunc(changeSize);
    glutKeyboardFunc(processNormalKeys);


    glClearColor(0.0,0.0,0.0,0.0);//清除颜色设置为白色,这样glclear后面clear color就用白色clear
    glewInit();




    projection = glm::perspective( glm::radians(50.0f),(float)1024/1024,1.0f,100.0f);
}
void InitPosArrayandColorArray()
{
    float dx = 1.0f/(float)WIN_WIDTH;
    float dy = 1.0f/(float)WIN_HEIGHT;
    int index=0;
    for(int i = 0; i < WIN_WIDTH; i++)
        for(int j = 0; j < WIN_HEIGHT; j++)
        {
            float screenPosX = (float)i * dx * 2 - 1;
            float screenPosY = (float)j * dy * 2 - 1;
            int add1 = index + 1;
            int add2 = index + 2;
            positionData[ index ]    = screenPosX;
            positionData[ add1 ] = screenPosY;
            positionData[ add2 ] = .0f;
            colorData[ index ] = screenPosX;
            colorData[ add1 ] = screenPosY;
            colorData[ add2 ] = .2f;
            index+=3;
        }
}
}
void InitBuffer()
{
    GLuint vboHandles[2];
    glGenBuffers(2,vboHandles);
    GLuint positionBufferHandle = vboHandles[0];
    GLuint colorBufferHandle = vboHandles[1];
    //
    glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
    glBufferData(GL_ARRAY_BUFFER, TOTAL_POINTS_NUM * sizeof(float), positionData, GL_STATIC_DRAW);
    //
    glBindBuffer(GL_ARRAY_BUFFER,colorBufferHandle);
    glBufferData(GL_ARRAY_BUFFER, TOTAL_POINTS_NUM * sizeof(float), colorData, GL_STATIC_DRAW);
    //VAO
    glGenVertexArrays(1,&vaoHandle);
    glBindVertexArray(vaoHandle);
    //
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    //
    glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
    glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(GLubyte*)NULL);
    glBindBuffer(GL_ARRAY_BUFFER, colorBufferHandle);
    glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,(GLubyte*)NULL);
    //
    glBindVertexArray(0);


}
void renderScene(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
   
    glBindVertexArray(vaoHandle);
    glDrawArrays(GL_POINTS,0,TOTAL_POINTS_NUM);
    glBindVertexArray(0);
    glutSwapBuffers();
}
int main(int argc,char* argv[])
{


    //1.
    InitGL(argc,argv);
    InitPosArrayandColorArray();
    //2.steshader其实也属于initScene的一部分,只是下个阶段而已
    setShaders();
    //after linking,use the following steps to assign data to uniform block in the frag shader
   // InitUniformBlockBuffer();
    InitBuffer();
   // LogGLVersion();
     //4.
    glutMainLoop();  //消息循环
    //


    //check gl version


    return 0;
}
虽然效果很简单,但是理解材才是最重要的。

下面是着色器的代码:

顶点着色器:

#version 430

layout (location=0) in vec3 VertexPosiotion;
layout (location=1) in vec3 VertexColor;

out vec3 Color;

void main()
{
    Color = VertexColor;
    gl_Position = vec4(VertexPosiotion,1.0);
} ​​​​

片单着色器:

#version 430

in vec3 Color;
layout (location=0) out vec4 FragColor;
void main()
{
gl_FragColor = vec4(Color,1.0);
}

如果是使用固定管线的话,就很简单了,伪代码如下:

glPointSize(1.0f);

glBegin(GL_POINTS);

for(i=0; i < winwidth;i++)

for(int j = 0; j  < winheight ; j++)

{

glcolor(....);

glvertex3f(x,y,0);

}

glend();


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值