OpenGL进阶01.使用Shader绘制三角形
Posted stq_wyy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL进阶01.使用Shader绘制三角形相关的知识,希望对你有一定的参考价值。
在前一个阶段的文章中,主要是使用OpenGL的固定管线来实现了一系列的操作,内容并不复杂,十分好理解,接下来的进阶系列中,我们将使用shader代码来实现一些效果。首先通过shader来实现一个三角形的绘制。
首先来看main.cs,创建窗口以及调用绘制指令都在这个脚本中实现:
#include "ggl.h"
#include "scene.h"
#include "Utils.h"
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glew32.lib")
unsigned char* LoadFileContent(const char* path, int& filesize)
{
unsigned char* fileContent = nullptr;
filesize = 0;
FILE* pFile = fopen(path, "rb");
if (pFile)
{
fseek(pFile, 0, SEEK_END);
int nLen = ftell(pFile);
if (nLen > 0)
{
rewind(pFile);
fileContent = new unsigned char[nLen + 1];
fread(fileContent, sizeof(unsigned char), nLen, pFile);
fileContent[nLen] = '\\0';
filesize = nLen;
}
fclose(pFile);
}
return fileContent;
}
LRESULT CALLBACK GLWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
INT WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX wndclass;
wndclass.cbClsExtra = 0;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = NULL;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = NULL;
wndclass.hIconSm = NULL;
wndclass.hInstance = hinstance;
wndclass.lpfnWndProc = GLWindowProc;
wndclass.lpszClassName = L"GLWindow";
wndclass.lpszMenuName = NULL;
wndclass.style = CS_VREDRAW | CS_HREDRAW;
ATOM atom = RegisterClassEx(&wndclass);
if (!atom)
{
MessageBox(NULL, L"Notice", L"Error", MB_OK);
return 0;
}
RECT rect;
rect.left = 0;
rect.right = 800;
rect.top = 0;
rect.bottom = 600;
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, NULL);
int windowWidth = rect.right - rect.left;
int windowHeight = rect.bottom - rect.top;
HWND hwnd = CreateWindowEx(NULL, L"GLWindow", L"OpenGL Window", WS_OVERLAPPEDWINDOW,
100, 100, windowWidth, windowHeight,
NULL, NULL, hinstance, NULL);
HDC hdc = GetDC(hwnd);
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nVersion = 1;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
int pixelFormat = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, pixelFormat, &pfd);
HGLRC rc = wglCreateContext(hdc);
wglMakeCurrent(hdc, rc);
glewInit();
Init();
SetViewPortSize(800.0f, 600.0f);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
MSG msg;
while (true)
{
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Draw();
SwapBuffers(hdc);
}
return 0;
}
我们看到main.cs中include了三个.h文件,分别是ggl.h,scene.h,Utils.h。我们分别看下里边的内容:
ggl.h:
#pragma once
#include <windows.h>
#include "glew.h"
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <sstream>
#include <vector>
#include <functional>
#include <map>
#include "Glm/glm.hpp"
#include "Glm/ext.hpp"
里边包含了我们会使用到的头文件。
scene.h:
#pragma once
#include "ggl.h"
void Init();
void SetViewPortSize(float width, float height);
void Draw();
scene.cpp:
#include "scene.h"
#include "ggl.h"
#include "Utils.h"
GLuint vbo;
GLuint program;
GLint positionLocation, modelMatrixLocation, viewMatrixLocation, projectionMatrixLocation;
glm::mat4 modelMatrix, viewMatrix, projectionMatrix;
void Init()
{
float data[] = {
-0.2f,-0.2f,-0.6f,1.0f,
0.2f,-0.2f,-0.6f,1.0f,
0.0f,0.2f,-0.6f,1.0f
};
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 12, data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
int fileSize = 0;
//读取shader代码
unsigned char* shaderCode = LoadFileContent("Res/test.vs", fileSize);
GLuint vsShader = CompileShader(GL_VERTEX_SHADER, (char*)shaderCode);
delete shaderCode;
shaderCode = LoadFileContent("Res/test.fs", fileSize);
GLuint fsShader = CompileShader(GL_FRAGMENT_SHADER, (char*)shaderCode);
delete shaderCode;
program = CreateProgram(vsShader, fsShader);
glDeleteShader(vsShader);
glDeleteShader(fsShader);
//获取shader中的变量
positionLocation = glGetAttribLocation(program, "position");
modelMatrixLocation = glGetUniformLocation(program, "ModelMatrix");
viewMatrixLocation = glGetUniformLocation(program, "ViewMatrix");
projectionMatrixLocation = glGetUniformLocation(program, "ProjectionMatrix");
}
void SetViewPortSize(float width, float height)
{
projectionMatrix = glm::perspective(60.0f, width / height, 0.1f, 1000.0f);
}
void Draw()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
}
Unitls.h主要是编译shader已经创建程序的功能。
#pragma once
#include "ggl.h"
unsigned char* LoadFileContent(const char* path, int& filesize);
GLuint CompileShader(GLenum shaderType, const char* shaderCode);
GLuint CreateProgram(GLuint vsShader, GLuint fsShader);
Utils.cpp:
#include "Utils.h"
GLuint CompileShader(GLenum shaderType, const char* shaderCode)
{
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &shaderCode, nullptr);
glCompileShader(shader);
GLint compileResult = GL_TRUE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
if (compileResult==GL_FALSE)
{
char szLog[1024] = { 0 };
GLsizei logLen = 0;
glGetShaderInfoLog(shader, 1024, &logLen, szLog);
printf("Complie Shader fail error log: %s \\nshader code: \\n%s\\n", szLog, shaderCode);
glDeleteShader(shader);
shader = 0;
}
return shader;
}
GLuint CreateProgram(GLuint vsShader, GLuint fsShader)
{
GLuint program = glCreateProgram();
glAttachShader(program, vsShader);
glAttachShader(program, fsShader);
glLinkProgram(program);
glDetachShader(program, vsShader);
glDetachShader(program, fsShader);
GLint nResult;
glGetProgramiv(program, GL_LINK_STATUS, &nResult);
if (nResult == GL_FALSE)
{
char log[1024] = { 0 };
GLsizei writed = 0;
glGetProgramInfoLog(program, 1024, &writed, log);
printf("create gpu program fail,link error: %s\\n", log);
glDeleteProgram(program);
program = 0;
}
return program;
}
最后附上顶点和片元着色器,即test.vs和test.fs:
attribute vec4 position;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
void main()
{
gl_Position = ProjectionMatrix*ViewMatrix*ModelMatrix*position;
}
#ifdef GL_ES
precision mediump float;
#endif
void main()
{
gl_FragColor = vec4(1.0,1.0,1.0,1.0);
}
最后来看下效果吧:
今天就写到这里了~
以上是关于OpenGL进阶01.使用Shader绘制三角形的主要内容,如果未能解决你的问题,请参考以下文章
我的OpenGL学习进阶之旅介绍顶点缓冲区对象VBO和元素数组缓冲区对象EBO,并对比使用VBO和不使用VBO绘制三角形的效果