本文作者:qiaoqingyi

3d编程大师技巧(3d编程大师技巧大全)

qiaoqingyi 2023-11-12 115

  前言

  在现在市面上很多全景H5的环境下,要实现全景的方式有很多,可以用css3直接构建也可以用基于threeJs的库来实现,还有很多别的制作全景的软件使用。

  本教学适用于未开发过3D全景的工程狮,如果觉得内容太无聊可以直接跳到最后。

  理论

  整个3D全景所用的相关理论就不多说了,就稍微讲一下本案例用到的相关理论,相信程序猿们会更加关注代码实现的内容。

  这次讲解的demo是用css3DRender来构建一个正方体的全景场景。

  想象一下,我们需要做的就是构建一个正方体的盒子,然后把镜头放在以下这个正方体盒子里,每个面都贴上我们场景的一个面,那么当镜头转动时看到的就是置身其中的全景。

  

  详细理论的东西以后再说,这次先跑起来一个简单的demo吧

  demo解析

  本教学用到两个库:threeJS和基于它的CSS3DRender.js,代码是从官网上样例上扒下来做了一点调整。

!DOCTYPE html

html

head

titlethree.js css3d - panorama/title

metacharset="utf-8"

metaname="viewport"content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"

style

body {

background-color:#000000;

margin:0;

cursor:move;

overflow:hidden;

}

.surface {width:1026px;height:1026px;background-size:cover;position:absolute;}

.surface .bg {position:absolute;width:1026px;height:1026px;}

/style

/head

body

div

divid="surface_0"class="surface"

imgclass="bg"src="images/posx.jpg"alt=""

/div

divid="surface_1"class="surface"

imgclass="bg"src="images/negx.jpg"alt=""

/div

divid="surface_2"class="surface"

imgclass="bg"src="images/posy.jpg"alt=""

/div

divid="surface_3"class="surface"

imgclass="bg"src="images/negy.jpg"alt=""

/div

divid="surface_4"class="surface"

imgclass="bg"src="images/posz.jpg"alt=""

/div

divid="surface_5"class="surface"

imgclass="bg"src="images/negz.jpg"alt=""

/div

/div

src="js/three.min.js"/

src="js/CSS3DRenderer.min.js"/

src="js/index.js"/

/body

/html

  html这边没什么特别的,首先把每个面放进去,用div把每个面的图片放进去。

  没有用官网demo的实现方式是因为官网是create一个img插入到页面,我们在对每个面添加元素的时候不太方便。先把六个面定义好,如果要在每个面上加入一些交互的元素,直接在html上添加dom就可以了。

  一共就引入了3个js,除了index另外两个都是压缩过的js,不用关心,看一下index.js的实现:

camera =newTHREE.PerspectiveCamera(75,window.innerWidth /window.innerHeight,1,1000);

scene =newTHREE.Scene();

  那么很明显这两行代码,字面上的意思就是创建了一个相机,创建了一个场景。那这里稍微解释一下这两个类。

  PerspectiveCamera

  以下是官网的解释:

  

  大概意思:这是一个模仿人眼的投影模式,它是用于渲染3D场景最常见的投影模式。

  总之这个类就是new一个镜头。下面是样例代码:

  

  这个类的构造函数接受四个参数:

  

  那么这四个参数具体是什么东西?

  

  图片来源:https://isux.tencent.com/3d.html

  分别表示:镜头夹角,宽高比,最近焦距,最远焦距。

  Scene

  接下来,用Scene类创建场景。以下官方说明:

  

  这东西创建了一个场景,这个场景允许你对某个东西某个位置通过threeJs渲染场景。创建了场景和相机,我们需要往场景里面放入之前说的正方体。

  首先定义好六个面的数据,每个面的位置,3D旋转的旋转角度。

  position三个参数分别对应的x,y,z轴的位置。因为我选的面宽度是1024px,所以位置是基于中心点的正负1024/2。

  rotation的三个参数分贝对应xyz轴的旋转角度。Math.PI/2代表90度。

varsides =[

{

position:[-512,0,0],//位置

rotation:[0,Math.PI /2,0]//角度

},

{

position:[512,0,0],

rotation:[0,-Math.PI /2,0]

},

{

position:[0,512,0],

rotation:[Math.PI /2,0,Math.PI ]

},

{

position:[0,-512,0],

rotation:[-Math.PI /2,0,Math.PI ]

},

{

position:[0,0,512],

rotation:[0,Math.PI,0]

},

{

position:[0,0,-512],

rotation:[0,0,0]

}

];

