您的位置:首页 > Web前端 > JavaScript

Three.js的学习心得

2014-09-12 09:42 609 查看
这几天自己一直在瞎琢磨Three.js,发现它的强大,也发现她的不易。我就我自己根据一个Demo自己写的一个小Demo来讲讲Three.js吧。

Three.js初始化的时候需要一点东西的首先是渲染的,就是叫Renderer的东西,这个东西好像还蛮厉害的,我没有深究也没有研究源代码,就是自己的理解啦,我现在才学习了几天而已。接着就是Camera,Scene,Light,灯光和很多都是要加到场景里的,不然就不会显示的。下面是几个重要部件的初始化代码:

Camera:

camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
camera.position.x = 250;//设置相机的位置坐标
camera.position.y = 250;//设置相机的位置坐标
camera.position.z = 250;//设置相机的位置坐标
camera.up.x = 0;//设置相机的上为「x」轴方向
camera.up.y = 1;//设置相机的上为「y」轴方向
camera.up.z = 0;//设置相机的上为「z」轴方向
Scene:

<span style="white-space:pre">	</span>    scene = new THREE.Scene();
Light:

<span style="white-space:pre">	</span>    light = new THREE.DirectionalLight(0xFFFFFF,1.0,0);//设置平行光DirectionalLight
light.position.set(1,1,1);//光源向量,即光源的位置

定义完这些我们就可以在上面添加我们自己的东西啦,Three.js里面有很多图形,就我现在用到的有正方体,球形还有其他的东西,这些东西API上都有的,可以看看API的,去官网下源码,里面有文档有例子的。我是借用是Demo上一个3D模型来用的,那个模型实现的是模型通过键盘控制运动的。我自己将他改了改,变成了按鼠标右键进行控制的,当然是无障碍的啦。这个部分最重要的要用到Projector,这个东西有个方法能够获得相机发出的射线,在通过这个射线和与物体相交的地方就能够获得交点了。

<span style="white-space:pre">	</span>    var vector = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1,
100 );
//projector.unprojectVector( vector, camera );
var ray = projector.pickingRay(vector, camera);
var intersects = ray.intersectObject(plane);

接着就是模型需要向着鼠标点击的方向,这个使用lookAt就可以了。下面是完整的源代码:Demo地址:http://wangxingyang.com.cn/htmls/testAndroid.html

原先的类似的Demo地址:http://wangxingyang.com.cn/htmls/3D.html

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>会动的机器人</title>
<script src="../js/three.min.js" ></script>
<script src="../js/OrbitControls.js"></script>
<script src="../js/Stats.js"></script>
<script src="../js/THREEx.KeyboardState.js"></script>
<!--<script src="js/three.min.js" ></script>-->
<!--<script src="js/OrbitControls.js"></script>-->
<!--<script src="js/Stats.js"></script>-->
<!--<script src="js/THREEx.KeyboardState.js"></script>-->
<!--<script src="js/thumbs.0.6.0.min.js"></script>-->
<script type="text/javascript">
var renderer,
stats,
camera,
controls,
scene,
light,
projector,
plane,
nowplace;
var android,
animOffset = 0, // starting frame of animation
walking = false,
duration = 1000, // milliseconds to complete animation
keyframes = 20, // total number of animation frames
interpolation = duration / keyframes, // milliseconds per frame
lastKeyframe = 0, // previous keyframe
currentKeyframe = 0;
var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();

function testAndroid ()
{
var SCREEN_WIDTH = window.screen.availWidth-25, SCREEN_HEIGHT = window.screen.availHeight-80;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;

document.getElementById('canvas3d').clientWidth = SCREEN_WIDTH-100;//获取画布「canvas3d」的宽
document.getElementById('canvas3d').clientHeight=SCREEN_HEIGHT;//获取画布「canvas3d」的高
renderer=new THREE.WebGLRenderer({antialias:true});//生成渲染器对象(属性:抗锯齿效果为设置有效)
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT );//指定渲染器的高宽(和画布框大小一致)
document.getElementById('canvas3d').appendChild(renderer.domElement);//追加 【canvas】 元素到 【canvas3d】 元素中。
renderer.setClearColor(0xFFFFFF, 1.0);//设置canvas背景色(clearColor)
/*添加状态显示*/
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById('canvas3d').appendChild(stats.domElement);
/*添加摄像机*/
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
controls = new THREE.OrbitControls(camera,renderer.domElement );
//controls.addEventListener('change', updateControls );
camera.position.x = 250;//设置相机的位置坐标
camera.position.y = 250;//设置相机的位置坐标
camera.position.z = 250;//设置相机的位置坐标
camera.up.x = 0;//设置相机的上为「x」轴方向
camera.up.y = 1;//设置相机的上为「y」轴方向
camera.up.z = 0;//设置相机的上为「z」轴方向
/*添加场景*/
scene = new THREE.Scene();
/*添加灯光*/
light = new THREE.DirectionalLight(0xFFFFFF,1.0,0);//设置平行光DirectionalLight
light.position.set(1,1,1);//光源向量,即光源的位置
scene.add(light);// 追加光源到场景
/*添加地面*/
var geometry = new THREE.PlaneGeometry( 1000, 1000 );
var material = new THREE.MeshBasicMaterial( {color: 0xff0000, side: THREE.DoubleSide} );
plane = new THREE.Mesh( geometry, material );
plane.rotation.x = 90*Math.PI/180;
scene.add( plane );
/*添加机器人*/
var jsonLoader = new THREE.JSONLoader();
jsonLoader.load( "../models/android-animations.js", addModelToScene );

