webGL      2018.06.18 ( 最終更新日:2021/01/12 )

【WebGL特集】第7回:影とアンチエイリアシング

※この記事は2013年の記事を2018年6月に加筆修正したものです。three.jsの使用バージョンはr92です。

【前記事】
【WebGL特集】第1回:WebGLって何?
【WebGL特集】第2回:回転する立方体
【WebGL特集】第3回:カメラをグリグリ
【WebGL特集】第4回:Blenderでモデル出力
【WebGL特集】第5回:Blenderでアニメーション出力
【WebGL特集】第6回:他のCGツールからBlenderへの移植

今回はアンチエイリアシングの設定をしてwebGLの表示をきれいにしてみます。

影ありなし比較

Scriptの記述

次のソースは、「第5回:Blenderでアニメーション出力」で作ったwebGLに、影とアンチエイリアシングの設定を与えたものです。
ハイライト部分が追記、修正した記述です。

<html>
<meta charset="utf-8">
<body>
<script src="build/three.min.js"></script>
<script src="js/controls/TrackballControls.js"></script>
<script>
var camera, scene, renderer, trackball, mixer;
var clock = new THREE.Clock();
var action ={};

init();

function init() {
//シーン
scene = new THREE.Scene();

//カメラ
camera = new THREE.PerspectiveCamera( 70, 640/480, 1, 2000 );
camera.position.set( 0, 50, 500 );
trackball = new THREE.TrackballControls( camera );

//ライティング
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1);
directionalLight.position.set(0,0,3);
scene.add( directionalLight );

var AmbientLight = new THREE.AmbientLight( 0xA9A9A9 ); // soft white light
scene.add( AmbientLight );

var SpotLight =  new THREE.SpotLight( 0xffffff );
SpotLight.position.set( -300, 500, 100 );
SpotLight.castShadow = true;//影
SpotLight.shadow.mapSize.width = 1024;
SpotLight.shadow.mapSize.height = 1024;
SpotLight.angle = 1;
SpotLight.castShadow = true;
SpotLight.shadow.camera.near = 200;
SpotLight.shadow.camera.far = 5000;
SpotLight.shadow.camera.fov = 30;
SpotLight.shadow.camera.visible = true;
scene.add( SpotLight );

//Blenderで出力したjsonオブジェクト
var loader = new THREE.JSONLoader();
loader.load( 'charaAni.json', function ( geometry, materials ) {
materials.forEach(function (material) { material.skinning = true; } );


var character = new THREE.SkinnedMesh( geometry, materials);
character.position.set(0, 0, 0);
character.scale.set(20, 20, 20);
character.castShadow = true;
character.receiveShadow = true;

//ANIMATION
mixer = new THREE.AnimationMixer(character);
action.dance = mixer.clipAction(geometry.animations[ 0 ]);
scene.add( character );
animate();
action.dance.play();
} );

//グリッド
var grid = new THREE.GridHelper( 1000, 10, 0x808080, 0x808080 );
grid.position.set( 0, 0, 0 );
scene.add( grid );

//グリッド 影専用
planeGeometry2 = new THREE.PlaneGeometry( 1000, 1000, 10, 10 );
planeMaterial2 = new THREE.MeshLambertMaterial( { color: 0xffffff });
planeMesh2 = new THREE.Mesh( planeGeometry2, planeMaterial2 );
planeMesh2.rotation.x = -90 * 2 * Math.PI / 360; //左に角度いれるとラジアンに変換
planeMesh2.receiveShadow = true; //影
scene.add( planeMesh2 );

//レンダラー
renderer = new THREE.WebGLRenderer( { antialias: true });
renderer.setSize( 640, 480 );
renderer.shadowMap.enabled = true;//影
renderer.setClearColor(new THREE.Color('white'));//背景色の設定
document.body.appendChild( renderer.domElement );
}

function animate() {
requestAnimationFrame( animate );
render();
}

function render() {
var delta = clock.getDelta();
mixer.update( delta );
renderer.render( scene, camera );
trackball.update();
}
</script>
</body>
</html>

See the Pen WebGLGreenManShadow by 住岡義和 (@mox-motion) on CodePen.

ソースの解説

影をつけるためには、オブジェクトとライトとレンダーの3つの設定を行います。
アンチエイリアシングは、レンダラーの設定でアンチエイリアシングをTrueにするだけです。

character.castShadow = true;
character.receiveShadow = true;


オブジェクトの影の設定です。castShadowプロパティでキャラに光が当たったときに、影のもとになるかどうかの設定をし、
receiveShadowプロパティで、キャラ自体に影を落とすかどうかを設定します。

//グリッド 影専用
planeGeometry2 = new THREE.PlaneGeometry( 1000, 1000, 10, 10 );
planeMaterial2 = new THREE.MeshBasicMaterial( { color: 0xffffff } );
planeMesh2 = new THREE.Mesh( planeGeometry2, planeMaterial2 );
planeMesh2.rotation.x = -90 * 2 * Math.PI / 360; //左に角度いれるとラジアンに変換
planeMesh2.receiveShadow = true; //影
scene.add( planeMesh2 );


必須ではありませんが。地面がワイヤーフレームなのでこのままでは影が投影されません。
影専用の板ポリゴンを用意してグリッドなのに影を無理やり投影させています。73行目のreceiveShadowで影を受ける設定をします。板ポリではなくBoxを平べったくしてもよいです。

var AmbientLight = new THREE.AmbientLight( 0xA9A9A9 ); // soft white light
scene.add( AmbientLight );

var SpotLight =  new THREE.SpotLight( 0xffffff );
SpotLight.position.set( -300, 500, 100 );
SpotLight.castShadow = true;//影
SpotLight.shadow.mapSize.width = 1024;
SpotLight.shadow.mapSize.height = 1024;
SpotLight.angle = 1;
SpotLight.castShadow = true;
SpotLight.shadow.camera.near = 200;
SpotLight.shadow.camera.far = 5000;
SpotLight.shadow.camera.fov = 30;
SpotLight.shadow.camera.visible = true;
scene.add( SpotLight );


ディレクションライトのみでは、影が落ちないので、スポットライトを設定しています。また擬似環境光としてアンビエントライトを設定しています。
影の設定はスポットライトのみに設定しています。32行目のcastShadowで影を放つ設定をしています。

renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( 640, 480 );
renderer.shadowMapEnabled = true;//影


77行目はアンチエイリアシングの設定です。webGLRendererの引数でantialiasプロパティをtrueにするだけでOKです。
79行目のshadowMap.enabledプロパティをTrueにすると、影もレンダリングされるようになります。

追記:影が妙に汚かったり、アーティファクトが出ているときは、両面ポリゴンになっていることがあります。jsonファイルをテキストで開き”doubleSided”:false,を削除してみてください。
また、ディレクションライトが強すぎるとアーティファクトが出やすくなります。

以上です。

次回はMaya、3dsMAXから直接、データを出力する方法を解説します。

【WebGL特集】第8回:各ツールからglTF形式でアニメーション出力

AUTHOR

sumioka