[three.js] 光の効果 (2)

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

threejs_effect2

WebGLRendererで描画するよ。
CylinderGeometry, MeshPhongMaterial, Mesh を使ってみたよ。 :bouzu:
んでもって、ImageUtils, Texture も使ったりして。 :beer:

HSV とか マテリアルの blending プロパティも使ってみたよ。 :bouzu:
あ!PointLight も使ってる。 :girl:

itoz 師匠 :hakase: のスクリプトをこっそり使わせてもらったよ。
@mrdoob 先生 :hakase: に、Object3D の代わりに Group を使うといいよって教えてもらったよ。 :sun:

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0">
<title>光の効果 (2) | three.js</title>
<script src="js/three.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 material, texture;
var container, lights, content, front, ground;
var light;
var id = 0;
var radius = 500;
var angle = - 90;
var degree = 0;
var depression = 15;
var radian = Math.PI/180;
var center = new THREE.Object3D();

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.PointLight(0xFFFFFF, 1, 200);
  scene.add(light);
  renderer = new THREE.WebGLRenderer({antialias: true});
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);
  setup();
  background();
  //initialize();
  THREE.ImageUtils.loadTexture("assets/light.png", undefined, loaded);

  stats = new Stats();
  stats.setMode(0);
  stats.domElement.style.position = "fixed";
  stats.domElement.style.right = "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, -100, 0);
}
function background() {
  var geometry = new THREE.PlaneGeometry(400, 400);
  var material = new THREE.MeshPhongMaterial({side: THREE.BackSide , color: 0xFFFFFF});
  material.emissive.set(0x333333);
  material.specular.set(0xFFFFFF);
  material.shininess = 16;
  ground = new THREE.Mesh(geometry, material);
  ground.rotation.x = 90*radian;
  ground.position.y = - 200;
  scene.add(ground);
}
function loaded(data) {
  texture = data;

  initialize();

  render();
}
function initialize() {
  container = new THREE.Group();
  scene.add(container);

  material = new THREE.MeshBasicMaterial({map: texture, side: THREE.DoubleSide});
  material.transparent = true;
  material.depthTest = false;
  lights = [];
  for (var n = 0; n < 3; n++) {
    var offset = 64*n;
    var geometry = new THREE.CylinderGeometry(0, 256 - offset, offset, 60, 15, true);
    var light1 = new THREE.Mesh(geometry, material.clone());
    light1.rotation.y = 120*n*radian;
    light1.position.y = - offset/2;
    var light2 = new THREE.Mesh(geometry, material.clone());
    light2.rotation.y = 120*n*radian;
    light2.rotation.x = 180*radian;
    light2.position.y = offset/2;
    var light3 = new THREE.Mesh(geometry, material.clone());
    light3.rotation.y = 120*n*radian;
    light3.rotation.x = 90*radian;
    light3.position.z = - offset/2;
    container.add(light1);
    container.add(light2);
    container.add(light3);
    lights.push(light1);
    lights.push(light2);
    lights.push(light3);
  }
  overlay();
}
function overlay() {
  content = new THREE.Group();
  scene.add(content);

  var geometry = new THREE.CylinderGeometry(0, 256, 0, 60, 15, true);
  var _material = material.clone();
  _material.blending = THREE.AdditiveBlending;
  front = new THREE.Mesh(geometry, _material);
  content.add(front);
  front.rotation.x = 90*radian;
}
function render() {
  requestAnimationFrame(render);

  var alpha = Math.random()*0.4 + 0.6;
  var hue = id + 40;
  var rgb = convert(hue, 1, 1);
  var argb = convert(hue, 1, 0.3*alpha);

  ground.material.specular.set(rgb);
  ground.material.shininess = 16*alpha;
  ground.material.color.set(argb);

  container.rotation.x += 0.1*radian;
  container.rotation.y += 0.2*radian;
  container.rotation.z += 0.15*radian;
  for (var n = 0; n < lights.length; n++) {
    rgb = convert(id + 10*n, 1, 1);
    var light = lights[n];
    light.rotation.y += 0.2*n*radian;
    light.material.opacity = alpha;
    light.material.color.set(rgb);
  }
  id = (id + 1)%360;

  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);

  front.rotation.y += 0.2*radian;
  front.material.opacity = 0.8*alpha;
  content.position.x = camera.position.x*0.08;
  content.position.y = camera.position.y*0.08;
  content.position.z = camera.position.z*0.08;
  content.lookAt(camera.position);

  renderer.render(scene, camera);

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

function convert(h, s, v) {
  var r, g, b, rgb;
  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 = Math.floor(h/60)%6;
  var f = (h/60) - i;
  var p = v*(1 - s);
  var q = v*(1 - f*s);
  var t = 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;
}
</script>
</body>
</html>


[修正] (14/12/03 Wed 00:40)
PerspectiveCamera の fov の値を 75 から 60 に変更。
[修正] (14/12/04 Thu 02:00)
コンテナとしての Object3D を Group に変更。
[修正] (14/12/07 Sun 20:16)
AmbientLight を使用せず、マテリアルの emissive プロパティの値を 0x333333 に設定。
[修正] (14/12/27 Sat 21:17)
HTML記述を変更。