GLSL 创建自己的着色器

来源:互联网 发布:编程c语言入门 编辑:程序博客网 时间:2024/06/07 21:11

这里讨论如何将类似于上一节的流经着色器编译和链接到OpenGL的程序中去
为了方便编译和修改,着色器程序都写在单独的文本文件中。
1.首先建立一个着色器对象,使用函数glCreateShader():

GLuint glCreateShader(GLenum type)/*type指代着色器类型,GL_VERTEX_SHADER顶点着色器,GL_FRAGMENT_SHADER片段着色器*///返回一个唯一的对象标识符

下面代码分别建立了2个着色器对象:

GLuint v,f;v=glCreateShader(GL_VERTEX_SHADER);f=glCreateShader(GL_FRAGMENT_SHADER);

这是2个空白着色器,接下来要将它们关联到着色器上,假设2个着色器已经保存在文本文件中,流经顶点着色器保存在passthrough.vert,流经片段着色器保存在passthrough.frag。
首先要将着色器读取到内存中,可以使用CReader或自己写函数。
例:

char *vs=NULL,*fs=NULL;CReader reader;vs = reader.textFileRead("passthrough.vert");fs = reader.textFileRead("passthrough.frag");

2.接着,将读取到内存中的着色器加载到着色器对象中,通过函数glShaderSource():

glShaderSource(GLuint unShaderObj,GLsizeit nNoStrings,const GLchar **ppchSource,const GLint nLength);//该函数将ppchSource中保存的着色器程序放入着色器对象标识符unShaderObj指代的对象中。//一种常用的参数组合是:将nLength设为NULL,字符串数量nNoStrings设为1,则ppchSources是一个以NULL结尾的字符串

例:

const char *vv=vs;onst char *ff=fs;glShaderSource(v,1,&vv,NULL);glShaderSource(f,1,&ff,NULL);

3.然后对已经加载的着色器进行编译,使用函数glCompileShader():

void glCompileShader(GLuint nShaderObj)

例:

glCompileShader(v);glCompileShader(f);

不在使用着色器时,可以使用glDeleteShader()删除void glDeleteShader(GLuint nShaderObj)
4.编译结束,该到链接了。在链接着色器对象之前,先要建立程序对象,使用函数:

GLuint glCreateProgram()

5.接下来使用glAttachShader(GLuint nProgramObj,GLuint nShaderObj)将着色器程序添加到程序对象中去。不在使用某着色器对象时,使用函数void glAttachShader(GLuint nProgramObj,GLuint nShaderObj)将着色器抽离程序对象。
6.然后使用void glLinkProgram(GLuint nProgramObj)进行链接。
7.当有多个程序对象时,可以使用void gluseProgram(GLuint nProgramObj)选择想要使用的程序对象。
例:

GLuint p;p = glCreateProgram();glAttachShader(p,v);glAttachShader(p,f);glLinkProgram(p);gluseProgram(p);

8.在程序末尾不在使用某程序时,使用函数void glDeleteProgram(GLuint nProgramObj)来删除。
注意:编写着色器时:
1.main的返回值必须是void,不能是int;
2.需要下载glew库,并在加入前shader使用glewInit()初始化。
3.严格注意拼写问题!!!
例:
顶点流经着色器vertex.v:

void main(){    vec4 a;    a = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;    gl_Position.x = a.x*0.4;    gl_Position.y = a.y*0.1;}

片段流经着色器fragment.f:

void main(){    gl_FragColor = vec4(0.4,0.4,0.8,1.0);}

cpp:

