java3D--地月仿真模型

下边的图形是一个动画截图,是模拟地球和月亮的转情况­

图片­

一.显示3D物体的基本步骤:
1.创建一个用来容纳你的场景的虚拟宇宙(Virtual Universe)
2.创建一个用来放置一组物体的数据结构
3.向组中添加物体
4.放置观察者(Viewer)使之面对物体
5.将物体组添加至宇宙
例:
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.geometry.Sphere;
import javax.media.j3d.BranchGroup;
public class Hello3d{
  public Hello3d()
  {
   SimpleUniverse universe=new SimpleUniverse();
   BranchGroup group=new BranchGroup();
   group.addChild(new ColorCuble(0.3));
   universe.getViewingPaltform().setNominalViewingTransform();
   universe.addBranchGraph(group);
  }
  public static void main(String[] args){
   new Hello3d();
  }
}
 
二.点亮宇宙

这个例子说明了怎样显示一个被红光照亮的球
import coum.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d;
import javax.vecmath.*;
public class Ball{
   public Ball(){
       SimpleUniverse universe=new SimpleUniverse(); //创建宇宙
       BranchGroup group=new BanchGroup();  //创建容纳物体的结构
       Sphere sphere=new Sphere(0.5f);  //创建一个球体并加入到物体组
        group.addChild(sphere);
        Color3f light1Colo=new Color3f(1.8f,0.1f,0.1f);  //创建一个从在点延伸100米的红色光源
        BoundingSphere bounds=new BoundingSphere(new Point3d(0.0,0.0,0.0),100.0);
        Vector3f light1Direction=new Vector3f(4.0f,-7.0f,-12.0f);
        DirectionalLight light1=new DirectinalLight(light1color,light1Direction);
        light1.setinluencingBounds(bounds);
        group.addChild(light1);
        universe.getViewingPlatform().setNominalViewingTransform();   // 注视球体
         universe.addBranchGraph(group);
     }
    public static void main(String[] args){new Ball();}
}
我们创建的球体默认时是白色的,由于红色的灯光看起来它是红色.因为是定向光源(DirectionalLight),我们必须指定光线照射的距离和方向.在这个例子里,光线由原点照射100米,方向为向右.向下由屏幕向内(由向量定义:4.0向右,-7.0向下,-12.0向内).
你也可以建立一个产生无方向光的环境光源(AmbientLight),或者使用聚光灯(SpotLight)指向场景中某个特定部份.使用强有向光和弱些的环境光组合可以使你的场景有更自然的外观.Java3D光源不会产生阴影.

