Away3D TypeScriptではじめる3次元表現

第4回 床の追加とカメラのパン・チルト

この記事を読むのに必要な時間:およそ 12.5 分

前回は,第2回に書上げたコード第2回コード2を,2014年11月5日付のAway3D最新ビルドで動くように手直しした第3回コード1)。今回は,それにふたつ手を加えて仕上げよう。第1に,テクスチャが貼られた床を3次元空間に加える。そして第2に,マウスドラッグでカメラの視界が変えられるようにしたい。

テクスチャが貼られた床を加える

床は矩形の平面として3次元空間に加える。貼りつけるテクスチャは,ビーチボールと同じくAway 3D TypeScriptサイトの作例GitHub: StageGL Examplesにある素材から,floor_diffuse.jpgを使う。升目に敷石を並べたようなテクスチャだ図1)。

図1 石畳のようなテクスチャ

図1 石畳のようなテクスチャ

矩形の平面もボールのように,別に定める関数(createPlane())でつくることにする。引数には矩形の幅と高さ,およびライトに加えて,ボールの下に置きたいので垂直位置を与えた。

createPlane(幅, 高さ, ライト, 垂直位置)

平面をつくる関数(createPlane())は,つぎのように初期設定の関数(initialize())から呼び出す。床のテクスチャは,AssetLibrary.load()メソッドで読み込む。なお,View.sceneプロパティは,球体(sphere)と平面(plane)のふたつで参照するため,あらかじめローカル変数(scene)にとった。また,アニメーションで秒間60回の再描画をするため,ここであえてView.render()メソッドを呼び出すのは止めた。

var plane;

var planeDiffuse = "assets/floor_diffuse.jpg";
function initialize() {

  view = createView(240, 180, 0x0);
  var scene = view.scene;

  plane = createPlane(800, 800, directionalLight, -300);
  // view.scene.addChild(sphere);
  scene.addChild(sphere);
  scene.addChild(plane);
  AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);

  AssetLibrary.load(new URLRequest(planeDiffuse));

  // view.render();
  // view.render();
}

平面をつくる関数(createPlane())は,以下のように定めた。用いるプレハブのクラスがPrimitivePlanePrefabであることを除けば,組立ては球体をつくる関数(createSphere())と同じだ。PrimitivePlanePrefab()コンストラクタには幅と高さを引数に渡す。そして,球と同じくPrefabBase.getNewObject()メソッドでオブジェクトを得る。そして,マテリアルとライトを定め,垂直位置を動かしたら,平面のオブジェクトを返している。

new PrimitivePlanePrefab(幅, 高さ)
var PrimitivePlanePrefab = require("awayjs-display/lib/prefabs/PrimitivePlanePrefab");

function createPlane(width, height, light, y) {
  var material = new TriangleMethodMaterial();
  var plane = new PrimitivePlanePrefab(width, height).getNewObject();
  plane.material = material;
  material.lightPicker = new StaticLightPicker([light]);
  plane.y = y;
  return plane;
}

読み込んだテクスチャをLoaderEvent.RESOURCE_COMPLETEイベントのリスナー関数(onResourceComplete())で扱うことは変わらない。ただし,素材がビーチボールと石畳のふたつになったので,そのどちらが読込まれたのかを確かめなければならない。そのために,引数のイベントオブジェクトのLoaderEvent.urlプロパティを用いる。

LoaderEvent.urlプロパティは,読み込んだ素材のURLを文字列で示す。それを,あらかじめ変数(imageDiffuseとplaneDiffuse)に与えてあったURLと比べればよい。リスナー関数(onResourceComplete())は大幅に書き替えることになるため,つぎに関数本体すべてを抜書きした。LoaderEvent.assetsプロパティは素材の配列なので,for文ですべてを取り出す。そして,switch文でLoaderEvent.urlプロパティがどちらのURLかを確かめたうえで,そのマテリアルのテクスチャ(MaterialBase.textureプロパティ)に素材を定めた。

function onResourceComplete(eventObject) {
  var assets = eventObject.assets;
  // var material = sphere.material;
  var material;
  var count = assets.length;
  var url = eventObject.url;
  // material.texture = assets[0];
  for (var i = 0; i < count; i++) {
    var asset = assets[i];
    switch (url) {
      case (imageDiffuse):
        material = sphere.material;
        material.texture = asset;
        break;
      case (planeDiffuse):
        material = plane.material;
        material.texture = asset;
        break;
    }
  }
  // view.render();
}

