47、VS2019之OpenGL开发笔记

说明:OpenGL是基础的底层渲染API,其在3D渲染中的地位类似于编程语言中的C语言,是入门3D渲染首先要学的,打好基础,才是学习好上层封装库的关键。对于OpenGL的上层封装库很多,其中著名的有VTK,OSG等,这里以OpenGL4.5学习为主,VTK9.1学习为辅。VTK多用于医学图像渲染,其封装了很多优秀的算法,在算法上参考价值很大(而且VTK是开源的)。

 

学习OpenGL可以参照网站http://learnopengl.com、书籍《OpenGL编程指南/红宝书》、书籍《OpenGL超级宝典/蓝宝书》等。本博客以红宝书第九版为例进行学习。

一、Open Graphics Library

1.1、OpenGL前言

OpenGL相关的开发库有很多,大致可以如下三类:
第一类:GLUT、FreeGLUT、GLFW:窗口的管理,事件的处理等。
第二类:GLEW、GLAD、GL3W:获取OpenGL扩展函数的地址(扩展可理解为3.0之后新增)。
第三类:GLM、VMATH:适用于OpenGL的矩阵运算库。
其    他:Qt也是支持OpenGL的,关于上面这三类库,Qt都有自己专属的库。

创建工程时从每类中任选一个库进行组合即可,例如:GLFW+GLAD+GLM、GLFW+GL3W+VMATH、FreeGLUT+GLAD+GLM等,其中网站http://learnopengl.com使用的第一种组合,OpenGL编程指南(第九版)使用的第二种组合需要注意的是第一种组合是最流行的。
红宝书配套源码可去官方网址http://www.opengl-redbook.com下载,需要注意的是源码工程生成的VS2019工程可能有很多error,如果你不能解决,可加QQ群649692007获取作者重构的VS工程。

OpenGL的好多函数是没有返回值的,所以我们无法确定函数是否执行成功,好在有一个函数可以返回当前的错误代码,可以根据函数glGetError()的返回值,大致判断失败原因:

GL_NO_ERROR :(0)当前无错误值
GL_INVALID_ENUM :(1280)仅当使用非法枚举参数时,如果使用该参数有指定环境,则返回 GL_INVALID_OPERATION 
GL_INVALID_VALUE :(1281)仅当使用非法值参数时,如果使用该参数有指定环境,则返回 GL_INVALID_OPERATION 
GL_INVALID_OPERATION :(1282)命令的状态集合对于指定的参数非法。
GL_STACK_OVERFLOW :(1283)压栈操作超出堆栈大小。
GL_STACK_UNDERFLOW :(1284)出栈操作达到堆栈底部。
GL_OUT_OF_MEMORY :(1285)不能分配足够内存时。
GL_INVALID_FRAMEBUFFER_OPERATION :(1286)当操作未准备好的真缓存时。
GL_CONTEXT_LOST :(1287)由于显卡重置导致 OpenGL context 丢失。

使用如下代码配置OPENGL程序优先选择NVIDIA显卡执行:

extern "C" { //设置优先使用NVIDIA显卡执行
    __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
}

1.2、工程创建

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

项目=>属性=>C/C++=>常规=>附加包含目录:
$(ProjectDir)includes
$(ProjectDir)libraries\gl3w\include
$(ProjectDir)libraries\glm-0.9.9.8\glm
$(ProjectDir)libraries\glfw-3.3.6.bin.win64\include

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

项目=>属性=>链接器=>常规=>附加库目录:
$(ProjectDir)libraries\glfw-3.3.6.bin.win64\lib

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

项目=>属性=>链接器=>输入=>附加依赖项:
glfw3.lib
opengl32.lib
watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

 项目=>属性=>链接器=>输入=>忽略特定默认库:
msvcrt.lib
watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

//01_triangles.h

#ifndef __01_TRIANGLES_H__
#define __01_TRIANGLES_H__

#include "vapp.h"
#include "loadshaders.h"
class triangles:public VermilionApplication
{
public:                                                     
    typedef class VermilionApplication base; //宏              
    static VermilionApplication* Create(void)              
    {                                                       
        return (s_app = new triangles);
    }
    virtual void Initialize(const char* title);
    virtual void Display(bool auto_redraw);
    virtual void Finalize(void);
    virtual void Resize(int width, int height);
    void OnKey(int key, int scancode, int action, int mods);
};
#endif
//01_triangles.cpp

