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 );
}
threejs 形状几何体_ThreeJS学习笔记(五)——二维几何体元素及穿梭动画相关推荐
- opencv 学习笔记五 二维离散卷积
卷积的用途: 卷积主要用于降噪处理,是降噪处理的一种方式: 二维离散卷积包含高斯滤波,平滑滤波,中值滤波,以及能保证图像边缘的双边滤波和导向滤波算法等: 一.了解噪声的来源以及噪声的分类: 图像中难免 ...
- python做直方图-python OpenCV学习笔记实现二维直方图
本文介绍了python OpenCV学习笔记实现二维直方图,分享给大家,具体如下: 官方文档 – https://docs.opencv.org/3.4.0/dd/d0d/tutorial_py_2d ...
- C语言学习笔记 (005) - 二维数组作为函数参数传递剖析
前言 很多文章不外乎告诉你下面这几种标准的形式,你如果按照它们来用,准没错: //对于一个2行13列int元素的二维数组 //函数f的形参形式 f(int daytab[2][13]) {...}// ...
- python对二维数组排序_python学习笔记:二维数组排序问题
首先先说一下题目:有一个文件,文件目录及名称:d:\\test1.txt 文件内容: 0001 Jone 1000.00 0002 Stone 30000.00 0008 Smith 50000.00 ...
- 【OS学习笔记】二十五 保护模式七:任务和特权级保护对应的汇编源代码
本汇编代码是以下两篇文章讲解的内容的内核代码; [OS学习笔记]二十三 保护模式七:保护模式下任务的隔离与任务的特权级概念 [OS学习笔记]二十四 保护模式七:调用门与依从的代码段----特权级保护 ...
- Deep Learning(深度学习)学习笔记整理(二)
本文整理了网上几位大牛的博客,详细地讲解了CNN的基础结构与核心思想,欢迎交流 [1]Deep learning简介 [2]Deep Learning训练过程 [3]Deep Learning模型之: ...
- 吴恩达《机器学习》学习笔记五——逻辑回归
吴恩达<机器学习>学习笔记五--逻辑回归 一. 分类(classification) 1.定义 2.阈值 二. 逻辑(logistic)回归假设函数 1.假设的表达式 2.假设表达式的意义 ...
- PyTorch学习笔记(二):PyTorch简介与基础知识
往期学习资料推荐: 1.Pytorch实战笔记_GoAI的博客-CSDN博客 2.Pytorch入门教程_GoAI的博客-CSDN博客 本系列目录: PyTorch学习笔记(一):PyTorch环境安 ...
- 【K210】K210学习笔记五——串口通信
[K210]K210学习笔记五--串口通信 前言 K210如何进行串口通信 K210串口配置 K210串口发送相关定义 K210串口接收相关定义 K210串口发送接收测试 完整源码 前言 本人大四学生 ...
最新文章
- LeetCode简单题之检查句子中的数字是否递增
- linux环境安装python-pip
- Java与C++Socket通讯注意
- 廖雪峰JS教程学习记录---字符串
- 维度变换--首先将矩阵倒过来
- 线程:创建--【J2SE】
- zoj3806Incircle and Circumcircle
- 联想(Lenovo)小新310经典版进bios方法
- 基于JAVA+SpringMVC+MYSQL的考研帮社区管理系统
- verilog读入.txt的有符号十进制数,把有符号十进制数写入到.txt文件中
- 判断变量是空_python基础(二):变量的数据类型、常量、操作符、分支、循环、条件判断...
- 【python学习】如何批量从文件夹中根据文件后缀名提取文件,并存储到新的文件夹
- 2011天涯上令人心酸至极的微瞬间
- Matlab获取tif各格点经纬度
- 【Verilog基础】ROM IP 核基础知识
- PHP编辑器哪个好用些?
- JS模块化(node.js模块化和es6模块化)
- ESP32 - ESP32_ULP_EB 低功耗应用评估板
- 面试题--小白鼠实验
- C# 编程入门第二课 注释变量,VS2019快捷键,String和string,命名规则,赋值运算符,+号作用占位符,转义字符算术运算符,类型转换
热门文章
- SAP License:SAP项目文档的考核标准
- 巴赛尔协议与贷款产品利率解析
- 天池实验室-Task02-Python入门(中)
- oracle PL/SL编程基础
- JavaScript中各存在性函数
- css实现自适应正方形
- php用魔术方法__call实现类函数重载
- getAttribute, getParamter区别 转帖
- php+高德地图webapi 高德jsapi 实现 当前位置与目标位置距离 并按照距离排序(坐标逆转换)...
- Codevs 1205 单词反转(Vector以及如何输出string)