#include <Windows.h>#include <iostream>#include<stdlib.h>#include<gl\glew.h>//#include <gl\GL.h>//#include <gl\GLU.h>#pragma comment(lib,"opengl32.lib")//opengl相关库#pragma comment(lib,"glu32.lib")#pragma comment(lib,"glew32.lib")#pragma comment(lib,"glew32s.lib")/////全局句柄HGLRC hRC;HDC hDC;HWND hWnd;/////全局句柄//全局变量bool flag_depth = true;//是否深度测试float rx = 0,ry=0;char *vdata = NULL;char *fdata = NULL;GLfloat vec[][3] = {    { -1, 1, -1 }, { 1, 1, -1 }, { 1, 1, 1 }, { -1, 1, -1 }, { 1, 1, 1 }, { -1, 1, 1 },//前    { -1, -1, -1 }, { 1, -1, -1 }, { 1, -1, 1 }, { -1, -1, -1 }, { 1, -1, 1 }, { -1, -1, 1 },//后    { -1, 1, 1 }, { -1, 1, -1 }, { -1, -1, -1 }, { -1, 1, 1 }, { -1, -1, -1 }, { -1, -1, 1 },//左    { 1, 1, 1 }, { 1, 1, -1 }, { 1, -1, -1 }, { 1, 1, 1 }, { 1, -1, -1 }, { 1, -1, 1 },//右    { -1, -1, 1 }, { -1, 1, 1 }, { 1, 1, 1 }, { -1, -1, 1 }, { 1, 1, 1 }, { 1, -1, 1 },//上    { -1, -1, -1 }, { -1, 1, -1 }, { 1, 1, -1 }, { -1, -1, -1 }, { 1, 1, -1 }, { 1, -1, -1 },//下};GLfloat col[][3] = {    { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 }, { 0.1, 0.2, 0.3 }, { 0.1, 0.2, 0.3 }, { 0.1, 0.2, 0.3 },//前    { 0.4, 0.4, 0.0 }, { 0.4, 0.4, 0.0 }, { 0.4, 0.4, 0.0 }, { 0.8, 0.4, 0.0 }, { 0.8, 0.4, 0.0 }, { 0.8, 0.4, 0.0 },//后    { 0.8, 0.4, 0.8 }, { 0.8, 0.4, 0.8 }, { 0.8, 0.4, 0.8 }, { 0.0, 0.4, 0.8 }, { 0.0, 0.4, 0.8 }, { 0.0, 0.4, 0.8 },//左    { 0.3, 0.3, 0.3 }, { 0.3, 0.3, 0.3 }, { 0.3, 0.3, 0.3 }, { 0.4, 0.4, 0.4 }, { 0.4, 0.4, 0.4 }, { 0.4, 0.4, 0.4 },//右    { 0.4, 0.0, 0.4 }, { 0.4, 0.0, 0.4 }, { 0.4, 0.0, 0.4 }, { 0.4, 0.0, 0.0 }, { 0.4, 0.0, 0.0 }, { 0.4, 0.0, 0.0 },//上    { 0.0, 0.4, 0.0 }, { 0.0, 0.4, 0.0 }, { 0.0, 0.4, 0.0 }, { 0.0, 0.0, 0.4 }, { 0.0, 0.0, 0.4 }, { 0.0, 0.0, 0.4 },//下};void InitGL()//初始化opengl参数{    glClearColor(0.5, 0.5, 0.5, 1);//设置颜色缓存颜色    glEnableClientState(GL_VERTEX_ARRAY);//  glEnableClientState(GL_COLOR_ARRAY);    glTranslated(0, 0, -1);    glVertexPointer(3, GL_FLOAT, 0, vec);//  glColorPointer(3, GL_FLOAT, 0, col);    glMatrixMode(GL_PROJECTION);                        // 选择投影矩阵    glLoadIdentity();                           // 重置投影矩阵    glMatrixMode(GL_MODELVIEW);                     // 选择模型观察矩阵    glLoadIdentity();                           // 重置模型观察矩阵    glScalef(0.5,0.5,0.5); //缩放0.5倍}char* ReadFile(char *filename){    FILE *file = NULL;    fopen_s(&file, filename, "rt");    if (file == NULL)    {        return NULL;    }    fseek(file, 0, SEEK_END);    long count = ftell(file);    rewind(file);    char *fileData = NULL;    if (count > 0)    {        fileData = new char[count+1];        fread(fileData, sizeof(char), count, file);        fileData[count] = '\0';    }    return fileData;}void setShader(){    glewInit();//添加此句    GLuint v, f;    v = glCreateShader(GL_VERTEX_SHADER);    f = glCreateShader(GL_FRAGMENT_SHADER);    vdata = ReadFile("vertex.v");    fdata = ReadFile("fragment.f");    char *vv = vdata;    char *ff = fdata;    glShaderSource(v, 1, &vv, NULL);    glShaderSource(f, 1, &ff, NULL);    glCompileShader(v);    glCompileShader(f);    GLuint p = glCreateProgram();    glAttachShader(p, v);    glAttachShader(p, f);    glLinkProgram(p);    glUseProgram(p);}void DrawGLScene(){    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 每次刷新屏幕颜色缓存    if (flag_depth) glEnable(GL_DEPTH_TEST);    else glDisable(GL_DEPTH_TEST);    glRotated(rx, 1, 0, 0);    glRotated(ry, 0, 1, 0);    glDrawArrays(GL_TRIANGLES, 0, 36);}LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)// 消息处理回调函数{    switch (uMsg)                                   // Check For Windows Messages    {        case WM_ACTIVATE:                           // Watch For Window Activate Message        {            return 0;                               // Return To The Message Loop        }        case WM_SYSCOMMAND:                         // Intercept System Commands        {            switch (wParam)                         // Check System Calls            {            case SC_SCREENSAVE:                 // Screensaver Trying To Start?            case SC_MONITORPOWER:               // Monitor Trying To Enter Powersave?                return 0;                           // Prevent From Happening            }            break;                                  // Exit        }        case WM_CLOSE:                              // Did We Receive A Close Message?        {            PostQuitMessage(0);                     // Send A Quit Message            return 0;                               // Jump Back        }        case WM_KEYDOWN:                            // 按键按下 由wParam决定        {            switch (wParam)            {            case 'D':                flag_depth = !flag_depth;                break;            case VK_UP:                rx += 0.001;                break;            case VK_DOWN:                rx -= 0.001;                break;            case VK_LEFT:                ry += 0.001;                break;            case VK_RIGHT:                ry -= 0.001;                break;            }            return 0;                               // Jump Back        }        case WM_KEYUP:                              // 按键松开        {            return 0;                               // Jump Back        }        case WM_SIZE:                               // Resize The OpenGL Window        {            glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));//改变GL窗口大小            return 0;                               // Jump Back        }        case WM_PAINT:        {            DrawGLScene();                  // Draw The Scene            SwapBuffers(hDC);               // Swap Buffers (Double Buffering)            return 0;                               // Jump Back        }    }    // Pass All Unhandled Messages To DefWindowProc    return DefWindowProc(hwnd, uMsg, wParam, lParam);//默认消息回调处理函数}void KillGLWindow(){    if (hRC)                                            // 删除着色描述表    {        if (!wglMakeCurrent(NULL, NULL))                    // Are We Able To Release The DC And RC Contexts?        {            MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);        }        if (!wglDeleteContext(hRC))                     // Are We Able To Delete The RC?        {            MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);        }        hRC = NULL;                                     // Set RC To NULL    }    if (hDC && !ReleaseDC(hWnd, hDC))                   // 释放DC    {        MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);        hDC = NULL;                                     // Set DC To NULL    }    if (hWnd && !DestroyWindow(hWnd))                   // Are We Able To Destroy The Window?    {        MessageBox(NULL, "Could Not Release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);        hWnd = NULL;                                        // Set hWnd To NULL    }}int WINAPI WinMain(HINSTANCE h,HINSTANCE,LPSTR lpCmdLine,int nCmdShow){    WNDCLASS wc;    wc.hInstance = h;    wc.hbrBackground = NULL;    wc.hCursor = LoadCursor(NULL, IDC_ARROW);    wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);    wc.lpszMenuName = NULL;    wc.lpszClassName = "OpenGL";    wc.cbClsExtra = 0;                                  // No Extra Window Data    wc.cbWndExtra = 0;    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;  // Redraw On Size, And Own DC For Window.    wc.lpfnWndProc = (WNDPROC)WndProc;    RegisterClass(&wc);    hWnd = CreateWindow("OpenGL", "test", WS_OVERLAPPEDWINDOW | WS_SYSMENU | WS_BORDER | WS_MAXIMIZEBOX, 0, 0, 300, 300, NULL, NULL, h, NULL);    //opengl设定    hDC = GetDC(hWnd);    static  PIXELFORMATDESCRIPTOR pfd =             // pfd Tells Windows How We Want Things To Be    {        sizeof(PIXELFORMATDESCRIPTOR),              // Size Of This Pixel Format Descriptor        1,                                          // Version Number        PFD_DRAW_TO_WINDOW |                        // Format Must Support Window        PFD_SUPPORT_OPENGL |                        // Format Must Support OpenGL        PFD_DOUBLEBUFFER,                           // Must Support Double Buffering        PFD_TYPE_RGBA,                              // Request An RGBA Format        24,                                     // Select Our Color Depth        0, 0, 0, 0, 0, 0,                           // Color Bits Ignored        0,                                          // No Alpha Buffer        0,                                          // Shift Bit Ignored        0,                                          // No Accumulation Buffer        0, 0, 0, 0,                                 // Accumulation Bits Ignored        16,                                         // 16Bit Z-Buffer (Depth Buffer)          0,                                          // No Stencil Buffer        0,                                          // No Auxiliary Buffer        PFD_MAIN_PLANE,                             // Main Drawing Layer        0,                                          // Reserved        0, 0, 0                                     // Layer Masks Ignored    };    int PixelFormat;    if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd)))              // 按照给定像素格式规范匹配与设备上下文合适的像素格式    {        KillGLWindow();                         // 重置显示区        MessageBox(NULL, "不能设置像素格式", "错误", MB_OK | MB_ICONEXCLAMATION);        return FALSE;                           // 返回 FALSE    }    if (!SetPixelFormat(hDC, PixelFormat, &pfd))                // 设置像素格式    {        KillGLWindow();                         // 重置显示区        MessageBox(NULL, "不能设置像素格式", "错误", MB_OK | MB_ICONEXCLAMATION);        return FALSE;                           // 返回 FALSE    }    if (!(hRC = wglCreateContext(hDC)))                 // 设置合适设备的OpenGL渲染上下文    {        KillGLWindow();                         // 重置显示区        MessageBox(NULL, "不能创建OpenGL渲染描述表", "错误", MB_OK | MB_ICONEXCLAMATION);        return FALSE;                           // 返回 FALSE    }    if (!wglMakeCurrent(hDC, hRC))                      // 尝试激活着色描述表    {        KillGLWindow();                         // 重置显示区        MessageBox(NULL, "不能激活当前的OpenGL渲然描述表", "错误", MB_OK | MB_ICONEXCLAMATION);        return FALSE;                           // 返回 FALSE    }    //opengl着色表设定结束    ShowWindow(hWnd, SW_SHOW);    InitGL();//opengl相关初始化    setShader();    //消息处理    bool done = false;    MSG msg;    while (!done)                                   // Loop That Runs While done=FALSE    {        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))   // 如果有消息就处理消息        {            if (msg.message == WM_QUIT)             // Have We Received A Quit Message?            {                done = TRUE;                            // If So done=TRUE            }            else                                    // If Not, Deal With Window Messages            {                TranslateMessage(&msg);             // Translate The Message                DispatchMessage(&msg);              // Dispatch The Message            }        }        else                                        // 没消息就处理界面        {            // Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()                      }    }    return TRUE;}
0 0