二维几何体

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学习笔记(五)——二维几何体元素及穿梭动画相关推荐

  1. opencv 学习笔记五 二维离散卷积

    卷积的用途: 卷积主要用于降噪处理,是降噪处理的一种方式: 二维离散卷积包含高斯滤波,平滑滤波,中值滤波,以及能保证图像边缘的双边滤波和导向滤波算法等: 一.了解噪声的来源以及噪声的分类: 图像中难免 ...

  2. python做直方图-python OpenCV学习笔记实现二维直方图

    本文介绍了python OpenCV学习笔记实现二维直方图,分享给大家,具体如下: 官方文档 – https://docs.opencv.org/3.4.0/dd/d0d/tutorial_py_2d ...

  3. C语言学习笔记 (005) - 二维数组作为函数参数传递剖析

    前言 很多文章不外乎告诉你下面这几种标准的形式,你如果按照它们来用,准没错: //对于一个2行13列int元素的二维数组 //函数f的形参形式 f(int daytab[2][13]) {...}// ...

  4. python对二维数组排序_python学习笔记:二维数组排序问题

    首先先说一下题目:有一个文件,文件目录及名称:d:\\test1.txt 文件内容: 0001 Jone 1000.00 0002 Stone 30000.00 0008 Smith 50000.00 ...

  5. 【OS学习笔记】二十五 保护模式七:任务和特权级保护对应的汇编源代码

    本汇编代码是以下两篇文章讲解的内容的内核代码; [OS学习笔记]二十三 保护模式七:保护模式下任务的隔离与任务的特权级概念 [OS学习笔记]二十四 保护模式七:调用门与依从的代码段----特权级保护 ...

  6. Deep Learning(深度学习)学习笔记整理(二)

    本文整理了网上几位大牛的博客,详细地讲解了CNN的基础结构与核心思想,欢迎交流 [1]Deep learning简介 [2]Deep Learning训练过程 [3]Deep Learning模型之: ...

  7. 吴恩达《机器学习》学习笔记五——逻辑回归

    吴恩达<机器学习>学习笔记五--逻辑回归 一. 分类(classification) 1.定义 2.阈值 二. 逻辑(logistic)回归假设函数 1.假设的表达式 2.假设表达式的意义 ...

  8. PyTorch学习笔记(二):PyTorch简介与基础知识

    往期学习资料推荐: 1.Pytorch实战笔记_GoAI的博客-CSDN博客 2.Pytorch入门教程_GoAI的博客-CSDN博客 本系列目录: PyTorch学习笔记(一):PyTorch环境安 ...

  9. 【K210】K210学习笔记五——串口通信

    [K210]K210学习笔记五--串口通信 前言 K210如何进行串口通信 K210串口配置 K210串口发送相关定义 K210串口接收相关定义 K210串口发送接收测试 完整源码 前言 本人大四学生 ...

最新文章

  1. LeetCode简单题之检查句子中的数字是否递增
  2. linux环境安装python-pip
  3. Java与C++Socket通讯注意
  4. 廖雪峰JS教程学习记录---字符串
  5. 维度变换--首先将矩阵倒过来
  6. 线程:创建--【J2SE】
  7. zoj3806Incircle and Circumcircle
  8. 联想(Lenovo)小新310经典版进bios方法
  9. 基于JAVA+SpringMVC+MYSQL的考研帮社区管理系统
  10. verilog读入.txt的有符号十进制数,把有符号十进制数写入到.txt文件中
  11. 判断变量是空_python基础(二):变量的数据类型、常量、操作符、分支、循环、条件判断...
  12. 【python学习】如何批量从文件夹中根据文件后缀名提取文件,并存储到新的文件夹
  13. 2011天涯上令人心酸至极的微瞬间
  14. Matlab获取tif各格点经纬度
  15. 【Verilog基础】ROM IP 核基础知识
  16. PHP编辑器哪个好用些?
  17. JS模块化(node.js模块化和es6模块化)
  18. ESP32 - ESP32_ULP_EB 低功耗应用评估板
  19. 面试题--小白鼠实验
  20. C# 编程入门第二课 注释变量,VS2019快捷键,String和string,命名规则,赋值运算符,+号作用占位符,转义字符算术运算符,类型转换

热门文章

  1. SAP License:SAP项目文档的考核标准
  2. 巴赛尔协议与贷款产品利率解析
  3. 天池实验室-Task02-Python入门(中)
  4. oracle PL/SL编程基础
  5. JavaScript中各存在性函数
  6. css实现自适应正方形
  7. php用魔术方法__call实现类函数重载
  8. getAttribute, getParamter区别 转帖
  9. php+高德地图webapi 高德jsapi 实现 当前位置与目标位置距离 并按照距离排序(坐标逆转换)...
  10. Codevs 1205 单词反转(Vector以及如何输出string)