在Java 3D中载入外部3D模型文件

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

在Java 3D中载入外部3DJava 3D虽然能支持众多的外部3D模型文件,但能支持被Java 3D使用的外部模型文件仅为.obj和.lwd两种;分别对应ObjectFile类和Lw3dLoader类。

相比之下几款主流的3D建模软件都能生成.obj格式的文件,因此本文主要介绍使用ObjectFile类载入.obj文件的方法。

ObjectFile类有三个构造方法,分别为:
ObjectFile()
ObjectFile(int flags)
ObjectFile(int flags, float radians)
其中flags为一个整型的常量参数,用于决定载入的3D模型以什么方式生成。

参数radians用于决定载入模型的可显示半径。

flags参数可在以下四个值之间任取一个或者用逻辑或("|")将几个参数组合使用。

ObjectFile.RESIZE:忽略被载入的模型大小,直接把载入的模型放在一个范围在(1,1,1)到(-1,-1,-1)之间的立方体空间内,并把坐标原点设为(0,0,0)。

ObjectFile.REVERSE:反转载入的外部模型,即可能看模型的后面。

ObjectFile.TRIANGULATE:将模型的面以三角形方式显示,此参数主要便于观察模型凹凸面。

ObjectFile.STRIPIFY:以模型文件内模型的实际情况显示,此参数也是默认参数。

当初始化了ObjectFile对象后就可以用load方法载入.obj格式的文件,如果模型中已包含了贴图和光照的话也将一起被载入。

load方法需要一个参数用于指出.obj格式文件所在的路径,load方法有多个重载方法可以使参数即可以接受String类的值也可以接受Url类的值或者从输入法流读入,如果模型载入成功将返回一个Scene类的对象,如果载入失败将抛异常。

Java 3D针对load方法定义了三个异常类:
FileNotFoundException类:表示文件未找到。

IncorrectFormatException类:表示文件格式不正确。

ParsingErrorException类:装载器解析文件时出错。

下面的代码用以演示如何用load方法将一个模型载入到Scene类的实例:view plaincopy to clipboardprint?
Scene loadScene = null;
int flag = ObjectFile.STRIPIFY;
ObjectFile obj = new ObjectFile(flag);
try {
loadScene = obj.load(this.getClass().getClassLoader().getResource(filenam e));
} catch (FileNotFoundException e) {
System.out.println("文件未找到或文件路径不正确");
e.printStackTrace();
} catch (IncorrectFormatException e) {
System.out.println("文件格式不正确");
e.printStackTrace();
} catch (ParsingErrorException e) {
System.out.println("装载器解析文件时出错");
e.printStackTrace();
}
Scene loadScene = null;
int flag = ObjectFile.STRIPIFY;
ObjectFile obj = new ObjectFile(flag);
try {
loadScene = obj.load(this.getClass().getClassLoader().getResource(filenam e));
} catch (FileNotFoundException e) {
System.out.println("文件未找到或文件路径不正确");
e.printStackTrace();
} catch (IncorrectFormatException e) {
System.out.println("文件格式不正确");
e.printStackTrace();
} catch (ParsingErrorException e) {
System.out.println("装载器解析文件时出错");
e.printStackTrace();
}
虽然至此我们已经载入了一个.obj格式文件的3D模型,但把它载入到场景后我们却模型并没有按我们想像的那么显示。

对比在3D建模工具中看到模型的样子,我们的模型被绕X轴逆时针的旋转了90度,这主要是Java 3D的坐标系和大多数的3D建模工具的坐标系不同。

我们假设用户的显示器是垂直于桌面上,那么在Java 3D中显示器的宽代表X轴,显示器的高代表Y轴,显示器垂直朝向用户的方法为Z轴(此方向也是Z轴的正数方向)。

而多数的建模工具使用的是世界坐标系,即将显示器的高代表Z轴。

因此我们需要在程序将模型绕X轴顺时针旋转90度,旋转轴坐标的方法是使用Transform3D类的rotX方法,相应的还有rotY和rotZ方法。

