2006年度 システム情報科学特別演習(イントロダクトリセミナー)

サイバーフィールド実習
実世界の3次元モデル構築 第2日目

担当:システム環境情報学研究室 小野里 雅彦/伊達 宏昭
最終改訂:2006年4月18日

第2日目の演習の概要

第2日目の演習では,オブジェクト指向プログラミング言語Javaの機能拡張版 Java3Dを用いて,3次元のモデリングとコンピュータグラフィックスの基礎を 体験します.またJavaのプログラミング開発環境としてEclipseを使用します. 元々はJavaはSun Microsystems, EclipseはIBMがそれぞれ膨大な人員と経費を投入して 開発を行って来ましたが,現在はオープンなソフトウェア資源として 広く,無料で使用することができます.

Java,Eclipse, Java3Dを90分の演習の中で駆け足で使っていきます. なお,参考図書として演習場所には Java3DとEclipseの参考書がおいてありますので,必要に応じて参照してください. また,インターネット上にも優れた解説などが数多くあります. 研究室に配備してある参考文献としては,

があります.(5冊) 参考にしてください.

JAVA3Dのサンプルプログラム

Eclipseの使い方の初歩については,Eclipseの参考図書の「3.1 はじめてのJDT」 をやってみてください.それで必要最低限のことができるはずです.

それがわかったら,次にEclipseを起動して,新しいプロジェクトを定義します.皆さんの名前を 使うとよいでしょう.そこに,Simple3Dという名称のクラスを新規に作成します. ここではインターネットブラウザから呼び出されるアプレット(Applet)の形式で 作成しましょう. 以下の内容を入力するとSimple3D.javaという名称のファイルが作成されます.

import java.applet.Applet;
import java.awt.BorderLayout;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class Simple3D extends Applet
{
	private Canvas3D s3dcanvas;
	private SimpleUniverse universe;

	public void init()
	{
		s3dcanvas=new Canvas3D(SimpleUniverse.getPreferredConfiguration());
		universe=new SimpleUniverse(s3dcanvas);
		
		universe.getViewingPlatform().setNominalViewingTransform();
		universe.addBranchGraph(createSceneGraph());
		
		setLayout(new BorderLayout());
		add(s3dcanvas,BorderLayout.CENTER);
	}

	private BranchGroup createSceneGraph()	
	{
		BranchGroup sceneroot;
	
		sceneroot=new BranchGroup();
		sceneroot.addChild(new ColorCube(0.5));	
		
		return sceneroot;
	}
}

これをEclipseの環境の中で,Javaアプレットして実行してみてください. 各面が塗り分けられた立体が表示されたでしょうか?

もう少し複雑なプログラム

つぎにもう少し複雑な形状を表示するプログラムを作成してみます. 次のプログラムを入力して実行してみましょう.クラスの名称はNext3Dです.
import java.applet.Applet;
import java.awt.BorderLayout;

import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.vp.*;
import com.sun.j3d.utils.universe.*;

public class Next3D extends Applet
{
	private Canvas3D canvas;
	private SimpleUniverse universe;
	
	public void init()
	{
		canvas=new Canvas3D(SimpleUniverse.getPreferredConfiguration());
		universe=new SimpleUniverse(canvas);

		universe.getViewingPlatform().setNominalViewingTransform();
		universe.getViewingPlatform().setViewPlatformBehavior(createPlatformBehavior());
		universe.addBranchGraph(createSceneGraph());
		setLayout(new BorderLayout());
		add(canvas,BorderLayout.CENTER);
	}
	
	private BranchGroup createSceneGraph()
	{
		BranchGroup root;
		TransformGroup transformA;
		Transform3D rotation,rotationX,rotationY;
		
		root=new BranchGroup();
		rotationX=new Transform3D();
		rotationX.rotX(Math.PI/4.0);
		rotationY=new Transform3D();
		rotationY.rotY(Math.PI/5.0);
		rotation=new Transform3D();
		rotation.mul(rotationX,rotationY);
		transformA=new TransformGroup(rotation);

		transformA.addChild(createPolygon());
		transformA.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		root.addChild(transformA);
		return root;
	}

	private Shape3D createPolygon()
	{
		Point3d[] vcoords ={
		new Point3d(0.0, -1.0, 0.0),
		new Point3d(2.0, 0.0, 1.0),
		new Point3d(2.0, 0.0, -1.0),
		new Point3d(2.0, 1.0, -1.0),
		new Point3d(2.0, 1.0, 1.0),
		new Point3d(-2.0, 0.0, 1.0),
		new Point3d(-2.0, 0.0, -1.0),
		new Point3d(-2.0, 1.0, -1.0),
		new Point3d(-2.0, 1.0, 1.0),
		new Point3d(1.0, 2.0, 0.5),
		new Point3d(1.0, 2.0, -0.5),
		new Point3d(-1.0, 2.0,-0.5),
		new Point3d(-1.0, 2.0, 0.5)
		};
		
		int[] indices = { 0, 2, 1,  // 0
						0, 6, 2,    // 1
						0, 5, 6,    // 2
						0, 1, 5,
						1, 3, 4,
						1, 2, 3,
						2, 7, 3,
						2, 6, 7,
						5, 8, 7,
						5, 7, 6,
						1, 4, 8,
						1, 8, 5,
						4, 3, 9,
						3, 10, 9,
						3, 11, 10,
						3, 7, 11,
						8, 12, 11,
						8, 11, 7,
						4, 9, 12,
						4, 12, 8,
						9, 10, 11,
						9, 11, 12};  //21
		
		Color3f[] colors = { new Color3f(1.0f, 0.0f, 0.0f),		// 0 red
							 new Color3f(0.0f, 1.0f, 0.0f),		// 1 green
							 new Color3f(0.0f, 0.0f, 1.0f),		// 2 blue
							 new Color3f(0.0f, 1.0f, 1.0f),		// 3 cyan
							 new Color3f(1.0f, 0.0f, 1.0f),		// 4 magenta
							 new Color3f(1.0f, 1.0f, 0.0f),		// 5 yellow
							 new Color3f(1.0f, 1.0f, 1.0f)};	// 6 white
		int[] colorIndices = { 0, 0, 0,
							   1, 1, 1,
							   2, 2, 3,
							   3, 3, 3,
							   4, 4, 4, 4, 4, 4,
							   5, 5, 5, 5, 5, 5,
							   2, 2, 2, 6, 6, 6,
							   0, 0, 0, 0, 0, 0,
							   3, 3, 3, 3, 3, 3,
							   3, 3, 3, 2, 2, 2,
							   3, 3, 3, 3, 3, 3,
							   5, 5, 5, 3, 3, 3,
							   0, 0, 0, 0, 0, 0
		};
		
			IndexedTriangleArray	geometry;
			Material mat=new Material();
			Appearance appearance = new Appearance();
			mat.setDiffuseColor(new Color3f(0.0f, 0.0f, 1.0f));
			
			geometry=new IndexedTriangleArray(vcoords.length,
						IndexedTriangleArray.COORDINATES | IndexedTriangleArray.COLOR_3,
						indices.length);
			geometry.setCoordinates(0, vcoords);
			geometry.setCoordinateIndices(0,indices);
			geometry.setColors(0, colors);
			geometry.setColorIndices(0, colorIndices);
			Shape3D shape = new Shape3D(geometry);
			return shape;
		}
	
	private ViewPlatformBehavior createPlatformBehavior()
	{
		ViewPlatformBehavior	cameraBehavior;
		BoundingSphere bounds;
		bounds = new BoundingSphere(new Point3d(),
				Double.POSITIVE_INFINITY);
		cameraBehavior=new OrbitBehavior(canvas);
		cameraBehavior.setSchedulingBounds(bounds);
		
		return cameraBehavior;
	}
}
このプログラムではマウスによって表示を変化させることができます. 左ボタンを押しながら上下左右にドラッグするとみる方向の変化, 中ボタンを押しながら上下にドラッグすると視線方向で前後します. また,右ボタンを押しながら上下左右にドラッグすると,視点の平行移動が 生じます.

前回,VRMLをやっていますので,ここで形状定義に関してはおおよそ予想がつくのでは ないでしょうか? またここでは面に色を与えています.自分で座標や形状,色の値などを いろいろと修正をしてみて,表示がどのように変化するかを確認してみてください.

また,Java 3DにはVRMLローダーのパッケージを追加することで,VRML97のファイルを 読み込んでJava 3Dの世界で扱うことができます.これに関しては最終回の演習で挑戦 してみることにしましょう.


演習担当:
     小野里 雅彦まで.
onosato@ssi.ist.hokudai.ac.jp  情報科学研究科棟5-14 内線6435