three.jsで多色グラデーション

three.jsで多色グラデーションを作る。
多色グラデーション
9頂点8平面で構成されるメッシュにShaderMaterialで作成した多色グラデーションを貼り付けている。多色グラデーションは頂点シェーダーとフラグメントシェーダーの組み合わせで実現する。

頂点シェーダー

attribute vec3 verpos;
attribute vec3 verrgb;
varying vec3 varingrgb;
void main() {
  gl_Position = projectionMatrix * modelViewMatrix * vec4(verpos, 1.0);
  varingrgb = verrgb;
}

フラグメントシェーダー

varying mediump vec3 varingrgb;
void main() {
  gl_FragColor = vec4(varingrgb, 1.0);
}

verposには頂点の座標、verrgbには頂点の色が渡り、varingrgbでフラグメントシェーダーに引き渡される。頂点シェーダーの処理はVertexに対するが、フラグメントシェーダーはピクセルに対するため、GLSLが色を案分することでグラデーションが実現する。

3D操作はOrbitControls.jsを使っている。
OrbitControls.js

以下は全ソース(html)です。
直下にthree.min.jsとOrbitControls.jsがあれば動作します。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>shade test</title>
  <script type="text/javascript" src="three.min.js"></script>
  <script type="text/javascript" src="OrbitControls.js"></script>
  <script type="text/javascript">
    var renderer;
    var camera;
    var controls;
    var scene;
    var container;
    var light;
    var light2;
    var mesh;
    var geometry;
    function shadetest() {
      init_threejs();
      init_scene();
      init_camera();
      init_light();
      init_object();
      reset_position();
      loop();
    }
    function init_threejs() {
      renderer = new THREE.WebGLRenderer({antialias: true});
      renderer.setClearColor(0xffffff, 1);
      renderer.setSize(1, 1);
      container = document.getElementById('canvas3d');
      container.appendChild(renderer.domElement);
    }
    function init_scene() {
      scene = new THREE.Scene();
    }
    function init_camera() {
      camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 100000);
      camera.up.x = 0;
      camera.up.y = 0;
      camera.up.z = 1;
      camera.position.set(0, 0, 5);
      controls = new THREE.OrbitControls(camera, renderer.domElement);
    }
    function init_light() {
      light = new THREE.DirectionalLight(0xcccccc, 1.6);
      light.position = new THREE.Vector3(-100, 500, 800);
      scene.add(light);
      light2 = new THREE.AmbientLight(0x333333);
      scene.add(light2);
    }
    function init_object() {
      var vertexPositions = [
        [-1.0, -1.0, 1.0],
        [0.0, -1.0, 1.0],
        [1.0, -1.0, 1.0],
        [-1.0, 0.0, 1.0],
        [0.0, 0.0, 1.0],
        [1.0, 0.0, 1.0],
        [-1.0, 1.0, 1.0],
        [0.0, 1.0, 1.0],
        [1.0, 1.0, 1.0]
      ];
      var vertexColors = [
        [1.0, 0.0, 0.0],
        [0.0, 1.0, 0.0],
        [0.0, 0.0, 1.0],
        [1.0, 1.0, 0.0],
        [0.0, 1.0, 1.0],
        [1.0, 0.0, 1.0],
        [0.5, 0.5, 0.0],
        [0.0, 0.5, 0.5],
        [0.5, 0.0, 0.5]
      ];
      var indices = new Uint16Array([
        0, 1, 4,
        1, 2, 4,
        2, 5, 4,
        5, 8, 4,
        8, 7, 4,
        7, 6, 4,
        6, 3, 4,
        3, 0, 4
      ]);
      var vertices = new Float32Array(vertexPositions.length * 3);
      var colors = new Float32Array(vertexPositions.length * 3);
      for (var i = 0; i < vertexPositions.length; i++) {
        vertices[i * 3 + 0] = vertexPositions[i][0];
        vertices[i * 3 + 1] = vertexPositions[i][1];
        vertices[i * 3 + 2] = vertexPositions[i][2];
        colors[i * 3 + 0] = vertexColors[i][0];
        colors[i * 3 + 1] = vertexColors[i][1];
        colors[i * 3 + 2] = vertexColors[i][2];
      }
      var shader = {
        fragmentShader: [
          "varying mediump vec3 varingrgb;",
          "void main() {",
            "gl_FragColor = vec4(varingrgb, 1.0);",
          "}"
        ].join("\n"),
        vertexShader: [
        
          "attribute vec3 verpos;",
          "attribute vec3 verrgb;",
          "varying vec3 varingrgb;",
          "void main() {",
            "gl_Position = projectionMatrix * modelViewMatrix * vec4(verpos, 1.0);",
            "varingrgb = verrgb;",
          "}"
        ].join("\n")
      }
      var material = new THREE.ShaderMaterial(
        {
          vertexShader: shader.vertexShader,
          fragmentShader: shader.fragmentShader
        }
      );
      var geometry = new THREE.BufferGeometry();
      geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
      geometry.setIndex(new THREE.BufferAttribute(indices,  1));
      geometry.addAttribute('verpos', new THREE.BufferAttribute(vertices, 3));
      geometry.addAttribute('verrgb', new THREE.BufferAttribute(colors, 3));
      var mesh = new THREE.Mesh(geometry, material);
      mesh.position.set(0, 0, 0);
      scene.add(mesh);
    }
    function reset_position() {
      var sz = {w:container.offsetWidth, h:container.offsetHeight};
      renderer.setSize(sz.w, sz.h);
      camera.aspect = sz.w / sz.h;
      camera.updateProjectionMatrix();
    }
    function loop() {
      requestAnimationFrame(loop);
      controls.update();
      renderer.clear();
      renderer.render(scene, camera);
    }
  </script>
</head>
<body onload="shadetest();" onresize="reset_position();">
  <div id="canvas3d" style="width:300px;height:300px;">
  </div>
</body>
</html>

1 thought on “three.jsで多色グラデーション”

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です