zl程序教程

您现在的位置是:首页 >  后端

当前栏目

3D房间,从零到移动观察

3D 移动 观察 零到 房间
2023-09-14 09:00:29 时间

代码见我的github:
https://github.com/qq20004604/some_demo/tree/master/3D%E6%88%BF%E9%97%B4

DEMO地址见:(对手机不友好,不建议用手机打开,流量耗费约500kb)
http://jianwangsan.cn/3Droom/3Droom.html

**前注**

本文内容参考学习【张鑫旭】的文章所写。

DEMO链接域名为zhagnxinyu的,则引自其个人网站。

如果对某些概念不能理解,可以查看以下链接来看示意图。

参考链接:

http://www.zhangxinxu.com/wordpress/2012/09/css3-3d-transform-perspective-animate-transition/

**基础**

DOM结构如下:

舞台

|———— 容器1

| |———— 图片1

| |———— 图片2(以及其他)

|———— 容器2

…… |—— 图片1

 |—— 图片2(以及其他)

3D在Z轴上的结构如下:

视角(用户在屏幕外距离屏幕的距离)——————屏幕(具体而言是舞台元素)——————动画元素(相对舞台元素的深度)

perspective:

perspective:??px; //问号表示number数值

视角-屏幕的距离;

一般是正值;

当该属性设置给舞台元素时,所有动画元素初始位置距离用户的距离则为该值。

该属性也可以设置给具体一个动画元素,则该动画元素距离用户的距离为该值。

translateZ:

transform: translateZ(3000px); //使用时,所有基于transform属性下的属性,应该放在同一条transform属性上(即使一个是Z轴一个是X轴),否则后面使用的会覆盖前面的。

屏幕(舞台元素)和动画元素相对运动的距离;

值为正时,则在Z轴上往观察者(用户)靠近,值为负时,则远离。

当该值和perspective的值相等时,说明该元素和用户视角所在位置重合(刚好看不到该元素);

具体的话,请看DEMO图片(我自己画的):

当视角固定时,某个动画元素靠近用户时,只能看到部分区域的示意图.png

**舞台元素**

简单来说,就是所有动画元素的根元素。

所有动画元素都在这个元素上显示,通过设置舞台元素的大小,可以控制显示动画元素的范围。

而通过设置overflow:hidden这样的属性,让动画元素不能超出舞台元素显示。

perspective:??px; //透视属性,问号表示数字

本属性是指,你从距离多少px的位置来查看该元素。

具体而言,指视角(人的眼睛),距离屏幕的距离,所看到的3D模型投影在舞台元素上的2D画面。

简单来说,你透过窗户往外看,窗口大小是固定的,当你距离窗户越近,能看到的外面景色就越多,当你距离窗户越远,能看到外面的景色就越小。(依然是参考上面那个图片)

overflow:hidden; //超出部分不显示:即显示投影到视角范围的部分(demo图片的紫色区域)

设置这个属性,可以限制图片只在指定区域内显示。

position:absolute; //设置为非static(默认)属性值,方便子元素定位和调整位置(否则可能不好确定动画元素所在位置)。

用于方便容器定位其相对位置。

perspective-origin:50% 50%; //默认是居中

用于定位观察焦点在舞台元素上的位置,默认是居中。

**容器**

将几个位置相关的动画元素放在同一个容器里,然后只需要设置他们相对于容器的位置即可。(例如创建一个长方体)

当需要调整动画元素的位置、旋转方向等时,只需要调整他们的容器的位置即可,便可以改变容器内所有元素的位置。

transform-style: preserve-3d;

用于应用于父元素,设置其子元素是否继承3d,默认是flat(不继承),在使用3D时,应该使用preserve-3d这个值。

另外,【张鑫旭】的文章中说应该应用给舞台元素,但我在实践中发现,如果取消容器的该属性,单纯给舞台元素的话,则不能正常显示。

transform: translateZ(0px);

用于调整容器的位置。除了Z之外,还可以修改X和Y。或者干脆使用translate3d(x, y, z)这样的形式。

以下指容器移动相对于舞台元素

X:+右-左;

Y:+下-上;(这个请参考html的XY轴坐标体系理解)

Z:+近-远;

transform:rotateX(45deg); //旋转,沿X轴旋转

transform-origin: x y z; //旋转的坐标轴

这2个属性用于对容器进行旋转。

简单来说,如果我们要旋转一个立方体,

首先,肯定要有一根轴线,即rotateX/Y/Z(沿X轴Y轴Z轴旋转);

其次,我们需要确定这跟轴线在三维空间中的位置(注意,这里的三维空间,指的是相对于当前元素:如容器,的三维空间,而不是整个HTML的三维空间);

因此,我们需要通过transform-origin给出的原点,来确定旋转时,坐标的基准点(即计算旋转时,x、y、z轴相交会的那个点);有了点之后,再加上旋转轴就可以确定旋转情况了。

其中,transform-origin的x和y可以使用px也可以使用百分比(其左上角的点坐标为x:0, y:0),默认是50% 50%(居中);

而默认z的值为0,可以使用px,但不能使用百分比。

至于rotateX(45deg),表示沿X轴旋转45度,360deg是旋转一圈(和初始一样),正值是顺时针,负值是逆时针;

另外请注意,旋转的顺时针和逆时针跟轴的方向有关(x向右,y向下,z靠近用户)

**动画元素**

多个动画元素放在同一个容器里,组成一个整体(比如说长方体)。

动画元素只需要考虑相对于容器的位置即可。

transform: rotateX(-90deg);

transform-origin: 0 0;

同容器元素


backface-visibility: hidden; //背面是否可见,默认是可见

当元素是半透明时,则默认可以看到元素的背面情况。但若属性设置为hidden,则背面元素将不可见。

position设置之后,top、left、right、bottom相关

需要注意,旋转动画元素时,例如长100,宽100,深度是500时,我们需要设置上下左右四个方向的dom的基准位置。例如,放置于下方的元素,其除了设置transform-origin:0 100%;之外,应设置为bottom:0; left:0这样(只有这样才能构成一个长方体,不明白的话仔细想想,或者自己动手试试)

3D坐标计算原理 计划结构如下:

舞台元素

————】动画容器之根元素

————————】动画容器一

————————————】动画元素1、2、3……

————————】动画容器二

————————】动画容器三

3D移动原理 由于所有的 动画元素 相对于 动画容器 的坐标是固定的; 动画容器元素 相对于 动画容器根元素 是固定的; 因此,只需要控制 动画容器跟元素 的旋转坐标圆心和旋转角度,即可形成整个场景的变换。 可能存在的潜在缺陷:假如场景里的结点很多,也许会有性能方面的问题?不确定。 有没有替代的方案?不确定

基础属性:

var xyz = {

 x: 250, //xyz的坐标

 y: 250,

 z: 0,

 rotate: 0 //面向角度

角度弧度换算:

//通过角度来得到弧度

function getRadianFromAngle(angle) {

 return angle * Math.PI / 180;

XZ平面上前进的计算函数:

//前进的话,根据角度计算坐标变化

function goFrontAndGetNewValue() {

 var radian = getRadianFromAngle(xyz.rotate);

 var x = Math.sin(radian) * 50;

 var z = Math.cos(radian) * 50;

 x = Number(x.toFixed(2));

 z = Number(z.toFixed(2));

 //首先让rotate的值是0~359之间

 if (xyz.rotate = 360) {

 xyz.rotate -= 360;

 } else if (xyz.rotate 0) {

 xyz.rotate += 360;

 if (xyz.rotate 90) {

 //右上方角度

 xyz.x += x;

 xyz.z -= z;

 console.log("右上");

 } else if (xyz.rotate 180) {

 //右下方角度

 xyz.x += x;

 xyz.z -= z;

 console.log("右下");

 } else if (xyz.rotate 270) {

 //左下方角度

 xyz.x += x;

 xyz.z -= z;

 console.log("左下");

 } else if (xyz.rotate 360) {

 //左上方角度

 xyz.x += x;

 xyz.z -= z;

 console.log("左上");

 console.log(xyz);

前进行为完成的函数:

//先计算坐标变化,然后计算当前的坐标中心(方便之后旋转)

function GoAhead() {

 var transformValue = parent.style.transform;

 goFrontAndGetNewValue();

 //先设置位移

 var newString = translate3d( + (-xyz.x) + px, + 0 + px, + (-xyz.z) + px);

 parent.style.transform = transformValue.replace(/translate3d\([^)]+\)/, newString);

 //然后设置当前旋转中心

 var originValue = String(250 + xyz.x) + px  + String(250 + xyz.y) + px  + String(xyz.z) + px;

 console.log(originValue);

 parent.style[transform-origin] = originValue;

后退同理,其中计算坐标变化的函数,把+x变为-x(-x变为+x),z轴同理,变换正负即可。

向上看:

//原理是以X轴为坐标旋转整个容器,向上看即为把容器向下旋转。但需要注意,是以当前旋转情况下的X轴来旋转

下来复习3d旋转的css属性:

rotate3d(x, y, z, 角度) //以从0,0,0到参数的点为轴,进行3d旋转

transform:rotate3d(1, 0, 0, 45deg); 相当于以x轴为轴进行旋转

transform:rotate3d(0, 0, 1, 45deg); 以z轴进行旋转(顺时针)

具体来说,从参数给的坐标点,看向原点,然后以这个状态进行顺时针旋转。

《1》y轴的正数为靠近观测点,负数为远离。

《2》值用1或者100没区别(因为只是表达方向);

《3》这里的x、y、z的值,与其他坐标无关(即例如不受translate3d这样属性的影响)

因此,我们需要得知从哪里(观察点,即上面的x,y,z坐标)来旋转这个3d模型。

计算方法:

讲道理说,这个不是很好理解,需要有一定3d空间想象的能力。这里使用rotateY来确定左右旋转的情况,然后使用rotate3d来确定左右旋转后,上下旋转的情况。

1、由于我们已知当前点的x、y、z坐标,因此,在计算中假设其为0,在最终算出来的结果上再加上当前点的x、y、z坐标值即可;

2、我们需要有2个圆,第一个圆用于确定左右旋转,第二个圆用于确定上下旋转。

3、第一个圆使用rotateY属性,他的初始三点坐标是:圆心O(0,0,0),圆顶点A(0,1,0),圆第三点B(1,0,0)。这个圆面对的方向(OB射线的左边为面对方向,例如,初始情况下,面向指从(0,0,0)-(1,0,0)这个线段往(0,0,-1)-(1,0,-1)这个线段看去。注意:z轴远离我们是负值),即为我们观察的方向。其中:O和A为固定值,B点以O为圆心,长度1为半径,在XZ轴平面移动,即可改变代表面向的方向。例如,当B旋转-90deg时,我们正好看向初始情况下,我们左手边(rotateY(-90deg)),此时,B坐标为(0,0,-1);

4、第二个圆根据第一个圆而变化。具体而言,第二个圆的圆心O为(0,0,0),其中一个点为第一个圆的点B,另一个点初始是(0,1,0),但无需去注意他,因为我们只需要知道第二个圆的倾斜角度即可,具体而言,是rotate3d的第四个参数。其中,正值往上看,负值往下看。

5、因此,我们最重要的是,计算出第一个圆的点B的坐标,而这个坐标,可以根据左右旋转时的角度得知。

6、计算方法:

x坐标:1*sin(旋转的弧度);

y坐标:固定为0;

z坐标:1*cos(旋转的弧度);

小明特别喜欢打扑克牌,除了喜欢斗地主和德州扑克之外,还喜欢一种叫桥牌的游戏,桥牌的具体规则相当复杂,有叫牌、打牌和计分三个阶段,还有不断变化的局况,局况可能影响叫牌打牌策略。但是小明暂时不关心这一些, 小明特别喜欢打扑克牌,除了喜欢斗地主和德州扑克之外,还喜欢一种叫桥牌的游戏,桥牌的具体规则相当复杂,有叫牌、打牌和计分三个阶段,还有不断变化的局况,局况可能影响叫牌打牌策略。但是小明暂时不关心这一些,
养成类玩法的初次试探 将消除与养成类玩法结合其实并不少见,之前也一直有这样的想法,想在精致1010中加入一点儿养成类的元素。只不过将其安排在后面,优先去在游戏的玩法上做丰富。如今终于轮到了,也就试探性的先做了出来。
PHP编程模拟病毒传播过程,告诉你为什么不能随意出门溜达? 由于近期新冠状肺炎病毒的传播,我们看到上图中的病毒传播过程介绍。同时,为了让这个过程更加的直观,我们用计算机编程模拟了一个简单的模型来演示,通过视觉效果给大家做个演示!