OpenglC++学习笔记

OpenGL 学习

注:以下是个人学习笔记,仅供参考,其中记载了许多个人遇到的错误。

19.10.13OpenGL环境配置


OpengGL是什么?

OpenGL本身并不是一个API,它仅仅是一个由Khronos组织制定并维护的规范(Specification)。
只要你记住OpenGL本质上是个大状态机,就能更容易理解它的大部分特性。OpenGL状态机又通常被称为上下文(contex)。

GLFW

GLFW是一个专门针对OpenGL的C语言库,他为我们创建windows程序提供了便利。

预编译文件和源代码文件

GLFW已经有针对Visual Studio 2013/2015的预编译的二进制版本和相应的头文件,但是为了完整性我们将从编译源代码开始。
源代码编译库可以保证生成的库是兼容你的操作系统和CPU的,而预编译的二进制文件可能会出现兼容问题(甚至有时候没提供支持你系统的文件)。

源代码+IDE=解决方案/工程文件(.project?)

GLFW配置
  1. 右键项目属性
    为了使我们的程序使用GLFW,我们需要把GLFW库链接(Link)进工程。这可以通过在链接器的设置里指定我们要使用glfw3.lib来完成,但是由于我们将第三方库放在另外的目录中,我们的工程还不知道在哪寻找这个文件。于是我们首先需要将我们放第三方库的目录添加进设置。
    在这里插入图片描述
  2. 需要在Linker(链接器)选项卡里的Input(输入)选项卡里添加glfw3.lib还有opengl32.lib文件。

在这里插入图片描述

CMAKE

生成解决方案/工程文件的工具。

GLAD和GLEW

由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。所以任务就落在了开发者身上,开发者需要在运行时获取函数地址并将其保存在一个函数指针中供以后使用。幸运的是,有些库能简化此过程,其中GLAD是目前最新,也是最流行的库。GLEW也是一个这样的库。


创建一个窗口

  1. 初始化GLFW。
    glfwInit();
  2. 配置GLFW 。
    glfwWindowHint(选项,值);
    主版本号(Major)次版本号(Minor)都设为3。
    我们同样明确告诉GLFW我们使用的是核心模式(Core-profile)。
  3. 创建窗口对象(存放了所有和窗口相关的数据,会被GLFW的函数频繁用到)。
    GLFWwindow窗口对象
    glfwCreateWindow(宽,高,名字,Null,null)返回一个窗口对象
  4. 通知GLFW将这个窗口对象设置为当前线程的主上下文。
    glfwMakeContextCurrent
  5. 初始化GLAD。
    GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLAD。
    gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)返回了一个bool值。
  6. 告诉OpenGL渲染窗口的尺寸大小。
    glViewport(0,0,800,600);前两个坐标为窗口左下角的坐标。后两个为渲染窗口的宽高px。
  7. 增加渲染循环。
  8. 正确释放/删除分配的所有资源。
    glfwTerminate()

渲染循环

glClearColor和glClear

glClearColor函数是一个状态设置函数,而glClear函数则是一个状态使用的函数,它使用了当前的状态来获取应该清除为的颜色。

三角形

  • 顶点数组对象:Vertex Array Object,VAO
  • 顶点缓冲对象:Vertex Buffer Object,VBO
  • 索引缓冲对象:Element Buffer Object,EBO或Index Buffer Object,IBO
    在这里插入图片描述
  • VAO里面配置着许多的属性指针,不同的属性指针解释了VBO里的顶点数组的不同含义,有些解释顶点,有些解释法向量。
  • VAO是对VBO(一组顶点数据)的解释,要配置一个vao首先要绑定vao,再绑定vbo,通过vbo绑定的槽给vbo灌入数据,再调用glVertexAttribPointer设置的顶点属性配置。
  • 每个顶点属性从一个VBO管理的内存中获得它的数据,而具体是从哪个VBO(程序中可以有多个VBO)获取则是通过在调用glVertexAttribPointer时绑定到GL_ARRAY_BUFFER的VBO决定的。由于在调用glVertexAttribPointer之前绑定的是先前定义的VBO对象,顶点属性0现在会链接到它的顶点数据。
  • 这之后再激活顶点属性。glEnableVertexAttribArray(0);
    //激活0号位置上的顶点属性。
  • glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    0:表示我们要在配置第0号位置的顶点属性。
    3:每三个数组元素构成一个顶点属性。三个分量.
    float:顶点类型。
    flase:不标准化数据(映射到1区间).
    步长:如上图所示stride。间隔。
    void:它表示位置数据在缓冲中起始位置的偏移量(Offset)。由于位置数据在数组的开头,所以这里是0。