放置物体
在Java3D中,位置由XYZ坐标描述,X轴坐标值沿向右方向增长,Y轴向上,Z轴由屏幕向外.
旋转一个物体到场景中,你将从点(0,0,0)开始,然后移动物体到你想要的地方.移动物体被称为"变换(transformation)",所以你要使用的类是:TransformGroup和Transform3D.移动物体就要先把物体和Transform3D对象加入TransformGroup,再把TransformGroup放入场景中.
1.创建一个变换(transform),一个变换组(transformGroup)和物体
Transform=new Transform3D();
transformGroup tg=new TransformGroup();
Cone cone=new Cone(0.5f,0.5f);
2.为物体指定位置
Vector3fvector=new Vector3f(-.2f,.1f,-.4f);
3.设置Transform移动物体到指定位置
Transform.setTranslation(vector);
4.把Transform加入TransformGroup
tg.setTransform(transform);
5.把物体加入TransformGroup
tg.addChild(cone);
变换组TransformGroup允许把物体聚集在一起并作为一个整体移动
Transform3D类还可以改变物体大小,使物体绕某个坐标轴旋转
这个例子在每个坐标轴上显示不同物体。
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class Position {
public Position() {
SimpleUniverse universe = new SimpleUniverse();
BranchGroup group = new BranchGroup();
// X轴由球体组成
for (float x = -1.0f; x <= 1.0f; x = x + 0.1f)
{
Sphere sphere = new Sphere(0.05f);
TransformGroup tg = new TransformGroup();
Transform3D transform = new Transform3D();
Vector3f vector = new Vector3f( x, .0f, .0f);
transform.setTranslation(vector);
tg.setTransform(transform);
tg.addChild(sphere);
group.addChild(tg);}
// Y>轴由锥体组成
for (float y = -1.0f; y <= 1.0f; y = y + 0.1f)
{
TransformGroup tg = new TransformGroup();
Transform3D transform = new Transform3D();
Cone cone = new Cone(0.05f, 0.1f);
Vector3f vector = new Vector3f(.0f, y, .0f);
transform.setTranslation(vector);
tg.setTransform(transform);
tg.addChild(cone);
group.addChild(tg);}
// Z轴由柱体组成
for (float z = -1.0f; z <= 1.0f; z = z+ 0.1f)
{TransformGroup tg = new TransformGroup();
Transform3D transform = new Transform3D();
Cylinder cylinder = new Cylinder(0.05f, 0.1f);
Vector3f vector = new Vector3f(.0f, .0f, z);
transform.setTranslation(vector);
tg.setTransform(transform);
tg.addChild(cylinder);
group.addChild(tg);}
Color3f light1Color = new Color3f(.1f, 1.4f, .1f); // green light
BoundingSphere bounds =new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
Vector3f light1Direction= new Vector3f(4.0f, -7.0f, -12.0f);
DirectionalLight light1= new DirectionalLight(light1Color, light1Direction);
light1.setInfluencingBounds(bounds);
group.addChild(light1);
universe.getViewingPlatform().setNominalViewingTransform();
// 把物体组加入宇宙
universe.addBranchGraph(group);}
public static void main(String[] args) {new Position();}
}

三.外观
有很多方法改变你的场景中物体的外观.Apperance类包含了进行这些改变的功能
指定外观的最简单方式是指定颜色和描影方法.
1.建立物体 Shere sphere=new Sphere();
2.建立外观 Appearance ap=new Appearance();
3.建立颜色对象 Color3f col=new Color3f(0.0f,0.0f,1.0f);
4.创建色彩属性对象 ColoringAttributes ca=new ColoringAttributes(col,ColoringAttributes.NICEST);
5.把属性加入外观对象 ap.setColoringAttributes(ca);
6.设置外观 sphere.setAppearance(ap);

四.材质

Material对象有五个属性允许对你指定物体如何显示. 其中有四种颜色:环境Ambient 放射Emissive 漫射Diffuse 镜射Specular 发光度Shininess
环境交通反射在环境中发散方向无法确定的光线.
放射即使在黑暗中也可发出.可以用来作为霓虹灯或黑暗中发光的物体
漫射光反射来自一个方向的光线,所以当光线垂直射入表面时会更亮,因为光线几乎不会掠过表面.
镜面光来自一个特定方向,并且从一个最佳的方向弹出表面.
纹理
材质改变整个图形的外观,但有时最闪亮的物体也会看起来暗淡.通过添加纹理你能够制作出象大理石或二维图片包裹物体这样的效果.
纹理装载器(TextureLoader)类允许你装载一个图片作为纹理.图片的尺寸必须是2的幂.
装载纹理后,你可以改变TextureAttributes对象使图片替换下面的物体或修改下面的颜色。 你也可以应用它为帖图或把图片和你选择的颜色混合。
如果你在使用一个简单物体如球体,那你需要通过设置“原始标记”允许纹理化。这些可以在你创建物体的时候被设置为Primitive.GENERATE_NORMALS + Primitive.GENERATE_TEXTURE_COORDS 。
五.范例
你可以试着改变纹理设置并对比结果。你可以从
http://www.java3d.org/Arizona.jpg 下载我所使用的图片或者你也可以用你自己的替代。.

import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.image.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.Container;

