threejs 形状几何体_ThreeJS学习笔记(五)——二维几何体元素及穿梭动画

二维几何体

ThreeJS可以创建三种二维几何体,包括CircleGeometry(圆形),PlaneGeometry(矩形),ShapeGeometry(自定义形状)。

创建二维几何体和创建三维几何体差不多,同样由形状和材质两个参数,拥有的属性也和三维几何体一样。

new THREE.Mesh(new THREE.PlaneGeometry(width, height, 1, 1 ),new THREE.MeshBasicMaterial(MaterialParam ));

需要注意的是,由于贴图的尺寸必须是(2的幂数)X (2的幂数),如:1024*512,所以为了防止贴图变形,平面的宽度比例需要与贴图的比例一致。

代码示例如下:

function createPlane(options){

// options={

// width:0,

// height:0,

// pic:"",

// transparent:true,

// opacity:1

// blending:false

// }

if(typeof options.pic=="string"){//传入的材质是图片路径,使用 textureloader加载图片作为材质

var loader = new THREE.TextureLoader();

loader.setCrossOrigin( this.crossOrigin );

var texture = loader.load( options.pic, function() {}, undefined, function(){});

}else{传入的材质是canvas

var texture= new THREE.CanvasTexture( options.pic )

}

var MaterParam={//材质的参数

map:texture,

overdraw: true,

side: THREE.FrontSide,

// blending: THREE.AdditiveBlending,

transparent: options.transparent,

//needsUpdate:true,

//premultipliedAlpha: true,

opacity:options.opacity

}

if(options.blending){

MaterParam.blending=THREE.AdditiveBlending//使用饱和度叠加渲染

}

var plane = new THREE.Mesh(

new THREE.PlaneGeometry( options.width, options.height, 1, 1 ),

new THREE.MeshBasicMaterial(MaterParam )

);

return plane;

}

在3维空间中还原平面元素在设计稿上的大小和位置

设计稿如下图,要求三维空间中,A元素和背景处于不同的深度,A元素位于背景前方

那么在三维空间中,与相机所在位置的相对空间位置如下图所示,

A在该平面元素在三维空间中的位置如上图所示,面B为A平面最终渲染在屏幕上的区域,此区域应该与设计稿上的A的大小一致,那必然就有一个问题,在三维空间中,A元素的大小和坐标要如何设置,才能使A在屏幕上的投影B能与设计稿上的一致?

这里我们需要做一些计算,计算中会用到以下已知数值:

fov:创建相机时设置的垂直方向的夹角,

W:canvas的width,这里以1920为示例

H:canvas的height,这里以1080为示例

D:相机与屏幕所在平面的距离,

d:相机与元素A的距离,

aw: 元素A在设计稿上的宽度

ah: 元素A在设计稿上的高度

ax: 元素A中点心在设计稿上的中心点X轴上的偏移值

ay: 元素A中点心在设计稿上的中心点Y轴上的偏移值

其中D可以视为在屏幕上投影面积为1920(W)*1080(H)的平面元素离相机的距离

计算公式为:D=H/(2*Math.tan(fov/2));

平面A在三维空间中尺寸与投影大小(即设计稿上的尺寸)的缩放倍数为

zoom=d/D=d*2*Math.tan(fov/2)/H

由此可得出平面元素A在三维空间中的大小设置为

w=aw*d*2*Math.tan(fov/2)/H;

h=ah*d*2*Math.tan(fov/2)/H;

位置坐标为

x=ax*d*2*Math.tan(fov/2)/H;

y=ay*d*2*Math.tan(fov/2)/H;

以下创建多个平面的代码示例:

var fov=45;

var camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 300000 );

camera.position.set(0, 0, 1500);

var planes=[

["ship1","../resource/part1/ship1.png",1024,1024,700,-400,0,1],//name,pic,w,h,x,y,z,透明度

["plan1","../resource/part1/plan_1.png",1024,256,-170,50,-2000,1],

["air","../resource/part1/airplane_1.png",512,512,150,100,-3000,1],

["star1","../resource/part1/star_1.png",2317,979,150,0,-4500,1],

["star2","../resource/part1/star_2.png",256,128,500,-100,-6000,1],

["light","../resource/part1/light.png",1152,1024,200,50,-7500,1],

["part1_bg","../resource/part1/part1_bg.jpg",2048*1.5,1024*1.5,0,0,-18000,1]

]

planes.forEach(function(planeSet){

var scale=(camera.position.z-planeSet[6])*2*Math.tan(fov/2*Math.PI/180)/1080;//此处的1080为设计稿的高度

var plane=createPlane({

width:parseInt(planeSet[2]*scale),

height:parseInt(planeSet[3]*scale),

pic:planeSet[1],

transparent:true,

opacity:1//planeSet[7]

})

plane.position.set(parseInt(planeSet[4]*scale),parseInt(planeSet[5]*scale),planeSet[6]);

plane.name=planeSet[0];

scene.add(plane);

})

穿梭动画

穿梭动画是通过修改camera.position.z坐标来实现的。

需要说明的是,要改变position.z的时候还要注意camera.lookAt的坐标点,若camera.position.z超过了lookAt.z,画面会以180度翻转过来,所以要保持在一个纵向深度可穿越的话,需要将camera.lookAt的z坐标设置比所有可见元素的Z坐标还要大一点。

