openGL之glsl入门3--正弦函数叠加为方波

    使用GLSL画点,画线,画面,与原来使用glBegin(), glEnd()的方式有类似的地方,原来方式api比较多,GLSL采用的数组一次传送,程序的本质还是坐标点的设计与确认,只要知道图怎么画,哪种方式差异不大,本章主要介绍:

1. 正弦函数的基本画法

2. 键盘的控制

3. uniform变量的用法

4. 正弦波叠加为方波的GLSL实现

 

    GLSL画这些基本的类型是,使用的函数主要是glDraw*系列的函数,这里再说一下:

void  glDrawArrays (GLenum mode, GLint first, GLsizei count);

    mode与老的方式一致,有以下类型,画点GL_POINTS,画线 GL_LINES,顺连线段GL_LINE_STRIP,回环线段GL_LINE_LOOP,三角形GL_TRIANGLESGL_TRIANGLE_STRIPGL_TRIANGLE_FAN,四边形GL_QUADSGL_QUAD_STRIP,多边形GL_POLYGONfirst0即可,count表示要绘制顶点的个数,这个上章说的比较多。

    点面的画法的例子比较多,请大家自己去练(可以找老的程序改用GLSL方式实现来练手)。

说明:严格的说,以上关于新老绘制方式的描述并不准确,openGL绘制方式一直在改进,这里主要表达的意思是大家需区分使用shader的方式绘制与直接绘制方式的异同,详细的绘制演进过程,可以看一下这篇文章的介绍:

基本图形绘制方式比较

     上一章的helloworld程序非常简单,这里通过正弦波的画法来实现一个稍微复杂一点的shader程序,让大家尽快感受shader编程。

1. 正弦波绘制

    正弦波公式y = sin(x ) ,公式大家都熟悉,怎么画出来呢?这里我确定了以下几个参数来画正弦波:

1. sampleCnt:采样点个数,openGL画东西都采用逼近的方式,采样点越多,正弦波就越精细。

2. factor:用来控制正弦波的频率,如sin(2x ),sin(3x ) 等。

3. amplitude:振幅,用来控制正弦波的振幅,如3sin(2x )

4. rangeL:我们要把正弦波映射到[-1.0,1.0]的范围内,否则画出来的正弦波都看不到。

5. rangeR:如传的-pi~pi的范围,会把这个范围的正弦波映射到[-1.0,1.0]范围内。

    注意:shader里面y坐标统一乘了0.9,主要是避免图形顶到边框,代码如下,可以改参数效果:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/glut.h>
#define PI          3.14159265
#define SAMPLE_CNT  200
 
typedef struct
{
    GLfloat x;
    GLfloat y;
}Point;
static const GLchar * vertex_source =
    "#version 330 core\n"
    "layout (location = 0) in vec2 position;\n"
    "void main()\n"
    "{\n"
        "gl_Position = vec4(position.x,position.y*0.9,0.0,1.0);\n"
    "}\0";
