最近在学习threejs,是一个基于webgl的三维库
web前端开发人员可以直接用webgl 接口进行编程,但webgl只是非常基础的绘图API,需要编程人员有很多的数学知识、绘图知识才能完成3D编程任务,而且代码量巨大。threejs 对webgl进行了封装,让前端开发人员在不需要掌握很多数学知识和绘图知识的情况下,也能够轻松进行web 3D开发,降低了门槛,同时大大提升了效率。
想用threejs 实现一个旋转的门效果,效果如下:
涉及到的知识点有 纹理贴图、对象沿轴旋转、灯光渲染、摄像机运动等
1.准备threejs文件
将three.js复制到该HTML文件所在的目录下的js/目录下
2.跨域问题
因为代码中涉及到加载本地图像,会遇到浏览器禁止跨域加载的问题。解决方法可以参考下面这篇教程。
3.threejs 纹理
下面博客是对threejs中不同纹理使用方式的介绍,比较详细:
宫本勇次:关于Three.js-网格材质种类总结
我们可以通过MeshLambertMaterial 实现对一个扁平的长方体贴上门的纹理图像,并实现光漫反射的效果,其中map参数可以加载图像,用于将图像纹理贴在几何体上面,可以参考 http://www.linhongxu.com/post/view?id=222
4.threejs动画
threejs 很容易绘制一个 我们得到了一个静态的点、线、面,那么如果想让它动起来该怎么操作呢?
js 提供了requestAnimationFrame 这个函数,用法可以参考下面这个博客介绍
大概方案如下。
function draw(){
//`绘制代码
requestAnimationFrame(draw);//递归调用,实现循环绘制
//参数变化
}
通过 requestAnimationFrame 递归调用draw函数 实现循环绘制。
5.门沿着边沿旋转
three js 可以方便的对目标进行旋转,例如door是一个长方体,想让它在y轴方向旋转,那么只要在draw函数中,改变door.rotation.y的值就可以了,例如下面就表示每一帧沿着y轴 旋转0.01弧度
function draw(){
//`绘制代码
door.rotation.y += 0.01;//沿着y轴旋转0.01弧度
renderer.render( scene, camera );//绘制
requestAnimationFrame(draw);//递归调用,实现循环绘制
//参数变化
}
但是这样的旋转只能是目标沿着它的 y方向中心轴旋转,门一般都是沿着边沿旋转,所以直接旋转行不通(如下图所示)
解决方案如这个博客,把待旋转目标外面套一个父对象(Group),通过旋转父对象来实现。虽然父对象旋转依然是按照中心轴来旋转,但是如果待旋转目标 刚好占据父对象一半大小,那么父对象沿着中心轴来旋转,待旋转目标就能沿着边沿旋转。参考:three.js 对象绕任意轴旋转–模拟门转动
6.摄像机运动
如果想在门动的同时加入摄像机运动,可以在requestAnimationFrame 函数中,动态设置摄像机位置,例如下面代码中就通过三角函数值实现摄像机围绕目标实现
var cam_R = 50;//摄像机旋转半径
var theta = 0.01;//弧度值
function draw(){
//`绘制代码
camera.position.set( cam_R*Math.cos(theta), cam_R*Math.sin(theta), cam_R*Math.sin(theta) );
theta += 0.01;
renderer.render( scene, camera );//绘制
requestAnimationFrame(draw);//递归调用,实现循环绘制
//参数变化
}
完整 html 代码如下:
<!DOCTYPE html>
<html>
</style>
<head>
<meta charset=utf–8>
<title>My first three.js app</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
#info {
position: absolute;
top: px;
width: 100%;
text–align: center;
z–index: 100;
display:block;
}
</style>
</head>
<body>
<script src=“./js/three.js”></script>
<script>
// Our Javascript will go here.
var scene = new THREE.Scene();
// var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 0, 0, 50 );
camera.lookAt( 0, 0, 0 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// 创建门
const door = new THREE.BoxBufferGeometry(10, 20, 0.5);
// const doorMaterial = new THREE.MeshLambertMaterial({ color: 0xd88c00 , side: THREE.DoubleSide});
var materials = [
new THREE.MeshLambertMaterial( { map:new THREE.TextureLoader().load(“door.png”) } ), // right
new THREE.MeshLambertMaterial( { map:new THREE.TextureLoader().load(“door.png”) } ), // left
new THREE.MeshLambertMaterial( { map:new THREE.TextureLoader().load(“door.png”) } ), // top
new THREE.MeshLambertMaterial( { map:new THREE.TextureLoader().load(“door.png”) } ), // bottom
new THREE.MeshLambertMaterial( { map:new THREE.TextureLoader().load(“door.png”) } ), // front
new THREE.MeshLambertMaterial( { map:new THREE.TextureLoader().load(“door.png”) } ), // back
];
var cubeSidesMaterial = new THREE.MultiMaterial( materials );
const doorMesh = new THREE.Mesh(door, cubeSidesMaterial);
// 实现门围绕特定轴旋转
const group = new THREE.Group(); // 外层对象
group.position.set(–5, 10, 0); // 设置外层对象的中心为原本想要旋转的位置
group.add(doorMesh); // 把门添加进外层对象中
doorMesh.position.set(5, 0, 0); // 调整门在外层对象中的相对位置
scene.add( doorMesh );
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
//Create a PointLight and turn on shadows for the light
var light = new THREE.PointLight( 0xffffff, 1, 200 );
light.position.set( 20, 20, 0 );
light.castShadow = true; // default false
scene.add( light );
//Set up shadow properties for the light
light.shadow.mapSize.width = 512; // default
light.shadow.mapSize.height = 512; // default
light.shadow.camera.near = 1; // default
light.shadow.camera.far = 30 // default
//Create a helper for the shadow camera (optional)
var helper = new THREE.CameraHelper( light.shadow.camera );
scene.add( helper );
renderer.setClearColor(0xb9d3ff,1);//设置背景颜色
renderer.render( scene, camera );
var cam_R = 50;
var theta = 0.01;
var animate = function () {
requestAnimationFrame( animate );
camera.position.set( cam_R*Math.cos(theta), cam_R*Math.sin(theta), cam_R*Math.sin(theta) );
camera.lookAt( 0, 0, 0 );
theta += 0.01;
doorMesh.rotation.y += 0.01;
renderer.render( scene, camera );
};
animate();
</script>
</body>
</html>
暂无评论内容