OpenGL学习进程(9)在3D空间的绘制实例
本节将演示在3D空间中绘制图形的几个简单实例:
(1)在3D空间内绘制圆锥体:
#include <GL/glut.h>
#include <math.h>
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#define PI 3.1416
GLfloat xRot = ;
GLfloat yRot = ;
GLfloat zRot = ; void Init(void)
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glColor3f(1.0f, 1.0f, 0.0f);
// 把着色模式设置为单调着色
glShadeModel(GL_FLAT); //glShadeModel(GL_SMOOTH);
// 把顺时针环绕的多边形设为正面,这与默认是相反的,因为我们使用的是三角形扇
glFrontFace(GL_CW);
glOrtho(-1.0f,1.0f,-1.0f,1.0f,-1.0f,1.0f);
}
void SpecialKeys(int key, int x, int y)
{
if (key == GLUT_KEY_UP)
xRot -= 5.0f; if (key == GLUT_KEY_DOWN)
xRot += 5.0f; if (key == GLUT_KEY_LEFT)
yRot -= 5.0f; if (key == GLUT_KEY_RIGHT)
yRot += 5.0f; if (key> 356.0f)
xRot = 0.0f; if (key< -1.0f)
xRot = 355.0f; if (key> 356.0f)
yRot = 0.0f; if (key< -1.0f)
yRot = 355.0f; if (key==GLUT_KEY_F1) //绕着z轴旋转
zRot+= 5.0f; // 使用新的坐标重新绘制场景
glutPostRedisplay();
}
void RenderScene()
{
// 存储坐标和角度
GLfloat x, y, z, angle,x1,y1;
// 用于三角形颜色的交替设置
int iPivot = ;
// 用默认颜色设置背景色,并清除深度缓冲区(必须的,因为3D空间有视景深度)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//打开剔除功能(背面剔除,它用于消除一个表面的背面)
//glEnable(GL_CULL_FACE);
// 打开深度测试,如果不打开深度测试,3D锥体的显示就会与现实情况不符合
glEnable(GL_DEPTH_TEST); // 保存矩阵状态并旋转
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glRotatef(zRot, 0.0f, 0.0f, 1.0f); glBegin(GL_TRIANGLE_FAN);
// 三角形扇的共享顶点,z轴中心点上方
glVertex3f(0.0f,0.0f,0.75);
for (angle = 0.0f; angle < (2.0f * PI + PI / 8.0f); angle += (PI / 8.0f)) {
// 计算下一个顶点的位置
x = 0.50f * sin(angle);
y = 0.50f * cos(angle);
if ((iPivot % ) == ) {
glColor3f(1.0f, 1.0f, 0.0f);
}
else{
glColor3f(0.0f, 1.0f, 1.0f);
}
// 增加基准值,下次改变颜色
++iPivot;
// 指定三角形扇的下一个顶点
glVertex2f(x, y);
}
glEnd(); // 绘制一个新的三角形扇,作为覆盖圆锥的底
glBegin(GL_TRIANGLE_FAN);
// 三角形扇的共享顶点,中心位于原点
glVertex3f(0.0f, 0.0f,0.0f);
for (angle = 0.0f; angle < (2.0f * PI + PI / 8.0f); angle += (PI / 8.0f)) {
// 计算下一个顶点的位置
x = 0.50f * sin(angle);
y = 0.50f * cos(angle);
if ((iPivot % ) == ) {
glColor3f(0.5f, 0.0f, 0.5f);
}
else{
glColor3f(1.0f, 0.0f, 1.0f);
}
// 增加基准值,下次改变颜色
++iPivot;
// 指定三角形扇的下一个顶点
glVertex2f(x, y);
}
glEnd();
glPopMatrix();
glutSwapBuffers();
}
int main(int argv,char *argc[]){ glutInit(&argv,argc);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
glutInitWindowSize(,);
glutInitWindowPosition(,);
glutCreateWindow("3D空间绘制圆锥面");
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
Init();
glutMainLoop();
}
按F1键绕z轴旋转,按方向键绕x轴或y轴旋转:
(2)在3D空间中模拟地球环绕太阳旋转:
#include <GL/glut.h>
#include <stdlib.h>
#include <math.h>
#define PI 3.1416
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
static int year = ; void init(void)
{
glClearColor(0.2, 0.2, 0.2, 1.0);
glShadeModel(GL_FLAT);
}
void paintLoopPlant()
{
GLfloat x, z; int i;
glColor3f(0.0f,1.0f,0.5f);
glLineWidth(2.0f);
glBegin(GL_LINE_LOOP);
for (i = ; i < ;i++)
{
x = 0.35*sin(i * * PI / -PI);
z = 0.35*cos(i * * PI / -PI);
glVertex3f(x,,z);
}
glEnd(); glLineWidth(5.0f);
glColor3f(0.5,,);
glBegin(GL_LINE_LOOP);
for (i = ; i < ; i++)
{
x = 3.5*sin(i * * PI / )-3.5;
z = 3.5*cos(i * * PI / );
glVertex3f(x, , z);
}
glEnd();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(, 0.0, 0.0);//设置太阳的颜色
glPushMatrix();
glPointSize(1.0f);
//在坐标系中央画太阳
glutWireSphere(0.8, , );
//给太阳进平移
glRotatef((GLfloat)year, 0.0, 1.0, 0.0);
glTranslatef(3.5, 0.0, 0.0);
//画地球
glColor3f(, 0.2, 1.0);
glutWireSphere(0.15, , );
paintLoopPlant(); glPopMatrix();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(, , (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 6.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
} void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'y':
year = (year + ) % ;
break;
case 'Y':
year = (year - ) % ;
break;
case :
exit();
break;
default:
break;
}
glutPostRedisplay();
} int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(, );
glutInitWindowPosition(, );
glutCreateWindow("RotateAroundSun");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop(); return ;
}
(3)在3D空间用OpenGL自带的库函数绘制立方体:
#include <GL/glut.h>
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") GLfloat yRot = ; //用来画一个坐标轴的函数
void axis(double length)
{
glColor3f(1.0f, 1.0f, 1.0f);
glPushMatrix();
glBegin(GL_LINES);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, length);
glEnd();
//将当前操作点移到指定位置
glTranslated(0.0, 0.0, length - 0.2);
glColor3f(1.0, 0.0, 0.0);
glutWireCone(0.04, 0.3, , );
glPopMatrix();
}
void paint(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glOrtho(-2.0, 2.0, -2.0, 2.0, -, );
glPointSize();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(1.3, 1.6, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); //画坐标系
axis(); glPushMatrix();
glRotated(90.0, , 1.0, );//绕y轴正方向旋转90度
axis();
glPopMatrix(); glPushMatrix();
glRotated(-90.0, 1.0, 0.0, 0.0);//绕x轴负方向旋转
axis();
glPopMatrix(); glPushMatrix();//旋转除坐标轴之外的物体
glRotated(yRot, 0.0, yRot, 0.0);
glPushMatrix();
glColor3f(0.0f, 0.0f, 1.0f);
glTranslated(0.125, 0.125, 0.125);
glutWireCube(0.25);
glPopMatrix(); glPushMatrix();
glTranslated(1.125,0.125,0.125);
glutWireTeapot(0.25);
glPopMatrix(); glPushMatrix();
glTranslated(0.125, 0.125, 1.125);
glutWireSphere(0.25, , );
glPopMatrix(); glPushMatrix();
glTranslated(1.125,0.125,1.125);
glRotated(-, 1.0, 0.0, 0.0);
glutWireTorus(0.1, 0.25, , );
glPopMatrix(); glPushMatrix();
glTranslated(0.125, 1.125, 0.125);
glScaled(0.5*0.25, 0.5*0.25, 0.5*0.25);
glRotated(-, 0.0, 0.0, 1.0);
glutWireDodecahedron();
glPopMatrix(); glPushMatrix();
glTranslated(0.0, 1.0, 1.0);
GLUquadricObj * quadricObj = gluNewQuadric();
gluQuadricDrawStyle(quadricObj, GLU_LINE);
gluCylinder(quadricObj, 0.2, 0.2, 0.3, , );
glRotated(-, 0.0, 0.0, 0.0);
glPopMatrix(); glPopMatrix();//用来整体绕y轴旋转
glutSwapBuffers();
}
void Init()
{
glClearColor(0.8,0.8,0.8,1.0);
}
void reshape(int w, int h)
{
glViewport(, , (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(1.3, 1.6, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}
void SpecialKeys(int key, int x, int y)
{
if (key == GLUT_KEY_LEFT)
yRot -= 5.0f; if (key == GLUT_KEY_RIGHT)
yRot += 5.0f; if (key> 356.0f)
yRot = 0.0f; if (key< -1.0f)
yRot = 355.0f;
glutPostRedisplay();
}
int main(int argv, char *argc[])
{
glutInit(&argv, argc);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(, );
glutInitWindowPosition(, );
glutCreateWindow("3D空间绘制各种系统自带立方体");
Init();
glutDisplayFunc(paint);
glutReshapeFunc(reshape);
glutSpecialFunc(SpecialKeys);
glutMainLoop();
}
在这个例子下按左右方向键也是可以让立方体绕y轴旋转的,在此不做演示。
(4)相关知识:
1)OpenGL中的空间变换:(http://www.cnblogs.com/chengmin/archive/2011/09/12/2174004.html)
在使用OpenGL的三维虚拟程序中,当我们指定了模型的顶点之后,在屏幕上显示它们之前,一共会发生3种类型的变换:
视图变换、模型变换、投影变换。
1.视图变换:指定观察者(摄像机)的位置;
2.模型变换:在场景中移动物体;
3.投影变换:改变可视区域的大小;
视口变换:这是一种伪变换,它对窗口上的最终输出进行缩放。
1.视觉坐标:
它表示一种虚拟的固定坐标系统,通常作为一种参考系使用。它是根据观察者(摄像机)的角度而言的,与可能发生的变换无关。我们接下来所讨论的所有变换都是根据它们相对于视觉坐标的效果进行描述的。
用OpenGL在3D空间中进行绘图时,使用的是笛卡尔坐标系统。在不进行任何变换的情况下,这个坐标系统与视觉坐标系相同。
2.视图变换:
这是场景中所应用的第一个变换,它用于确定场景的观察点(拍摄点)。视图变换允许把观察点放在自己所希望的任何位置(观察点的位置任意),并允许在任何方向上观察场景(观察点的朝向任意)。确定视图变换就像在场景中放置照相机并让它指向某个方向。
作为总体原则,在进行任何其他变换之前必须先指定视图变换。因为视图变换的效果相当于根据视觉坐标系统来移动当前所使用的坐标系统。然后,根据最新修改的坐标系统,进行其它所有的后续变换。
3.模型变换
它可以移动物体,对它们进行旋转、平移或者缩放。并且,缩放可以是非一致的(物体的各个方向根据不同的数值进行伸缩)。 场景或物体的最终外观很大程度上取决于模型变换的应用顺序。因为每次变换都是在上次变换执行的基础上进行的。
4.投影变换:
它是在模型视图变换之后应用于物体的顶点之上的。它实际上定义了可视区域,并建立了裁剪平面。其中,投影又有两种不同的类型:正投影(平行投影)和透视投影。正投影通常用于2D绘图,此时你所需要的是像素和绘图单位之间的准确对应。透视投影则用于渲染那些包含了需要应用透视缩短的物体的场景。并且在大多数情况下,3D图形所使用的都是透视投影。
下面是2D投影变换与3D透视投影变换的对比:
5.视口变换
最终,场景的二维投影将被映射到屏幕上的某个窗口。这种到物理窗口坐标的映射是最后一个完成的变换,称为视口变换。
2)Win窗口坐标二维坐标与OpenGl的世界坐标:
1.Win的屏幕坐标的坐标系: 左上为坐标系原点,正右为X轴正方向, 正下方为Y轴正方向。视图类的窗口是这样的,如果是FrameWork的绘图区,则需要包含工具栏和状态栏的区域,二者是不一样的。
2.OpenGL中的屏幕坐标:以左下角为原点,正右方为x轴正方向,正上方为y轴正方向。
墨卡托坐标变换
OPENGL-----3D到2D坐标变换
OPENGL-----2D到3D坐标变换
OpenGL学习进程(9)在3D空间的绘制实例的更多相关文章
- OpenGL学习进程(12)第九课:矩阵乘法实现3D变换
本节是OpenGL学习的第九个课时,下面将详细介绍OpenGL的多种3D变换和如何操作矩阵堆栈. (1)3D变换: OpenGL中绘制3D世界的空间变换包括:模型变换.视图变换.投影变换和视口 ...
- OpenGL学习进程(10)第七课:四边形绘制与动画基础
本节是OpenGL学习的第七个课时,下面以四边形为例介绍绘制OpenGL动画的相关知识: (1)绘制几种不同的四边形: 1)四边形(GL_QUADS) OpenGL的GL_QUADS图 ...
- OpenGL学习进程(8)第六课:点、边和图形(三)绘制图形
本节是OpenGL学习的第六个课时,下面介绍OpenGL图形的相关知识: (1)多边形的概念: 多边形是由多条线段首尾相连而形成的闭合区域.OpenGL规定,一个多边形必须是一个“凸多边形”. ...
- OpenGL学习进程(7)第五课:点、边和图形(二)边
本节是OpenGL学习的第五个课时,下面介绍OpenGL边的相关知识: (1)边的概念: 数学上的直线没有宽度,但OpenGL的直线则是有宽度的.同时,OpenGL的直线必须是有限长度,而不是像数学概 ...
- OpenGL学习进程(11)第八课:颜色绘制的详解
本节是OpenGL学习的第八个课时,下面将详细介绍OpenGL的颜色模式,颜色混合以及抗锯齿. (1)颜色模式: OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. R ...
- OpenGL学习进程(6)第四课:点、边和图形(一)点
本节是OpenGL学习的第四个课时,下面介绍OpenGL点的相关知识: (1)点的概念: 数学上的点,只有位置,没有大小.但在计算机中,无论计算精度如何提高,始终不能表示一个无穷小的点 ...
- OpenGL学习进程(4)第二课:绘制图形
本节是OpenGL学习的第二个课时,下面介绍如何用点和线来绘制图形: (1)用点的坐标来绘制矩形: #include <GL/glut.h> void display(void) ...
- OpenGL学习进程(5)第三课:视口与裁剪区域
本节是OpenGL学习的第三个课时,下面介绍如何运用显示窗体的视口和裁剪区域: (1)知识点引入: 1)问题现象: 当在窗体中绘制图形后,拉伸窗体图形形状会发生变化: #include ...
- OpenGL学习进程(3)第一课:初始化窗体
本节是OpenGL学习的第一个课时,下面介绍如何初始化一个窗体: (1)显示一个有蓝色背景的窗体: #include <GL/glut.h> #include <st ...
随机推荐
- IOS MagicRecord 详解 (转载)
2014-10-22 14:37 6137人阅读 评论(6) 收藏 举报 IOSMagicRecordCoreData 目录(?)[+] 刚开始接触IOS不久,尝试着翻译一些博客,积累技术,与大家共享 ...
- Spring Java-based容器配置(二)
组装Java-based的配置 使用@Import注解 跟在Spring XML文件里使用<import>元素加入模块化的配置相似,@Import注解同意你载入其它配置类中的@Bean定义 ...
- windows 下node版管理
linux 下的node 多版本管理有nvm,windows 下同样有这样的工具gnvm 安装步骤(无node环境): 1.下载并解压缩 gnvm.exe 保存到任意文件夹,并将此文件夹加入到环境变量 ...
- Prelogin error: host 127.0.0.1 port 1434 Error reading prelogin response: Connection reset ClientConnectionId:26d4b559-c985-4b2e-bd8e-dd7a53b67e48
我在使用SSM框架的时候,连接的是sqlserver 2008r2数据库,但是查询数据的时候总是出现这样的警告信息,导致的结果是第一次登录的时候获取数据慢或者获取数据失败,具体的log信息如下 警告: ...
- Spring MVC文本框
以下示例显示如何使用Spring Web MVC框架在表单中使用文本框.首先使用Eclipse IDE来创建一个Web工程,按照以下步骤使用Spring Web Framework开发基于动态表单的W ...
- mysqldump: Got error: 1045
问题:最近备份mysql然后在执行mysqldump的时候提示权限和密码有问题 报错: Warning: Using a password on the command line interface ...
- phantom的使用
phantom页面加载 通过Phantomjs,一个网页可以被加载.分析和通过创建网页对象呈现,访问我的博客园地址:http://www.cnblogs.com/paulversion/p/83938 ...
- 49、android ListView几个比较特别的属性
由于这两天在做listView的东西,所以整理出来一些我个人认为比较特别的属性,通过设置这样的属性可以做出更加美观的列表 android:stackFromBottom="true" ...
- shell脚本中出现^M
在Windows中编辑的shell脚本,传到linux系统中,在末尾发现出现了很多^M字符 1.问题分析 在windows下使用notepad++写的脚本上传到Linux下,在使用vim编辑的时候我们 ...
- 将CodedUI Test 放到控制台程序中,模拟鼠标键盘操作
CodedUI Test是微软的自动化测试工具,在VS中非常好用.可以用来模拟鼠标点击,键盘输入.但执行的时候必须要用mstest调用,无法传入参数(当然可以写入config文件中,但每次修改十分麻烦 ...