Three.jsでハンドルを作る

3Dオブジェクトを操作させる時に何かと役に立つハンドルを作る。
今回は頂点のハンドルだ。
まずは9頂点8平面の矩形を作る。

var geometry = new THREE.Geometry();
for (var i = 0; i < vertexPositions.length; i++) {
  geometry.vertices.push(new THREE.Vector3(vertexPositions[i][0], vertexPositions[i][1], vertexPositions[i][2]));
}
for (var i = 0; i < indices.length; i++) {
  var face = new THREE.Face3(indices[i][0], indices[i][1], indices[i][2]);
  face.color = new THREE.Color(1.0, 0.0, 0.0);
  geometry.faces.push(face);
}
material = new THREE.MeshBasicMaterial({vertexColors: THREE.FaceColors});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

vertexPositionsとindicesは頂点及び面のデータ。
この頂点にハンドルを付けてみよう。

var point_material = new THREE.PointsMaterial({size: 0.5, color: 0x888888});
var point_geometry = new THREE.Geometry();
for (var i = 0; i < vertexPositions.length; i++) {
  point_geometry.vertices.push(new THREE.Vector3(vertexPositions[i][0], vertexPositions[i][1], vertexPositions[i][2]));
}
var points = new THREE.Points(point_geometry, point_material);
scene.add(points);

先ほどの9頂点8平面のオブジェクトと同じ位置に頂点を作成し、PointsMaterialでハンドルを作る。
sizeはハンドルの半径(矩形なので1/2幅)、colorは色。
これで以下のようになる。

因みに投影法は平行投影、3D操作はOrbitControlsを使う。

camera = new THREE.OrthographicCamera(-10, 10, 10, -10, 0, 10000);
camera.up.x = 0;
camera.up.y = 0;
camera.up.z = 1;
camera.position.set(0, 0, 10);
controls = new THREE.OrbitControls(camera, renderer.domElement);

それでは動かしてみよう。

こ、これは・・・。

平行投影なのに異常な遠近感がでてしまっている。
OrbitControlsとは相性が悪いのか。
THREE.Pointsの仕様を調べてみる。

.sizeAttenuation : Boolean
Specify whether points' size will get smaller with the distance. Default is true.

パラメータにsizeAttenuationというのがある。
距離によってポイントのサイズを小さくする・・・?
デフォルトはtrueだから、どうやらこのフラグが効いてるみたいだ。
offしてみよう。

var point_material = new THREE.PointsMaterial({size: 0.5, color: 0x888888, sizeAttenuation: false});

ハンドルが消えた。

sizeを少し大きくしてみよう。

表示された。
これは単位が変わったみたい。
どうやら物理単位のようだ。
ハンドルだから物理単位は便利だ。
sizeAttenuation=trueの時は論理単位で、且つ生成時のsizeに固定されているようで、しかも遠近がついてしまうところはハンドルとしては相応しくない。
さて、回転させてみる。

すべてうまくいった。
全ソースは以下です。

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>points 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.OrthographicCamera(-10, 10, 10, -10, 0, 10000);
			camera.up.x = 0;
			camera.up.y = 0;
			camera.up.z = 1;
			camera.position.set(0, 0, 10);
			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 = [
				[-5.0, -5.0, 5.0],
				[0.0, -5.0, 5.0],
				[5.0, -5.0, 5.0],
				[-5.0, 0.0, 5.0],
				[0.0, 0.0, 5.0],
				[5.0, 0.0, 5.0],
				[-5.0, 5.0, 5.0],
				[0.0, 5.0, 5.0],
				[5.0, 5.0, 5.0]
			];
			var indices = [
				[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 geometry = new THREE.Geometry();
			for (var i = 0; i < vertexPositions.length; i++) {
				geometry.vertices.push(new THREE.Vector3(vertexPositions[i][0], vertexPositions[i][1], vertexPositions[i][2]));
			}
			for (var i = 0; i < indices.length; i++) {
				var face = new THREE.Face3(indices[i][0], indices[i][1], indices[i][2]);
				face.color = new THREE.Color(1.0, 0.0, 0.0);
				geometry.faces.push(face);
			}
			material = new THREE.MeshBasicMaterial({vertexColors: THREE.FaceColors});
			var mesh = new THREE.Mesh(geometry, material);
			mesh.position.set(0, 0, 0);
			var point_material = new THREE.PointsMaterial({size: 10, color: 0x888888, sizeAttenuation: false});
			var point_geometry = new THREE.Geometry();
			for (var i = 0; i < vertexPositions.length; i++) {
				point_geometry.vertices.push(new THREE.Vector3(vertexPositions[i][0], vertexPositions[i][1], vertexPositions[i][2]));
			}
			var points = new THREE.Points(point_geometry, point_material);
			scene.add(mesh);
			scene.add(points);
		}
		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>

コメントを残す

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