ID 创建对象 绑定对象

图元(primitive)

为了让OpenGL知道我们的坐标和颜色值构成的到底是什么,OpenGL需要你去指定这些数据所表示的渲染类型。我们是希望把这些数据渲染成一系列的点?一系列的三角形?还是仅仅是一个长长的线?做出的这些提示叫做图元(Primitive)。

标准化设备坐标(Normalized Device Coordinates, NDC)

一旦你的顶点坐标已经在顶点着色器中处理过,它们就应该是标准化设备坐标了,标准化设备坐标是一个x、y和z值在-1.0到1.0的一小段空间。任何落在范围外的坐标都会被丢弃/裁剪,不会显示在你的屏幕上。你的标准化设备坐标接着会变换为屏幕空间坐标(Screen-space Coordinates),这是使用你通过glViewport函数提供的数据,进行视口变换(Viewport Transform)完成的。所得的屏幕空间坐标又会被变换为片段输入到片段着色器中。
所有在所谓的标准化设备坐标(Normalized Device Coordinates)范围内的坐标才会最终呈现在屏幕上(在这个范围以外的坐标都不会显示)。

10.15

vs解决方案sln文件

Visual Studio中,解决方案是够成应用程序的所有项目集,一个解决方案可以包含多个项目csproj文件,建立一个解决方案会生成一个.sln文件。
一个解决方案经过编译,应用程序会变成exe,其他成dll文件。

lib和头文件

lib文件里存贮了函数的具体实现,头文件里包含函数的声明,从而达到封装效果,所有要使用库函数需要引入头文件和链接lib文件。

c++里的数组和sizeof

1、首先数组首元素的地址和数组地址的值是相等的。

2、数组首元素的地址和数组地址是两个不同的概念。
int a[]={1,2};
a 表示的是数组首个元素的地址,除此之外,当作为sizeof()的参数时,计算得到的大小为数组的大小。
当a作为函数参数传入函数时再调用sizeof无法计算得到数组的大小而是单个元素的大小。
解决:使用&a,使用&a能够真实的获取到数组的地址,&a返回的是一个数组指针。int (*a)[];

VAO VBO EBO

unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);

unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);

unsigned int VEO;
glGenBuffers(1,&VEO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,VEO);

可以看出vao是数组,而vbo和veo是两种不同类型的缓冲类型。

对于导入到VBO的数组需要配置顶点属性指针,而对于EBO却不用。为什么?

因为opengl只能绘制三角形,所以对于ebo中的数组会默认每三个只绘制一次。

如何理解VAO VBO EBO

可以理解为opengl为一个工厂。有一个位置放入要装配的东西(VAO)。
在这里插入图片描述
VBO和EBO是两个漏斗,通过glBindBuffer指定要放在哪个缓冲池上,通过glBufferData注入数据,以便数据更好的进入到缓冲池中。
VBO–>ARRAY_BUFFER。使用glVertexAttribPointer方法配置顶点属性指针
EBO–>ELEMENT_ARRAY_BUFFER

绘制的方法

glDrawArrays默认逆时针绘制,同样只能绘制三角形所以绘制矩形要6个顶点。
glDrawElements通过索引绘制,需要指定索引缓冲。

10.20封装函数

struct GLFWwindow*

c++中结构体的名称不是地址,获取结构体的地址需要用&取址符。
struct GLFWwindow*表示GLFWwindow是个结构体,我们声明了一个结构体指针以存取结构体的地址。

const char*

