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

上传人:hjk****65 文档编号:172750677 上传时间:2022-12-06 格式:DOC 页数:25 大小:124.50KB
返回 下载 相关 举报
在Java 3D中载入外部3D模型文件_第1页
第1页 / 共25页
在Java 3D中载入外部3D模型文件_第2页
第2页 / 共25页
在Java 3D中载入外部3D模型文件_第3页
第3页 / 共25页
点击查看更多>>
资源描述
在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(filename); 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(filename); 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.javaview 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.javaview 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().getDefaultScreenDevice(); 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.isDisplayChangeSupported() 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().getDefaultScreenDevice(); 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().getDefaultScreenDevice();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);tryif(device.isFullScreenSupported()&device.isDisplayChangeSupported()device.setDisplayMode(new DisplayMode(scrWidth, scrHeight, scrBitdepth, DisplayMode.REFRESH_RATE_UNKNOWN);catch(IllegalArgumentException e)e.printStackTrace();System.exit(0);elseJOptionPane.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().getDefaultScreenDevice();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.javaview 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 TransformGroup4; sceneBG.addChild(objModel0 = loadModel(leet/Liit.obj,ObjectFile.RESIZE,new Vector3d(-5.4,0,0); sceneBG.addChild(objModel1 = loadModel(leet/Liit.obj,ObjectFile.REVERSE,new Vector3d(-1.8,0,0); sceneBG.addChild(objModel2 = loadModel(leet/Liit.obj,ObjectFile.TRIANGULATE,new Vector3d(1.8,0,0); sceneBG.addChild(objModel3 = loadModel(leet/Liit.obj,ObjectFile.STRIPIFY,new Vector3d(5.4,0,0); sceneBG.addChild(new CheckerFloor().getBG(); /对sceneBG有关的对象进行编译和缓存,如果在编译之后再次添加其它分支的话将抛异常 sceneBG.compile(); 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(filename); 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(); /计算比例因子,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 商业管理 > 营销创新


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!