[three.js] ライト (8) ~SpotLight, castShadow~

three.jsを使って、ライトについて調べてみるよ。 :boy:

threejs_light8

SpotLight を調べてみたよ。 :cake:  影をつけてみるよ。
レンダラー、ライト、影を落とす物体、影を落とされる物体の4つに設定が必要だよ! :beer:

@rect 先生 :hakase: の「note.x | [Papervision3D]ねぎ振り完了」から、Colladaデータとテクスチャをダウンロードさせていただきました。 :doki:

マテリアルのパラメータの値を変えてみてね。 :bouzu:
SpotLight のパラメータの値や位置も変えてみてね。 :bear:
dat.GUI を使ってみたよ。 :girl:

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0">
<title>ライト (8) | three.js</title>
<script src="js/three.min.js"></script>
<script src="js/loaders/ColladaLoader.js"></script>
<script src="js/createjs/easeljs-0.8.1.min.js"></script>
<script src="js/createjs/tweenjs-0.6.1.min.js"></script>
<script src="js/dat.gui.min.js"></script>
<script src="js/detector.js"></script>
<script src="js/stats.min.js"></script>
<style type="text/css">
  html { overflow:hidden; }
  body { margin:0; padding:0; }
</style>
</head>
<body style="background-color:#000000">
<script>
var scene, camera, renderer, stats;
var loader, negimiku, hand, arm, negi, plane, front, back;
var materials;
var light;
var radius = 500;
var angle = - 90;
var degree = 0;
var depression = 30;
var radian = Math.PI/180;
var center = new THREE.Object3D();
var filePath = "assets/negimiku/negimiku.dae";
var gui;

window.onload = init;