public class PictureBall {

public PictureBall() {

// >创建宇宙
SimpleUniverse universe = new SimpleUniverse();

// >创建容纳物体的结构
BranchGroup group = new BranchGroup();

// >建立颜色
Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
Color3f red = new Color3f(0.7f, .15f, .15f);

// >建立纹理帖图
TextureLoader loader = new TextureLoader("K://3d//Arizona.jpg",
"LUMINANCE", new Container());
Texture texture = loader.getTexture();
texture.setBoundaryModeS(Texture.WRAP);
texture.setBoundaryModeT(Texture.WRAP);
texture.setBoundaryColor( new Color4f( 0.0f, 1.0f, 0.0f, 0.0f ) );

// >建立纹理属性
//>可以用REPLACE, BLEND >或 DECAL >代替 MODULATE
TextureAttributes texAttr = new TextureAttributes();
texAttr.setTextureMode(TextureAttributes.MODULATE);
Appearance ap = new Appearance();
ap.setTexture(texture);
ap.setTextureAttributes(texAttr);

//>建立材质
ap.setMaterial(new Material(red, black, red, black, 1.0f));

// >创建一个球来展示纹理
int primflags = Primitive.GENERATE_NORMALS +
Primitive.GENERATE_TEXTURE_COORDS;
Sphere sphere = new Sphere(0.5f, primflags, ap);
group.addChild(sphere);

// >创建灯光
Color3f light1Color = new Color3f(1f, 1f, 1f);
BoundingSphere bounds =
new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);

Vector3f light1Direction= new Vector3f(4.0f, -7.0f, -12.0f);
DirectionalLight light1
= new DirectionalLight(light1Color, light1Direction);
light1.setInfluencingBounds(bounds);
group.addChild(light1);

AmbientLight ambientLight =
new AmbientLight(new Color3f(.5f,.5f,.5f));
ambientLight.setInfluencingBounds(bounds);
group.addChild(ambientLight);

// >注视球体
universe.getViewingPlatform().setNominalViewingTransform();

// >把物体组加入宇宙
universe.addBranchGraph(group);
}
public static void main(String[] args) {
new PictureBall();
}
}
你也可以建立三维纹理,使用形体代替平面图片。不幸的是,这些目前还不能很好的跨平台工作。
六.特效
看看Java 3D里的AppearanceTest例子,有更多你可以使用的效果。例如你可以使用线框显示物体,显示物体的一角等等。你甚至可以使物体透明,使用以下设置:
TransparencyAttributes t_attr =
new TransparencyAttributes(TransparencyAttributes.BLENDED,0.5,
TransparencyAttributes.BLEND_SRC_ALPHA,
TransparencyAttributes.BLEND_ONE);
ap.setTransparencyAttributes( t_attr );
Java 3D 和用户界面
现实中很多应用程序混合使用三维、二维元素。这一节会说明如何使Java 3D和你程序的其它部分结合起来。
Canvas3D
每个用来绘制三维图形的区域被称为Canvas3D。这是一个包含了你场景中物体的视图的矩形。你可以放置Canvas在你的框架(Frame)中,然后建立一个宇宙显示在Canvas中。

下面的例子显示如何在一个上下都有标签(Label)的框架中创建Canvas。这个程序既可以作为Applet也可以作为应用程序运行。

import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.geometry.ColorCube;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import java.awt.GraphicsConfiguration;
import java.awt.BorderLayout;
import java.awt.Label;
import java.applet.Applet;
import com.sun.j3d.utils.applet.MainFrame;
public class CanvasDemo extends Applet {

public CanvasDemo(){

setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas = new Canvas3D(config);
add("North",new Label("This is the top"));
add("Center", canvas);
add("South",new Label("This is the bottom"));
BranchGroup contents = new BranchGroup();
contents.addChild(new ColorCube(0.3));
SimpleUniverse universe = new SimpleUniverse(canvas);
universe.getViewingPlatform().setNominalViewingTransform();
universe.addBranchGraph(contents);
}

public static void main( String[] args ) {
CanvasDemo demo = new CanvasDemo();
new MainFrame(demo,400,400);
}
}
Java 3D 和 Swing
Canvas3D利用了你机器的显示卡增强性能。不幸的是,这说明它不能很好地和Sun的swing用户界面组件混合。这些组件被称为“轻量”。轻量组件会被Canvas3D遮蔽即使想要把它们放在前方。

