water shader を試す

Posted :

water shader を試す

ocean - Realistic water shader for Three.jsの basic のデモをもう少し分解して整理してみた。

動く例

利用手順

  • 水面の凹凸に使うノーマルマップを読み込む
  • THREE.Water のインスタンスを作る
  • インスタンスの material プロパティーを平面のマテリアルにしてメッシュを作る
  • 描画アップデート時 (requestAnimationFrame) に
    • シェーダーに送るユニフォーム変数を更新する water.material.uniforms.time.value = 経過時間;
    • インスタンス.render(); して反射用のテクスチャーを作る。ただし drawcall 回数が倍くらいになるので throttle したり、必要なければ実行しないほうがいい

コード例

<script src="http://ajax.googleapis.com/ajax/libs/threejs/r67/three.min.js"></script>
<script src="water-material.js"></script>

<script>
var width, height, clock, scene, camera, renderer,
    directionalLight, ground, sphere, waterSurface,
    water, colorMap1, colorMap2, waterNormals;

width = window.innerWidth;
height = window.innerHeight;
clock = new THREE.Clock();
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 40, width / height, 1, 1000 );
camera.position.set( 0, 5, 30 );
renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
document.body.appendChild( renderer.domElement );

colorMap1 = new THREE.ImageUtils.loadTexture( 'stone.jpg' );
colorMap1.wrapS = colorMap1.wrapT = THREE.RepeatWrapping;
colorMap1.repeat.set( 3, 3 );

ground = new THREE.Mesh(
  new THREE.PlaneGeometry( 30, 30, 10, 10 ),
  new THREE.MeshBasicMaterial( { map: colorMap1 } )
);
ground.position.set( 0, -3, 0 );
ground.rotation.x = THREE.Math.degToRad( -90 );
scene.add( ground );

colorMap2 = new THREE.ImageUtils.loadTexture( 'grass.jpg' );

sphere = new THREE.Mesh(
  new THREE.SphereGeometry( 2, 16, 16 ),
  new THREE.MeshBasicMaterial( { map: colorMap2 } )
);
scene.add( sphere );

directionalLight = new THREE.DirectionalLight( 0xffff55 );
directionalLight.position.set( -100, 30, 100 );
scene.add(directionalLight);

// Load textures
waterNormals = new THREE.ImageUtils.loadTexture( 'waternormals.jpg' );
waterNormals.wrapS = waterNormals.wrapT = THREE.RepeatWrapping; 

// Create the water effect
water = new THREE.Water( renderer, camera, scene, {
  textureWidth: 256,
  textureHeight: 256,
  waterNormals: waterNormals,
  distortionScale: 20,
  noiseScale: .5,
  alpha: .8,
  sunDirection: directionalLight.position.normalize(),
  sunColor: 0xffffff,
  waterColor: 0x000000,
  side: THREE.DoubleSide
} );

waterSurface = new THREE.Mesh(
  new THREE.PlaneGeometry( 30, 30, 10, 10 ),
  water.material
);
waterSurface.add(this.water);
waterSurface.rotation.x = - Math.PI * 0.5;

scene.add(waterSurface);

;( function update () {

  var elapsed = clock.getElapsedTime()
  requestAnimationFrame( update );
  water.render();
  renderer.render( scene, camera );
  water.material.uniforms.time.value = elapsed;

} )();

</script>