void loadShader(GLuint program,GLuint type,const GLchar * source)
{
    const GLchar * shaderSource[] = {source};
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, shaderSource, 0);
    glCompileShader(shader);
    glAttachShader(program, shader);
}
void init()
{
    GLuint program = glCreateProgram();
    loadShader(program,GL_VERTEX_SHADER,vertex_source);
    glLinkProgram(program);
        glUseProgram(program);
        
        glClearColor(0.5f,0.5f, 1.0f, 1.0f);    
}
Point * createSinArray(GLint sampleCnt,GLfloat factor,GLfloat amplitude,GLfloat rangeL,GLfloat rangeR)
{
    int i = 0;
    GLfloat range = rangeR-rangeL;
    Point * array = NULL;
   
    if((sampleCnt <= 4) || (rangeR <= rangeL))
    {
        printf("param error sampleCnt:%d rangeR:%f rangeL:%f\n",sampleCnt,rangeL,rangeR);
        return NULL;
    }   
    array = (Point * )malloc(sampleCnt * sizeof(Point));
        for(i = 0;i<sampleCnt;i++)
        {
                /* x坐标按采样点均匀的分布在[-1.0,1.0]的范围内*/
                array[i].x = (2.0*i-sampleCnt)/sampleCnt;
                /* y坐标考虑到了振幅,频率因素的影响*/
                array[i].y = amplitude*sin(factor*(rangeL+i*range/sampleCnt));
        //printf("array[%d]:%f-%f\n",i,array[i].x,array[i].y);
        }  
   
    return array;
}
void deletSinArray(Point * array)
{
    if(array)
    {
        free(array);
    }
}
void display()
{
        int i = 0;
        glClear(GL_COLOR_BUFFER_BIT);
   
        Point * sinaArray = createSinArray(SAMPLE_CNT,1.0,1.0,-3*PI,3 * PI);
        if( sinaArray)
        {
                glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE,sizeof(Point), (GLvoid *)sinaArray);
                glEnableVertexAttribArray(0);   
                glDrawArrays(GL_LINE_STRIP, 0, SAMPLE_CNT);
                deletSinArray(sinaArray);
        }
        glFlush();
        
}
int main(int argc, char * argv[])
{
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGBA);
    glutInitWindowPosition(200, 200);
    glutInitWindowSize(300,300);
        glutCreateWindow("article3");
    glewInit();
    init();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}

结果如下:

 

2. 按键捕获

    每次改参数需要编译才能看效果还是很不方便,下面的例子加入了键盘控制,并加入了正弦波合成方波的处理,可以使用箭头键移动正弦波,使用上下箭头进行振幅调整,使用+-号来调整正弦波叠加的次数。

傅里叶函数分解方波公式:

f(y) = 4/PI * (sinx+ sin3x/3 + sin5x/5 + ...);

实际程序里面公式为:

f(y) = sinx+ sin3x/3 + sin5x/5 + ...

    学习GLSL的同时,顺便来熟悉一下傅里叶函数,想起一句话,只要努力,弯的也能掰成直的(咳,不是我说的,有兴趣的可以搜一下傅里叶掐死教程)。键盘输入捕获主要使用一下两个函数:

void glutKeyboardFunc(void(*func)(unsigned char key,int x,int y));
void glutSpecialFunc(void (*func)(int key,int x,int y));

    glutKeyboardFunc能捕获普通的按键(数字,字母),而glutSpecialFunc用来捕获方向键,F10等特殊键,这两句话加到glutMainLoop之前就可以了。

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/glut.h>
#define PI          3.14159265
#define SAMPLE_CNT  200
 
typedef struct
{
    GLfloat x;
    GLfloat y;
}Point;
static const GLchar * vertex_source =
    "#version 330 core\n"
    "layout (location = 0) in vec2 position;\n"
        "uniform mat4 matrix;\n"
    "void main()\n"
    "{\n"
        "gl_Position = vec4(position.x,position.y*0.9,0.0,1.0);\n"
    "}\0";