同时,还要注意camera的最大可视深度。

window.addEventListener( 'mousewheel', onMouseWheel, false );

function onMouseWheel(event){

if(event.wheelDelta>0){

new TWEEN.Tween( camera.position )

.to( {z:camera.position.z+2500}, 500 )

.start();

}

if(event.wheelDelta<0){

new TWEEN.Tween( camera.position )

.to( {z:camera.position.z-2500}, 500 )

.start();

}

}

function render() {

camera.position.x += ( mouseX - camera.position.x ) ;

camera.position.y += ( mouseY - camera.position.y ) ;

camera.lookAt( new THREE.Vector3(0,0,-20000) );//此处-20000要设置得比最远的平面元素更大一些。

renderer.render( scene, camera );

}

本章DEMO

var container, stats;

var camera, scene, renderer;

var mouseX = 0, mouseY = 0;

var windowHalfX = window.innerWidth / 2;

var windowHalfY = window.innerHeight / 2;

var planes=[

["ship1","../resource/part1/ship1.png",1024,1024,700,-400,0,1],//name,pic,w,h,x,y,z,透明度

["plan1","../resource/part1/plan_1.png",1024,256,-170,50,-2000,1],

["air","../resource/part1/airplane_1.png",512,512,150,100,-3000,1],

["star1","../resource/part1/star_1.png",2317,979,150,0,-4500,1],

["star2","../resource/part1/star_2.png",256,128,500,-100,-6000,1],

["light","../resource/part1/light.png",1152,1024,200,50,-7500,1],

["part1_bg","../resource/part1/part1_bg.jpg",2048*1.5,1024*1.5,0,0,-18000,1]

]

init();

animate();

var mesh;

function createPlane(options){

// options={

// width:0,

// height:0,

// pic:"",

// transparent:true,

// opacity:1

// blending:false

// }

if(typeof options.pic=="string"){

var loader = new THREE.TextureLoader();

loader.setCrossOrigin( this.crossOrigin );

var texture = loader.load( options.pic, function() {}, undefined, function(){});

}else{

var texture= new THREE.CanvasTexture( options.pic )

}

var MaterParam={

map:texture,

overdraw: true,

side: THREE.FrontSide,

// blending: THREE.AdditiveBlending,

transparent: options.transparent,

//needsUpdate:true,

//premultipliedAlpha: true,

opacity:options.opacity

}

if(options.blending){

MaterParam.blending=THREE.AdditiveBlending

}

var plane = new THREE.Mesh(

new THREE.PlaneGeometry( options.width, options.height, 1, 1 ),

new THREE.MeshBasicMaterial(MaterParam )

);

return plane;

}

function addPlanes(){

planes.forEach(function(planeSet){

var scale=(1500-planeSet[6])*2*Math.tan(22.5*Math.PI/180)/1080;

var plane=createPlane({

width:parseInt(planeSet[2]*scale),

height:parseInt(planeSet[3]*scale),

pic:planeSet[1],

transparent:true,

opacity:1//planeSet[7]

})

plane.position.set(parseInt(planeSet[4]*scale),parseInt(planeSet[5]*scale),planeSet[6]);

plane.name=planeSet[0];

//plane.visible=false;

scene.add(plane);

})

}

function init() {

container = document.getElementById("space")

camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 500000 );

camera.position.set(0, 0, 1500);

scene = new THREE.Scene();

var ambient = new THREE.AmbientLight( 0xffffff );

scene.add( ambient );

var directionalLight = new THREE.DirectionalLight( 0xffffff );

directionalLight.position.set( -5, 5, 5).normalize();

scene.add( directionalLight );

addPlanes();

renderer = new THREE.WebGLRenderer();

renderer.setPixelRatio( window.devicePixelRatio );

renderer.setSize( window.innerWidth, window.innerHeight );

container.appendChild( renderer.domElement );

document.addEventListener( 'mousemove', onDocumentMouseMove, false );

window.addEventListener( 'resize', onWindowResize, false );

window.addEventListener( 'mousewheel', onMouseWheel, false );

}

function onWindowResize() {

windowHalfX = window.innerWidth / 2;

windowHalfY = window.innerHeight / 2;

camera.aspect = window.innerWidth / window.innerHeight;

camera.updateProjectionMatrix();

renderer.setSize( window.innerWidth, window.innerHeight );

}

function onMouseWheel(event){

if(event.wheelDelta>0){

new TWEEN.Tween( camera.position )

.to( {z:camera.position.z+2500}, 1500 )

.start();

}

if(event.wheelDelta<0){

new TWEEN.Tween( camera.position )

.to( {z:camera.position.z-2500}, 1500 )

.start();

}

}

function onDocumentMouseMove( event ) {

mouseX = ( event.clientX - windowHalfX ) / 2;

mouseY = ( event.clientY - windowHalfY ) / 2;

}

//

function animate() {

requestAnimationFrame( animate );

render();

TWEEN.update();

}

function render() {

camera.position.x += ( mouseX - camera.position.x ) ;

camera.position.y += ( mouseY - camera.position.y ) ;

camera.lookAt( new THREE.Vector3(0,0,-20000) );

renderer.render( scene, camera );

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值