本教程将是使用OpenGL 4.0的第一个真正的介绍。我们将解决三个主要问题,分别是初始化OpenGL 4.0,关闭它以及使用它进行基本渲染。本教程使用与上一教程相同的类,不同之处在于,我们将为每个类添加更多代码,以利于使用OpenGL 4.0进行渲染。
我们将通过查看填写好的OpenGLClass来开始本教程:
Openglclass
头文件中,OpenGL 4.0要求您在opengl32.lib库中进行链接。您可以在IDE中或直接在代码中执行此操作。我已将链接放入代码中,因为这是我的偏爱:
#pragma comment(lib,“ opengl32.lib”)
OpenGL 4.0还需要windows.h和gl.h头文件。我还包括了math.h,因为我们将需要编写一些数学函数来协助使用OpenGL进行渲染。
首先开始填充OpenGLClass来开始本教程:
OpenGL 4.0要求您在opengl32.lib库中进行链接。您可以在IDE中或直接在代码中执行此操作。我已将链接放入代码中,因为这是我的偏爱。
/
//链接//
/
#pragma comment(lib,“ opengl32.lib”)
如果找不到这些文件,就查看一下包含路径是否可靠:
我用的vs2019.
//
//包含//
//
#include <windows.h>
#include <gl \ gl.h>
#include <math.h>
在Windows中,gl.h标头仅包含OpenGL 1.0和OpenGL 1.1的定义,函数和函数指针。实际上,所有新的OpenGL功能都以扩展名的形式在您的显卡的显示驱动程序中实现。您可以在OpenGL 4.0文档中找到Khronos Group在其网站上维护的OpenGL 4.0规范中所有扩展的名称。您还可以下载wglext.h和glext.h之类的文件,其中也包含大量文件。对于这些教程,我们只需要所有函数的子集,因此我包括了将在此头文件中使用的定义,类型定义和函数指针。
以下是我们将使用的定义:
/
// DEFINES //
/
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_SWAP_METHOD_ARB 0x2007
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_COLOR_BITS_ARB 0x2014
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_SWAP_EXCHANGE_ARB 0x2028
#define WGL_TYPE_RGBA_ARB 0x202B
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GL_ARRAY_BUFFER 0x8892
#define GL_STATIC_DRAW 0x88E4
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_VERTEX_SHADER 0x8B31
#define GL_COMPILE_STATUS 0x8B81
#define GL_LINK_STATUS 0x8B82
#define GL_INFO_LOG_LENGTH 0x8B84
#define GL_TEXTURE0 0x84C0
#define GL_BGRA 0x80E1
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
//
// TYPEDEFS //
//
typedef BOOL(WINAPI* PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats,
int* piFormats, UINT* nNumFormats);
typedef HGLRC(WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int* attribList);
typedef BOOL(WINAPI* PFNWGLSWAPINTERVALEXTPROC) (int interval);
typedef void (APIENTRY* PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRY* PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRY* PFNGLBINDVERTEXARRAYPROC) (GLuint array);
typedef void (APIENTRY* PFNGLBUFFERDATAPROC) (GLenum target, ptrdiff_t size, const GLvoid* data, GLenum usage);
typedef void (APIENTRY* PFNGLCOMPILESHADERPROC) (GLuint shader);
typedef GLuint(APIENTRY* PFNGLCREATEPROGRAMPROC) (void);
typedef GLuint(APIENTRY* PFNGLCREATESHADERPROC) (GLenum type);
typedef void (APIENTRY* PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers);
typedef void (APIENTRY* PFNGLDELETEPROGRAMPROC) (GLuint program);
typedef void (APIENTRY* PFNGLDELETESHADERPROC) (GLuint shader);
typedef void (APIENTRY* PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint* arrays);
typedef void (APIENTRY* PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRY* PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (APIENTRY* PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers);
typedef void (APIENTRY* PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint* arrays);
typedef GLint(APIENTRY* PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const char* name);
typedef void (APIENTRY* PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei* length, char* infoLog);
typedef void (APIENTRY* PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint* params);
typedef void (APIENTRY* PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei* length, char* infoLog);
typedef void (APIENTRY* PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint* params);
typedef void (APIENTRY* PFNGLLINKPROGRAMPROC) (GLuint program);
typedef void (APIENTRY* PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const char** string, const GLint* length);
typedef void (APIENTRY* PFNGLUSEPROGRAMPROC) (GLuint program);
typedef void (APIENTRY* PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
const GLvoid* pointer);
typedef void (APIENTRY* PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const char* name);
typedef GLint(APIENTRY* PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const char* name);
typedef void (APIENTRY* PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
typedef void (APIENTRY* PFNGLACTIVETEXTUREPROC) (GLenum texture);
typedef void (APIENTRY* PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
typedef void (APIENTRY* PFNGLGENERATEMIPMAPPROC) (GLenum target);
typedef void (APIENTRY* PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (APIENTRY* PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat* value);
typedef void (APIENTRY* PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat* value);
OpenGLClass的类定义在此保持尽可能简单。它具有常规构造函数,复制构造函数和析构函数。然后更重要的是它具有InitializeExtensions,InitializeOpenGL和Shutdown函数。这将是我们在本教程中重点关注的内容。除此之外,我还有许多对本教程并不重要的帮助函数,以及许多私有成员变量,当我们检查openglclass.cpp文件时,它们会被查看。目前,我们只需要了解初始化和关闭功能即可。
// Class name: OpenGLClass
class OpenGLClass
{
public:
OpenGLClass();
OpenGLClass(const OpenGLClass&);
~OpenGLClass();
bool InitializeExtensions(HWND);
bool InitializeOpenGL(HWND, int, int, float, float, bool);
void Shutdown(HWND);
void BeginScene(float, float, float, float);
void EndScene();
void GetWorldMatrix(float*);
void GetProjectionMatrix(float*);
void GetVideoCardInfo(char*);
void BuildIdentityMatrix(float*);
void BuildPerspectiveFovLHMatrix(float*, float, float, float, float);
void MatrixRotationY(float*, float);
void MatrixTranslation(float*, float, float, float);
void MatrixMultiply(float*, float*, float*);
private:
bool LoadExtensionList();
private:
HDC m_deviceContext;
HGLRC m_renderingContext;
//以下三个OpenGL函数指针用于与Windows接口:
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
float m_worldMatrix[16];
float m_projectionMatrix[16];
char m_videoCardDescription[128];
//这些是用于与OpenGL接口的其余函数指针。我已经将它们公开,因此我们可以仅使用指向此类的指针来轻松调用它们。
public:
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLBINDBUFFERPROC glBindBuffer;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
PFNGLBUFFERDATAPROC glBufferData;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLCREATESHADERPROC glCreateShader;
PFNGLDELETEBUFFERSPROC glDeleteBuffers;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
PFNGLDETACHSHADERPROC glDetachShader;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
PFNGLGENBUFFERSPROC glGenBuffers;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLGETPROGRAMIVPROC glGetProgramiv;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLGETSHADERIVPROC glGetShaderiv;
PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
PFNGLACTIVETEXTUREPROC glActiveTexture;
PFNGLUNIFORM1IPROC glUniform1i;
PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
PFNGLUNIFORM3FVPROC glUniform3fv;
PFNGLUNIFORM4FVPROC glUniform4fv;
};
#endif
Openglclass.cpp
我们首先将两个成员句柄初始化为null。
OpenGLClass :: OpenGLClass()
{
m_deviceContext = 0;
m_renderingContext = 0;
}
InitializeExtensions函数使我们能够获取视频卡驱动程序中可用的所有OpenGL函数的指针。请注意,除非已经创建了一个窗口,否则无法调用此函数,因此SystemClass :: InitializeWindows函数中创建临时窗口,调用此函数以获取扩展,然后销毁该临时窗口并创建一个新窗口的原因。
在此函数中,我们将设置临时设备上下文,像素格式和渲染上下文,以便我们可以调用LoadExtensionList函数,该函数然后为我们获取所需的所有函数指针。完成后,我们将释放临时上下文。
//获取显卡驱动程序中可用的所有的OpenGL函数的指针。前提是已经创建了一个窗口
//一般在InitializeWindows函数中创建临时窗口,调用此函数以获取扩展,然后销毁临时窗口并创建一个新窗口
//InitializeExtensions函数:设置临时设备上下文,像素格式和渲染上下文,
bool OpenGLClass::InitializeExtensions(HWND hwnd)
{
HDC deviceContext;
PIXELFORMATDESCRIPTOR pixelFormat;
int error;
HGLRC renderContext;
bool result;
// 获取此窗口的设备上下文
deviceContext = GetDC(hwnd);
if (!deviceContext)
{
return false;
}
// 设置临时的默认像素格式
error = SetPixelFormat(deviceContext, 1, &pixelFormat);
if (error != 1)
{
return false;
}
// 创建一个临时渲染上下文
renderContext = wglCreateContext(deviceContext);
if (!renderContext)
{
return false;
}
// 将临时渲染上下文设置为此窗口的当前渲染上下文
error = wglMakeCurrent(deviceContext, renderContext);
if (error != 1)
{
return false;
}
// 初始化此应用程序所需的OpenGL扩展。注意,需要一个临时的渲染上下文
result = LoadExtensionList();
if (!result)
{
return false;
}
// 既然已经加载了扩展,就释放临时渲染上下文
wglMakeCurrent(NULL, NULL);
wglDeleteContext(renderContext);
renderContext = NULL;
// 释放该窗口的设备上下文。
ReleaseDC(hwnd, deviceContext);
deviceContext = 0;
return true;
}
InitializeOpenGL设置OpenGL 4.0。在调用此函数之前,必须从InitializeExtensions函数加载扩展。同样,需要创建正确的窗口,这是在SystemClass :: InitializeWindows中完成的。一旦这两件事到位,就可以调用此函数。
然后,此函数将创建OpenGL 4.0渲染上下文和适当的像素格式。设置好之后,此功能将设置一些额外的内容,例如背面剔除,垂直同步,深度缓冲区以及我们将需要渲染的一些矩阵。
bool OpenGLClass::InitializeOpenGL(HWND hwnd, int screenWidth, int screenHeight, float screenDepth, float screenNear, bool vsync)
{
int attributeListInt[19];
int pixelFormat[1];
unsigned int formatCount;
int result;
PIXELFORMATDESCRIPTOR pixelFormatDescriptor;
int attributeList[5];
float fieldOfView, screenAspect;
char* vendorString, * rendererString;
//获取此窗口的设备上下文。
m_deviceContext = GetDC(hwnd);
if (!m_deviceContext)
{
return false;
}
// 支持OpenGL渲染。
attributeListInt[0] = WGL_SUPPORT_OPENGL_ARB;
attributeListInt[1] = TRUE;
// 支持渲染到窗口。
attributeListInt[2] =