OpenGL绘制球形相关学习

二次曲面--gluQuadric

说是二次曲面图,其实从视觉效果上看还是三维图。通过glu实用库,我们可以轻松的画出球形、锥形、扇面、圆柱形,而不用像画立方体或立体三角形一样一个面一个面的去画。

 

要画二次曲面图形,首先我们要创建一个GLUquadricObj(二次曲面声明类型)。

创建完二次曲面声明并初始化之后,就可以利用这个指针绘制多个曲面图形了。

 

 

OpenGL的glu库提供了以下类型的二次曲面绘制:

1. Cylinder, 圆柱体。使用gluCylinder函数

2. Cone, 圆锥。使用gluCyliner函数。同Cylinder

3. Sphere, 球体。使用gluSphere函数

4. Disk, 碟盘,也就是同心圆。使用gluDisk函数

5.Partial Disk, 部分同心圆。使用gluPartialDisk函数

绘制二次曲面的步骤如下:

1. 创建二次曲面对象。gluNewQuadric。绘制二次曲面是复杂的工作,设计到各种数学理论的使用和计算,glu库简化了这一步骤,可以把二次曲面对象理解为一个结构体,保存着各种glu看得懂的信息。

2. 设置二次却面绘制风格。gluQuadricDrawStyle。一般都是选用GLU_FILL风格,采用多边形来模拟

3.设置法线风格。gluQuadricNormals。一般都是使用GLU_SMOOTH风格,对每个顶点都计算法线向量,是默认方式

4.设置二次曲面的绘制方向。gluQuadricOrientation。一般使用GLU_OUTSIDE, 按照所有的法线都指向外面的方式绘制。是默认方式

5.设置纹理。gluQuadricTexture。设置是否自动计算纹理。默认是GLU_FALSE。当需要使用纹理时应修改为GLU_TRUE.

6.调用二次曲面绘制函数。gluCylinder/gluSphere/gluDisk/gluPartialDisk

 

圆柱形

 void gluCylinder( GLUquadric* quad,    --创建的二次曲面指针
    GLdouble base,                                 --底面圆形的半径
    GLdouble top,                                   --顶面圆形的半径
    GLdouble height,                               --圆锥的高度
    GLint slices,                                      --纬线 环绕z轴的细分面(数字越大越平滑,相应的速度越慢)
    GLint stacks )                                    --经线 沿着z轴的细分面(数字越大越平滑,相应的速度越慢)

 

 

圆锥

圆锥的实现函数和圆柱体是一样的,只要将顶面圆形的半径设为0就可以了。

 

圆面

void gluDisk(
    GLUquadricObj *qobj,      --创建的二次曲面指针
    GLdouble innerRadius,     --内圆的半径
    GLdouble outerRadius,     --外圆的半径
    GLint slices,              --沿半径的细切面(数字越大越平滑,相应的速度越慢)
    GLint loops              --绕圆心的细切面(数字越大越平滑,相应的速度越慢)
);

 

球体

void gluSphere(
    GLUquadricObj *qobj,    --创建的二次曲面指针
    GLdouble radius,        --球半径
    GLint slices,            --纬线细分面(数字越大越平滑,相应的速度越慢)
    GLint stacks            --经线细分面(数字越大越平滑,相应的速度越慢)
);

 

扇形

void gluPartialDisk(
    GLUquadricObj *qobj,        --创建的二次曲面指针
    GLdouble innerRadius,       --内圆的半径
    GLdouble outerRadius,       --外圆的半径
    GLint slices,                --沿半径的细切面(数字越大越平滑,相应的速度越慢)
    GLint loops                --绕圆心的细切面(数字越大越平滑,相应的速度越慢)
    GLdouble startAngle,         --扇形开始的角度
    GLdouble sweepAngle        --扇形转过的角度
);

 

openGL使用右手坐标

从左到右,x递增
从下到上,y递增
从远到近,z递增


--------------------------------------------------------------------------------

 

OPENGL坐标系可分为:世界坐标系和当前绘图坐标系。

世界坐标系以屏幕中心为原点(0, 0, 0)。你面对屏幕,你的右边是x正轴,上面是y正轴,屏幕指向你的为z正轴。长度单位这样来定: 窗口范围按此单位恰好是(-1,-1)到(1,1)。

当前绘图坐标系是 绘制物体时的坐标系。程序刚初始化时,世界坐标系和当前绘图坐标系是重合的。当用glTranslatef(),glScalef(), glRotatef()对当前绘图坐标系进行平移、伸缩、旋转变换之后, 世界坐标系和当前绘图坐标系不再重合。改变以后,再用glVertex3f()等绘图函数绘图时,都是在当前绘图坐标系进行绘图,所有的函数参数也都是相 对当前绘图坐标系来讲的


OpenGL中的6种坐标系

OpenGL中存在6种坐标系,

1. Object or model coordinates

2. World coordinates

3. Eye (or Camera) coordinates

4. Clip coordinates

5. Normalized device coordinates

6. Window (or screen) coordinates