view plaincopy to clipboardprint?
Transform3D t3d = new Transform3D();
t3d.rotX(-Math.PI/2);
TransformGroup tg = new TransformGroup(t3d);
tg.addChild(loadScene.getSceneGroup);
Transform3D t3d = new Transform3D();
t3d.rotX(-Math.PI/2);
TransformGroup tg = new TransformGroup(t3d);
tg.addChild(loadScene.getSceneGroup);
注意:这里有一个容易混淆的概念,就是我们刚才的步骤是旋转的坐标系,而不是模型,模型是附加在坐标系的上,没有法被旋转。

而在刚才的步骤完成后就是将Z 轴转向了上方(即显示器的高),而此时场中如还有其它的模型的话,它们的坐标未受影响,仍是Java 3D的坐标系。

通常情况下我们载入的模型大小并不是我们所要的,我们必须要在场景中对模型进行缩放操作。

Java 3D中对模型进行缩放需要用到Transform3D的setScale 方法,方法可以接收一个double值或一个Vector3d对象的实例,当使用double值做参数时模型将在XYZ轴上使用同样的比例因子进行缩放,而Vector3d实例则可以分别为XYZ轴指定不同的比例因子,比例因子越接近0,模型就越小,当设为0时模型即小的不可见了。

t3d.setScale(0.05d);