void loadShader(GLuint program,GLuint type,const GLchar * source)
{
    const GLchar * shaderSource[] = {source};
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, shaderSource, 0);
    glCompileShader(shader);
    glAttachShader(program, shader);
}
void init()
{
    GLuint program = glCreateProgram();
    loadShader(program,GL_VERTEX_SHADER,vertex_source);
    glLinkProgram(program);
        glUseProgram(program);
        
        glClearColor(0.5f,0.5f, 1.0f, 1.0f);    
}
Point * createSinArray(GLint sampleCnt,GLfloat factor,GLfloat amplitude,GLfloat rangeL,GLfloat rangeR)
{
    int i = 0;
    GLfloat range = rangeR-rangeL;
    Point * array = NULL;
  
    if((sampleCnt <= 4) || (rangeR <= rangeL))
    {
        printf("param error sampleCnt:%d rangeR:%f rangeL:%f\n",sampleCnt,rangeL,rangeR);
        return NULL;
    }   
    array = (Point * )malloc(sampleCnt * sizeof(Point));
        for(i = 0;i<sampleCnt;i++)
        {
                array[i].x = (2.0*i-sampleCnt)/sampleCnt;
                array[i].y = amplitude*sin(factor*(rangeL+i*range/sampleCnt));
        //printf("array[%d]:%f-%f\n",i,array[i].x,array[i].y);
        }  
   
    return array;
}
void deletSinArray(Point * array)
{
    if(array)
    {
        free(array);
    }
}
/*
* @param sinCnt:正弦波叠加次数
* @param sampleCnt:采样点数,越多,正弦波越精细
* @param amplitude:叠加后的振幅
* @param rangeL:左边界坐标
* @param rangeR:右边界坐标
*/
Point * createSquareWave(GLint sinCnt,GLint sampleCnt,GLfloat amplitude,GLfloat rangeL,GLfloat rangeR)
{
        int i = 0,j = 0;
        Point * array = (Point * )calloc(sampleCnt,sizeof(Point));
        for(i = 0;i<sinCnt;i++)
        {
                int f = 2*i+1;
                /* 依次叠加正弦波,注意频域为奇数*/
                Point * sinaArray = createSinArray(sampleCnt,1.0*f,1.0/f,rangeL,rangeR);
                for( j = 0;j<sampleCnt;j++)
                {
                        array[j].x = sinaArray[j].x;
                        array[j].y += (sinaArray[j].y*amplitude);       
                }
                deletSinArray(sinaArray);
        }
        return array;
}
int g_sinCnt = 3;
GLfloat g_rangeL = -3*PI,g_rangeR = 3 * PI;
GLfloat g_amplitud = 1.0;
void display()
{
        glClear(GL_COLOR_BUFFER_BIT);
   
        Point * squareWaveArray = createSquareWave(g_sinCnt,SAMPLE_CNT,g_amplitud,g_rangeL,g_rangeR);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE,sizeof(Point), (GLvoid *)squareWaveArray);
    glEnableVertexAttribArray(0);       
    glDrawArrays(GL_LINE_STRIP, 0, SAMPLE_CNT);  
        deletSinArray(squareWaveArray);
        glFlush();
}
void keyboard(unsigned char key, int x, int y)
{
        switch(key)
        {
        case '-':
                if( g_sinCnt > 1) g_sinCnt--;
                break;
        case '=':
        case '+':
                if( g_sinCnt < 50) g_sinCnt++;
                break;
        default:
                break;
        }
        printf("g_sinCnt:%d g_rangeL:%f g_rangeR:%f g_amplitud:%f\n",g_sinCnt,g_rangeL,g_rangeR,g_amplitud);
        glutPostRedisplay();
}
void specialKey(GLint key,GLint x,GLint y)
{
        switch(key)
        {
        case GLUT_KEY_UP:
                if( g_amplitud < 2)     g_amplitud += 0.1;
                break;
        case GLUT_KEY_DOWN:
                if( g_amplitud > 0.3)   g_amplitud -= 0.1;
                break;
        case GLUT_KEY_LEFT:     
                g_rangeL -= 0.1;g_rangeR -= 0.1;
                break;
        case GLUT_KEY_RIGHT:
                g_rangeL += 0.1;g_rangeR += 0.1;
                break;
        default:
                break;
        }
        printf("g_sinCnt:%d g_rangeL:%f g_rangeR:%f g_amplitud:%f\n",g_sinCnt,g_rangeL,g_rangeR,g_amplitud);
        glutPostRedisplay();
}
int main(int argc, char * argv[])
{
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGBA);
    glutInitWindowPosition(200, 200);
    glutInitWindowSize(300,300);
        glutCreateWindow("article3");
    glewInit();
    init();
    glutDisplayFunc(display);
        glutKeyboardFunc(keyboard);
        glutSpecialFunc(specialKey);
    glutMainLoop();
    return 0;
}

    大家可以按方向键调整位置和振幅,通过+-键控制叠加次数。

    叠加次数4次效果:

 

    叠加次数50次效果:

 

    方波波形不完善的原因应该与采样精度不足、叠加次数不够及单浮点精度不足有关。

 

3. uniform变量

    以上程序问题大家应该看到了,效率太低,根本是用CPU来画正弦函数,计算基本在CPU上完成的,GPU的浮点计算与并行计算的优势完全没有发挥出来,有什么办法可以把浮点运算挪到GPU里去算呢?这个实现不复杂,有一个问题需先解决,除了向GPU传递顶点坐标外,我们还需要向GPU传递控制信息,如上面例子的方向键与+-的控制信息,这个可以通过uniform变量实现。

    uniform变量使用流程如下:

1. shader程序定义uniform变量

2. 客户程序使用glGetUniformLocation函数获取uniform变量的索引(句柄、描述符)

3. 使用 glUniform**(程序里用 glUniform1fglUniform1i就可以了)把uniform变量值传送到shader程序,shader就可以用这个值了。

不同类型的glUniform**函数参数差异还挺大的,都不用记,可以直接查API用法:

https://www.khronos.org/registry/OpenGL-Refpages/gl4/

注意:uniformin的区别需要弄清楚,红宝书2.3.2节说的比较详细。uniform 特点是所有shader都可以使用,且在shader里不可修改,in重数据传递,uniform 主要用于控制传递。

#include <GL/glew.h>
#include <GL/glut.h>
static const GLchar * vertex_source =
    "#version 330 core\n"
        "uniform float translate_x;\n"
        "uniform float translate_y;\n"
    "layout (location = 0) in vec2 position;\n"
    "void main()\n"
    "{\n"
        "gl_Position = vec4(position.x+translate_x,position.y+translate_y,0.0,1.0);\n"
    "}\0";
void loadShader(GLuint program,GLuint type,const GLchar * source)
{
    const GLchar * shaderSource[] = {source};
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, shaderSource, 0);
    glCompileShader(shader);
    glAttachShader(program, shader);
}
 
void init()
{
        GLfloat translate_x_index,translate_y_index;
    GLuint program = glCreateProgram();
    loadShader(program,GL_VERTEX_SHADER,vertex_source);
    glLinkProgram(program);
        glUseProgram(program);
        
        /* 获取uniform变量索引(位置),注意名称要和shader中的保持一致*/
        translate_x_index = glGetUniformLocation(program, "translate_x");
        translate_y_index = glGetUniformLocation(program, "translate_y");
        /* 通过索引把信息传到GPU,供shader使用*/
        glUniform1f(translate_x_index,-0.6);
        glUniform1f(translate_y_index,0.3);
        glClearColor(0.5f,0.5f, 1.0f, 1.0f);
}
void display()
{
        glClear(GL_COLOR_BUFFER_BIT);
        GLfloat vertices[] = {0.0, 0.0,0.5,0.5,0.5,0.0};
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid *)vertices);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
 
        glFlush();
}
int main(int argc, char * argv[])
{
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGBA);
    glutInitWindowPosition(200, 200);
    glutInitWindowSize(300,300);
        glutCreateWindow("HelloWord");
    glewInit();
    init();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}
     可以看到相比第二章的例子,shader 里增加了两个 uniform 变量, init 时先通过变量名获取 uniform 变量位置(一般叫位置,有的也称为索引),再通过位置   把数据传送给 GPU ,整体过程还是挺简单的,大家可以改 glUniform1f  传的值看效果,效果如下:

 

    glUniform*函数用来更新uniform变量 ,原型有很多,总的来说函数原型分成下3大类

1. 变量操作: glUniform{1|2|3|4}{f|i|d|ui}(GLint location,TYPE value);

2. 数组操作:glUniform{1|2|3|4}{f|i|d|ui}v(GLint location,GLsizei count,const TYPE * value);

3. 矩阵数组操作: glUniformFloatMatrix{2|3|4}fv(GLint location,GLsizei count,GLboolean transpose,const TYPE * value);

    其中f=floati = intd=doubleui=unsigned int TYPE为对应的类型,v结尾的都是数组类型。下面列的都是4维的函数原型:

void glUniform4i(GLint location,GLint v0,GLint v1,GLint v2,GLint v3);
void glUniform4f(GLint location,GLfloat v0,GLfloat v1,GLfloat v2,GLfloat v3);
void glUniform4iv(GLint location,GLsizei count,const GLint *value);
void glUniform4fv(GLint location,GLsizei count,const GLfloat *value);
void glUniformMatrix4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat *value);

    矩阵操作只提供了数组方式的操作,矩阵方式有参数transpose参数,为true时,以行主序方式读入(c语言数组方式),false为列主序方式读取(shader中,矩阵默认以列为主序,自己组矩阵的时候需注意)。