これらの手が加えられたJavaScriptコードを以下にまとめたコード1)。これで,3次元空間の球体の下に平面が置かれ,石畳のテクスチャが与えられる図2)。床にはとくにアニメーションを定めていないので動かない。

図2 3次元空間のビーチボールの下に石畳の床が置かれた

図2 3次元空間のビーチボールの下に石畳の床が置かれた

コード1 3次元空間の球体の下にテクスチャの貼られた平面を置く

var LoaderEvent = require("awayjs-core/lib/events/LoaderEvent");
var AssetLibrary = require("awayjs-core/lib/library/AssetLibrary");
var URLRequest = require("awayjs-core/lib/net/URLRequest");
var RequestAnimationFrame = require("awayjs-core/lib/utils/RequestAnimationFrame");
var View = require("awayjs-display/lib/containers/View");
var DirectionalLight = require("awayjs-display/lib/entities/DirectionalLight");
var StaticLightPicker = require("awayjs-display/lib/materials/lightpickers/StaticLightPicker");
var PrimitiveSpherePrefab = require("awayjs-display/lib/prefabs/PrimitiveSpherePrefab");
var PrimitivePlanePrefab = require("awayjs-display/lib/prefabs/PrimitivePlanePrefab");
var DefaultRenderer = require("awayjs-renderergl/lib/DefaultRenderer");
var TriangleMethodMaterial = require("awayjs-methodmaterials/lib/TriangleMethodMaterial");
var view;
var sphere;
var plane;
var timer;
var imageDiffuse = "assets/beachball_diffuse.jpg";
var planeDiffuse = "assets/floor_diffuse.jpg";
function initialize() {
  var directionalLight = createDirectionalLight(0.25, 0xFFFFFF);
  view = createView(240, 180, 0x0);
  var scene = view.scene;
  sphere = createSphere(300, 32, 24, directionalLight);
  plane = createPlane(800, 800, directionalLight, -300);
  scene.addChild(sphere);
  scene.addChild(plane);
  AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
  AssetLibrary.load(new URLRequest(imageDiffuse));
  AssetLibrary.load(new URLRequest(planeDiffuse));
  timer = new RequestAnimationFrame(rotate);
  timer.start();
}
function createView(width, height, backgroundColor) {
  var defaultRenderer = new DefaultRenderer();
  var view = new View(defaultRenderer);
  view.width = width;
  view.height = height;
  view.backgroundColor = backgroundColor;
  return view;
}
function createSphere(radius, segmentsH, segmentsV, light) {
  var material = new TriangleMethodMaterial();
  var sphere = new PrimitiveSpherePrefab(radius, segmentsH, segmentsV)
  .getNewObject();
  sphere.material = material;
  material.lightPicker = new StaticLightPicker([light]);
  return sphere;
}
function createPlane(width, height, light, y) {
  var material = new TriangleMethodMaterial();
  var plane = new PrimitivePlanePrefab(width, height).getNewObject();
  plane.material = material;
  material.lightPicker = new StaticLightPicker([light]);
  plane.y = y;
  return plane;
}
function createDirectionalLight(ambient, color) {
  var light = new DirectionalLight();
  light.ambient = ambient;
  light.color = color;
  return light;
}
function onResourceComplete(eventObject) {
  var assets = eventObject.assets;
  var material;
  var count = assets.length;
  var url = eventObject.url;
  for (var i = 0; i < count; i++) {
    var asset = assets[i];
    switch (url) {
      case (imageDiffuse):
        material = sphere.material;
        material.texture = asset;
        break;
      case (planeDiffuse):
        material = plane.material;
        material.texture = asset;
        break;
    }
  }
}

著者プロフィール

野中文雄(のなかふみお)

ソフトウェアトレーナー,テクニカルライター,オーサリングエンジニア。上智大学法学部卒,慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。独立系パソコン販売会社で,総務・人事,企画,外資系企業担当営業などに携わる。その後,マルチメディアコンテンツ制作会社に転職。ソフトウェアトレーニング,コンテンツ制作などの業務を担当する。2001年11月に独立。Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。

URLhttp://www.FumioNonaka.com/

著書

コメント

コメントの記入