OpenGL--shader入门

  • 理论基础
    着色器:opengl渲染管线分为固定管线和可编程管线,3.1版本后固定管线已经废除了。可编程管线主要是包括顶点着色器和片段着色器,而我们所讲的shader其实就是说我们可以自己控制这两个阶段的操作。本质其实和固定管线一样,还是走那套流程,只是现在更灵活些而已。
    下面是着色器编程的步骤示意图:

OpenGL--shader入门_第1张图片

  • 实例代码

//源程序

#include "GLTools.h"
#include "GLShaderManager.h"

#ifdef __APPLE__
#include 
#else
#define FREEGLUT_STATIC
#include 
#endif

GLuint v, f, f2,p;
GLint loc;

//文件读取(将本地shader文件读取为字符串形式加载)
char *textFileRead(char *fn)
{
    FILE *fp;
    char *content = NULL;

    int count=0;

    if (fn != NULL)
    {
        fp = fopen(fn,"rt");

        if (fp != NULL)
        {
            fseek(fp, 0, SEEK_END);
            count = ftell(fp);
            rewind(fp);

            if (count > 0)
            {
                content = (char *)malloc(sizeof(char) * (count+1));
                count = fread(content,sizeof(char),count,fp);
                content[count] = '\0';
            }
            fclose(fp);
        }
    }
    return content;
}


void changeSize(int w, int h)
{
    if(h == 0)
        h = 1;

    float ratio = 1.0* w/h;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glViewport(0, 0, w, h);

    gluPerspective(45, ratio, 1, 1000);

    glMatrixMode(GL_MODELVIEW);
}


float time = 0;
void renderScene(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glColor4f(1.0, 0.0, 0.0, 1.0);//初始化了gl_Color值,可给着色器使用

    glLoadIdentity();
    gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

    glUniform1f(loc, time);//给uniform属性loc所指地址赋值
    time+=0.01;

    glutSolidTeapot(1);//绘制茶壶

    glutSwapBuffers();
}

//着色器:自己处理渲染管线中的顶点着色器和片段着色器阶段
void setShaders()
{
    char *vs = NULL, *fs = NULL, *fs2 = NULL;
    /*第一阶段*/
    //创建着色器对象(类似C中的函数,可以复用)
    v = glCreateShader(GL_VERTEX_SHADER);//顶点着色器
    f = glCreateShader(GL_FRAGMENT_SHADER);//片段着色器
    f2 = glCreateShader(GL_FRAGMENT_SHADER);

    vs = textFileRead("/Users/app05/Desktop/opengl/opengl/minimal.vert");
    fs = textFileRead("/Users/app05/Desktop/opengl/opengl/minimal.frag");

    const char *vv = vs;
    const char *ff = fs;
    //将着色器代码添加到创建的着色器容器中
    glShaderSource(v, 1, &vv, NULL);
    glShaderSource(f, 1, &ff, NULL);

    free(vs);
    free(fs);
    //编译着色器源代码
    glCompileShader(v);
    glCompileShader(f);

    /*第二阶段*/
    p = glCreateProgram();//创建着色器程序
    glAttachShader(p, v);//将着色器对象关联到这个着色器程序
    glAttachShader(p, f);

    glLinkProgram(p); //链接着色器程序

    glUseProgram(p);//使用着色器

    //得到着色器程序中unifrom属性的time变量地址,以便外面修改它
    loc = glGetUniformLocation(p,"time");
}

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(320,320);
    glutCreateWindow("OpenGL Shader 入门");
    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);
    glutReshapeFunc(changeSize);

    glEnable(GL_DEPTH_TEST);
    glClearColor(1.0,1.0,1.0,1.0);
    //  glEnable(GL_CULL_FACE);

    glewInit();

    setShaders();

    glutMainLoop();

    return 0;
}

//顶点着色器程序(minimal.vert)

uniform float time;//uniform属性的变量值可以由opengl程序传进来

void main()
{
    //顶点颜色
    gl_FrontColor = gl_Color;

    //模型矩阵变换,将3D坐标投影到2D屏幕坐标
    //gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
    //gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    //gl_Position = ftransform();

    //实例:顶点z值正旋变化
    vec4 v = vec4(gl_Vertex);
    v.z = sin(5.0 * v.x + time) * 0.5;
    gl_Position = gl_ModelViewProjectionMatrix * v;
}

//片段着色器程序(minimal.frag)

void main()
{
    /*gl_FragColor:是设置片段的颜色,gl_Color:是外部glColor()默认初始化的uniform值*/
    gl_FragColor = gl_Color;
}

OpenGL--shader入门_第2张图片

OpenGL--shader入门_第3张图片

你可能感兴趣的:(OpenGL,OpenGL)