与上语句类似,这需要指出接下来要创建一个常量(" "或’ ')的指针。不可用名字来修改。

nullptr

c++中null默认的值为0,nullptr表示空指针。
NULL可能被定义为字面常量0(编译器默认),或者被定义为无类型指针(void*)的常量(如果要将其按照指针方式来使用,必 须对其进行强转(void *)0)
在使用nullptr表示指针空值时,不需要包含头文件

为什么要把函数声明和实现分开来写?

将定义放在头文件,那么当多个源文件使用#include命令包含此类的头文件便会在链接阶段出现“multiple definition”链接错误!

glm

在这里插入图片描述
为什么放cpp里有用,h里就报错
知道了。cpp里面之前复制了别人的头文件代码。
在这里插入图片描述
查看mat的定义发现mat是个结构体,而mat1234是它的模版衍生。
在这里插入图片描述

向shader传递变换矩阵。

  1. 声明矩阵.
    mat4 trans=mat4(1.0f);矩阵初始化
  2. 定义变换
    trans=translate/rotate (trans,…)
  3. 把变换传入shader。
    使用glGetUniformLocation(ourShader.ID, “transform”)获取该属性在shader上的地址,
    使用glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));往shader里的地址上灌数据。GL_FALSE表示不倒置矩阵,1表示只传递一个矩阵,glm::value_ptr(trans)或&trans[0][0]都行。(最后一个参数是真正的矩阵数据,但是GLM并不是把它们的矩阵储存为OpenGL所希望接受的那种,因此我们要先用GLM的自带的函数value_ptr来变换这些数据。)

c++中的字符串

  • C 风格字符串。实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
    在这里插入图片描述
    位于std命名空间。
  • C++ 引入的 string 类类型。C++ 标准库提供了 string 类类型,支持上述所有的操作,另外还增加了其他更多的功能。

C++ 引用 vs 指针

在这里插入图片描述

引用很容易与指针混淆,它们之间有三个主要的不同:

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。

c++中的string

string a;实际上已经调用了构造函数,对象a已被分配空间。
string% a;创建一个a的引用。(类似于java中的string a;)

语法:
*const char c_str();
c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同.,这是
为了与c语言兼容
,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。

函数后面的const

C++在函数声明时,后面跟个const是限定函数类型为常成员函数, 常成员函数是指不能改变成员变量值的函数

字符数组的处理比数值型数组要好处理的多,因为它解为有结束符,而数值型数组没有,作为参数时时常要指定数组有效值做参数,否则会越界。

10.26

边缘光照
在这里插入图片描述
cameraDir=normalize(cameraPos-FragPos); cameraDir=normalize(cameraPos);
在这里插入图片描述
(1-diff3)^4
在这里插入图片描述
高光算法,通过reflect函数计算出光的反射向量然后拿这个向量和视线向量做内积。
得到值就是高光度。

10.27

vs文件的引用,对于资源文件(视频,模型,图片)这些文件不能出现在vs项目管理器中,只需在main.cpp同级目录下即可。
而对于开源的软件源码,则需要把h文件和cpp文件放进项目管理器中(即使新建筛选器也可以,筛选器不会出现在真实的系统目录中)。
在这里插入图片描述在这里插入图片描述

10.29

DLL调用
  • 声明函数指针
  • 加载动态库
  • 获取函数地址(强制转换(去掉指针名)),存储函数地址给函数指针。
  • 调用函数
  • 释放动态库
    在这里插入图片描述

cpp文件中的.h文件,在处理时,文件会任务对应着.cpp文件,所以对于c类型的实现文件需要加上extern修饰
ini文件不指定路径写入到windows目录下。

10.30

belnder操作

n呼出右侧属性栏
z呼出视图渲染轮盘
g移动
s缩放
r旋转
按完以上操作键后按中键能捕捉xyz轴(或按x y z键,按两下切换为局部坐标模式),右键取消。
alt键+g/s/r能够恢复之前的状态。

宽字符

unicode字符集:使用的是宽字符。一个字符占两个字节,一个中文是一个字符占两个字节。
c语言输出宽字符要wprintf()表示一个宽字符的字符串要L(“adas”)
多字节字符集:使用的是窄字符。一个字符占一个字节,一个中文占两个字节。

10.31

在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 乘上了物体最后的颜色
  2. 把镜面反射贴图采样给了diffuse1光照贴图
  3. 采样给了spec
  4. 尝试加上发现贴图?
  5. 法线贴图采样*顶点法线信息。(毕竟法线贴图的法线信息没有经过世界坐标转换)
    在这里插入图片描述

高光信息应该是叠加+在漫反射层上的
以上都是错误的渲染
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-09kQwHTu-1581943583728)(./1572619111334.png)]

11.16

unity shader学习

使用世界坐标来计算一些静态的颜色:diffuse(漫反射颜色),每个点的relectLight(光照折射方向)。
以上需要使用世界Pos,世界Normal,世界光照pos。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值