GLSL 创建自己的着色器

这里讨论如何将类似于上一节的流经着色器编译和链接到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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值