/*添加事件*/
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDoc
4000
umentMouseUp, false );

projector = new THREE.Projector();
/*画面更新*/
animate();
};
//鼠标按下事件
function onDocumentMouseDown( event ) {
//remember mouse postion
var vector = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1,
100 );//使用projectpor转换
//projector.unprojectVector( vector, camera );
var ray = projector.pickingRay(vector, camera);//计算从相机发出的穿过近平面上mx my 点的射线
var intersects = ray.intersectObject(plane); //计算射线和 平面的所有交点 0 或者 1个
if(intersects.length > 0)
{
//存在交点
if(event.button==2)//右键点击
{
nowplace = intersects[0].point;
android.lookAt(nowplace);
console.log( 100 * delta);
walking =true;
}
}

}
//触摸事件
function onDocumentTouchStart( event ) {
//remember mouse postion
var vector = new THREE.Vector3(
( event.targetTouches[0].clientX / window.innerWidth ) * 2 - 1,
- ( event.targetTouches[0].clientY / window.innerHeight ) * 2 + 1,
100 );//使用projectpor转换
//projector.unprojectVector( vector, camera );
var ray = projector.pickingRay(vector, camera);//计算从相机发出的穿过近平面上mx my 点的射线
var intersects = ray.intersectObject(plane); //计算射线和 平面的所有交点 0 或者 1个
if(intersects.length > 0)
{
//存在交点
nowplace = intersects[0].point;
android.lookAt(nowplace);
//console.log(nowplace.x+":"+nowplace.y+":"+nowplace.z);
walking =true;
}

}
//鼠标移动
function onDocumentMouseMove( event ) {

}
//鼠标弹起
function onDocumentMouseUp( event ) {

}
function addModelToScene( geometry, materials )
{
// for preparing animation
for (var i = 0; i < materials.length; i++)
materials[i].morphTargets = true;

var material = new THREE.MeshFaceMaterial( materials );
android = new THREE.Mesh( geometry, material );
android.scale.set(5,5,5);
android.position.set(0,0,0);
scene.add( android );
}
function update() {
// delta = change in time since last call (seconds)
delta = clock.getDelta();
var moveDistance = 100 * delta;
//walking = false;

if(android&&walking)
{
if(Math.floor(android.position.z) != Math.ceil(nowplace.z) && Math.floor(android.position.x) != Math.ceil(nowplace.x)) {
android.translateZ(moveDistance);
//console.log(Math.floor(android.position.z)+":"+nowplace.z);
}else
{
walking =false;
}
}

controls.update();
stats.update();
// renderer.render(scene, camera);
};
function render()
{
if ( android&&walking ) // exists / is loaded
{
// Alternate morph targets
time = new Date().getTime() % duration;
keyframe = Math.floor( time / interpolation ) + animOffset;
if ( keyframe != currentKeyframe )
{
//console.log(currentKeyframe);
android.morphTargetInfluences[ lastKeyframe ] = 0;
android.morphTargetInfluences[ currentKeyframe ] = 1;
android.morphTargetInfluences[ keyframe ] = 0;
lastKeyframe = currentKeyframe;
currentKeyframe = keyframe;
}
android.morphTargetInfluences[ keyframe ] =
( time % interpolation ) / interpolation;
//console.log(( time % interpolation ) / interpolation);
android.morphTargetInfluences[ lastKeyframe ] =
1 - android.morphTargetInfluences[ keyframe ];
}

renderer.render( scene, camera );
};
function animate()
{
requestAnimationFrame(animate);
update();
render();
};
</script>
</head>

<body onload='testAndroid();'>
<div style="text-align: center;position: absolute; left: 400px; font-weight: bold">研究了好几天才完成的,例子给的是用方向键完成转向和行走,自己想用鼠标右键实现行走,类似Dota的。今天终于完成了,虽然走了很多弯路,但是还是开心极了。--支持触屏</div>
<div id="canvas3d"></div>
</body>
</html>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息