Uniform变量数组的操作例子如下:

mat4 model_matrix[8] = {...};
glUniformMatrix4fv(render_model_matrix_loc, 8, GL_FALSE, model_matrix[0]);

注意:count的值需与矩阵数组一致,否则传送的数据不对,红宝书第三章例子ch03_drawcommands.cpp中,count的值(应为1,程序为4)不正确导致程序一片黑。

model_matrix = vmath::translation(-3.0f, 0.0f, -5.0f);
glUniformMatrix4fv(render_model_matrix_loc, 4, GL_FALSE, model_matrix);
glDrawArrays(GL_TRIANGLES, 0, 3);

4. 正弦波叠加的GLSL实现

    通过uniform变量传送控制信息到shader中,就可以使用shader来实现本章的正弦叠加的例子。对于复杂的例子,使用shader文件的方式更好阅读,为方便大家编译,本章的例子先用notepad++写好,再复制上来的,阅读的时候,大家可以把分号去掉,比较方便。

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/glut.h>
#define PI          3.14159265
#define SAMPLE_CNT  200
static const GLchar * vertex_source =
"#version 330 core                                                                                      \n"
"layout (location = 0) in float vertexSerial;                                                           \n"
"uniform int g_sinCnt;                                                                                  \n"
"uniform float g_rangeL;                                                                                \n"
"uniform float g_rangeR;                                                                                \n"
"uniform float g_amplitud;                                                                              \n"
"const int sampleCnt=200;                                                                               \n"
"                                                                                                       \n"
"vec2 createSinPostion(float posIdex,float factor,float amplitude, float rangeL, float rangeR)          \n"
"{                                                                                                      \n"
"    vec2 sinPos;                                                                                       \n"
"    float range = rangeR - rangeL;                                                                     \n"
"                                                                                                       \n"
"    sinPos.x = (2.0 * posIdex - sampleCnt)/sampleCnt;                                                  \n"
"    sinPos.y = amplitude * sin(factor * (rangeL + posIdex * range / sampleCnt));                       \n"
"                                                                                                       \n"
"    return sinPos;                                                                                     \n"
"}                                                                                                      \n"
"                                                                                                       \n"
"vec2 createSquareWave(float posIdex,int sinCnt, float amplitude, float rangeL, float rangeR)           \n"
"{                                                                                                      \n"
"    vec2 SquareWarvePos, sinPos;                                                                       \n"
"    int i = 0;                                                                                         \n"
"                                                                                                       \n"
"    for(i = 0;i<sinCnt;i++)                                                                            \n"
"    {                                                                                                  \n"
"        int f = 2 * i + 1;                                                                             \n"
"                                                                                                       \n"
"        sinPos = createSinPostion(posIdex, 1.0 * f, 1.0 / f, rangeL, rangeR);                          \n"
"        SquareWarvePos.x = sinPos.x;                                                                   \n"
"        SquareWarvePos.y += (sinPos.y * amplitude);                                                    \n"
"    }                                                                                                  \n"
"                                                                                                       \n"
"    return SquareWarvePos;                                                                             \n"
"}                                                                                                      \n"
"                                                                                                       \n"
"void main()                                                                                            \n"
"{                                                                                                      \n"
"    vec2 SquareWarvePos  = createSquareWave(vertexSerial,g_sinCnt,g_amplitud,g_rangeL,g_rangeR);       \n"
"    gl_Position = vec4(SquareWarvePos,0.0,1.0);                                                        \n"
"}                                                                                                      \n"
"\0";
void loadShader(GLuint program, GLuint type, const GLchar * source)
{
    const GLchar * shaderSource[] = {source};
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, shaderSource, 0);
    glCompileShader(shader);  
    glAttachShader(program, shader);
}
/* uniform控制变量的位置定义*/
GLint sinCntIdx;
GLfloat rangeLIdx,rangeRIdx,amplitudIdx;
/* uniform控制变量的值定义*/
GLint g_sinCnt = 3;
GLfloat g_rangeL = -3 * PI,g_rangeR = 3 * PI,g_amplitud = 1.0;
void init()
{
    GLuint program = glCreateProgram();
    loadShader(program, GL_VERTEX_SHADER, vertex_source);
    glLinkProgram(program);
    glUseProgram(program);
    /* 获取shader中uniform变量位置*/
     sinCntIdx = glGetUniformLocation(program, "g_sinCnt");
    rangeLIdx = glGetUniformLocation(program, "g_rangeL");
    rangeRIdx = glGetUniformLocation(program, "g_rangeR");
    amplitudIdx = glGetUniformLocation(program, "g_amplitud");
    glClearColor(0.5f, 0.5f, 1.0f, 1.0f);
}
void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    /* 向shader中uniform变量传送值*/
    glUniform1i(sinCntIdx,g_sinCnt);   
    glUniform1f(rangeLIdx,g_rangeL);
    glUniform1f(rangeRIdx,g_rangeR);
    glUniform1f(amplitudIdx,g_amplitud);
    /* 顶点的坐标由shader自己生成,但需告知shader点的索引*/
    GLfloat vertexSerial[SAMPLE_CNT];
    for(int i = 0;i<SAMPLE_CNT;i++)
    {
        vertexSerial[i] = i;
    }
    glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, sizeof(GLfloat), (GLvoid *)vertexSerial);
    glEnableVertexAttribArray(0);
    glDrawArrays(GL_LINE_STRIP, 0, SAMPLE_CNT);
    glFlush();
}
void keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
        case '-':
            if (g_sinCnt > 1) g_sinCnt--;
            break;
        case '=':
        case '+':
            if (g_sinCnt < 50) g_sinCnt++;
            break;
        default:
            break;
    }
    printf("g_sinCnt:%d g_rangeL:%f g_rangeR:%f g_amplitud:%f\n", g_sinCnt, g_rangeL, g_rangeR, g_amplitud);
    glutPostRedisplay();
}
void specialKey(GLint key, GLint x, GLint y)
{
    switch (key)
    {
        case GLUT_KEY_UP:
            if (g_amplitud < 2)    g_amplitud += 0.1;
            break;
        case GLUT_KEY_DOWN:
            if (g_amplitud > 0.3)    g_amplitud -= 0.1;
            break;
        case GLUT_KEY_LEFT:
            g_rangeL -= 0.1;
            g_rangeR -= 0.1;
            break;
        case GLUT_KEY_RIGHT:
            g_rangeL += 0.1;
            g_rangeR += 0.1;
            break;
        default:
            break;
    }
    printf("g_sinCnt:%d g_rangeL:%f g_rangeR:%f g_amplitud:%f\n", g_sinCnt, g_rangeL, g_rangeR, g_amplitud);
    glutPostRedisplay();
}
int main(int argc, char * argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA);
    glutInitWindowPosition(200, 200);
    glutInitWindowSize(300, 300);
    glutCreateWindow("article3");
    glewInit();
    init();
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutSpecialFunc(specialKey);
    glutMainLoop();
    return 0;
}

    运行的结果(效果)与客户端实现是一致的,效率上应该会更高一些,这里就不贴截图了。

    大家可以看到使用shader语言来实现正弦叠加函数,shader的编写与客户端代码编写最大的不同是shader处理的是单个点坐标, 程序中去掉了采样点循环,程序更简洁,语法和C语言基本一致,客户端代码移植到shader中去,只需做简单的修改即可。

    客户度向GPU只传送了采样点的序列,传送的数据小很多,如果使用vbovaodisplay传送数据部分,可以进一步简化和提高效率。

 

注意:

1. 目前调试shader程序没什么好的办法,红宝书shader的例子都很简短,调试长一点的shader,请大家先把loadShader里的错误处理加上。

2. GLintGLfloat等是openGL客户端的变量类型,shader里面用的都是intfloat等,与c类似的未封装类型。

3. GLSL内置了很多函数,上述的sin函数就是内置的,内置函数原型用的时候可以查手册(红宝书附录C),避免与cc++的库函数搞混了。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值