function init() {
  if (!Detector.webgl) Detector.addGetWebGLMessage();

  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(60, window.innerWidth/window.innerHeight, 0.1, 1000);
  scene.add(camera);
  light = new THREE.SpotLight(0xFFFFFF);
  scene.add(light);
  renderer = new THREE.WebGLRenderer({antialias: true});
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);
  setup();
  //initialize();
  loader = new THREE.ColladaLoader();
  loader.options.convertUpAxis = true;
  loader.load(filePath, loaded);

  var Slider = function() {
    this.ambient = 15;
    this.emissive = 3;
    this.specular = 1;
    this.shininess = 30;
    this.intensity = 1;
    this.distance = 800;
    this.exponent = 10;
    this.position = 180;
  };
  var slider = new Slider();
  gui = new dat.GUI();
  var slider1 = gui.add(slider, "ambient", 0, 15).step(1);
  var slider2 = gui.add(slider, "emissive", 0, 15).step(1);
  var slider3 = gui.add(slider, "specular", 0, 15).step(1);
  var slider4 = gui.add(slider, "shininess", 0, 100);
  var slider5 = gui.add(slider, "intensity", 0, 10);
  var slider6 = gui.add(slider, "distance", 0, 2000);
  var slider7 = gui.add(slider, "exponent", 0, 100);
  var slider8 = gui.add(slider, "position", 0, 360);
  slider1.onChange(function(value) {
    var rgb = 0x111111*value;
    //plane.material.ambient.set(rgb);
    front.material.ambient.set(rgb);
    back.material.ambient.set(rgb);
    for (var n = 0; n < materials.length; n++) {
      var material = materials[n];
      material.ambient.set(rgb);
    }
  });
  slider2.onChange(function(value) {
    var rgb = 0x111111*value;
    //plane.material.emissive.set(rgb);
    front.material.emissive.set(rgb);
    back.material.emissive.set(rgb);
    for (var n = 0; n < materials.length; n++) {
      var material = materials[n];
      material.emissive.set(rgb);
    }
  });
  slider3.onChange(function(value) {
    var rgb = 0x111111*value;
    //plane.material.specular.set(rgb);
    front.material.specular.set(rgb);
    back.material.specular.set(rgb);
  });
  slider4.onChange(function(value) {
    //plane.material.shininess = value;
    front.material.shininess = value;
    back.material.shininess = value;
    for (var n = 0; n < materials.length; n++) {
      var material = materials[n];
      material.shininess = value;
    }
  });
  slider5.onChange(function(value) {
    light.intensity = value;
  });
  slider6.onChange(function(value) {
    light.distance = value;
  });
  slider7.onChange(function(value) {
    light.exponent = value;
  });
  slider8.onChange(function(value) {
    var angle = (270 - value)%360;
    var px = 160*Math.cos(angle*radian);
    var pz = 160*Math.sin(angle*radian);
    light.position.set(-px, 400, -pz);
  });

  stats = new Stats();
  stats.setMode(0);
  stats.domElement.style.position = "fixed";
  stats.domElement.style.left = "0px";
  stats.domElement.style.top = "0px";
  document.body.appendChild(stats.domElement);

  render();
  window.addEventListener("resize", resize, false);
}
function setup() {
  renderer.setClearColor(0x000000, 1);
  camera.position.z = -radius;
  light.position.set(0, 400, -160);
  light.distance = 800;

  renderer.shadowMapEnabled = true;
  light.castShadow = true;
  light.shadowDarkness = 0.5;
  light.shadowMapWidth = 1024;
  light.shadowMapHeight = 1024;
  //light.shadowCameraVisible = true;

  materials = [];
}
function loaded(data) {
  negimiku = data.scene;
  for (var n in negimiku.children) {
    var child = negimiku.children[n];
    switch (child.name) {
      case "R_arm" :
        arm = child;
        break;
      case "negi" :
        negi = child;
        break;
    }
    var material = child.children[0].material;
    material.transparent = true;
    material.emissive.set(0x333333);
    materials.push(material);
    child.children[0].castShadow = true;
  }

  background();
  initialize();
  jump();
  swingHand();
}
function background() {
  plane = new THREE.Group();
  scene.add(plane);
  var geometry = new THREE.PlaneGeometry(400, 400, 4, 4);
  var fmaterial = new THREE.MeshPhongMaterial({color: 0xFFFFFF, side: THREE.BackSide});
  fmaterial.emissive.set(0x333333);
  var bmaterial = new THREE.MeshPhongMaterial({color: 0xFFFFFF, side: THREE.FrontSide});
  bmaterial.emissive.set(0x333333);
  front = new THREE.Mesh(geometry, fmaterial);
  back = new THREE.Mesh(geometry, bmaterial);
  plane.add(front);
  plane.add(back);
  front.rotation.x = 90*radian;
  back.rotation.x = 90*radian;
  plane.position.y = - 184;
  front.receiveShadow = true;
}
function initialize() {
  negimiku.rotation.y = 180*radian;
  negimiku.scale.set(12.6, 12.6, 12.6);
  scene.add(negimiku);
  negimiku.position.y = - 50;
  hand = new THREE.Group();
  negimiku.add(hand);
  hand.add(arm);
  hand.add(negi);
  //negimiku.castShadow = true;
}
function jump() {
  createjs.Tween.get(negimiku.position, {override: false, paused: false, loop: true, useTicks: true})
    .to({"y": 50}, 30, createjs.Ease.circOut)
    .to({"y": -50}, 30, createjs.Ease.circIn)
  ;
}
function swingHand() {
  createjs.Tween.get(hand.rotation, {override: false, paused: false, loop: true, useTicks: true})
    .to({"x": -40*radian}, 9, createjs.Ease.quadOut)
    .to({"x": 0}, 9, createjs.Ease.quadIn)
    .to({"x": 20*radian}, 6, createjs.Ease.quadOut)
    .to({"x": 0}, 6, createjs.Ease.quadIn)
  ;
}
function render() {
  requestAnimationFrame(render);

  createjs.Tween.tick(16, false);

  angle -= 0.5;
  degree += 1;
  var dip = depression*Math.sin(degree*radian);
  camera.position.x = radius*Math.cos(angle*radian)*Math.cos(dip*radian);
  camera.position.y = radius*Math.sin(dip*radian);
  camera.position.z = radius*Math.sin(angle*radian)*Math.cos(dip*radian);
  camera.lookAt(center.position);

  renderer.render(scene, camera);

  stats.update();
}
function resize(event) {
  camera.aspect = window.innerWidth/window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</body>
</html>


[修正] (14/12/17 Wed 15:35)
CreateJS 0.8.0 にバージョンアップ。
[修正] (14/12/27 Sat 21:23)
HTML記述を変更。
[修正] (15/09/20 Sun 23:44)
CreateJS 0.8.1 にバージョンアップ。