/**

3d编程大师技巧(3d编程大师技巧大全)

* 根据六个面的信息,new出六个对象放入场景中

*/

for(vari =0;i sides.length;i ++){

varside =sides[i ];

varelement =document.getElementById("surface_"+i);

element.width =1026;// 2 pixels extra to close the gap.多余的2像素用于闭合正方体

varobject=newTHREE.CSS3DObject(element );

object.position.fromArray(side.position );

object.rotation.fromArray(side.rotation );

scene.add(object);

}

  CSS3DObject

  那么这里有一个新出现的类CSS3DObject,不过这个类不属于官方类,而是我们引用的3DRender库里的类。没有文档我们看一下代码:

THREE.CSS3DObject =function(element){

THREE.Object3D.call(this);

this.element =element;

this.element.style.position ='absolute';

this.addEventListener('removed',function(event){

if(this.element.parentNode !==null){

this.element.parentNode.removeChild(this.element);

for(vari =0,l =this.children.length;i l;i++){

this.children[i].dispatchEvent(event)

}

}

})

}

;

THREE.CSS3DObject.prototype =Object.create(THREE.Object3D.prototype);

  可以看出这是一个继承于THREE.Object3D的类,将传入的element的postion改为绝对定位,然后加了个被移除时的事件。

  没有定义什么别的特别的东西,那么我们查一下官方Object3D的类。

  Object3D

  

  这个类就是一个定义对象的基本类,其中new的对象包含以下两个属性

.position

Theobject's local position.

.rotation

Object's localrotation (see Eulerangles),inradians.

  分别表示对象的位置和旋转角度。那么for循环就是定义六个对象加入场景中。好,我们继续:

renderer =newTHREE.CSS3DRenderer();

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

document.body.(renderer.domElement );

  CSS3DRenderer

  这是我们引用的库里的类,这个类的主要功能是根据three中的场景和镜头的相关信息,使用dom元素和css3D的属性来渲染出来。

  在这里只是new了这个类和设置了宽高,但是CSS3DRender在这里还没有开始渲染页面。

document.addEventListener('mousedown',onDocumentMouseDown,false);

document.addEventListener('wheel',onDocumentMouseWheel,false);

document.addEventListener('touchstart',onDocumentTouchStart,false);

document.addEventListener('touchmove',onDocumentTouchMove,false);

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

  这里的事件绑定就不详细说了,接下来解析一下渲染时的代码。

animate();

functionanimate(){

requestAnimationFrame(animate );

// lat += 0.1;

lat =Math.max(-85,Math.min(85,lat ));

phi =THREE.Math.degToRad(90-lat );

theta =THREE.Math.degToRad(lon );

target.x =Math.sin(phi )*Math.cos(theta );

target.y =Math.cos(phi );

target.z =Math.sin(phi )*Math.sin(theta );

camera.lookAt(target );

/**

* 通过传入的scene和camera

* 获取其中object在创建时候传入的element信息

* 以及后面定义的包括位置,角度等信息

* 根据场景中的obj创建dom元素

* 插入render本身自己创建的场景div中

* 达到渲染场景的效果

*/

renderer.render(scene,camera );

}

  requestAnimationFrame(animate);这个方法可以根据帧速率触发animate方法。

lat =Math.max(-85,Math.min(85,lat ));

phi =THREE.Math.degToRad(90-lat );

theta =THREE.Math.degToRad(lon );

target.x =Math.sin(phi )*Math.cos(theta );

target.y =Math.cos(phi );

target.z =Math.sin(phi )*Math.sin(theta );

camera.lookAt(target );

  这段代码根据现成的(通过手指滑动或鼠标滑动实时更新的)属性值,调整camera镜头的位置.

renderer.render(scene,camera );

  然后渲染。

  因为render里面的代码比较多,这里就不贴代码了,大概总结一下render做的事情就是首先render自己创建一个作为场景的div,通过传入的scene和camera获取其中object在创建时候传入的element信息以及后面定义的包括位置,角度等信息,根据场景中的obj创建dom元素(就是通过dom实现本应在canvas里的东西),插入render本身自己创建的场景div中。当镜头方向变了,获取到的参数就变了,通过传入的对象身上带有的变化的参数改变页面上dom元素的位置,达到渲染场景的效果。

  代码下载

  链接: https://pan.baidu.com/s/1eR2Rlb8 密码: sdyt

  实战:用 threejs 创建一个地球

  

阅读
分享