这是解决这个问题的几个方案:

• 你可以在同屏中混合使用轻量和重量组件,只要让它们在不同的容器中。

• 如果你使用弹出式菜单,JPopupMenu类的一个静态函数可以解决这个问题:
setDefaultLightWeightPopupEnabled(false);

• 你可以使用老式的AWT组件代替swing。
动画和交互 – 跳动的小球
想要制作动画你就要在动画的每一帧间移动物体。你可以使用计时器并且每次经过一个很短的时间移动物体。你也可以用其它方式修改物体,下面的例子缩放了小球使它看起来在每次碰撞时被压扁。

为了和用户交互,你可以处理按键或按钮点击或其它组件。

有一点需要注意的是你必须通过设置功能属性告诉Java 3D你要移动物体。否则一旦物体被绘制你将不能再移动它们。

objTrans = new TransformGroup();
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

下面的例子组合了这些技术。点击按钮使它启动,小球开始上下跳动,然后你可以按下a或s左右移动小球。

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.WindowAdapter;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.Sphere;
import javax.swing.Timer;

public class BouncingBall extends Applet implements ActionListener, KeyListener {
private Button go = new Button("Go");
private TransformGroup objTrans;
private Transform3D trans = new Transform3D();
private float height=0.0f;
private float sign = 1.0f; // going up or down
private Timer timer;
private float xloc=0.0f;
public BranchGroup createSceneGraph() {
// >创建分支图的根
BranchGroup objRoot = new BranchGroup();
objTrans = new TransformGroup();
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objRoot.addChild(objTrans);

// >创建一个简单图形叶子节点,添加到场景图。
Sphere sphere = new Sphere(0.25f);
objTrans = new TransformGroup();
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
Transform3D pos1 = new Transform3D();
pos1.setTranslation(new Vector3f(0.0f,0.0f,0.0f));
objTrans.setTransform(pos1);
objTrans.addChild(sphere);
objRoot.addChild(objTrans);
BoundingSphere bounds =
new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
 
Color3f light1Color = new Color3f(1.0f, 0.0f, 0.2f);
Vector3f light1Direction= new Vector3f(4.0f, -7.0f, -12.0f);
DirectionalLight light1
= new DirectionalLight(light1Color, light1Direction);
light1.setInfluencingBounds(bounds);
objRoot.addChild(light1);

// >设置环境光
Color3f ambientColor = new Color3f(1.0f, 1.0f, 1.0f);
AmbientLight ambientLightNode = new AmbientLight(ambientColor);
ambientLightNode.setInfluencingBounds(bounds);
objRoot.addChild(ambientLightNode);

return objRoot;
}

public BouncingBall() {
setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
Canvas3D c = new Canvas3D(config);
add("Center", c);
c.addKeyListener(this);
timer = new Timer(100,this);
//timer.start();
Panel p =new Panel();
p.add(go);
add("North",p);
go.addActionListener(this);
go.addKeyListener(this);
// >创建一个简单场景附加到虚拟宇宙
BranchGroup scene = createSceneGraph();

SimpleUniverse u = new SimpleUniverse(c);
u.getViewingPlatform().setNominalViewingTransform();
u.addBranchGraph(scene);
}
public void keyPressed(KeyEvent e) {
//>按键被按下时调用
if (e.getKeyChar()=='s') {xloc = xloc + .1f;}
if (e.getKeyChar()=='a') {xloc = xloc - .1f;}
}

public void keyReleased(KeyEvent e){
// >按键放开是被调用
}
public void keyTyped(KeyEvent e){
//>按一个键时调用
}
public void actionPerformed(ActionEvent e ) {
// >按钮按下时启动计时器
if (e.getSource()==go){
if (!timer.isRunning()) {
timer.start();
}
}
else {
height += .1 * sign;
if (Math.abs(height *2)>= 1 ) sign = -1.0f * sign;
if (height<-0.4f) {
trans.setScale(new Vector3d(1.0, .8, 1.0));
}
else {
trans.setScale(new Vector3d(1.0, 1.0, 1.0));
}
trans.setTranslation(new Vector3f(xloc,height,0.0f));
objTrans.setTransform(trans);
}
}
public static void main(String[] args) {
System.out.println("Program Started");
BouncingBall bb = new BouncingBall();
bb.addKeyListener(bb);
MainFrame mf = new MainFrame(bb, 256, 256);
}}

  JAVA3D 旋转
