3D模型-3D建模不再复杂

时间:2024.3.31

3D模型-3D建模不再复杂

现实世界是个真实的三维空间,人眼特性就是看到近大远小的实物,所以能真实的感官距离和立体效果。我们在通过计算机传递信息时,普遍都显示的是2D平面的世界,后来有了视频能很好的表达信息,然而却不能真实的表达出现实的世界,于是科学家及相关技术人员开始研究计算机的三维技术。现在我们可以在计算机及各种移动终端设备上欣赏到真如实物般的3D模型,让人眼看上就像真的一样的视觉效果。

生活中,我们渐渐地开始接触3D、了解3D,于是很多需要利用3D模型展示物体商品的人群很想知道能方便快捷制作3D模型的技术,在网页上能够实现上下左右拖动、实现从不同角度观看3D模型。往往得到的答案是必须用到多种建模软件,这需要大量技术人员进行制作、抠图、渲染等等一系列繁琐的步骤,还要把3D模型转化成网页能直接识别和读取的3D模型其他格式的文件,一个被看到的完整3D模型用建模软件制作既耗时又耗力,成本也惊人。

基于照片的三维重建技术出现后,3D建模就变得非常简单,用户只需拍摄物体的一组序列照片,上传到3Dcloud平台就会自动生成3D模型,不需复杂的人工合成步骤也不需任何插件,直接就可获取3D模型,在3Dcloud平台还能储存、下载、分享3D模型等服务功能。


第二篇:在Java 3D中载入外部3D模型文件


在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.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

scrBitdepth,String title)

{

this.scrWidth = scrWidth;

this.scrHeight = scrHeight;

this.scrBitdepth = scrBitdepth;

scrHeight,int

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().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,

scrWidth+inset.right+inset.left,

scrHeight+inset.bottom+inset.top);

}

// 关闭窗体事件

public void closeFrame()

= scry-inset.top,

{

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 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);

}

scrHeight,int

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,

scrWidth+inset.right+inset.left,

scrHeight+inset.bottom+inset.top);

}

// 关闭窗体事件

public void closeFrame()

{

frame.dispose();

System.exit(0);

}

}

LoadModelDemo.java

view plaincopy to clipboardprint?

= scry-inset.top,

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有关的对象进行编译和缓存,如果在编译之后再次添加其它分支的话将抛异常

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();

//计算比例因子,当值越接近0时,所显示的物体越小,当等于0时物体即不可见

double scaleFactor = 5/max;

if(scaleFactor<0.005)

scaleFactor = 0.005;

return

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;

new

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有关的对象进行编译和缓存,如果在编译之后再次添加其它分支的话将抛异常

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();

//计算比例因子,当值越接近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;

}

}

更多相关推荐:
建筑模型制作心得体会

我们的模型可谓是凝结了无数的智慧与汗水,最终化成这个如诗如画搬雅致的山水中国馆。?质感。模型的每一个细节在材质上我们都经过精挑细选,颜色和肌理都尽力还原出建筑原有的味道。底座我们选用5mm厚的PVC板包上浅色牛…

建筑模型制作报告

学院:专业:年级:学号:姓名:指导教师:合肥学院建筑学12级(1)班120xx81026骆家伟张程王恺一、模型制作的时间:13—14学年8、9两周二、模型制作的目的本次实践是建筑学专业的综合性实践教学环节,旨在…

模型制作实习心得总结

实习时间:20xx.12.01—20xx.12.12实习地点:建筑模型制作教室实习目的:这次模型制作课程实习的主要目的是,通过动手操作方式来加强我们学生对空间的认识以及模型的制作能力,锻炼到我们做事情的耐性与细…

建筑模型总结

建模大赛总结本次浙江省东南网架杯第十届大学生结构设计竞赛在浙江大学紫荆港校区的临水报告厅完美的落下了帷幕本次竞赛共有84组参赛人员3人一组252名参赛学生很荣幸我站在了这支庞大而有力的队伍之中现在再回过头来看自...

20xx建筑模型设计实习总结

20xx建筑模型设计实习总结一目的与意义1这次建筑模型设计实习的主要是结合所学的初步课程知识通过搜索查找相关资料在动手操作中去加强提升学生对建筑空间的认识以及建筑模型的制作能力2通过这次建筑模型的实习进而培养学...

建筑模型制作报告

题目:建筑模型制作学生姓名:冯玉芝学号:1232203105院系:土木与环境工程学院专业:建筑设计技术20xx年x月x日一、实践目的本次实践是建筑设计专业的综合性实践教学环节,旨在培养我们的实际动手能力。其…

建筑模型制作报告

建筑模型制作报告林肯纪念馆学校专业年级学号姓名土木工程12级2班2108481212401郝歆跃北京建筑大学实验目的1在实践中提升学生造型审美能力2通过实际操作提高对材料和工艺的认识3提高学生的实践操作能力4了...

水工实验模型心得

水工模型试验与量测技术学习心得通过将近九周的课程学习让我了解到水工模型实验的一些知识和对科学学习的向往这项课程使我初步掌握各种水工建筑物模型试验的设计理论和方法模型制作的方法及试验量测的手段和仪器的使用为我进行...

建筑模型制作实验

建筑模型制作实验报告课程名称建筑模型制作学生姓名曾科学陈萍付志东韩洋洋李方方学院土木工程与建筑学院一实验目的这次模型制作主要目的是结合本学期对建筑模型制作课程的学习通过资料查找动手操作的方式来提高我们对建筑空间...

建筑模型制作报告

模型制作报告作者黄康轩土114学号前言经典建筑接个分析与模型制这个任务是我们大一下半学期科技活动周的主要任务由黄康轩谢法龙以及王立文组成的三人选择了古罗马穹顶艺术的最高成就罗马万神庙万神庙位于意大利首都罗马圆形...

建筑模型制作实验报告

学生实验报告课程名称学生学号所属院部理工类规划设计模型制作专业班级城乡规划学生姓名建筑工程学院指导教师刘琰20xx20xx学年第2学期金陵科技学院教务处制实验项目名称江宁校区总体规划模型制作实验学时24学时同组...

建筑法规学习心得

建筑法规学习心得系别城市规划设计系班级建设4班姓名栾亚飞我对建筑规范的理解和学习做设计作业时常常会觉得一定要和老师的设计任务符合本方案的建筑类型规范的要求所以建筑规范就成为了设计的一种负担那很正常刚学习建筑嘛不...

建筑模型心得(17篇)