OpenGL图形管线和坐标变换

2023-11-19

1. OpenGL 渲染管线

OpenGL渲染管线分为两大部分,模型观测变换(ModelView Transformation)投影变换(Projection Transformation)。做个比喻,计算机图形开发就像我们照相一样,目的就是把真实的场景在一张照相纸上表现出来。那么观测变换的过程就像是我们摆设相机的位置,选择好要照的物体,摆好物体的造型。而投影变换就像相机把真实的三维场景显示在相纸上一样。下面就分别详细的讲一下这两个过程。

1.1模型观测变换

http://www.cppblog.com/guojingjia2006/archive/2012/12/07/196089.html

让我们先来弄清楚OpenGL中的渲染管线。管线是一个抽象的概念,之所以称之为管线是因为显卡在处理数据的时候是按照一个固定的顺序来的,而且严格按照这个顺序。就像水从一根管子的一端流到另一端,这个顺序是不能打破的。先来看看下面的图1:

1                     图1 OPENGL渲染管线                                 

图中显示了OpenGL图形管线的主要部分,也是我们在进行图形编程的时候常常要用到的部分。一个顶点数据从图的左上角(MC)进入管线,最后从图的右下角(DC)输出MC是Model Coordinate的简写,表示模型坐标DCDevice Coordinate的简写,表示设备坐标。当然DC有很多了,什么显示器,打印机等等。这里DC我们就理解成常说的屏幕坐标好了。MC当然就是3D坐标了(注意:我说的3D坐标,而不是世界坐标),这个3D坐标就是模型坐标,也说成本地坐标(相对于世界坐标)。MC要经过模型变换(Modeling Transformation)才变换到世界坐标,图2:

2图2 世界坐标系和模型坐标系

变换到世界坐标WC(World Coordinate)说简单点就是如何用世界坐标系来表示本地坐标系中的坐标。为了讲得更清楚一些,这里举个2D的例子。如图3:

3图3 世界坐标系和模型坐标系的计算

图中红色坐标系是世界坐标系WC,绿色的是模型坐标系MC。现在有一个顶点,在模型坐标系中的坐标为(1,1),现在要把这个模型坐标转换到世界坐标中来表示。从图中可以看出,点(1,1)在世界坐标系中的坐标为(3,4),现在我们来通过计算得到我们希望的结果。首先我们要把模型坐标系MC在世界坐标系中表示出来,使用齐次坐标(Homogeneous Coordinate )可以表示为矩阵(注意,本教程中使用的矩阵都是以列向量组成):gif.latex 其中,矩阵的第一列为MC中x轴在WC中的向量表示第二列为MC中y轴WC中的向量表示第三列为MC中的原点在WC中的坐标。对齐次坐标系不了解的同学,请先学习游戏数学方面的知识。有了这个模型变换矩阵后,用这个矩阵乘以在MC中表示的坐标就可以得到该坐标在世界坐标系中的坐标。所以该矩阵和MC中的坐标(1,1)相乘有:

gif.latex2这也正是我们需要的结果。现在让我们把相机坐标也加进去,相机坐标也称为观测坐标(View Coordinate),如图4和图5。

4图4 ModelView变换的三个坐标系

5图5 ModelView变换计算

来看看MC坐标中的点(1,1)如何在相机坐标中表示。从图5中可以直接看出MC中的点(1,1)在相机坐标系VC中为(-2,-2)。和上面同样的道理,我们可以写出相机坐标系VC在世界标系WC中可以表示为:

gif.latex3那么世界坐标系中的点转换为相机坐标系中的点我们就需求VC的逆矩阵:

gif.latex4那么世界坐标系WC中的点(3,4)在相机坐标系VC中坐标为:

gif.latex5上面的变换过程,就是可以把模型坐标变换为相机坐标。在OpenGL中,当我们申明顶点的时候,有时候说的是世界坐标,这是因为初始化的时候世界坐标系、模型坐标系和相机坐标系是一样的,重合在一起的。所以OpenGL中提供了模型观测变换,它是把模型坐标系直接转换为相机坐标系,如图4。现在我们已经计算得到了VC-1和MC,如果把VC-1和MC相乘,就可以得到模型坐标在相机坐标中的表示。为了得到模型坐标系中的坐标在相机坐标系中的表示,这就是OpenGL中的ModelView变换矩阵。这也是ModelView变换的名字的由来,它是通过了上面两个步骤得到的。那么这里,ModelView变换矩阵M为:

gif.latex6现在只要用上面的模型观测矩阵M乘以模型坐标系MC中的坐标就可以得到相机坐标系中的坐标了。模型观测变换的关键就是要得到相机坐标系中的坐标,因为光照等计算都是在这个这个坐标系中完成的。下面我们实际OpenGL程序中检查一下。在程序中,为了计算方便,我们使用图6中的模型。

6图6 ModelView变换计算模型

根据图中的数据,我们分别可以写出对应MC和VC-1,从而求得观测变换矩阵M

gif.latex7现在程序中用glGetFloatv()这个函数来获得当前矩阵数据来检查一下。

 
  1. float m[16] {0}; //用来保存当前矩阵数据  
  2. glMatrixMode(GL_MODELVIEW);  
  3. glLoadIdentity();  
  4. glGetFloatv(GL_MODELVIEW_MATRIX, m);   
  5. //相机设置,View 变换  
  6. gluLookAt(0.0, 0.0, 5.0,  
  7. 0.0, 0.0, 0.0,  
  8. 0.0, 1.0, 0.0);  
  9. glGetFloatv(GL_MODELVIEW_MATRIX, m);   
  10. //投影设置  
  11. glMatrixMode(GL_PROJECTION);  
  12. glLoadIdentity();  
  13. glOrtho(-10,10,-10,10,-10,10);  
  14. glMatrixMode(GL_MODELVIEW);   
  15. //Modeling变换  
  16. glTranslatef(0, 0, -3);  
  17. glGetFloatv(GL_MODELVIEW_MATRIX, m);  
  18. glBegin(GL_POINTS);  
  19. glVertex3f(1,1,0);  
  20. glEnd();  

如果在上面程序段中最后一个glGetFloatv(GL_MODELVIEW_MATRIX, m)处设定断点的话,就可以看到图7所显示的数据。

7图7 ModelView变换矩阵数据

到这里,整个ModelView变换就完成了。通过ModelView变换后得到是相机坐标系内的坐标。在这个坐标系内典型的计算就是法线了。现在再来看看后面一个阶段。

1.2投影变换

先还是复习一下OpenGL的渲染管线。图1中可以看到,在投影变换(Projection Transformation)中也分为两个部分,第一个部分是将上个阶段得到的坐标转换为平面坐标,第二个部分是将转换后的平面坐标在进行归一化并进行剪裁。一般地,将三维坐标转换为平面坐标有两种投影方式:正交投影(Orthogonal Projection)和透视投影(Perspective Projection)

1.2.1 正交投影

正交投影很简单,如图8,对于三维空间中的坐标点和一个二维平面,要在对应的平面上投影,只需将非该平面上的点的坐标分量改为该平面上的坐标值,其余坐标不变。

8图8 正交投影

比如将点(1,1,5)正交投影到z=0的平面上,那么投影后的坐标为(1,1,0)。在openGL中,设置正交投影可以使用函数:

 
 
[cpp]  view plain copy
  1. glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)  

该函数可以设置正交投影的投影空间,在该空间以外的坐标点就不会被投影到投影平面上。函数中的六个参数分是投影空间六个平面,如图9:

9

图9 OpenGL正交投影空间和投影变换

在图9中,大的投影空间是根据这六个参数设置的投影空间,OpenGL会自动将该空间归一化,也就是将该空间或立方体转化为变长为1的正六面体投影空间,并且该证六面体的中心在相机坐标系的原点。一旦设置使用glortho函数设置投影空间,OpenGL会生成投影矩阵。这个矩阵的作用就是将坐标进行正交投影并且将投影后的坐标正规化(转换到-1到1之间)。要注意的是,生成该矩阵的时候,OpenGL会把右手坐标系转换为左手坐标系。原因很简单,右手坐标系的Z轴向平面外的,这样不符合我们的习惯。该矩阵的矩阵推导这里就不详细说明了,不了解的同学可以参考游戏数学方面资料,这里只给出正交投影矩阵。

15这个矩阵看来很复杂,其实计算很简单。举个例子,现在设置了这样的正交投影空间glOrtho(-10,10,-10,10,-10,10),这是个正六面体空间,变长为10。把这些参数带入上面的矩阵可以得到

