您的位置:首页 > 其它

GLSL 创建自己的着色器

2015-03-26 18:11 267 查看
这里讨论如何将类似于上一节的流经着色器编译和链接到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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: