View on GitHub

Yinjie - GitHub.io

Welcome to the Yinjie's notes

VR基础及其在页面级应用(4) — 场景搭建

书接上文 VR基础及其在页面级应用(3) — 场景基础。 上篇文章是不是觉得有点单调了,内容不多,东西也没说明白,就有一个“很晕”的例子,挺无趣的。实际上该系列讲到这里,能用文字说明的内容已经越多越少了,VR 的基础原理都是从3D建模和3D视觉原理过来的,这个东西本身就非常抽象,学习重点是培养感觉,不像是逻辑代码,你可以一行一行的表达出来。而这里的代码表现只是结果,是整个过程的最后一环,所以没有原理认知,把代码背下来也没什么用。 场景篇的文字说明还是会不多,只给出几个建模的思路,尽量做出有互动性的例子,看图比读文字有效多。

继续此系列的风格 —— “点击这里”先查看例子。本篇的例子会“有意思”一点。

本文应该是本系统的最后基础一讲,内容是实际在三维空间中布置物体和背景。

先说场景物体,这个包括空间中的房子、路、各种小物件等。立体形状都是由平面构成的,但是在页面中,因为面的默认方向都是都是和“显示器”在同一平面上,无法像高级的3D编辑软件,可以直接“画”出各种方向、角度的平面。 这成就增加了页面3D建模的复杂度,而且单纯用 transform 无法做出曲面,只能是一些矩形元素。下面给出两类基本的建造方式,一个是常规矩形,一个是背景的“圆”。

矩形

第一篇中就出现的“骰子”,在这里还是会有,因为它很有代表性,页面 transform 变形得到一切物体都可以在它身上找到影子。

还是以它为例,简单说一个完整矩形如何造出来。先看它的 html 结构:

<div class="wrapper">
    <div class="container">
        <div class="stage">
            <section class="ceil" style="transform: rotateX(90deg) translateZ(150px);"></section>
            <section class="floor" style="transform: rotateX(-90deg) translateZ(150px);"></section>
            <section class="wall" style="transform: rotateY(0deg) translateZ(150px);"></section>
            <section class="wall" style="transform: rotateY(90deg) translateZ(150px);"></section>
            <section class="wall" style="transform: rotateY(180deg) translateZ(150px);"></section>
            <section class="wall" style="transform: rotateY(270deg) translateZ(150px);">西</section>
        </div>
    </div>
</div>

方位变换

以下是步骤(正方体):

  1. stage 是舞台,也是矩形6个面的方位基准。将6个面都以absolute的布局模式“层叠”在stage里;
  2. 拉开空间距离:transform: translateZ(150px);,这一步可以将一个“屏幕”中的平面“拉”出来,同时也会确定矩形一边的长度;
  3. 旋转到东南西北四个方位:transform: rotateX([0 - 360]deg);,上面变换都是对全部的平面,在这一步,就要有差别性的对待,拿出四个面将它向以y轴方向旋转,组成矩形的四边;

alt

  1. 同样的原理,将“天地”两个面以x轴的方向旋转到上下两侧,将剩下的两个面补全。

alt

这样就把一个完整的矩形做出来了,当然网上也有其它的方式,个人总结出来此方法相比之下有几个优点:

  • 变换基准很稳定,要移动矩形只需控制 stage 就行;
  • 矩形中心点明确,就是stage的中心;
  • 代码量少,而且一致,唯一差异化的就是rotate部分,也容易理解。

这样,一个基础矩形就做完了,然后通过控制 stage 和视距,下面来控制它的摆放位置。

空间位置

通过控制 wrappercontainer 来让上面做好的矩形放置在空间的任意位置。还是举两个典型的例子。

1. 任意维度的摆放

这个比较简单,只要对 stage 进行 translate3d 变换就行,具体看实际需求。

2. 将自己置身矩形中

这实际是上一种情况的加强版,如何做到这样的效果呢?看下图:

满足以下公式时(当视距 > 目标矩形的总 translateZ),就会把自己放在矩形空间中,这也是做类似进入房子等效果时需要的情况。

.wrapper'persperctive <= .stage'translateZ + section'translateZ

矩形的建模大致就这些了,上面的例子为了方便理解都是以正文体为例的,如果是长宽高不一致的矩形,就需要其它的一些计算了,在最后的例子中有所动态体现,具体可以去认真看一下。

“圆形背景”

上面的矩形建模可以解决物体、房间等的构建。但是遇到背景就麻烦了,矩形的有棱有角在随着目光进行旋转时会出现明显的“漏洞”,一看就是“方”的,效果很差,正常的背景应该抽象成一个很大的圆柱形,你站在中间,这样目光转动时,正前方视距的感觉才能是一致的。

alt

但是,页面是无法画出曲面的,怎么解决背景旋转时的漏洞呢?

其实,如果你对计算机3d建模有一定了解的话,就会明白,不论是在哪个高大上的3D建模软件里,还是相对弱的页面里,计算机本身就画不出什么曲面来。 你所看到的那些平滑的曲线,都是靠非常多个平面拼接出来的,而拼接平面的数量就决定了曲面的平滑程度。

alt

上大学时常捣鼓硬件,从显卡了解到一个“曲面细分”的画面优化技术,知道了显示绘3D图的原理。

页面背景的圆,也是一样的,我们需要用较多个平面拼接出来。这里先以8分的圆举例说明,当然分的越多越好,做近似圆的方法。

alt

  1. 找一个可以头尾对接的大图,至少图要长;
  2. 将图以长边平均分成8份,这里有两个方法,一个是用PS人切片工具进行物理裁切,另一种是图不变,通过各平台的 background-size + background-position 选择性的进行显示裁切,效果都是一样的,但性能有较大的差别,笔者在这里没有具体测试;
  3. 计算拉开stage的距离:离stage距离 = (切片长度 / 2) / (sin(360 / 切片数 / 2 / 180 * PI))
  4. 计算各个平台依次旋转的度数:切片i = i * (360 / 切片数)

这样做出的近似圆,会将背景旋转时落点视距的“波动”降到最低。做为背景的圆做的越大越好,用上一篇的知识将“自己”放置在圆的中心,这样一个优美的背景图就做好了。

具体的可以看文章最后的例子。

展示的例子

总结

该系列到这就暂时结束了,主要围绕 VR 最最基本的知识点进行了简要说明,但这此知识的灵活应用足以在页面上做出你想要的效果。 笔者也在计划写一到两篇的进阶篇。

同时也听有人说,现在页面 H5(canvas) 的3D引擎也那么多,能做的东西比这个仅通过变换凑成的场景华丽的多,要看这个干什么。 “呵呵~~~”,说这个的一定是彻底不了解原理和没玩过3D引擎的人了,我只能说“3D效果结果的华丽和过程的复杂一定是成正比的”,你连这个都没弄明白别奢求在大型引擎里堆海量代码了,你去用过就知道。

VR 现在被运用的越来越多,慢慢呈现暴发式的增长,在以后的视觉编程和体验上必将成为一个重点。