gif.latex8现在还是在OpenGL程序中来检查一下。在OpenGL程序中添加下面代码段:

 
 
  1. //投影设置  
  2. glMatrixMode(GL_PROJECTION);  
  3. glLoadIdentity();  
  4. glOrtho(-10,10,-10,10,-10,10);  
  5. glMatrixMode(GL_MODELVIEW);  
  6. glGetFloatv(GL_PROJECTION_MATRIX,m)  
glGetFloatv(GL_PROJECTION_MATRIX,m)处设定断点就可以看到图10中所显示的信息。

10图10 正交变换矩阵数据 

1.2.2透视投影

透视投影和正交投影最大的区别就是透视投影具有远近感。

11

图11 透视投影

透视投影采用了图11中的模型,这样的模型就是保证远的物体看起来小,近的物体看起来大。 在OpenGL中设置透视投影可以使用函数:

 
 
  1. void APIENTRY gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);  

该函数也会根据给定的参数生成一个投影空间。如图11中,该投影空间是一个截头体。同样地,OpenGL会自动生成透视投影矩阵,该矩阵也会让3D坐标投影在投影平面上,并且将投影后的坐标也进行正规化。下面也直接给出OpenGL中使用的透视投影矩阵。

16下面在OpenGL中添加下面代码段:

 
 
  1. //投影设置  
  2. glMatrixMode(GL_PROJECTION);  
  3. glLoadIdentity();  
  4. gluPerspective(45, 1.0, 1.0, 100);  
  5. glMatrixMode(GL_MODELVIEW);  
  6. glGetFloatv(GL_PROJECTION_MATRIX,m)  

设置断点后,我们可以看到图12中显示的数据。

12图12 透视变换矩阵数据

到此为止,整个投影变换就完成了。透过投影变换后得到的是正规化的投影平面坐标。这为下一个阶段的视口变换(View port Transformation)做好了准备。

1.3视口变换

现在到了最后一个阶段了。这个阶段叫做视口变换,它把上个阶段得到的正规化的投影坐标转化为windows 窗口坐标。视口变换会将投影平面上的画面映射到窗口上。在OpenGL中可以使用函数

 
 
[cpp]  view plain copy
  1. GLAPI void GLAPIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);  

来进行对窗口的映射,如图13。

13图13 视口变换glViewport(width/2, 0, width/2, height/2)

举个例子说明,比如上个阶段中得到了一个顶点的坐标为(0,0,0.5,1),根据这个坐标,该顶点位于投影平面的正中间。如果将该点映射到大小为50*50的窗口上时,那么它应该位于屏幕的中间,坐标为(25,25, 0.5,1)。当然这里深度值0.5是不会改变的。有的同学肯定有疑问了,既然投影到了窗口上,那么还要深度值0.5干什么?这里要注意的是,虽然在窗口上显示时只需要x,y坐标就够了,但是要在2D窗口上显示3D图形时深度值是不可少的。这里的深度值不是用于显示,而是用于在光栅化的时候进行深度测试。

OpenGL也会根据glViewport函数提供的参数值生成一个视口变换矩阵

17该矩阵把上个阶段得到的正规化坐标映射到窗口上,并且将正规化坐标中的深度值在转换到0到1之间。所以在深度缓冲中最大值为1,最小值为0。视口变换结束后,OpenGL中主要的图形管线阶段就算完成了,后面就是光栅化等等操作。再来回顾一下图1,现在相信大家对这个渲染管线有了一定的认识了,也明白了每一个阶段对应的变换矩阵以及如何进行坐标之间的转换的。

2. 屏幕坐标转换为世界坐标

通过前面的教程,以及现在大家对OpenGL整个渲染管线理解后,现在要将屏幕上一点坐标转换为世界坐标就比较容易了。从图形管线的开始到结束,一个模型坐标系中的坐标被转化为了屏幕坐标,那么现在把整个过程倒过来的话,屏幕上一点坐标也可以转为为世界坐标。只要在对应的阶段求得对应变换矩阵的逆矩阵,就可以得到前一个阶段的坐标。这整个过程可以用图14表示。

14图14屏幕坐标转换为世界坐标

图中显示的过程完全就是OpenGL渲染管线的逆过程,通过这个过程,屏幕上的点就可以转化为世界坐标系中的点了。可能又有的同学要问,当鼠标点击屏幕上一点的时候并没有深度信息,转换的时候要怎么办呢?这个时候可以使用OpenGL函数

 
 
  1. void glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);  

该函数能够获得屏幕上一点对应像素的深度信息。有了这个深度信息,就可以利用上面过程把屏幕上一点转换为世界坐标了。在OpenGL中,上面的过程其实已经有现成的函数可以使用,那就是

 
 
  1. int APIENTRY gluUnProject  
  2.     GLdouble  winx, GLdouble  winy,  
  3.     GLdouble  winz,  
  4.     const GLdouble modelMatrix[16],  
  5.     const GLdouble projMatrix[16],  
  6.     const GLint    viewport[4],  
  7.     GLdouble  *objx,  GLdouble  *objy,  
  8.     GLdouble       *objz);  

该函数直接将屏幕上一点转换对应的世界坐标,该函数的内部实现其实还是上面的那么逆过程。下面给出利用该函数获取世界坐标的代码段。

 
 
[cpp]  view plain copy
  1. GVector screen2world(int x, int y)  
  2.  
  3.        GLint viewport[4];  
  4.        GLdouble modelview[16];  
  5.        GLdouble projection[16];  
  6.        GLfloat winX, winY, winZ;  
  7.        GLdouble posX, posY, posZ;  
  8.        glGetDoublev(GL_MODELVIEW_MATRIX, modelview);  
  9.        glGetDoublev(GL_PROJECTION_MATRIX, projection);  
  10.        glGetIntegerv(GL_VIEWPORT, viewport);  
  11.        winX (float)x;  
  12.        winY (float)viewport[3] (float)y;  
  13.        glReadPixels(x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);  
  14.        gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);  
  15.        GVector v(4, posX, posY, posZ, 1.0);  
  16.        return v;  
  17.  
代码中函数返回类型GVector是用户定义的向量类,返回的是齐次坐标。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenGL图形管线和坐标变换 的相关文章

  • D3D中的三种Buffer

    在D3D中 针对视窗有三种Buffer 它们分别是 Color Buffer Depth Buffer和Stencil Buffer Color Buffer在D3D中又称为Render Target 意思是最后着色的目标Buffer 就是
  • 图象:sine(正弦)、cosine(余弦)与Tangent(正切)

    http www 97ae com aebiaodashi geometry trig graphs html 目录 矢量加法 距离与长度 三角函数 图象 正弦 余弦与正切 圆周函数 简谐运动 频率与振幅 波形加法与乘法 反函数 其他材料
  • D3D纹理

    纹理映射是一种将图形施加到表面的技术 以简单的一堵墙为例 这种技术可以只需要两个绘制有砖纹理的三角形即可 这样就可以为表面增加大量的细节 而不必使用大量的多边形 纹理映射使用了图像数据并将图像数据绘制 映射 到表面上 该表面看上去就像有一幅
  • 使用CopperCube(IrrEdit)创建Irrlicht场景

    使用CopperCube IrrEdit 创建Irrlicht场景 标签 Irrlicht游戏引擎 2013 11 22 19 32 3384人阅读 评论 7 收藏 举报 分类 Irrlicht 13 版权声明 本文为博主原创文章 未经博主
  • D3D资源管理

    摘要 受管贴图 Managed textures 也就是我们通常所谓的 自动管理贴图 在DX6中首次被引入 经过一系列的改进和增强 在DX9中自动管理的资源类型增加到贴图 顶点缓冲 顶点索引缓冲 所有这些资源使用统一的公共接口 通过使用D3
  • 成功编译RenderingPluginExample53的cpp项目的步骤

    备忘 unity中调用d3d功能的示例项目 两个方面的配置 1 为了在项目中能够找到d3d12 h d3d11 h d3d9 h等 做如下操作 在项目属性中 VC 目录 包含目录 中添加 C Program Files x86 Window
  • 高级纹理映射技术(6)

    高级纹理映射技术 6 对一些特殊的应用需要对纹理坐标进行处理 主要包括纹理坐标自动生成和纹理坐标变换 下图显示了纹理坐标的来源 处理过程以及到达光栅处理器的过程 纹理坐标自动生成 在Direct3D程序中 不仅可以在模型载入阶段或渲染阶段指
  • 手把手教你如何配置和编译ogre 1.7.0 + cegui 0.7.1

    oiramario 博客园 首页 新随笔 联系 订阅 管理 随笔 423 文章 1 评论 838 手把手教你如何配置和编译ogre 1 7 0 cegui 0 7 1 ogre 1 7 0的下载 配置和编译指南 1 ogre 1 7 0的下
  • win10 graphedit存储的路径

    如果安装郭windows SDK的话 可能的存储位置为C Program Files x86 Windows Kits 10 bin x86 C Program Files x86 Windows Kits 10 bin x64
  • 使用GDI/GDI+绘制到D3D9缓冲区的方法

    这个其实是3D绘图里嵌入2D绘图的传统方式 D3D9直接使用GDI GDI 就可以画图 只不过需要额外的设置 而且只支持RGB和XRGB 不支持ARGB 因此这种方法比较适合合成UI元素和不透明的纹理贴图 不适合将要进行AlphaBlend
  • Ogre:Hardwarebuffer

    Ogre Hardwarebuffer 分类 OGRE 2012 07 03 15 56 1097人阅读 评论 0 收藏 举报 buffer float byte 存储 图形 upload Ogre中的硬件缓存是指在显卡上的存储 这和在内存
  • d3dUtility.cpp 统一回答:在vs2015中调试D3D9龙书 代码示例:4.4 d3dUtility.cpp

    龙书d3d9的代码 在作者的资源中 可查找 免分 注意 如果可能的话 请先安装DXSDK Jun10 exe 然后再安装VS2010或VS2015 否则 会在安装DXSDK Jun10 exe的过程的最后阶段会报错 不过 即使是报错 也不影
  • 深入理解Direct3D9

    String Of Brilliant Blue QQ群 8082814 随笔 34 文章 32 评论 136 博客园 首页 新随笔 联系 管理 深入理解Direct3D9 深入理解D3D9对图形程序员来说意义重大 我把以前的一些学习笔记都
  • 欧拉角与四元数

    以下文章摘自wiki百科 对于在三维空间里的一个参考系 任何坐标系的取向 都可以用三个欧拉角来表现 参考系又称为全局坐标系 是静止不动的 而局部坐标系则固定于刚体 随着刚体的旋转而旋转 参閲右图 设定 x y z轴为全局坐标系的参考轴 称
  • 关于visual studio中的$(ConfigurationName)疑问

    关于visual studio中的 ConfigurationName 疑问 2012 12 02 16 09 15 转载 标签 it 分类 程序员之路 关于vs中的各种路径的值de查看方法 来源 http social msdn micr
  • Texture::getSourceFileType()

    Texture getSourceFileType
  • mesa 教程

    只有这个是靠谱的 Compiling and Installing The Mesa 3D Graphics Library latest documentation
  • 三维旋转:旋转矩阵,欧拉角,四元数

    在介绍下面的文章前 大家如果接触到欧拉角的话 就一定要关注一个词 要顺规 在欧拉角体系里面 有12种顺规 这一点是好多文章没有让读书意识到 导致后面学习图形学里面的 heading pitch bank 时对不上号 一般百度百科里面说到的
  • 介绍D3DPOOL和Lock

    介绍D3DPOOL和Lock 分类 DirectX 2013 02 28 00 21 322人阅读 评论 0 收藏 举报 D3D RUTIME的内存类型 分为3种 VIDEO MEMORY VM AGP MEMORY AM 和SYSTEM
  • Ogre引擎源码——资源之Skeleton

    Ogre引擎源码 资源之Skeleton 分类 OGRE 游戏开发 引擎开发 图形引擎 游戏引擎 2012 09 21 06 17 1231人阅读 评论 0 收藏 举报 引擎 animation vector binding pointer

随机推荐

  • 程序员常用命令集,只收集名字 ^^

    export PATH home hanmeimei local bin PATH which ls file helloworld objdump help objdump h s d exit o ldd helloworld ulim
  • ROS里程计:navigation/Tutorials/RobotSetup/Odom

    ROS里程计 navigation Tutorials RobotSetup Odom 通过ROS发布里程表信息 1 通过ROS发布里程表信息 2 nav msgs Odometry消息 3 使用tf发布Odometry转换 4 编写代码
  • IDEA中web项目c3p0-config.xml文件的配置及存放目录

    IDEA中web项目c3p0 config xml文件的配置及存放目录 今天在IDEA上折腾了很长一段时间 始终连接不上数据库 日志总是说找不到mysql 这是我的测试代码 Test public void fun2 throws SQLE
  • windows下java swt实现操作redis的客户端工具

    原文 windows下java swt实现操作redis的客户端工具 源代码下载地址 http www zuidaima com share 1902705862708224 htm redisclient 1 0 正式发布 适用于多个 R
  • ip广播系统服务器软件,【网络广播服务器软件IP网络广播软件数字广播软件】 - 太平洋安防网...

    参数说明 品牌 万凯wankai 详细描述 具备 版权局颁发的计算机软件 标准TCP IP网络协议 安装于连接以太网的计算机 IP广播的网络终端具有 立的ID号与IP地址 可以单 接收服务器的个性化定时播放节目 定时播放的操作 可以通过电脑
  • Hibernate之inverse和cascade详解

    继Hibernate学习笔记整理之后 发现inverse和cascade这两个属性在配置过程中比较含糊 仔细比较一下是有些地方比较像 所以很容易搞糊涂 借助此文来阐述下inverse和cascade的区别 什么是inverse 默认值为fa
  • centos8安装postgresql步骤

    1 安装源 1 sudo yum y install epel release 2 postgresql官网发布的postgresql对应的安装源 sudo yum install y https download postgresql o
  • There are multiple modules with names that only differ in casing.

    问题 在 npm run dev 后 控制台出现警告 没有出现链接 但是在浏览器上直接输入地址http localhost 8080 又可显示界面 There are multiple modules with names that onl
  • 华为机试HJ55 挑7

    HJ55 挑7 Python 题目 解题思路 代码 结果 题目 解题思路 1 多组输入 需要循环 2 循环查找到输入数值即可 字符串查找用in 能否整除 求余后判断是否 0 3 最后打印找到的数字的列表长度 代码 def func n in
  • 逐行对比LLaMA2和LLaMA模型源代码

    几个小时前 2023年7月18日 Meta发布了允许商用的开源模型LLaMA2 笔者逐行对比了LLaMA2模型源代码 和LLaMA相比 几乎没有改动 细节如下 是否改动 LLaMA2 LLaMA 模型整体构架 无 Transformer T
  • 面试必考真题

    1 输入一个链表 反转链表后 输出新链表的表头 package com csu marden public class Demo1 public static void main String args Node head new Node
  • 解决“17: 错误:程序中有游离的‘\240’,\302’

    参考链接 https blog csdn net asuphy article details 54602426 执行如下命令即可 sed i s o240 o302 g dy haikang test cpp
  • Invalid bound statement (not found):

    BUG描述 在执行动态SQL出现问题 原因 mapper接口中的方法名和mapper xml中的id标签不一致 解决方案 修改mapper接口中的方法名 使其对应到mapper xml中的id标签 参考资料
  • openssl的x509命令简单入门

    openssl的x509命令简单入门 openssl是一个强大的开源工具包 它能够完成完成各种和ssl有关的操作 命令说明 openssl help 会得到如下的提示 openssl Error help is an invalid com
  • 数据库常用命令之外键(foreign key)之多对一(总结,基础)

    我是小白 刚接触MySQL不久 现阶段正在学习 为此在CSDN上留下自己的学习笔记 如果有错误的地方还请大家见谅 评论或者私发我错误地方哦 谢谢大家 嘿嘿 此篇将记录外键的相关知识 上篇内容为对一张表的约束条件 传送门 创建表的完整性语法
  • golang基础教程

    目录 golang基础教程 一 环境搭建 golang基础教程 二 开发规范及API golang基础教程 三 变量与数据类型概述 golang基础教程 四 基本数据类型 golang基础教程 五 基本数据类型的转换 golang基础教程
  • 缺少nodejs环境,请在设置中配置nodejs的安装路径 - HBuilder - uniapp

    HBuilder运行uni app项目 点击 运行到 提示 缺少nodejs环境 请在设置中配置nodejs的安装路径 解决办法 找到工具 设置 运行配置 node运行配置 运行终端类型 选择 内置 外部 如果已经配置过 关闭编译器 重新打
  • Unity_如何使相机视角一直跟随角色移动

    实例代码如下 using System Collections using System Collections Generic using UnityEngine 相机视角跟踪 public class FollowTarget Mono
  • QHash & QMap 的顺序问题 (***)

    QT关联容器QMap QHash的Key值自动排序问题 对QMap中的key进行自定义排序 如何取消QMap自动排序 让QMap按照插入的顺序排列 通过插入顺序循环QHash QMap QHash插入后的显示顺序以及记录插入顺序的数据结构
  • OpenGL图形管线和坐标变换

    1 OpenGL 渲染管线 OpenGL渲染管线分为两大部分 模型观测变换 ModelView Transformation 和投影变换 Projection Transformation 做个比喻 计算机图形开发就像我们照相一样 目的就是