#include "01_triangles.h"
enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };
GLuint  VAOs[NumVAOs];
GLuint  Buffers[NumBuffers];
const GLuint  NumVertices = 6;
void triangles::Initialize(const char* title)
{
    base::Initialize(title); //初始化
    glGenVertexArrays(NumVAOs, VAOs); //创建VAO
    glBindVertexArray(VAOs[Triangles]); //绑定VAO
    GLfloat  vertices[NumVertices][2] = {
        { -0.90f, -0.90f }, {  0.85f, -0.90f }, { -0.90f,  0.85f },  // Triangle 1
        {  0.90f, -0.85f }, {  0.90f,  0.90f }, { -0.85f,  0.90f }   // Triangle 2
    };
    glGenBuffers(NumBuffers, Buffers); //创建VBO
    glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]); //绑定VAO
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //往VAO加载数据
    ShaderInfo  shaders[] = {
        { GL_VERTEX_SHADER, "shaders/01_triangles.vert" },
        { GL_FRAGMENT_SHADER, "shaders/01_triangles.frag" },
        { GL_NONE, NULL }
    };
    GLuint program = LoadShaders(shaders);
    glUseProgram(program);
    //设置VAO的属性0
    glVertexAttribPointer(0, //顶点属性值
                          2,         //顶点属性大小 
                          GL_FLOAT,  //参数二的类型
                          GL_FALSE,  //是否归一化 
                          0,         //步长 
                          BUFFER_OFFSET(0));//起始偏移
    //使能VAO的属性0
    glEnableVertexAttribArray(0); 
}
void triangles::Display(bool auto_redraw) {
    glClear(GL_COLOR_BUFFER_BIT);
    glBindVertexArray(VAOs[Triangles]);
    glDrawArrays(GL_TRIANGLES, 0, NumVertices);
    base::Display(auto_redraw);
}
void triangles::Finalize(void) {

}
void triangles::Resize(int width, int height) {
    glViewport(0, 0, width, height);
}
void triangles::OnKey(int key, int scancode, int action, int mods)
{
    if (action == GLFW_PRESS)
    {
        switch (key)
        {
        case GLFW_KEY_M:
        {
            static GLenum  mode = GL_FILL;

            mode = (mode == GL_FILL ? GL_LINE : GL_FILL);
            glPolygonMode(GL_FRONT_AND_BACK, mode);
        }
        return;
        }
    }

    base::OnKey(key, scancode, action, mods);
}
//main.cpp

#include "01_triangles.h"
int main(int argc,char* argv[])
{
    VermilionApplication* app = triangles::Create();
    app->Initialize("triangles");
    app->MainLoop();
    app->Finalize();
}

程序运行结果: 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

  【基于vs2019的工程模板下载地址】:https://download.csdn.net/download/BaoTTing/85186641

1.3、渲染管线

1.4、坐标系统

(1)世界坐标系内的坐标乘以观察矩阵变换到眼坐标空间  eye.xyzw = viewMatrix * world.xyzw;

(2)眼坐标系内的坐标通过乘上投影矩阵变换到裁剪空间 clip.xyzw = projectMatrix * eye.xyzw;

(3)裁剪坐标系内的坐标通过透视除法(也就是  w 为 1 化) 到 规范化设备坐标系 ndc.xyz = clip.xyz / clip.w; (片段着色器的输入是:规范化设备坐标)

(4)设备规范化坐标系到窗口坐标系 win.z = (dfar - dnear)/2 * ndc.z + (dfar+dnear)/2;

在透视投影中,为啥倾斜角越大,物体越小的原因。

1.5、着色器程序

1.6、模型文件的加载

1.7、体渲染之切片式

1.8、体渲染之等值面

1.9、体渲染之光线投影

二、The Visualization Tookit

2.1、VTK的下载

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

2.2、VTK的编译

        接下来使用CMakeVS2019两个软件,没有软件的请先安装这俩软件,其中CMake用于给源码配置编译环境,即构建一个VS工程来用来编译源码<1>。CMake构建的VS工程经过编译后,生成头文件和库文件<2>。头文件和库文件讲用于后续工程的建立<3>。
上述<1><2><3>三个步骤的最终目的:把源码编译成库文件使用。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

 Bin ===>用来存放头文件以及共享库 
 Build ==>用来存放VTK编译后的文件
 Data  ==>用于存放下载的 VTKData-9.1.0.tar.gz解压后的所有文件  
 Source =>用于存放下载的 VTK-9.1.0.tar.gz 解压后的所有源文件watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_18,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

10.1、生成DEBUG版本的库和头文件

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

10.2、生成RELEASE版本的库和头文件

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

10.3、生成DEBUG、RELEASE版本的库和头文件

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFvQFRpbmc=,size_20,color_FFFFFF,t_70,g_se,x_16

2.3、工程的创建

2.4、绘制三角形

2.5、2D纹理的使用

2.6、3D纹理的使用

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值