- 浏览: 42735 次
- 性别:
- 来自: 北京
最新评论
-
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;
相关推荐
在3D世界中漫游,意味着我们需要实现视图控制,这通常涉及到相机(视点)的位置和方向管理。OpenGL提供了一系列的矩阵操作,如旋转、平移和缩放,来改变视点的视角。通过操纵这些矩阵,用户可以实现前后移动、左右...
在本文中,我们将深入探讨Flash 3D及其在3D漫游中的应用。 首先,Flash 3D是Adobe Flash平台的一部分,用于在Web浏览器上呈现3D图形。在2008年,Adobe发布了Flash Player 10,其中引入了Stage3D API,这是一个高...
在给定的标题“3DWorld实现了3D漫游”中,我们可以推测这是一个关于如何利用编程技术,特别是NeHe教程和OpenGL库来创建3D漫游的应用程序。 NeHe是一个广泛使用的初学者友好的OpenGL教程集合,由Jeffrey Ventrella...
7. **资源管理**:有效管理和加载3D模型、纹理、音频等资源,防止内存泄漏。 8. **用户界面**:设计友好的UI,展示系统状态、设置选项,提供帮助信息。 通过以上技术的结合运用,"3D空间漫游系统"能够创建出一个...
加载3D世界,并在其中漫游: ...在这一课中,你将学会如何加载3D世界,并在3D世界中漫游。这一课使用第一课的代码,当然在课程说明中我只介绍改变了代码。 (更改了键盘的响应,跟Nehe源码里的程序效果差不多)
在提供的文件列表中,“用Direct3D实现3D漫游.doc”可能是详细教程或代码示例,可以帮助你理解和实现这一过程。“Readme.txt”通常包含项目介绍或使用指南,“D3DSCR”可能是项目相关的源代码或资源文件。通过深入...
总结来说,"Away3D场景漫游Demo"是一个展示Away3D引擎强大功能的实例,它通过library.swf加载3D资源,通过catalog.xml配置场景,实现了用户可以自由探索的3D空间。这个Demo不仅教育了开发者如何使用Away3D进行3D场景...
例如,通过编写C#脚本,可以让用户通过键盘的WSAD键来控制角色在校园内的移动,类似于在真实世界中的行走体验。JavaScript则可以用来实现更复杂的交互逻辑,如通过按钮触发特定动作,或者加载不同的游戏级别。 除此...
OpenGL3D游戏引擎的场景漫游系统是游戏开发中的一个重要组成部分,它允许用户在三维空间内自由探索虚拟环境。这个系统通常由多个关键模块组成,包括相机控制、碰撞检测、导航网格、动画系统以及用户输入处理等。下面...
可能需要设置类路径,启动服务器,加载地形数据,最后在客户端(可能是Web浏览器)中查看和控制3D场景。 在开发3D漫游系统时,开发者需要掌握的知识点包括: - Java编程基础:理解面向对象编程的概念,以及Java...
总结起来,"纯API实现的3D室内漫游VB源代码"代表了一种使用VB编程并直接操作底层API来创建3D环境的技术,这需要开发者具备深厚的图形学知识和编程技巧。通过分析和理解源代码,可以学习到如何在没有现成图形库支持的...
在"EmptyProject_3_OK_1_SceneLoad"这个文件中,很可能是项目的初始化部分,包括加载3D模型、设置场景和初始化DirectX环境。场景加载通常涉及读取模型文件(如.obj或.fbx格式),解析其结构,并将其转化为Direct3D...
在这个例子中,`THREE.TextureLoader`用于加载全景图片,`THREE.MeshBasicMaterial`和`THREE.Mesh`则用来创建一个带有纹理的3D网格。`THREE.PerspectiveCamera`设置相机视角,`THREE.WebGLRenderer`处理图形渲染,而...
这种技术能够给用户带来沉浸式的体验,让他们能够在虚拟世界中自由探索。 "www.pudn.com.txt"可能是一个文本文件,包含了关于资源来源或者代码的说明,可能包括作者信息、使用许可、教程链接等。而"lesson10_bcb6...
设计一个 OpenGL 程序, 创建一个三维迷宫, 支持替身通过一定交互手段在迷宫中漫游。 基本功能包括: 1、 迷宫应当至少包含 10 * 10 个 Cell,不能过于简单,下图给出一种示例。 2、 读取给定的替身模型,加载到...
漫游功能是让用户能够在3D场景中自由移动和观察,通常通过键盘或鼠标控制。在VC6.0的源码中,这可能涉及到相机模型的更新,通过改变相机的位置和视角来模拟用户的移动。相机模型的常见类型有第一人称视角、第三人称...
总的来说,Cesium加载3DTiles技术是现代GIS和Web应用中处理大规模3D数据的关键工具,它的高效性和灵活性使得复杂的3D场景在Web环境中得以流畅呈现。无论是用于建筑、地形、城市规划,还是地质勘探,Cesium和3DTiles...
本文将详细讲解如何利用DirectX .x技术实现飞机模型在空中场景中的漫游功能。 首先,我们需要了解DirectX .x。它是微软提供的一套API(应用程序编程接口),主要用于多媒体应用,尤其是游戏开发,它包括了音频、...