本程序介绍AreaClodMesh, BezierCurve, CurveController, CameraNode. 学习增加 FPS, 摄像机如何沿弯曲的路径移动.
import com.jme.app.SimpleGame;
import com.jme.scene.model.XMLparser.Converters.FormatConverter;
import com.jme.scene.model.XMLparser.Converters.ObjToJme;
import com.jme.scene.model.XMLparser.JmeBinaryReader;
import com.jme.scene.Node;
import com.jme.scene.TriMesh;
import com.jme.scene.CameraNode;
import com.jme.scene.Controller;
import com.jme.scene.state.RenderState;
import com.jme.scene.lod.AreaClodMesh;
import com.jme.bounding.BoundingSphere;
import com.jme.math.Vector3f;
import com.jme.math.Matrix3f;
import com.jme.curve.CurveController;
import com.jme.curve.BezierCurve;
import com.jme.input.KeyInput;
import com.jme.input.action.KeyExitAction;
import java.net.URL;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ByteArrayInputStream;
/**
* Started Date: Aug 16, 2004<br><br>
*
* This program teaches Complex Level of Detail mesh objects. To use this program, move
* the camera backwards and watch the model disappear.
*
* @author Jack Lindamood
*/
public class HelloLOD extends SimpleGame {
CameraNode cn;
public static void main(String[] args) {
HelloLOD app = new HelloLOD();
app.setDialogBehaviour(SimpleGame.ALWAYS_SHOW_PROPS_DIALOG);
app.start();
}
protected void simpleInitGame() {
// Point to a URL of my model
URL model =
HelloModelLoading.class.getClassLoader().
getResource("jmetest/data/model/maggie.obj");
// Create something to convert .obj format to .jme
FormatConverter converter=new ObjToJme();
// Point the converter to where it will find the .mtl file from
converter.setProperty("mtllib",model);
// This byte array will hold my .jme file
ByteArrayOutputStream BO=new ByteArrayOutputStream();
// This will read the .jme format and convert it into a scene graph
JmeBinaryReader jbr=new JmeBinaryReader();
// Use an exact BoundingSphere bounds
BoundingSphere.useExactBounds=true;
Node meshParent=null;
try {
// Use the format converter to convert .obj to .jme
converter.convert(model.openStream(), BO);
// Load the binary .jme format into a scene graph
Node maggie = jbr.loadBinaryFormat(new
ByteArrayInputStream(BO.toByteArray()));
meshParent=(Node) maggie.getChild(0);
} catch (IOException e) { // Just in case anything happens
System.out.println("Damn exceptions!" + e);
e.printStackTrace();
System.exit(0);
}
// Create a clod duplicate of meshParent.
Node clodNode=getClodNodeFromParent(meshParent);
// Attach the clod mesh at the origin.
clodNode.setLocalScale(.1f);
rootNode.attachChild(clodNode);
// Attach the original at -15,0,0
meshParent.setLocalScale(.1f);
meshParent.setLocalTranslation(new Vector3f(-15,0,0));
rootNode.attachChild(meshParent);
// Clear the keyboard commands that can move the camera.
input.clearKeyboardActions();
input.clearMouseActions();
// Insert a keyboard command that can exit the application.
input.addKeyboardAction("exit",KeyInput.KEY_ESCAPE,
new KeyExitAction(this));
// The path the camera will take.
Vector3f[]cameraPoints=new Vector3f[]{
new Vector3f(0,5,20),
new Vector3f(0,20,90),
new Vector3f(0,30,200),
new Vector3f(0,100,300),
new Vector3f(0,150,400),
};
// Create a path for the camera.
BezierCurve bc=new BezierCurve("camera path",cameraPoints);
// Create a camera node to move along that path. cn=new CameraNode("camera node",cam);
// Create a curve controller to move the CameraNode along the path CurveController cc=new CurveController(bc,cn);
// Cycle the animation. cc.setRepeatType(Controller.RT_CYCLE);
// Slow down the curve controller a bit cc.setSpeed(.25f);
// Add the controller to the node. cn.addController(cc);
// Attach the node to rootNode rootNode.attachChild(cn); }
private Node getClodNodeFromParent(Node meshParent) {
// Create a node to hold my cLOD mesh objects
Node clodNode=new Node("Clod node");
// For each mesh in maggie
for (int i=0;i<meshParent.getQuantity();i++){
// Create an AreaClodMesh for that mesh. Let it compute
// records automatically
AreaClodMesh acm=new AreaClodMesh("part"+i,
(TriMesh) meshParent.getChild(i),null);
acm.setModelBound(new BoundingSphere()); acm.updateModelBound();
// Allow 1/2 of a triangle in every pixel on the screen in
// the bounds. acm.setTrisPerPixel(.5f);
// Force a move of 2 units before updating the mesh geometry acm.setDistanceTolerance(2);
// Give the clodMesh node the material state that the
// original had.
acm.setRenderState(meshParent.getChild(i). getRenderStateList()[RenderState.RS_MATERIAL]);
// Attach clod node. clodNode.attachChild(acm);
} return clodNode; }
Vector3f up=new Vector3f(0,1,0); Vector3f left=new Vector3f(1,0,0);
private static Vector3f tempVa=new Vector3f();
private static Vector3f tempVb=new Vector3f();
private static Vector3f tempVc=new Vector3f();
private static Vector3f tempVd=new Vector3f(); private static Matrix3f tempMa=new Matrix3f();
protected void simpleUpdate(){
// Get the center of root's bound. Vector3f objectCenter=rootNode.getWorldBound().getCenter(tempVa);
// My direction is the place I want to look minus the location
// of the camera.
Vector3f lookAtObject = tempVb.set(objectCenter). subtractLocal(cam.getLocation()).normalizeLocal();
// Left vector
tempMa.setColumn(0,up.cross(lookAtObject,tempVc).normalizeLocal());
// Up vector
tempMa.setColumn(1,left.cross(lookAtObject,tempVd).normalizeLocal());
// Direction vector tempMa.setColumn(2,lookAtObject); cn.setLocalRotation(tempMa); } }
用maggie模型构造一个网深mesh建立一个边对边的模型镜象,相机的移动通过CameraNode实现.
private Node getClodNodeFromParent(Node meshParent) {
// Create a node to hold my cLOD mesh objects
Node clodNode=new Node("Clod node");
// For each mesh in maggie
for (int i=0;i<meshParent.getQuantity();i++){
// Create an AreaClodMesh for that mesh. Let it compute
// records automatically
AreaClodMesh acm=new AreaClodMesh("part"+i,
(TriMesh) meshParent.getChild(i),null);
acm.setModelBound(new BoundingSphere());
acm.updateModelBound();
// Allow 1/2 of a triangle in every pixel on the screen in
// the bounds.
acm.setTrisPerPixel(.5f);
// Force a move of 2 units before updating the mesh geometry
acm.setDistanceTolerance(2);
// Give the clodMesh node the material state that the
// original had.
acm.setRenderState(meshParent.getChild(i).
getRenderStateList()[RenderState.RS_MATERIAL]);
// Attach clod node.
clodNode.attachChild(acm);
}
return clodNode;
}
一个cloudmesh是一个"细节复杂度层次"的mesh,他允许你修剪少量的三角形,效果如例子的复制模型且花费更小
的开销,cloudmesh使渲染速度更快,例如你游戏的角色需要5000个多边形绘制,但是如果角色远离你1000英尺的话
只需要400个多边形绘制就够了,对玩家来说这个区别是无关紧要的,但对计算机来说是一个很大的开销,ClodMesh可以
仅被Trimesh创建,因为maggie本身就是多个trimesh构成的(一个是黄色,另一个是蓝色...),我必须为每一个mesh
创建ClodMesh,这里ClodMesh类型是AreaClodMesh,它使用物体约束边界的屏幕区域觉得那个三角形的数量,
最近的物体有全部的三角形,越远的就越少.
AreaClodMesh acm=new AreaClodMesh("part"+i,(TriMesh) meshParent.getChild(i),null);
第一个是Clodmesh的参数名,全部的Spatials必须有一个名字,第2个参数是创建ClodMesh的Trimesh的集合.集合通知
ClodMesh如何减少三角形,为null时几个被创建
// Allow 1/2 of a triangle in every pixel on the screen in
// the bounds.
acm.setTrisPerPixel(.5f);
这个方法告诉clodmesh如何快速减少三角形,我故意让
mesh变小从而让你看到marrie的变化,在你的游戏中
你将设定可以忽略的三角形的值,clodmesh将预计算acm的区域约束
// Force a move of 2 units before updating the mesh geometry
acm.setDistanceTolerance(2);
每当摄像机的距离改变2个单位强制更新三角形的清除,这个更新在每帧中将会非常慢,为减少更新次数需要用
高速缓存(high FPS)
// Give the clodMesh node the material state that the
// original had.
acm.setRenderState(meshParent.getChild(i).
getRenderStateList()[RenderState.RS_MATERIAL]);
因为acm有原始几何信息并不代表他有原始的渲染状态,因此,我设定acm的材质状态和原始的材质状态一致,
在创建AreaClodMesh节点后,我设置键盘action
// Clear the keyboard commands that can move the camera.
input.clearKeyboardActions();
input.clearMouseActions();
// Insert a keyboard command that can exit the application.
input.addKeyboardAction("exit",KeyInput.KEY_ESCAPE,
new KeyExitAction(this));
在这个程序中我没有要用户象平常一样控制摄像头,因此我
刷新鼠标和键盘输入的input action,我必须重新插入一
个KEYEXITACtion否则用户将没有办法关闭应用,最后去创建我的摄像机的路径
// The path the camera will take.
Vector3f[]cameraPoints=new Vector3f[]{
new Vector3f(0,5,20),
new Vector3f(0,20,90),
new Vector3f(0,30,200),
new Vector3f(0,100,300),
new Vector3f(0,150,400),
};
// Create a path for the camera.
BezierCurve bc=new BezierCurve("camera path",cameraPoints);
我定义摄像机路径的点并创建BezierCurve,一个curve是实际的spatial(所以需要名字),但是curve不用被渲染,
它只需要描述路径,在设置curve后,我创建一个cameranode去移动
// Create a camera node to move along that path.
cn=new CameraNode("camera node",cam);
一个cameranode是一个可以被旋转的spatial,cam的值被Simplegame创建,下面是
// Create a camera node to move along that path.
cn=new CameraNode("camera node",display.getRenderer().getCamera());
摄像机被建立后,我可以为摄像机创建controller了
// Create a curve controller to move the CameraNode along the path
CurveController cc=new CurveController(bc,cn);
// Cycle the animation.
cc.setRepeatType(Controller.RT_CYCLE);
// Slow down the curve controller a bit
cc.setSpeed(.25f);
// Add the controller to the node.
cn.addController(cc);
// Attach the node to rootNode
rootNode.attachChild(cn);
上面实现了完美的旋转,一个curvecontroller让spatial沿曲线移动,最后让cameranode面向maggie模型对象旋转
protected void simpleUpdate(){
// Get the center of root's bound.
Vector3f objectCenter=rootNode.getWorldBound().getCenter(tempVa);
// My direction is the place I want to look minus the location
// of the camera.
Vector3f lookAtObject = tempVb.set(objectCenter).
subtractLocal(cam.getLocation()).normalizeLocal();
// Left vector
tempMa.setColumn(0,up.cross(lookAtObject,tempVc).normalizeLocal());
// Up vector
tempMa.setColumn(1,left.cross(lookAtObject,tempVd).normalizeLocal());
// Direction vector
tempMa.setColumn(2,lookAtObject);
cn.setLocalRotation(tempMa);
}
注意我创建了大量的临时静态变量,它们是更新时
需要数学调用的值,cameranode的旋转仿真使用摄像机
对象的东边,curvecontroller仅是摄像机的位置,开头2行设置一个摄像机到物体方向的vector,最后4行虽然有些奇怪:
// Left vector
tempMa.setColumn(0,up.cross(lookAtObject,tempVc).normalizeLocal());
// Up vector
tempMa.setColumn(1,left.cross(lookAtObject,tempVd).normalizeLocal());
// Direction vector
tempMa.setColumn(2,lookAtObject);
cn.setLocalRotation(tempMa);
第一行是摄像机左边的vector,第2个是上面的,第3个是
摄像机面向的方向,我使用up vector的矢量积和方向
得到left 矢量(up vector如同)。cross的两个向量
是彼此垂直的(也就是高中学的U*V=0. U,V为垂直矢量)
分享到:
相关推荐
游戏中的3D模型是通过建模软件(如Blender或3ds Max)创建的,然后导入到jme3中。jme3支持多种3D格式,如OBJ、FBX等。场景构建则涉及到节点树的概念,每个节点代表一个对象或者一组对象,通过父子关系构成复杂的3D...
标题中的“联想的JME2207P键盘驱动”是指专门为联想品牌的一款键盘型号为JME2207P的设备设计的驱动程序。在计算机硬件系统中,驱动程序是连接操作系统与硬件设备的关键软件,它使得操作系统能够识别并控制特定硬件,...
### JME中文教程知识点概述 #### 一、jMonkeyEngine3简介 - **定义与特点**:jMonkeyEngine3(简称JME3)是一款纯Java编写的免费3D游戏引擎,具备丰富的功能集,适用于各类游戏开发需求。该引擎不仅功能全面,其...
### JME3游戏开发引擎中文学习指南 #### 引言 JME3,全称jMonkeyEngine3,是一款开源的3D游戏开发引擎,专为Java开发者设计,旨在简化3D游戏和应用程序的开发过程。本文档将详细介绍如何在Netbeans6.x环境下搭建...
jme-3.0.10 兼容): 版本:1.+ 分支:jme_3.0 JME3-JFX 需要 java 8,但是可以使用 java 7 在纹理上绘制视频。对于 jME SDK,您应该创建一个 java 8 平台,但是 java8 支持非常糟糕(因为它基于 netbeans 7)。 ...
jme8002b蓝牙键盘驱动
JMonkeyEngine3(简称JME3)是一款强大的开源3D游戏引擎,它基于Java语言,提供了丰富的图形渲染功能,使得开发者能够创建高质量的3D游戏。而Clojure则是一种现代的、动态类型的Lisp方言,以其简洁的语法和强大的...
jme-remoterpiui-demo RemoteRPIUIControllerDemo MIDlet 该程序允许从JME Emulator远程控制在Raspberry Pi上运行的RPIUIDemoMIDlet应用程序(jme-rpiui-demo存储库)。 该程序连接到RPIUIDemoMIDlet的服务器套接...
标题“ant-jme.jar.zip”指的是一个压缩文件,其中包含了两个关键元素:ant-jme.jar和ant.license.txt。这个文件主要与Java开发工具有关,特别是Apache Ant和Java Micro Edition (JME)。 Apache Ant是一个Java库和...
这份"JME学习文档—中文版"压缩包文件,显然是为了帮助初学者或有经验的Java开发者掌握JME的使用和开发技巧。 JME的核心在于它的可移植性,它允许开发者编写一次代码,就能在多个平台上运行,这得益于其“Write ...
1. **j3o**:这是JME3的二进制3D模型或场景文件格式。使用这种格式,可以存储整个场景或者模型的数据,包括几何、材质、光照等信息。j3o文件经过优化,加载速度更快,且在最新版本的JMonkeyEngine中推荐使用。 2. *...
**JME程序设计实例教程详解** Java Micro Edition(JME),又称为Java 2 Micro Edition...通过学习,开发者不仅能够理解JME的编程模型,还能熟练运用其API,解决实际问题,为移动和嵌入式领域的软件开发打下坚实基础。
通过深入学习《2015jme3指南》,开发者不仅可以了解JME3的使用,还能掌握3D游戏开发的基本流程和技巧,为今后的项目开发打下坚实基础。同时,结合博主的博客文章,可以得到更全面的开发经验,解决实际遇到的问题。
com.jme3.animation com.jme3.app com.jme3.app.state com.jme3.asset com.jme3.asset.pack com.jme3.asset.plugins com.jme3.audio com.jme3.audio.joal ...jme3tools.preview
其中,材质系统是jME3的核心部分之一,用于控制模型表面的外观,包括颜色、反射、透明度等属性。 材质在jME3中由`Material`类表示,它包含了多个`Texture`和`ShaderProgram`。`Texture`用于存储图像数据,如颜色、...
标题中的“联想FN功能键 jme2207p键盘驱动. XP windows7”表明这是一个针对联想笔记本电脑的FN功能键以及JME2207P型号键盘的驱动程序,适用于Windows XP和Windows 7操作系统。FN键是许多笔记本电脑上常见的辅助功能...
### JME试题及答案知识点详解 #### 一、选择题知识点解析 ...这些知识点涵盖了JME中的多个方面,包括网络通信、图形处理、游戏开发等,旨在帮助中级水平的学习者深入理解JME的相关概念和技术细节。
Java Micro Edition(JME,前身为Java 2 Platform, Micro Edition,J2ME)是一个针对嵌入式设备和移动设备的Java平台。本教程将深入探讨JME的基础知识及其在开发移动应用程序中的应用。 JME的目标是为资源有限的...
标题“jme-process-site”可能指的是一个基于Java ME(Micro Edition)平台的项目站点,用于处理特定的工作流程或过程管理。然而,由于信息有限,我们无法深入探讨该项目的具体功能和目的。不过,我们可以从标签...