t3d.setScale(new Vector3d(0.01d,0,02d,0.03d));
好了,现在我将代码整理如下:
Gamemain.java程序主入口
ScreenManager.java 窗口框架类
LoadModelDemo.java演示载入一个外部3D模型文件
ColourTile.java实现一个平面用于地面中的单块地砖
CheckedFloor.java实现场景中的地面
GameMain.java
view plaincopy to clipboardprint?
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class GameMain {
private static int scrWidth = 800;
private static int scrHeight = 600;
private static int scrBitdepth = 32;
private JFrame gameFrame;
private JPanel gamePanel;
public static void main(String[] args)
{
GameMain game = new GameMain();
}
public GameMain()
{
ScreenManager screen = new ScreenManager(scrWidth,scrHeight,scrBitdepth,"Java 3D Test");
screen.setWindowMode();
gameFrame = screen.getFrame();
gamePanel = new LoadModelDemo(scrWidth,scrHeight);
gameFrame.add(gamePanel);
}
}
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class GameMain {
private static int scrWidth = 800;
private static int scrHeight = 600;
private static int scrBitdepth = 32;
private JFrame gameFrame;
private JPanel gamePanel;
public static void main(String[] args)
{
GameMain game = new GameMain();
}
public GameMain()
{
ScreenManager screen = new
ScreenManager(scrWidth,scrHeight,scrBitdepth,"Java 3D Test");
screen.setWindowMode();
gameFrame = screen.getFrame();
gamePanel = new LoadModelDemo(scrWidth,scrHeight);
gameFrame.add(gamePanel);
}
}
ScreenManager.java
view plaincopy to clipboardprint?
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class ScreenManager {
private GraphicsDevice device;
private JFrame frame;
private String title;
private boolean isResizable;
private boolean isWindowMode;
private int scrWidth;
private int scrHeight;
private int scrBitdepth;
public ScreenManager(int scrWidth,int scrHeight,int scrBitdepth,String title)
{
this.scrWidth = scrWidth;
this.scrHeight = scrHeight;
this.scrBitdepth = scrBitdepth;
this.title = title;
}
public ScreenManager(String title)
{
this.title = title;
this.frame.setTitle(title);
}
public void setFullScreenMode()
{
device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefau ltScreenDevice();
if(isSupportDisplayMode(scrWidth,scrHeight,scrBitdepth)) {
frame = new JFrame();
frame.setUndecorated(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CL OSE);
frame.setVisible(true);
device.setFullScreenWindow(frame);
try{
if(device.isFullScreenSupported()&&device.isDisplayChangeSup ported())
device.setDisplayMode(new
DisplayMode(scrWidth, scrHeight, scrBitdepth, DisplayMode.REFRESH_RATE_UNKNOWN));
}catch(IllegalArgumentException e)
{
e.printStackTrace();
System.exit(0);
}
}
else
{
JOptionPane.showMessageDialog(null, "不支持的显示分辨率!","错误",JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
}
private boolean isSupportDisplayMode(int width,int height,int bitdepth)
{
DisplayMode[] modes = device.getDisplayModes();
for(DisplayMode mode : modes)
{
if(mode.getWidth()==width && mode.getHeight()==height && mode.getBitDepth()==bitdepth) return true;
}
return false;
}
public void setWindowMode()
{
frame = new JFrame();
frame.setResizable(false);//禁止窗体改变大小
frame.setPreferredSize(new
Dimension(scrWidth,scrHeight));
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CL OSE);//响应窗体的关闭事件,但不关闭窗体
frame.setVisible(true);
// 侦听窗体事件并捕获窗体关闭中的事件,在用户确认后退出程序frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e)
{
int res = JOptionPane.showConfirmDialog(null, "是否退出!","退出",JOptionPane.YES_NO_OPTION);
if(res == JOptionPane.YES_OPTION)
closeFrame();
}
});
this.setFrametoCenter();
}
public void setFullWindowMode()
{
if(frame != null)
{
device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefau
ltScreenDevice();
DisplayMode displayMode = device.getDisplayMode();
frame.setPreferredSize(new
Dimension(displayMode.getWidth(),displayMode.getHeight()));
}
}
public int getWidth()
{
return scrWidth;
}
public int getHeight()
{
return scrHeight;
}
public JFrame getFrame()
{
return frame;
}
// 将窗体在显示屏幕内居中显示
public void setFrametoCenter()
{
if(device!=null)
return;
Insets inset = frame.getInsets();
int scrx=0;
int scry=0;
Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize();
if(scrSize.width > scrWidth)
scrx = (scrSize.width-scrWidth)/2;
if(scrSize.height > scrHeight)
scry = (scrSize.height-scrHeight)/2;
frame.setBounds(scrx-inset.left, scry-inset.top, scrWidth+inset.right+inset.left,
scrHeight+inset.bottom+inset.top);
}
// 关闭窗体事件
public void closeFrame()
{
frame.dispose();
System.exit(0);
}
}
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class ScreenManager {
private GraphicsDevice device;
private JFrame frame;
private String title;
private boolean isResizable;
private boolean isWindowMode;
private int scrWidth;
private int scrHeight;
private int scrBitdepth;
public ScreenManager(int scrWidth,int scrHeight,int scrBitdepth,String title)
{
this.scrWidth = scrWidth;
this.scrHeight = scrHeight;
this.scrBitdepth = scrBitdepth;
this.title = title;
}
public ScreenManager(String title)
{
this.title = title;
this.frame.setTitle(title);
}
public void setFullScreenMode()
{
device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefau ltScreenDevice();
if(isSupportDisplayMode(scrWidth,scrHeight,scrBitdepth)) {
frame = new JFrame();
frame.setUndecorated(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_ CLOSE);
frame.setVisible(true);
device.setFullScreenWindow(frame);
try{
if(device.isFullScreenSupported()&&device.isDisplayChange Supported())
device.setDisplayMode(new
DisplayMode(scrWidth, scrHeight, scrBitdepth, DisplayMode.REFRESH_RATE_UNKNOWN));
}catch(IllegalArgumentException e)
{
e.printStackTrace();
System.exit(0);
}
}
else
{
JOptionPane.showMessageDialog(null, "不支持的显示分辨率!","错误",JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
}
private boolean isSupportDisplayMode(int width,int height,int bitdepth)
{
DisplayMode[] modes = device.getDisplayModes();
for(DisplayMode mode : modes)
{
if(mode.getWidth()==width &&
mode.getHeight()==height && mode.getBitDepth()==bitdepth) return true;
}
return false;
}
public void setWindowMode()
{
frame = new JFrame();
frame.setResizable(false);//禁止窗体改变大小
frame.setPreferredSize(new
Dimension(scrWidth,scrHeight));
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_ CLOSE);//响应窗体的关闭事件,但不关闭窗体
frame.setVisible(true);
// 侦听窗体事件并捕获窗体关闭中的事件,在用户确认后退出程序frame.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e)
{
int res = JOptionPane.showConfirmDialog(null, "是否退出!","退出",JOptionPane.YES_NO_OPTION);
if(res == JOptionPane.YES_OPTION)
closeFrame();
}
});
this.setFrametoCenter();
}
public void setFullWindowMode()
{
if(frame != null)
{
device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefau ltScreenDevice();
DisplayMode displayMode = device.getDisplayMode();
frame.setPreferredSize(new
Dimension(displayMode.getWidth(),displayMode.getHeight()));
}
}
public int getWidth()
{
return scrWidth;
}
public int getHeight()
{
return scrHeight;
}
public JFrame getFrame()
{
return frame;
}
// 将窗体在显示屏幕内居中显示
public void setFrametoCenter()
{
if(device!=null)
return;
Insets inset = frame.getInsets();
int scrx=0;
int scry=0;
Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize();
if(scrSize.width > scrWidth)
scrx = (scrSize.width-scrWidth)/2;
if(scrSize.height > scrHeight)
scry = (scrSize.height-scrHeight)/2;
frame.setBounds(scrx-inset.left, scry-inset.top, scrWidth+inset.right+inset.left,
scrHeight+inset.bottom+inset.top);
}
// 关闭窗体事件
public void closeFrame()
{
frame.dispose();
System.exit(0);
}
}
LoadModelDemo.java
view plaincopy to clipboardprint?
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GraphicsConfiguration;
import java.io.FileNotFoundException;
import java.util.Enumeration;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingBox;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.swing.JPanel;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;
import com.sun.j3d.loaders.IncorrectFormatException;
import com.sun.j3d.loaders.ParsingErrorException;
import com.sun.j3d.loaders.Scene;
import com.sun.j3d.loaders.objectfile.ObjectFile;
import com.sun.j3d.utils.behaviors.vp.OrbitBehavior;
import com.sun.j3d.utils.geometry.Text2D;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.universe.ViewingPlatform;
public class LoadModelDemo extends JPanel{
private BranchGroup sceneBG;
private SimpleUniverse universe;
private BoundingSphere bounds;
private double boundRadius = 100;
public LoadModelDemo(int width,int height)
{
this.setLayout(new BorderLayout());
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas = new Canvas3D(config);
canvas.setSize(width, height);
this.add(canvas,BorderLayout.CENTER);
universe = new SimpleUniverse(canvas);
createSceneGroup();
initUserPosition();
orbitControls(canvas);
universe.addBranchGraph(sceneBG);
}
public void createSceneGroup()
{
sceneBG = new BranchGroup();
bounds = new BoundingSphere(new Point3d(0,0,0),boundRadius);
addBackground();
TransformGroup[] objModel = new TransformGroup[4];
sceneBG.addChild(objModel[0] = loadModel("leet/Liit.obj",ObjectFile.RESIZE,new
Vector3d(-5.4,0,0)));
sceneBG.addChild(objModel[1] = loadModel("leet/Liit.obj",ObjectFile.REVERSE,new
Vector3d(-1.8,0,0)));
sceneBG.addChild(objModel[2] = loadModel("leet/Liit.obj",ObjectFile.TRIANGULATE,new
Vector3d(1.8,0,0)));
sceneBG.addChild(objModel[3] = loadModel("leet/Liit.obj",ObjectFile.STRIPIFY,new
Vector3d(5.4,0,0)));
sceneBG.addChild(new CheckerFloor().getBG());
//对sceneBG有关的对象进行编译和缓存,如果在编译之后再次添加其它分支的话将抛异常
pile();
}
public void addBackground()
{
Background back = new Background();
back.setApplicationBounds(bounds);
back.setColor(0.17f, 0.62f, 0.92f);
sceneBG.addChild(back);
}
private void initUserPosition()
{
//返回当前虚拟世界的观察平台
ViewingPlatform vp = universe.getViewingPlatform();
//得到观察平台的坐标枝花点
TransformGroup steerTG = vp.getViewPlatformTransform();
Transform3D t3d = new Transform3D();
steerTG.getTransform(t3d);
//设置观察点坐标在(0,5,20),看向坐标(0,0,0)处,指定Y轴向正数沿伸方向为正方向
t3d.lookAt(new Point3d(0,5,20), new Point3d(0,0,0), new Vector3d(0,1,0));
t3d.invert();
steerTG.setTransform(t3d);
}
private void orbitControls(Canvas3D canvas)
{
OrbitBehavior orbit = new OrbitBehavior(canvas, OrbitBehavior.REVERSE_ALL);
orbit.setSchedulingBounds(bounds);
ViewingPlatform vp = universe.getViewingPlatform( );
vp.setViewPlatformBehavior(orbit);
}
private TransformGroup loadModel(String filename,int flag,Vector3d translation)
{
Scene loadScene = this.loadFromFile(filename,flag);
Transform3D t3d = new Transform3D();
t3d = this.rotateModel();
t3d.setScale(this.calcScaleFactor(loadScene.getSceneGroup())) ;
t3d.setTranslation(translation);
TransformGroup tg = new TransformGroup(t3d);
tg.addChild(loadScene.getSceneGroup());
return tg;
}
private Scene loadFromFile(String filename,int flag)
{
Scene loadScene = null;
ObjectFile obj = new ObjectFile(flag);
try {
loadScene = obj.load(this.getClass().getClassLoader().getResource(filenam e));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("文件未找到或文件路径不正确");
e.printStackTrace();
} catch (IncorrectFormatException e) {
// TODO Auto-generated catch block
System.out.println("文件格式不正确");
e.printStackTrace();
} catch (ParsingErrorException e) {
// TODO Auto-generated catch block
System.out.println("装载器解析文件时出错");
e.printStackTrace();
} finally {
return loadScene;
}
}
//obj格式的文件坐标空间是Z轴指向上方,Y轴指向屏幕。

而Java 3D //的坐标空间是Y轴指向上方,Z轴指向屏幕。

因此需要把导入的外部模型//作一个坐标转换,即将X轴转动90度
private Transform3D rotateModel()
{
Transform3D t3d = new Transform3D();
t3d.rotX(-Math.PI/2);
return t3d;
}
private Vector3d calcScaleFactor(BranchGroup bg)
{
//根据枝节点得到一个立方位形的范围空间
BoundingBox boundBox = new BoundingBox(bg.getBounds());
Point3d upper = new Point3d();
//范围空间的XYZ轴在正方向的最大值载一个Point3d对象
boundBox.getUpper(upper);
//范围空间的XYZ轴在负方向的最大值载一个Point3d对象
Point3d lower = new Point3d();
boundBox.getLower(lower);
double max = 0.0;
//物体的长宽高三个数值中找出最大的一个值
if((upper.getX()-lower.getX())>max)
max = upper.getX()-lower.getX();
if((upper.getY()-lower.getY())>max)
max = upper.getY()-lower.getY();
if((upper.getZ()-lower.getZ())>max)
max = upper.getZ()-lower.getZ();
//计算比例因子,当值越接近0时,所显示的物体越小,当等于0时物体即不可见
double scaleFactor = 5/max;
if(scaleFactor<0.005)
scaleFactor = 0.005;
return new Vector3d(scaleFactor,scaleFactor*2,scaleFactor);
}
}
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GraphicsConfiguration;
import java.io.FileNotFoundException;
import java.util.Enumeration;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingBox;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.swing.JPanel;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;
import com.sun.j3d.loaders.IncorrectFormatException;
import com.sun.j3d.loaders.ParsingErrorException;
import com.sun.j3d.loaders.Scene;
import com.sun.j3d.loaders.objectfile.ObjectFile;
import com.sun.j3d.utils.behaviors.vp.OrbitBehavior;
import com.sun.j3d.utils.geometry.Text2D;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.universe.ViewingPlatform;
public class LoadModelDemo extends JPanel{
private BranchGroup sceneBG;
private SimpleUniverse universe;
private BoundingSphere bounds;
private double boundRadius = 100;
public LoadModelDemo(int width,int height)
{
this.setLayout(new BorderLayout());
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas = new Canvas3D(config);
canvas.setSize(width, height);
this.add(canvas,BorderLayout.CENTER);
universe = new SimpleUniverse(canvas);
createSceneGroup();
initUserPosition();
orbitControls(canvas);
universe.addBranchGraph(sceneBG);
}
public void createSceneGroup()
{
sceneBG = new BranchGroup();
bounds = new BoundingSphere(new Point3d(0,0,0),boundRadius);
addBackground();
TransformGroup[] objModel = new TransformGroup[4];
sceneBG.addChild(objModel[0] = loadModel("leet/Liit.obj",ObjectFile.RESIZE,new
Vector3d(-5.4,0,0)));
sceneBG.addChild(objModel[1] = loadModel("leet/Liit.obj",ObjectFile.REVERSE,new
Vector3d(-1.8,0,0)));
sceneBG.addChild(objModel[2] = loadModel("leet/Liit.obj",ObjectFile.TRIANGULATE,new
Vector3d(1.8,0,0)));
sceneBG.addChild(objModel[3] = loadModel("leet/Liit.obj",ObjectFile.STRIPIFY,new
Vector3d(5.4,0,0)));
sceneBG.addChild(new CheckerFloor().getBG());
//对sceneBG有关的对象进行编译和缓存,如果在编译之后再次添加其它分支的话将抛异常
pile();
}
public void addBackground()
{
Background back = new Background();
back.setApplicationBounds(bounds);
back.setColor(0.17f, 0.62f, 0.92f);
sceneBG.addChild(back);
}
private void initUserPosition()
{
//返回当前虚拟世界的观察平台
ViewingPlatform vp = universe.getViewingPlatform();
//得到观察平台的坐标枝花点
TransformGroup steerTG = vp.getViewPlatformTransform();
Transform3D t3d = new Transform3D();
steerTG.getTransform(t3d);
//设置观察点坐标在(0,5,20),看向坐标(0,0,0)处,指定Y轴向正数沿伸方向为正方向
t3d.lookAt(new Point3d(0,5,20), new Point3d(0,0,0), new Vector3d(0,1,0));
t3d.invert();
steerTG.setTransform(t3d);
}
private void orbitControls(Canvas3D canvas)
{
OrbitBehavior orbit = new OrbitBehavior(canvas, OrbitBehavior.REVERSE_ALL);
orbit.setSchedulingBounds(bounds);
ViewingPlatform vp = universe.getViewingPlatform( );
vp.setViewPlatformBehavior(orbit);
}
private TransformGroup loadModel(String filename,int flag,Vector3d translation)
{
Scene loadScene = this.loadFromFile(filename,flag);
Transform3D t3d = new Transform3D();
t3d = this.rotateModel();
t3d.setScale(this.calcScaleFactor(loadScene.getSceneGroup ()));
t3d.setTranslation(translation);
TransformGroup tg = new TransformGroup(t3d);
tg.addChild(loadScene.getSceneGroup());
return tg;
}
private Scene loadFromFile(String filename,int flag)
{
Scene loadScene = null;
ObjectFile obj = new ObjectFile(flag);
try {
loadScene = obj.load(this.getClass().getClassLoader().getResource(filenam e));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("文件未找到或文件路径不正确");
e.printStackTrace();
} catch (IncorrectFormatException e) {
// TODO Auto-generated catch block
System.out.println("文件格式不正确");
e.printStackTrace();
} catch (ParsingErrorException e) {
// TODO Auto-generated catch block
System.out.println("装载器解析文件时出错");
e.printStackTrace();
} finally {
return loadScene;
}
}
//obj格式的文件坐标空间是Z轴指向上方,Y轴指向屏幕。

而Java 3D //的坐标空间是Y轴指向上方,Z轴指向屏幕。

因此需要把导入的外部模型//作一个坐标转换,即将X轴转动90度
private Transform3D rotateModel()
{
Transform3D t3d = new Transform3D();
t3d.rotX(-Math.PI/2);
return t3d;
}
private Vector3d calcScaleFactor(BranchGroup bg)
{
//根据枝节点得到一个立方位形的范围空间
BoundingBox boundBox = new BoundingBox(bg.getBounds());
Point3d upper = new Point3d();
//范围空间的XYZ轴在正方向的最大值载一个Point3d对象
boundBox.getUpper(upper);
//范围空间的XYZ轴在负方向的最大值载一个Point3d对象
Point3d lower = new Point3d();
boundBox.getLower(lower);
double max = 0.0;
//物体的长宽高三个数值中找出最大的一个值
if((upper.getX()-lower.getX())>max)
max = upper.getX()-lower.getX();
if((upper.getY()-lower.getY())>max)
max = upper.getY()-lower.getY();
if((upper.getZ()-lower.getZ())>max)
max = upper.getZ()-lower.getZ();
//计算比例因子,当值越接近0时,所显示的物体越小,当等于0时物体即不可见
double scaleFactor = 5/max;
if(scaleFactor<0.005)
scaleFactor = 0.005;
return new Vector3d(scaleFactor,scaleFactor*2,scaleFactor);
}
}
ColouredTile.java
view plaincopy to clipboardprint?
import java.util.ArrayList;
import javax.media.j3d.Appearance;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
public class ColouredTile extends Shape3D {
private ArrayList<Point3d> coord;
private Color3f color;
private QuadArray plane;
public ColouredTile(ArrayList<Point3d> coord,Color3f color) {
this.coord = coord;
this.color = color;
plane = new QuadArray(coord.size(),GeometryArray.COORDINATES | GeometryArray.COLOR_3);
createGeometry();
createAppearance();
}
public void createGeometry()
{
int numPoints = coord.size();
Point3d[] points = new Point3d[numPoints];
coord.toArray(points);
plane.setCoordinates(0, points);
Color3f[] colors = new Color3f[numPoints];
for(int i=0;i<numPoints;i++)
colors[i] = this.color;
plane.setColors(0, colors);
this.setGeometry(plane);
}
public void createAppearance()
{
Appearance app = new Appearance();
PolygonAttributes pa = new PolygonAttributes();
pa.setCullFace(PolygonAttributes.CULL_NONE);
app.setPolygonAttributes(pa);
this.setAppearance(app);
}
}
import java.util.ArrayList;
import javax.media.j3d.Appearance;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
public class ColouredTile extends Shape3D {
private ArrayList<Point3d> coord;
private Color3f color;
private QuadArray plane;
public ColouredTile(ArrayList<Point3d> coord,Color3f color) {
this.coord = coord;
this.color = color;
plane = new QuadArray(coord.size(),GeometryArray.COORDINATES | GeometryArray.COLOR_3);
createGeometry();
createAppearance();
}
public void createGeometry()
{
int numPoints = coord.size();
Point3d[] points = new Point3d[numPoints];
coord.toArray(points);
plane.setCoordinates(0, points);
Color3f[] colors = new Color3f[numPoints];
for(int i=0;i<numPoints;i++)
colors[i] = this.color;
plane.setColors(0, colors);
this.setGeometry(plane);
}
public void createAppearance()
{
Appearance app = new Appearance();
PolygonAttributes pa = new PolygonAttributes();
pa.setCullFace(PolygonAttributes.CULL_NONE);
app.setPolygonAttributes(pa);
this.setAppearance(app);
}
}
CheckedFloor.java
view plaincopy to clipboardprint?
import java.awt.Font;
import java.util.ArrayList;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;
import com.sun.j3d.utils.geometry.Text2D;
public class CheckerFloor {
private BranchGroup floor;
public CheckerFloor() {
floor = new BranchGroup();
}
public BranchGroup getBG() {
Color3f blue = new Color3f(0, 0, 1);
Color3f green = new Color3f(0, 1, 0);
boolean isBlue = true;
for (int j = -9; j < 10; j++) {
for (int i = -9; i < 10; i++) {
Point3d t1 = new Point3d(i, 0, j);
Point3d t2 = new Point3d(i + 1, 0, j);
Point3d t3 = new Point3d(i + 1, 0, j + 1);
Point3d t4 = new Point3d(i, 0, j + 1);
ArrayList<Point3d> tileCoord = new ArrayList<Point3d>();
tileCoord.add(t1);
tileCoord.add(t2);
tileCoord.add(t3);
tileCoord.add(t4);
if (isBlue)
floor.addChild(new ColouredTile(tileCoord, blue));
else
floor.addChild(new ColouredTile(tileCoord, green));
isBlue = !isBlue;
floor.addChild(makeText(new
Vector3f(i,0,j),"("+i+","+j+")"));
}
}
return floor;
}
public TransformGroup makeText(Vector3f pt, String text) { Color3f white = new Color3f(1, 1, 1);
Text2D message = new Text2D(text, white, "SansSerif", 36, Font.BOLD);
TransformGroup tg = new TransformGroup();
Transform3D t3d = new Transform3D();
t3d.setTranslation(pt);
tg.setTransform(t3d);
tg.addChild(message);
return tg;
}
}。

相关文档
最新文档