在3D游戏中有一个共同的特征就是玩家可以更改视角,这样就使得他(她)可以从不同的角度观察3D世界。旋转视角有时仅仅被认为一个特征或者一个不错的效果,然而有时它却是一个游戏的主要部分。无论你更改视角的目的是什么,实现这种效果的技术都并非十分难以把握。然而,采用的方式却完全不是你期望的那一种。在3D编程中普遍采用的解决方法是旋转和移动你的3D模型,而照相机(译者注:照相机相当于观察者)却保持静止不动。并非是在重新计算你的场景前在3D空间中移动和旋转照相机到不同的位置。

        在不探究任何细节的前提下,采用这种方式的主要原因就是它非常便于实际操作。假如你移动和旋转照相机将会需要很多3D到2D的复杂变换,然而你假如移动和旋转模型,这种变换将会减少很多。

       注重,当使用旋转3D世界代替照相机时,你不得不认为这样做有一些“落后”。照相机20度的旋转必须通过模型的-20度的旋转来模拟。

        本文例子中的MIDlet展示了在Sony EriCsson K700中如何使用3D引擎旋转3D模型。这些代码遵循一个最基础的思想——应该如何简单地操纵一个3D动画。例子中的3D模型和动画由一个3D建模工具创建,然后导出并转化为“mbac”文件(模型)、“mtra”文件(动画数据)和普通的“bmp”文件(纹理)。这些文件都可以很轻易被3D引擎导入,剩下的需要Java编码实现的或多或少的就是灯光的设置,当然在这个例子中还有旋转的逻辑。

        使用操作杆(方向键)旋转模型,按下fire按钮(方向键中间的按钮)改变动画。
通过这篇文章我们可以得到的信息并不多,下面我们共同来看一下例子中的源代码,分析一下旋转的实现过程。通过阅读代码我们可以发现,实现旋转效果的核心代码其实只有下面的几行:
d1_xtrans.rotationX (rotX); // X轴旋转
d1_ytrans.rotationY (rotY); // Y轴旋转
d1_ztrans.rotationZ (0); // 我们不作Z轴的旋转
所以实现旋转最重要的三个方法就是:rotationX(int)、rotationY(int)和rotationZ(int)。rotationX()方法是指在右手坐标系中以X轴为轴心旋转,旋转方向的定义为从X轴正方向观察是逆时针方向,也就是由Y轴向Z轴旋转,并且Y轴和Z轴(正方向)所组成的角的度数逐渐减小,如下图所示:


方法传入的参数是旋转的角度,这个角度是相对于0度位置来说的,所以要实现顺时针旋转时,只需要本次旋转的角度值小于上次旋转的角度值即可,例子中通过rotX -= rotPlus实现。因为在Micro3D中将0-1范围的值转化为了0-4096的整数,所以4096就相当于2π。rotationY()和rotationZ()的作用和rotationX()方法类似,所不同的就是分别是以Y轴和Z轴为旋转轴。

        请注重,rotation后面的是旋转轴而不是旋转方向,因此在X方向旋转时就需要改变rotY的值,而在Y方向旋转时就需要改变rotX的值。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值