从object coordainates到world coordinates再到camera coordinate的变换,在OPENGL中统一称为model-view转换,初始化的时候,object coordinates和world coordinates还有camera coordinates坐标重合在原点,变换矩阵都为Identity。model-view matix转换points,vectorsd到camera坐标系。

 

在opengl编程中,有个困惑的问题,就是那个坐标系是不动的,我想是你想参考坐标系是不动的。比如我想建立了一个object,放到 camera坐标系中,这时,我以camera的原点为参考点。当然,我想看这个物体的时候,我就以object的原点为参考点,移动camera坐标系的原点,就可以看到object了。好像写了一堆废话,呵呵。

 

其中四种坐标经常要在程序中用到:世界坐标,物体坐标,设备坐标和眼坐标

 

世界坐标是OpenGL中用来描述场景的坐标,Z+轴垂直屏幕向外,X+从左到右,Y+轴从下到上,是右手笛卡尔坐标系统。我们用这个坐标系来描述物体及光源的位置。

将物体放到场景中也就是将物体平移到特定位置、旋转一定角度,这些操作就是坐标变换。OpenGL中提供了glTranslate*/glRotate*/glScale*三条坐标变换命令,利用OpenGL的矩阵运算命令,则可以实现任意复杂的坐标变换。

 

非常重要:OpenGL 中有一个坐标变换矩阵栈(ModelView),栈顶就是当前坐标变换矩阵,进入OpenGL管道的每个坐标(齐次坐标)都会先乘上这个矩阵,结果才是对应点在场景中的世界坐标。OpenGL中的坐标变换都是通过矩阵运算完成的,与图形学课本的描述完全一致。要注意的是变换中的矩阵乘法是左乘,而矩阵乘法与算术乘法不同,不符合交换律(万一不明白去看矩阵代数书好了)。

 

glTranslate*(x,y,z):平移,参数为各轴向的移动量。
glRotate(d,x,y,z):旋转,第一个参数为转动的度数,后三个参数表明是否绕该轴旋转。通常x,y,z中只有一个为1,其余为0,用连续几条旋转命令完成复杂旋转。由于矩阵运算的左乘特点,旋转命令的顺序与旋转动作的顺序正好相反

 

物体坐标是以物体某一点为原点而建立的“世界坐标”,该坐标系仅对该物体适用,用来简化对物体各部分坐标的描述。物体放到场景中时,各部分经历的坐标变换相同,相对位置不变,所以可视为一个整体,与人类的思维习惯一致。

 

眼坐标是以视点为原点,以视线的方向为Z+轴正方向的坐标系中的方向。OpenGL管道会将世界坐标先变换到眼坐标,然后进行裁剪,只有在视线范围(视见体)之内的场景才会进入下一阶段的计算。

 

同样的,有投影变换矩阵栈(Projection),栈顶矩阵就是当前投影变换矩阵,负责将场景各坐标变换到眼坐标,由所得到的结果是裁剪后的场景部分,称为裁剪坐标。前面提到过的视见体设定其实就是在建立该矩阵。

 

设备坐标:OpenGL 的重要功能之一就是将三维的世界坐标经过变换、投影等计算,最终算出它在显示设备上对应的位置,这个位置就称为设备坐标。在屏幕、打印机等设备上的坐标是二维坐标。值得一提的是,OpenGL可以只使用设备的一部分进行绘制,这个部分称为视区或视口(viewport)。投影得到的是视区内的坐标(投影坐标),从投影坐标到设备坐标的计算过程就是设备变换了。

 

矩阵栈切换:glMatrixMode(GL_MODELVIEWING或GL_PROJECTION);本命令执行后参数所指矩阵栈就成为当前矩阵栈,以后的矩阵栈操纵命令将作用于它。

 

矩阵栈操纵命令:
glPushMatrix(); 当前矩阵入栈,这时矩阵栈将栈顶值压入栈。
glPopMatrix(); 栈顶出栈,通常与上一条命令配合使用。
glLoadIdentity(); 将栈顶设为不变矩阵(就是对角线全为1其它为0的那个)。
glMultMatrix(M);将栈顶T设为M·T。

OpenGL 函数 gluLookAt() glScalef() glTranslatef() glRotatef() glFrustum()

glPerspective() 的使用

1.gluLookAt()——视图变换函数

把自己的眼睛当成是照相机,前三个参数表示眼睛的坐标,中间三个参数表示要拍照的物体的中心位置,可以理解成焦点吧,

后三个参数表示头顶的朝向,比如说头可以歪着(哈哈)。但是我测试过,如果歪的不对,原来的正前方现在已经不是正前方

了,那么就看不见物体了。举个例子:

gluLookAt (0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);//这个就表示头顶是朝着y方向

gluLookAt (0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0);//这个表示头歪了45度,头顶朝着(1.0,1.0,0.0)这个方向

2.glScalef() ——模型变换函数 缩放

void glScalef(GLfloat  x,  GLfloat  y,  GLfloat  z);

模型变换的目的是设置模型的位置和方向,例如可以对模型进行旋转、移动和缩放,或者联合这几种操作。

这个函数表示模型在各轴上是如果进行缩放的。举个例子:

glScalef (1.0, 2.0, 1.0);//表示y坐标值扩大两倍,这样原本方的物体就变成长的了。

3.glTranslatef() ——模型变换函数 移动

void glTranslatef(GLfloat  x,  GLfloat  y,  GLfloat  z);

这个函数表示模型是怎样移动的。举个例子:

glTranslatef(-1.0,0.0,-2.0);//表示物体沿x负方向移动1.0,沿z轴负方向移动2.0。所以就好像能看见侧面一样

4.glRotatef()——模型变换函数  旋转

void glRotatef(GLfloat  angle,  GLfloat  x,  GLfloat  y,  GLfloat  z);

angle表示旋转的角度(注意单位不是弧度),(x,y,z)表示转轴。举个例子:

glRotatef(45.0, 0.0, 0.0, 1.0);//表示模型沿着(0,0,1)这个轴旋转45°。

5.glFrustum() ——投影变换函数 透视投影

前四个参数表示裁剪范围,后两个参数(要求为正数)表示近的面和远的面离眼睛的距离。有点儿像调焦。裁剪完后拉伸铺满整个屏幕。

6.glPerspective() ——投影变换函数 透视投影

void gluPerspective(GLdouble  fovy,  GLdouble  aspect,  GLdouble  zNear,  GLdouble  zFar);

第一个参数表示在y方向上的视角度数。个人理解:比如45,表示眼睛和模型中心这个条线与y轴的夹角。

第二个参数表示纵横比。x/y。比如2表示x、y本来都是1个长度,现在x可以当两个长度用,这样,模型就好像被x方向压缩了一样。

后两个参数glFrustum()中后两个相近。要求都是正数。

基本函数的用法:
视点变换可以通过gluLookAt()函数完成,那三组参数分别指定了相机的位置、瞄准方向的参考点和相机向上方向。
通常视点变换操作在模型变换操作之前发出,以便模型变换先对物体发生作用。这样,场景中物体的顶点经过模型转换后一定到所希望的位置,然后再对场景进行视点定位等操作。模型变换和视点变换共同构成模型视景矩阵。

gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
1、改变前三个参数的值可以模拟人在实际环境中的移动;
2、改变中间三个参数的值,可以模拟人眼的转动,即所观察场景的变化。
3、后三个参数的值比较特殊,它所制定的不是一个点,而是一个方向,即决定将哪一个坐标轴作为向上的方向,如果向上方向与观察点到中心点的方向一致,结果将是不确定的。

gluLookAt(
摄像机x,摄像机y,摄像机z,
目标点x,目标点y,目标点z,
摄像机顶朝向x,摄像机顶朝向y,摄像机顶朝向z
)

 

 

 

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用OpenGL ES 3.0绘制球形的示例代码: ``` #include <GLES3/gl3.h> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <vector> // 定义球形的顶点和索引 const int SPHERE_LONG = 36; const int SPHERE_LAT = 18; std::vector<GLfloat> sphereVertices; std::vector<GLuint> sphereIndices; void generateSphere() { sphereVertices.clear(); sphereIndices.clear(); for (int j = 0; j <= SPHERE_LAT; j++) { float lat0 = glm::pi<float>() * (-0.5f + (float)(j - 1) / SPHERE_LAT); float z0 = sin(lat0); float zr0 = cos(lat0); float lat1 = glm::pi<float>() * (-0.5f + (float)j / SPHERE_LAT); float z1 = sin(lat1); float zr1 = cos(lat1); for (int i = 0; i <= SPHERE_LONG; i++) { float lng = 2 * glm::pi<float>() * (float)(i - 1) / SPHERE_LONG; float x = cos(lng); float y = sin(lng); sphereVertices.push_back(x * zr0); sphereVertices.push_back(y * zr0); sphereVertices.push_back(z0); sphereVertices.push_back(x * zr1); sphereVertices.push_back(y * zr1); sphereVertices.push_back(z1); } } for (int i = 0; i < SPHERE_LAT; i++) { for (int j = 0; j < SPHERE_LONG; j++) { int a = (SPHERE_LONG + 1) * i + j; int b = (SPHERE_LONG + 1) * (i + 1) + j; int c = (SPHERE_LONG + 1) * (i + 1) + (j + 1); int d = (SPHERE_LONG + 1) * i + (j + 1); sphereIndices.push_back(a); sphereIndices.push_back(b); sphereIndices.push_back(c); sphereIndices.push_back(a); sphereIndices.push_back(c); sphereIndices.push_back(d); } } } // 渲染球形 void renderSphere(GLuint program) { GLuint positionLocation = glGetAttribLocation(program, "a_Position"); glEnableVertexAttribArray(positionLocation); glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), &sphereVertices[0]); glDrawElements(GL_TRIANGLES, sphereIndices.size(), GL_UNSIGNED_INT, &sphereIndices[0]); glDisableVertexAttribArray(positionLocation); } ``` 使用时需要先调用`generateSphere()`函数生成球形的顶点和索引,然后在渲染时调用`renderSphere()`函数即可。需要注意的是,需要在OpenGL ES 3.0环境下运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值