[AwayJS] 光の効果 (2)

AwayJSを使って、光のエフェクトを作るよ。 :boy:

awayjs_effect2

Mesh を使ってみるよ。 :bouzu:
PrimitiveConePrefab と TriangleMethodMaterial を使ってみたよ。
そして、AssetLibrary で、外部画像を読み込んでみたよ。 :sun:

さらに、PrimitivePlanePrefab と PointLight も使ってみたよ。 :cake:

ColorTransform とか BlendMode も使ってみたよ。 :bouzu:

Main.ts
/// <reference path="libs/awayjs-core/build/awayjs-core.d.ts" />
/// <reference path="libs/awayjs-stagegl/build/awayjs-stagegl.d.ts" />
/// <reference path="libs/awayjs-renderergl/build/awayjs-renderergl.d.ts" />
/// <reference path="libs/awayjs-display/build/awayjs-display.d.ts" />
/// <reference path="libs/awayjs-methodmaterials/build/awayjs-methodmaterials.d.ts" />


import ContextGLProfile = require("awayjs-stagegl/lib/base/ContextGLProfile");
import DefaultRenderer = require("awayjs-renderergl/lib/DefaultRenderer");
import View = require("awayjs-display/lib/containers/View");
import Scene = require("awayjs-display/lib/containers/Scene");
import Camera = require("awayjs-display/lib/entities/Camera");
import PointLight = require("awayjs-display/lib/entities/PointLight");
import StaticLightPicker = require("awayjs-display/lib/materials/lightpickers/StaticLightPicker");
import Vector3D = require("awayjs-core/lib/geom/Vector3D");
import RequestAnimationFrame = require("awayjs-core/lib/utils/RequestAnimationFrame");
import DisplayObjectContainer = require("awayjs-display/lib/containers/DisplayObjectContainer");
import Mesh = require("awayjs-display/lib/entities/Mesh");
import Geometry = require("awayjs-display/lib/base/Geometry");
import PrimitiveConePrefab = require("awayjs-display/lib/prefabs/PrimitiveConePrefab");
import PrimitivePlanePrefab = require("awayjs-display/lib/prefabs/PrimitivePlanePrefab");
import TriangleMethodMaterial = require("awayjs-methodmaterials/lib/TriangleMethodMaterial");
import Texture2DBase = require("awayjs-core/lib/textures/Texture2DBase");
import AssetLibrary = require("awayjs-core/lib/library/AssetLibrary");
import LoaderEvent = require("awayjs-core/lib/events/LoaderEvent");
import URLRequest = require("awayjs-core/lib/net/URLRequest");
import ColorTransform = require("awayjs-core/lib/geom/ColorTransform");
import EffectColorTransformMethod = require("awayjs-methodmaterials/lib/methods/EffectColorTransformMethod");
import BlendMode = require("awayjs-display/lib/base/BlendMode");

class Main {

  private renderer:DefaultRenderer;
  private view:View;
  private scene:Scene;
  private camera:Camera;
  private timer:RequestAnimationFrame;
  private light:PointLight;
  private container:DisplayObjectContainer;
  private material:TriangleMethodMaterial;
  private texture:Texture2DBase;
  private lights:Array<Mesh>;
  private ground:Mesh;
  private reflection:TriangleMethodMaterial;
  private content:DisplayObjectContainer;
  private front:Mesh;
  private id:number = 0;
  private radius:number = 500;
  private angle:number = - 90;
  private degree:number = 0;
  private depression:number = 15;
  private radian:number = Math.PI/180;
  private center:Vector3D = new Vector3D();
  private filePath:string = "assets/light.png";

