- 浏览: 41936 次
- 性别:
- 来自: 北京
最新评论
-
guanggsanguo:
运行了,很牛的场景!
97年世界编程大赛第一名写的程序 -
public_private:
发几张效果图就更好啦
3D桌面效果动画类 -
dianqijiaojian:
嘻嘻我是第一个。。。
使用Memory Analyzer tool(MAT)分析内存泄漏(二) -
huchunming2010:
deltaAnchorPosition这个变量作用?OnFee ...
Gallery3D中画图时调用glTranslate函数参数赋值过程 -
zhaoyu_h:
...
Android学习笔记
在这一课中,你将学会如何加载3D世界,并在3D世界中漫游。
现在这些日子您所需要的是一个大一点的、更复杂些的、动态3D世界,它带有空间的六自由度和花哨的效果如镜像、入口、扭曲等等,当然还要有更快的帧显示速度。这一课就要解释一个基本的3D世界"结构",以及如何在这个世界里游走。
数据结构
当您想要使用一系列的数字来完美的表达3D环境时,随着环境复杂度的上升,这个工作的难度也会随之上升。出于这个原因,我们必须将数据归类,使其具有更多的可操作性风格。在程序清单头部出现了sector(区段)的定义。每个3D世界基本上可以看作是sector(区段)的集合。一个sector(区段)可以是一个房间、一个立方体、或者任意一个闭合的区间。
这里我们在渲染类Render里面定义了三个内部类,内部类的代码如下所示:
- /**
- * 定义顶点
- * 顶点包含了OpenGL真正感兴趣的数据。
- * 我们用3D空间中的坐标值(x,y,z)以及它们的纹理坐标(u,v)来定义三角形的每个顶点。
- */
- private static class Vertex {
- public float x, y, z;
- public float u, v;
- }
- /**
- * 定义三边形
- * 三角形本质上是由一些(两个以上)顶点组成的多边形,
- * 顶点同时也是我们的最基本的分类单位。
- */
- private static class Triangle {
- public Vertex[] vertex = new Vertex[3];
- public Triangle() {
- for (int i = 0; i < 3; i++)
- vertex[i] = new Vertex();
- }
- }
- /**
- * 区段定义
- * 一个sector(区段)包含了一系列的多边形,
- * 所以下一个目标就是triangle(我们将只用三角形,这样写代码更容易些)。
- */
- private static class Sector {
- public int numtriangles;
- public Triangle[] triangles;
- public Sector(int inTri) {
- //确定了三边形的数量
- numtriangles = inTri;
- triangles = new Triangle[inTri];
- //对三边形赋值
- for (int i = 0; i < inTri; i++)
- triangles[i] = new Triangle();
- }
- }
/** * 定义顶点 * 顶点包含了OpenGL真正感兴趣的数据。 * 我们用3D空间中的坐标值(x,y,z)以及它们的纹理坐标(u,v)来定义三角形的每个顶点。 */ private static class Vertex { public float x, y, z; public float u, v; } /** * 定义三边形 * 三角形本质上是由一些(两个以上)顶点组成的多边形, * 顶点同时也是我们的最基本的分类单位。 */ private static class Triangle { public Vertex[] vertex = new Vertex[3]; public Triangle() { for (int i = 0; i < 3; i++) vertex[i] = new Vertex(); } } /** * 区段定义 * 一个sector(区段)包含了一系列的多边形, * 所以下一个目标就是triangle(我们将只用三角形,这样写代码更容易些)。 */ private static class Sector { public int numtriangles; public Triangle[] triangles; public Sector(int inTri) { //确定了三边形的数量 numtriangles = inTri; triangles = new Triangle[inTri]; //对三边形赋值 for (int i = 0; i < inTri; i++) triangles[i] = new Triangle(); } }
下面是渲染类的全部的代码:
- package demos.nehe.lesson10;
- import demos.common.ResourceRetriever;
- import demos.common.TextureReader;
- import javax.media.opengl.GL;
- import javax.media.opengl.GLAutoDrawable;
- import javax.media.opengl.GLEventListener;
- import javax.media.opengl.glu.GLU;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.util.StringTokenizer;
- import javax.media.opengl.GL2;
- import javax.media.opengl.glu.gl2.GLUgl2;
- class Renderer implements GLEventListener {
- //常量
- private final float PI_180 = (float) (Math.PI / 180.0);
- //启用混合的开关
- private boolean blendingEnabled; // Blending ON/OFF
- //
- private float heading;
- private float xpos;
- private float zpos;
- //设置是否可以在上下左右移动或旋转视角
- private boolean stepForward;
- private boolean stepBackward;
- private boolean turnRight;
- private boolean turnLeft;
- /**
- * 当左右方向键按下后,旋转变量yrot相应增加或减少。
- * 当前后方向键按下后,我们使用sine和cosine函数重新生成镜头位置(您需要些许三角函数学的知识:-)。
- * Piover180是一个很简单的折算因子用来折算度和弧度。
- *
- */
- //Y轴方向上的旋转量
- private float yrot; // Y Rotation
- /**
- * walkbias:基本上就是当人行走时头部产生上下摆动的幅度。
- * 我们使用简单的sine正弦波来调节镜头的Y轴位置。
- * 如果不添加这个而只是前后移动的话,程序看起来就没这么棒了。
- */
- private float walkbias = 0;
- private float walkbiasangle = 0;
- private float lookupdown = 0.0f;
- private boolean lookUp;
- private boolean lookDown;
- //选择过滤的种类
- private int filter;
- //使用的纹理贴图
- private int[] textures = new int[3];
- //我们的模型存储
- private Sector sector1;
- private GLU glu = new GLUgl2();
- /**
- * 下面是相关的设置启动上面的上下左右及其混合
- */
- public void toggleBlending() {
- blendingEnabled = !blendingEnabled;
- }
- public void switchFilter() {
- filter = (filter + 1) % 3;
- }
- public void stepForward(boolean step) {
- stepForward = step;
- }
- public void stepBackward(boolean step) {
- stepBackward = step;
- }
- public void turnRight(boolean turn) {
- turnRight = turn;
- }
- public void turnLeft(boolean turn) {
- turnLeft = turn;
- }
- public void lookUp(boolean look) {
- lookUp = look;
- }
- public void lookDown(boolean look) {
- lookDown = look;
- }
- /**
- * 导入3D的模型
- * 载入文件
- * 在程序内部直接存储数据会让程序显得太过死板和无趣。
- * 从磁盘上载入世界资料,会给我们带来更多的弹性,
- * 可以让我们体验不同的世界,而不用被迫重新编译程序。
- * 另一个好处就是用户可以切换世界资料并修改它们而无需知道程序如何读入输出这些资料的。
- * 数据文件的类型我们准备使用文本格式。
- * 这样编辑起来更容易,写的代码也更少。等将来我们也许会使用二进制文件。
- * @throws IOException
- */
- private void setupWorld() throws IOException {
- BufferedReader in = null;
- try {
- /**
- * 文件格式
- * 数据文件中每个三角形都以如下形式声明:
- * X1 Y1 Z1 U1 V1
- * X2 Y2 Z2 U2 V2
- * X3 Y3 Z3 U3 V3
- */
- in = new BufferedReader(new InputStreamReader(ResourceRetriever.getResourceAsStream("demos/data/models/world.txt")));
- String line = null;
- while ((line = in.readLine()) != null) {
- //如果一行为空
- if (line.trim().length() == 0 || line.trim().startsWith("//"))
- continue;
- //读取第一行 第一行里以字符串“NUMPOLLIES”开头,记录了这个区段里的三边形的数量
- if (line.startsWith("NUMPOLLIES")) {
- int numTriangles;
- //将读取的数量的字符串转化为整形
- numTriangles = Integer.parseInt(line.substring(line.indexOf("NUMPOLLIES") + "NUMPOLLIES".length() + 1));
- //构建区段将顶点和面的信息存储在区段里并保存在内存中
- sector1 = new Sector(numTriangles);
- break;
- }
- }
- //将顶点信息和面的信息保存在区段中
- for (int i = 0; i < sector1.numtriangles; i++) {
- for (int vert = 0; vert < 3; vert++) {
- //去除空格行
- while ((line = in.readLine()) != null) {
- if (line.trim().length() == 0 || line.trim().startsWith("//"))
- continue;
- break;
- }
- //如果不为空格行
- if (line != null) {
- StringTokenizer st = new StringTokenizer(line, " ");
- //由文件txt中存储的格式,将每行中的数据转换为浮点型,储存到三边形的顶点数组中
- sector1.triangles[i].vertex[vert].x = Float.valueOf(st.nextToken()).floatValue();
- sector1.triangles[i].vertex[vert].y = Float.valueOf(st.nextToken()).floatValue();
- sector1.triangles[i].vertex[vert].z = Float.valueOf(st.nextToken()).floatValue();
- sector1.triangles[i].vertex[vert].u = Float.valueOf(st.nextToken()).floatValue();
- sector1.triangles[i].vertex[vert].v = Float.valueOf(st.nextToken()).floatValue();
- }
- }
- }
- } finally {
- if (in != null)
- in.close();
- }
- }
- /**
- * 导入纹理图片,纹理图片banding
- * @param gl
- * @param glu
- * @throws IOException
- */
- private void loadGLTextures(GL2 gl, GLU glu) throws IOException {
- TextureReader.Texture texture = TextureReader.readTexture("demos/data/images/mud.png");
- //Create Nearest Filtered Texture
- //启用Nearest 过滤
- gl.glGenTextures(3, textures, 0);
- gl.glBindTexture(GL2.GL_TEXTURE_2D, textures[0]);
- gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
- gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
- gl.glTexImage2D(GL2.GL_TEXTURE_2D,
- 0,
- 3,
- texture.getWidth(),
- texture.getHeight(),
- 0,
- GL.GL_RGB,
- GL.GL_UNSIGNED_BYTE,
- texture.getPixels());
- //Create Linear Filtered Texture
- //启用线性过滤的纹理
- gl.glBindTexture(GL2.GL_TEXTURE_2D, textures[1]);
- gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
- gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
- gl.glTexImage2D(GL2.GL_TEXTURE_2D,
- 0,
- 3,
- texture.getWidth(),
- texture.getHeight(),
- 0,
- GL.GL_RGB,
- GL.GL_UNSIGNED_BYTE,
- texture.getPixels());
- //启用 mipmapped滤波方式
- gl.glBindTexture(GL2.GL_TEXTURE_2D, textures[2]);
- gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
- gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_NEAREST);
- glu.gluBuild2DMipmaps(GL2.GL_TEXTURE_2D,
- 3,
- texture.getWidth(),
- texture.getHeight(),
- GL.GL_RGB,
- GL.GL_UNSIGNED_BYTE,
- texture.getPixels());
- }
- public void init(GLAutoDrawable drawable) {
- GL2 gl = drawable.getGL().getGL2();
- try {
- //导入纹理图片并banding
- loadGLTextures(gl, glu);
- //导入模型顶点和三边形
- setupWorld();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- //启用纹理映射
- gl.glEnable(GL2.GL_TEXTURE_2D);
- //设置混合
- gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL.GL_ONE);
- //启用高斯模糊
- gl.glShadeModel(GL2.GL_SMOOTH);
- //设置背景颜色
- gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- //启用深度缓存
- gl.glClearDepth(1.0);
- //启用深度测试
- gl.glEnable(GL.GL_DEPTH_TEST);
- gl.glDepthFunc(GL.GL_LEQUAL); //The Type Of Depth Test To Do
- //启用
- gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); // Really Nice Perspective Calculations
- }
- private void update() {
- /**
- * 这个实现很简单。当左右方向键按下后,旋转变量yrot相应增加或减少。
- * 当前后方向键按下后,我们使用sine和cosine函数重新生成镜头位置
- * (您需要些许三角函数学的知识:-)。
- * Piover180是一个很简单的折算因子用来折算度和弧度。
- * walkbias是什么意思?这是NeHe的发明的单词:-)。
- * 基本上就是当人行走时头部产生上下摆动的幅度。
- * 我们使用简单的sine正弦波来调节镜头的Y轴位置。
- * 如果不添加这个而只是前后移动的话,程序看起来就没这么棒了。
- */
- if (stepForward) {
- xpos -= (float) Math.sin(heading * PI_180) * 0.05f;
- zpos -= (float) Math.cos(heading * PI_180) * 0.05f;
- if (walkbiasangle >= 359.0f) {
- walkbiasangle = 0.0f;
- } else {
- walkbiasangle += 10;
- }
- walkbias = (float) Math.sin(walkbiasangle * PI_180) / 20.0f;
- }
- if (stepBackward) {
- xpos += (float) Math.sin(heading * PI_180) * 0.05f;
- zpos += (float) Math.cos(heading * PI_180) * 0.05f;
- if (walkbiasangle <= 1.0f) {
- walkbiasangle = 359.0f;
- } else {
- walkbiasangle -= 10;
- }
- walkbias = (float) Math.sin(walkbiasangle * PI_180) / 20.0f;
- }
- if (turnRight) {
- heading -= 1.0f;
- yrot = heading;
- }
- if (turnLeft) {
- heading += 1.0f;
- yrot = heading;
- }
- if (lookUp) {
- lookupdown -= 1.0f;
- }
- if (lookDown) {
- lookupdown += 1.0f;
- }
- }
- /**
- * 绘制模型
- * @param drawable
- */
- public void display(GLAutoDrawable drawable) {
- //更新
- update();
- GL2 gl = drawable.getGL().getGL2();
- //启用颜色缓存和深度缓存
- gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); //Clear The Screen And The Depth Buffer
- //重置观察模型
- gl.glLoadIdentity(); //Reset The View
- //如果混合启用就开启混合
- if (!blendingEnabled) {
- gl.glDisable(GL.GL_BLEND);
- gl.glEnable(GL.GL_DEPTH_TEST);
- } else {
- gl.glEnable(GL.GL_BLEND);
- gl.glDisable(GL.GL_DEPTH_TEST);
- }
- // 顶点的临时 X, Y, Z, U 和 V 的数值
- float x = 0,y = 0,z = 0,u = 0,v = 0;
- //平移的三维分量
- //// 用于游戏者沿X轴平移时的大小
- float xtrans = -xpos;
- // 用于游戏者沿Z轴平移时的大小
- float ztrans = -zpos;
- // 用于头部的上下摆动
- float ytrans = -walkbias - 0.25f;
- // 位于游戏者方向的360度角
- float sceneroty = 360.0f - yrot;
- // 上下旋转
- gl.glRotatef(lookupdown, 1.0f, 0, 0);
- // 根据游戏者正面所对方向所作的旋转
- gl.glRotatef(sceneroty, 0, 1.0f, 0);
- // 以游戏者为中心的平移场景
- gl.glTranslatef(xtrans, ytrans, ztrans);
- // 根据 filter 选择的纹理
- gl.glBindTexture(GL2.GL_TEXTURE_2D, textures[filter]);
- // 处理各个三边形
- for (int i = 0; i < sector1.numtriangles; i++) {
- //绘制三边形
- gl.glBegin(GL2.GL_TRIANGLES);
- // 指向前面的法线
- gl.glNormal3f(0.0f, 0.0f, 1.0f);
- //第一个顶点的各分量
- x = sector1.triangles[i].vertex[0].x;
- y = sector1.triangles[i].vertex[0].y;
- z = sector1.triangles[i].vertex[0].z;
- u = sector1.triangles[i].vertex[0].u;
- v = sector1.triangles[i].vertex[0].v;
- gl.glTexCoord2f(u, v);
- gl.glVertex3f(x, y, z);
- //第二个顶点的各分量
- x = sector1.triangles[i].vertex[1].x;
- y = sector1.triangles[i].vertex[1].y;
- z = sector1.triangles[i].vertex[1].z;
- u = sector1.triangles[i].vertex[1].u;
- v = sector1.triangles[i].vertex[1].v;
- gl.glTexCoord2f(u, v);
- gl.glVertex3f(x, y, z);
- //第三个顶点的各分量
- x = sector1.triangles[i].vertex[2].x;
相关推荐
Nehe第10课3D世界:加载3D世界,并在3D世界中漫游。
加载3D世界,并在其中漫游: ...在这一课中,你将学会如何加载3D世界,并在3D世界中漫游。这一课使用第一课的代码,当然在课程说明中我只介绍改变了代码。 (更改了键盘的响应,跟Nehe源码里的程序效果差不多)
设计一个 OpenGL 程序, 创建一个三维迷宫, 支持替身通过一定交互手段在迷宫中漫游。 基本功能包括: 1、 迷宫应当至少包含 10 * 10 个 Cell,不能过于简单,下图给出一种示例。 2、 读取给定的替身模型,加载到...
基于OpenGL的3D迷宫漫游程序,包括模型加载、纹理映射、碰撞处理、摄像漫游等,带详细按键说明和文档
包括的功能: 1.采用全景酷炫背景,非常酷炫; ... ... 4.汽车内部有内饰,包括导航触摸屏,座椅等, 包括全部源码,可以进行二次开发。 注意:threejs版本比较低,本地预览请用火狐浏览器,谷歌浏览器需要localhost/...
第六节:在Quest3d中实现动画 第七节:在Quest3d中制作GUI(操作界面) 第八节:模型加载控制、变量的操作与系统函数调用 第九节:特效的实现(实时阴影、实时反射、粒子系统……) 第十节:制作一个完整的虚拟现实...
实验二 设计一个OpenGL程序,创建一个三维迷宫,支持替身通过一定交互手段在迷宫中漫游,基本功能包括: 迷宫应当至少包含10 * 10 个Cell,不能过于简单,下图给出一种示例。 读取给定的替身模型,加载到场景...
此代码是一个自己做的3D加载模型,是一个以第一人称为主角的室内漫游模型,为一些手机游戏感兴趣的开发者尤其是3D游戏的爱好者参考。
FreeTour是一款设计和制作全景漫游项目的软件,可同时发布FLASH和HTML5格式,发布作品可在PC、触摸设备、移动设备的系统中使用。软件使用拖拽式和其它可视化操作,图像质量和渲染效率极高。 FreeTour功能介绍...
该代码由Unity3D 4.2开发,福建里包括了所有的源代码程序,安装好Unity3D软件后,可以直接将本文件加载进来打开,带上VR产品,该成果在虚拟环境下可以与场景互动,实现房地产样板房的逼真展示和室内漫游。
常见建筑模型加载,模型常见室内效果渲染,室内场景漫游行走,室内家具动态提示。
演示.X文件模型的使用,包括从.X文件中加载模型生成网格模型对象,渲染网格模型。 2、StateControlUseMatrix 演示使用矩阵旋转网格模型。程序运行时按下“D”和“A”键可以使飞机模型绕自身z轴旋转;按下“S”和“W...
Nehe Opengl教程第十课代码,使用MFC实现 题名:加载3D世界,并在其中漫游 次版本有延迟 键盘不能做到连续响应
用Unity3D创建简单漫游 1 基本设置 1 修改视角控制键为右键 9 如何取消浏览窗口上的右键菜单 10 植物效果设置 10 水面效果的设置 15 烘培光影贴图的处理 16 如何制作连续加载的场景漫游 29
cesium视频投影功能,视频投放,m3u8视频流接入投放,集成vue项目,定义三角视锥等
主要内容:用Unity3D创建简单漫游,基本设置,修改视角控制键为右键,如何取消浏览窗口上的右键菜单,植物效果设置,水面效果的设置,烘培光影贴图的处理,如何制作连续加载的场景漫游
Unity3D十五分钟教程引擎操作教程 用Unity3D创建简单漫游 1 基本设置 1 修改视角控制键为右键 9 如何取消浏览窗口上的右键菜单 10 植物效果设置 10 水面效果的设置 15 ...如何制作连续加载的场景漫游 29
10.加载3D世界,并在其中漫游: 你一直期待的教程来了!这一章友一个叫Lionel Brites的伙伴制作。这一课里你讲学到如何导入一个3D世界。代码仍然使用第一章的,但是,课程页面只是解释了新的部分,包括导入3D场景,...
加载3D世界,并在其中漫游: 你一直期待的教程来了!这一章友一个叫Lionel Brites的伙伴制作。这一课里你讲学到如何导入一个3D世界。代码仍然使用第一章的,但是,课程页面只是解释了新的部分,包括导入3D场景,在3D...
了解图形系统的性能, 掌握可交互的OpenGL应用程序的开发设计的方法,掌握系统处理鼠标和键盘事件的编程方法...熟练运用OpenGL的相关函数和辅助函数,了解MD2三维模型的文件格式,熟悉并学会读取模型、加载到场景中的方法.