  constructor() {
    this.renderer = new DefaultRenderer(false, ContextGLProfile.BASELINE);
    this.renderer.antiAlias = 4;
    this.view = new View(this.renderer);
    this.scene = this.view.scene;
    this.camera = this.view.camera;
    this.light = new PointLight();
    this.setup();
    //this.initialize();
    window.onresize = (evt:UIEvent) => this.resize(evt);
    this.resize();
    this.timer = new RequestAnimationFrame(this.render, this);
    this.timer.start();
    AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, (evt:LoaderEvent) => this.loaded(evt));
    AssetLibrary.load(new URLRequest(this.filePath));
  }

  private setup():void {
    this.view.backgroundColor = 0x000000;
    this.camera.x = 0;
    this.camera.y = 0;
    this.camera.z = - this.radius;
    this.light.x = 0;
    this.light.y = 0;
    this.light.z = 0;
    this.light.ambient = 0.2;
    this.light.diffuse = 1;
    this.light.specular = 1;

    this.container = new DisplayObjectContainer();
    this.scene.addChild(this.container);
    this.lights = new Array<Mesh>();
    this.content = new DisplayObjectContainer();
    this.scene.addChild(this.content);
  }
  private loaded(evt:LoaderEvent):void {
    switch (evt.url) {
      case this.filePath :
        this.texture = <Texture2DBase> evt.assets[0];
        break;
    }
    if (this.texture) {
      this.initialize();
    }
  }
  private initialize():void {
    this.reflection = new TriangleMethodMaterial(0x333333, 1);
    var lightPicker:StaticLightPicker = new StaticLightPicker([this.light]);
    this.reflection.lightPicker = lightPicker;
    this.ground = <Mesh> new PrimitivePlanePrefab(400, 400, 20, 20, true, false).getNewObject();
    this.ground.material = this.reflection;
    this.ground.y = - 200;
    this.scene.addChild(this.ground);

    var method:EffectColorTransformMethod = new EffectColorTransformMethod();
    var colorTransform:ColorTransform = new ColorTransform();
    method.colorTransform = colorTransform;
    for (var n:number = 0; n < 3; n++) {
      var offset:number = 64*n;
      var light:Mesh = <Mesh> new PrimitiveConePrefab(256 - offset, offset, 60, 15, false, true).getNewObject();
      var geometry:Geometry = light.geometry;
      var material1:TriangleMethodMaterial = new TriangleMethodMaterial(this.texture);
      material1.bothSides = true;
      material1.alphaBlending = true;
      material1.addEffectMethod(method);
      //material1.blendMode = BlendMode.ADD;
      var light1:Mesh = new Mesh(geometry, material1);
      light1.rotationY = 120*n;
      light1.y = - offset/2;
      var material2:TriangleMethodMaterial = new TriangleMethodMaterial(this.texture);
      material2.bothSides = true;
      material2.alphaBlending = true;
      material2.addEffectMethod(method);
      //material2.blendMode = BlendMode.ADD;
      var light2:Mesh = new Mesh(geometry, material2);
      light2.rotationY = 120*n;
      light2.rotationX = 180;
      light2.y = offset/2;
      var material3:TriangleMethodMaterial = new TriangleMethodMaterial(this.texture);
      material3.bothSides = true;
      material3.alphaBlending = true;
      material3.addEffectMethod(method);
      //material3.blendMode = BlendMode.ADD;
      var light3:Mesh = new Mesh(geometry, material3);
      light3.rotationY = 120*n;
      light3.rotationZ = - 90;
      light3.x = - offset/2;
      this.container.addChild(light1);
      this.container.addChild(light2);
      this.container.addChild(light3);
      this.lights.push(light1);
      this.lights.push(light2);
      this.lights.push(light3);
      //geometry.dispose();
      light.dispose();
    }

    this.material = new TriangleMethodMaterial(this.texture);
    this.material.alphaBlending = true;
    this.material.blendMode = BlendMode.ADD;
    this.front = <Mesh> new PrimitiveConePrefab(256, 0, 60, 15, false, false).getNewObject();
    this.content.addChild(this.front);
    this.front.rotationY = 180;
    this.front.material = this.material;
  }
  private render(dt:number):void {
    var alpha:number = Math.random()*0.4 + 0.6;
    var rgb:number = this.convert(this.id + 40, 1, 1);
    if (this.reflection) {
      this.reflection.specularColor = rgb;
      this.reflection.specular = alpha;
    }
    this.light.ambientColor = rgb;
    this.light.ambient = 0.2*alpha;

    this.container.rotationX += 0.1;
    this.container.rotationY += 0.2;
    this.container.rotationZ += 0.15;
    var material:TriangleMethodMaterial;
    for (var n:number = 0; n < this.lights.length; n++) {
      rgb = this.convert(this.id + 10*n, 1, 1);
      var light:Mesh = this.lights[n];
      light.rotationY += 0.2*n;
      material = <TriangleMethodMaterial> light.material;
      material.alpha = alpha;
      if (material.colorTransform) {
        material.colorTransform.color = rgb;
      }
    }
    this.id = (this.id + 1)%360;

    this.angle += 0.5;
    this.degree += 1;
    var dip:number = this.depression*Math.sin(this.degree*this.radian);
    this.camera.x = this.radius*Math.cos(this.angle*this.radian)*Math.cos(dip*this.radian);
    this.camera.y = this.radius*Math.sin(dip*this.radian);
    this.camera.z = this.radius*Math.sin(this.angle*this.radian)*Math.cos(dip*this.radian);
    this.camera.lookAt(this.center);
    if (this.front) {
      this.front.rotationZ += 0.2;
      material = <TriangleMethodMaterial> this.front.material;
      material.alpha = 0.8*alpha;
    }
    this.content.x = this.camera.x*0.08;
    this.content.y = this.camera.y*0.08;
    this.content.z = this.camera.z*0.08;
    this.content.lookAt(this.camera.scenePosition);
    this.view.render();
  }
  private resize(evt:UIEvent = null):void {
    this.view.width = window.innerWidth;
    this.view.height = window.innerHeight;
  }

  private convert(h:number, s:number, v:number):number {
    var r:number, g:number, b:number;
    var rgb:number;
    v = 0xFF*v;
    while (h < 0) {
      h += 360;
    }
    h %= 360;
    if (s == 0) {
      v = Math.round(v);
      rgb = v << 16 | v << 8 | v;
      return rgb;
    }
    var i:number = Math.floor(h/60)%6;
    var f:number = (h/60) - i;
    var p:number = v*(1 - s);
    var q:number = v*(1 - f*s);
    var t:number = v*(1 - (1 - f)*s);
    switch (i) {
      case 0 :
        r = v;
        g = t;
        b = p;
        break;
      case 1 :
        r = q;
        g = v;
        b = p;
        break;
      case 2 :
        r = p;
        g = v;
        b = t;
        break;
      case 3 :
        r = p;
        g = q;
        b = v;
        break;
      case 4 :
        r = t;
        g = p;
        b = v;
        break;
      case 5 :
        r = v;
        g = p;
        b = q;
        break;
    }
    rgb = r << 16 | g << 8 | b;
    return rgb;
  }
}

window.onload = function() {
  new Main();
}

build.txt
src/Main.ts
-target ES5
-module commonjs
-outDir bin

build.txt 上で、[Command + B] して、ビルド。

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0">
<title>[AwayJS] 光の効果 (2)</title>
<script type="text/javascript" src="js/awayjs-core.min.js">/script>
<script type="text/javascript" src="js/awayjs-stagegl.min.js">/script>
<script type="text/javascript" src="js/awayjs-renderergl.min.js">/script>
<script type="text/javascript" src="js/awayjs-display.min.js">/script>
<script type="text/javascript" src="js/awayjs-methodmaterials.min.js">/script>
<script type="text/javascript" src="Main.js">/script>
<style type="text/css">
  html { overflow:hidden; }
  body { margin:0; padding:0; }
</style>
</head>
<body style="background-color:#000000;">
</body>
</html>

:caution: AwayJSでの注意点
マテリアルのColorTransformを使うためには、EffectColorTransformMethodを設定したうえでごにょごにょしないといけないらしい。


:banana: [TypeScript] AwayJSを始めよう! 参照。


[修正] (14/12/27 Sat 19:47)
HTML記述を変更。