<!-- The main Three.js file -->
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.min.js'></script>
<!-- This brings in the ability to load custom 3D objects in the .gltf file format. Blender allows the ability to export to this format out the box -->
<script src='https://cdn.jsdelivr.net/gh/mrdoob/Three.js@r92/examples/js/loaders/GLTFLoader.js'></script>
<!-- This is a simple to use extension for Three.js that activates all the rotating, dragging and zooming controls we need for both mouse and touch, there isn't a clear CDN for this that I can find -->
<script src='https://threejs.org/examples/js/controls/OrbitControls.js'></script>
引入 canvas 标签。整个 3D 体验将渲染于此,而其余 HTML 标签作为 UI 辅助于它。将 canvas 放在 HTML 底部(脚本前)。
<!-- The canvas element is used to draw the 3D scene -->
<canvas id="c"></canvas>
现在为 Three.js 创建一个 scene。
// Init the scene
const scene = new THREE.Scene();
function animate() {
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();
请注意,上面代码了引用摄像机(camera),但我们仍未添加它。
在 JavaScript 代码顶部,添加一个名为 cameraFar 的变量。当我们添加 camera 到 scene 时,其默认位置是 0,0,0。但这可是椅子的位置!因此 cameraFar 变量是告诉 camera 应离此多远,以确保能看到椅子。
var cameraFar = 5;
在 animate() 函数上方添加 camera。
// Add a camera
var camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = cameraFar;
camera.position.x = 0;
这是一个透视摄像机,其参数为 50 视场(field of view,fov),宽高比和默认的裁剪区域。裁剪区域指定了可视区域的前后边界。当然,这些都不是本应用关心的事情。(译者注:可参考《Three.js 现学现卖》)
我们的场景仍然是黑色,下面设置背景色。
在顶部的 scene 变量上方,添加背景色变量 BACKGROUND_COLOR。
const BACKGROUND_COLOR = 0xf1f1f1;
注意我们这里的十六进制是使用 0x 而不是 #。这不是字符串,而是以 0x 开头的整数。
在 scence 变量下方,更新 scene 的背景色,并在远处添加同样颜色的雾,旨在隐藏地板的边界。
const BACKGROUND_COLOR = 0xf1f1f1;
// Init the scene
const scene = new THREE.Scene();
// Set background
scene.background = new THREE.Color(BACKGROUND_COLOR );
scene.fog = new THREE.Fog(BACKGROUND_COLOR, 20, 100);
// Init the object loader
var loader = new THREE.GLTFLoader();
loader.load(MODEL_PATH, function(gltf) {
theModel = gltf.scene;
// Set the models initial scale
theModel.scale.set(2,2,2);
// Offset the y position a bit
theModel.position.y = -1;
// Add the model to the scene
scene.add(theModel);
}, undefined, function(error) {
console.error(error)
});
// Add lights
var hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.61 );
hemiLight.position.set( 0, 50, 0 );
// Add hemisphere light to scene
scene.add( hemiLight );
var dirLight = new THREE.DirectionalLight( 0xffffff, 0.54 );
dirLight.position.set( -8, 12, 8 );
dirLight.castShadow = true;
dirLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
// Add directional Light to scene
scene.add( dirLight );
此时,椅子看起来稍微好一些!到目前为止,JavaScript 如下:
var cameraFar = 5;
var theModel;
const MODEL_PATH = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/1376484/chair.glb";
const BACKGROUND_COLOR = 0xf1f1f1;
// Init the scene
const scene = new THREE.Scene();
// Set background
scene.background = new THREE.Color(BACKGROUND_COLOR );
scene.fog = new THREE.Fog(BACKGROUND_COLOR, 20, 100);
const canvas = document.querySelector('#c');
// Init the renderer
const renderer = new THREE.WebGLRenderer({canvas, antialias: true});
document.body.appendChild(renderer.domElement);
// Add a camerra
var camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = cameraFar;
camera.position.x = 0;
// Init the object loader
var loader = new THREE.GLTFLoader();
loader.load(MODEL_PATH, function(gltf) {
theModel = gltf.scene;
// Set the models initial scale
theModel.scale.set(2,2,2);
// Offset the y position a bit
theModel.position.y = -1;
// Add the model to the scene
scene.add(theModel);
}, undefined, function(error) {
console.error(error)
});
// Add lights
var hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.61 );
hemiLight.position.set( 0, 50, 0 );
// Add hemisphere light to scene
scene.add( hemiLight );
var dirLight = new THREE.DirectionalLight( 0xffffff, 0.54 );
dirLight.position.set( -8, 12, 8 );
dirLight.castShadow = true;
dirLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
// Add directional Light to scene
scene.add( dirLight );
function animate() {
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();
// Function - Add the textures to the models
function initColor(parent, type, mtl) {
parent.traverse((o) => {
if (o.isMesh) {
if (o.name.includes(type)) {
o.material = mtl;
o.nameID = type; // Set a new property to identify this object
}
}
});
}
// Set initial textures
for (let object of INITIAL_MAP) {
initColor(theModel, object.childID, object.mtl);
}
最后,回到地板,将其颜色从红色(0xff0000)改为亮灰色(0xeeeeee)。
// Floor
var floorGeometry = new THREE.PlaneGeometry(5000, 5000, 1, 1);
var floorMaterial = new THREE.MeshPhongMaterial({
color: 0xeeeeee, // <------- Here
shininess: 0
});
<div class="controls">
<!-- This tray will be filled with colors via JS, and the ability to slide this panel will be added in with a lightweight slider script (no dependency used for this) -->
<div id="js-tray" class="tray">
<div id="js-tray-slide" class="tray__slide"></div>
</div>
</div>
.controls DIV 标签吸附在视口底部,.tray 设为 100%(相对于 body),其子元素 .tray__slide 作为色板,色板可根据需要进行补充。
首先添加几种颜色。在 JavaScript 顶部,添加含有 5 个对象的数组,每个对象都带有 color 属性。
我们已经能更改椅腿的颜色。现在就让我们添加指定更改哪部分颜色的能力。在 body 标签内的顶部添加以下 HTML:
<!-- These toggle the the different parts of the chair that can be edited, note data-option is the key that links to the name of the part in the 3D file -->
<div class="options">
<div class="option --is-active" data-option="legs">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1376484/legs.svg" alt=""/>
</div>
<div class="option" data-option="cushions">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1376484/cushions.svg" alt=""/>
</div>
<div class="option" data-option="base">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1376484/base.svg" alt=""/>
</div>
<div class="option" data-option="supports">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1376484/supports.svg" alt=""/>
</div>
<div class="option" data-option="back">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1376484/back.svg" alt=""/>
</div>
</div>
这是带有自定义图标的按钮集合。.option DIV 吸附在视口一侧(另外,通过 CSS 的媒介查询还会使其随着视口大小而进行调整)。每个 .option DIV 都是白色正方形,而带有 --is-active 类名的还会有红色边框。另外,还带有用于匹配 nameID data-option 属性。最后,image 元素拥有 pointer-events 属性,即使点击了 image,点击事件的触发始终保留在其父元素。
在 JavaScript 顶部添加另一个变量 activeOptions,其默认值为 legs:
var activeOption = 'legs';
回到 selectSwatch 函数,更改硬编码的 legs 参数为 activeOption:
setMaterial(theModel, activeOption, new_mtl);
现在我们需要做的是创建事件处理函数,当点击 .option 时更改 activeOption。
在 const swtaches 和 selectSwatch 函数上方添加:
// Select Option
const options = document.querySelectorAll(".option");
for (const option of options) {
option.addEventListener('click',selectOption);
}
function selectOption(e) {
let option = e.target;
activeOption = e.target.dataset.option;
for (const otherOption of options) {
otherOption.classList.remove('--is-active');
}
option.classList.add('--is-active');
}
<div class="controls">
<div class="info">
<div class="info__message">
<p><strong> Grab </strong> to rotate chair. <strong> Scroll </strong> to zoom. <strong> Drag </strong> swatches to view more.</p>
</div>
</div>
<!-- This tray will be filled with colors via JS, and the ability to slide this panel will be added in with a lightweight slider script (no dependency used for this) -->
<div id="js-tray" class="tray">
<div id="js-tray-slide" class="tray__slide"></div>
</div>
</div>
现在我们拥有了一个新的信息块,其包含描述如何控制应用的一些说明。
最后,增加一个 loading 遮罩层,以确保在应用加载期间页面是干净的,并在模型加载后将其删除。
在 body 内的顶部增加以下 HTML。
<!-- The loading element overlays all else until the model is loaded, at which point we remove this element from the DOM -->
<div class="loading" id="js-loader"><div class="loader"></div></div>
为了使其优先加载,我们将这些 CSS 单独放在 head 标签内,而不是链接式的 CSS 中。所以,在 head 闭合标签上方添加以下 CSS。
原文:How to Build a Color Customizer App for a 3D Model with Three.js
本文将阐述如何基于 Three.js 创建一个完整的 3D 模型(椅子)颜色自定义应用。
马上体验:3D Model Color Customizer App with Three.js
快速介绍
该工具的灵感来源于 Vans shoe customizer,并采用优秀的 JavaScript 3D 库 Three.js 实现。
阅读本文的前提是已掌握 JavaScript、HTML 和 CSS。
为了能让你确切学到东西,而不是单纯地粘贴/复制。本文不按常规出牌,在一开始就给出全部 CSS。CSS 起到装扮应用的作用,即仅专注于 UI。每当我们粘贴部分 HTML 时,都会讲解相应 CSS 的作用。
Part 1: 3D 模型
你可以完全跳过本节,但它可以让你对这一切有更深入的了解。
这不是一篇关于 3D 建模的教程,但我将阐述如何在 Blender 中设置模型,这有助于你创建属于自己的模型、修改网上的免费模型或指点他人调试。以下是创作 3D 模型——椅子的一些经验。
尺寸(Scale)
模型需设置为符合真实世界的尺寸。我也不知道这是否重要,但感觉没问题,为什么不这样做呢?
分层和命名约定(Layering and naming conventions)
这部分很重要:物体中每个需要独立控制的元素都必须是 3D 场景中独立的对象。这些对象也必须拥有唯一的名字。这里有 back(背部)、base(底座)、cushions(坐垫)、legs(椅腿)和 supports(支架)。若有三个元素都命名为
supports
,那么 Blender 会将它们命名为supports
、supports.001
、supports.002
。这没问题,因为我们可以在 JavaScript 中使用includes("supports")
找到它们。落点(Placement)
模型应放置在场景的原点,并落在地板上。另外,最好能面向正确的方向,但这可通过 JavaScript 旋转易实现。
导出设置(Setting up for export)
导出前,要使用 Blender 的
Smart UV unwrap
。在此不深入细节,总之这会让纹理可以保持宽高比不变,保证不会在包裹模型中因各类形状而产生怪异的拉伸(建议你制作自己的模型时才仔细研究它)。确保所有对象应用 transformations(译者注:即将缩放转为对象实际尺寸)。
文件格式(File Format)
显然 Three.js 支持很多 3D 对象文件格式,但它推荐的格式之一是 glTF(.glb)。而且 Blender 也支持导出该格式。
Part 2:建立环境
Fork 这个 pen(译者注:即 codepen 的一个案例),或创建一个 pen 并从其中复制 CSS。这是一个含有本教程所有 CSS 的空白 pen。
3D Chair Customizer Tutorial - Blank
若不选择 fork,也需要复制 HTML。这包含响应式 meta 标签和 Google 字体。
本教程使用了 3 个依赖,我在它们各自上方写有描述用途的注释。
引入 canvas 标签。整个 3D 体验将渲染于此,而其余 HTML 标签作为 UI 辅助于它。将 canvas 放在 HTML 底部(脚本前)。
现在为 Three.js 创建一个 scene。
接着引用 canvas 元素:
Three.js 需要具备一些元素才能跑起来。第一个是 scene,第二个是 renderer。在 canvas 变量下方添加它。创建一个 WebGLRenderer,传入 canvas 和选项参数(抗齿距,使 3D 模型的边缘更光滑)。
然后将 renderer 插入到 body 元素(译者注:此行代码可省略)。:
虽然场景目前漆黑一片,但我们走在正确的道路上。
接着 Three.js 需要一个更新循环,这是一个在每帧都会执行的函数,对运行我们的应用程序起到重要作用。我们将更新函数命名为
animate()
,并将其放置在 JavaScript 代码的最底部。请注意,上面代码了引用摄像机(camera),但我们仍未添加它。
在 JavaScript 代码顶部,添加一个名为
cameraFar
的变量。当我们添加 camera 到 scene 时,其默认位置是0,0,0
。但这可是椅子的位置!因此cameraFar
变量是告诉 camera 应离此多远,以确保能看到椅子。在
animate()
函数上方添加 camera。这是一个透视摄像机,其参数为 50 视场(field of view,fov),宽高比和默认的裁剪区域。裁剪区域指定了可视区域的前后边界。当然,这些都不是本应用关心的事情。(译者注:可参考《Three.js 现学现卖》)
我们的场景仍然是黑色,下面设置背景色。
在顶部的 scene 变量上方,添加背景色变量
BACKGROUND_COLOR
。在 scence 变量下方,更新 scene 的背景色,并在远处添加同样颜色的雾,旨在隐藏地板的边界。
现在仍是一个空白的世界,没有东西,没有投影。是时候加载模型了。
Part 3:加载模型
我们将使用第二个依赖来加载模型。
在此之前,我们先声明引用模型的变量,该变量会被频繁使用。我们将其放在 JavaScript 顶部的
BACKGROUND_COLOR
前。同时,添加该模型的路径。我已对其进行托管,供大家使用。它有 1Mb 左右的大小。现在创建一个 loader,并使用其 load 方法。
theModel
就是整个场景的 3D 模型。将其设置合适的尺寸大小,这里设为原大小的 2 倍。接着,设置其 y 轴偏移量为 -1,使其往下移动。最后将其添加到场景中。load
函数的第一个参数是模型的路径,第二个参数是资源加载成功后的回调函数,第三个参数目前是undefined
,但它其实是资源加载期间的回调函数,最后一个参数是报错回调函数。将这部分代码放在 camera 下方。
此时,你应该看到的是一张被拉伸、黑色且像素化的椅子。看起来很糟糕,但这是正常的,别担心!
除了摄像机,我们还需要光。背景不受光影响,但如果此时添加地板,那么它依然会是黑色。Three.js 有几种类型的光且有丰富的选项可供调整。这里我们添加两种:环境光和定向光。两者的设置是专门适配该应用的,其中包括位置和强度。如果你对它们有使用经验,可以尝试更改。但现在就使用我提供的参数吧。将光放在 loader 下方。
此时,椅子看起来稍微好一些!到目前为止,JavaScript 如下:
现在看起来如下:
让我们解决像素化和拉伸的问题。Three.js 需要在(视口)改变时更新 canvas 尺寸,其内部分辨率需依赖于 canvas 尺寸和设备屏幕像素比(手机的像素比一般比较高)。
在 JavaScript 代码底部,即调用
animate()
的下方添加该函数。该函数会监听 canvas 的尺寸和 window 的尺寸,并返回一个判断两者是否相同的布尔值。我们将会在animate
函数内使用该函数,以决定是否需要重新渲染场景(设置场景大小)。该函数还会考虑设备像素比,以确保 canvas 在手机上也清晰。(译者注:建议通过监听 window resize 事件进行判断,且设备像素比上限为 2)在 JavaScript 底部添加该函数:
现在更新
animate
函数后看起来如下:椅子看起来好多了。
我需要提醒两点:
跳到 loader 方法,还记得设置缩放比例的地方吗
theModal.scale.set(2,2,2)
?我们将调整的旋转角度添加在它下方:哇哦,看起来好多了。还有一件事是:据我所知,Three.js 目前仍不支持角度(deg)单位。因此,这里使用 Math.PI,即 180 度,如果想旋转至 45 度角,那么就设置 Math.PI / 4。
我们还需要一块地板,不然怎么产生投影呢?
创建一个平面(二维平面,或高度为 0 的三维体)作为地板。
在光的下方添加:
下面讲解一下这里发生了什么。
首先,我们创建了一个几何图形。这是本文创建的唯一一个几何图形,你可以进行各种参数的调整。
第二,我们使用了
MeshPhongMaterial
,为其设置了颜色和反光度(shininess)。在讲 Three.js 其他材质前,我们先看看 Phong。我们能调整它的反光度(reflectiveness)和镜面高光(specular highlights)。另外,还有 MeshStandardMaterial,其支持更多的纹理特性,如金属(metallic)和环境光遮蔽(ambient occlusion);另外,还有不支持阴影的 MeshBasicMaterial。本文仅用到 Phong 材质。我们创建了变量 floor,并将 geometry 和 material 合为 Mesh。
我们还对地板进行了以下操作:旋转至平坦状态,使其能接收阴影、往下移至椅子的位置。最后将其添加至场景。
现在看起来如下:
我们暂时将地板设为红色,但阴影在哪?为此,我们还需要做几件事。首先在
const renderer
下方添加这几行代码:我们同时设置了设备像素比,这与阴影无关,恰巧是适当的位置。我们启用了 shadowMap,但仍没有阴影?
在 loader 函数内,我们能遍历 3D 模型(的组成元素)。因此,跳到 loader 函数,在
theModel = gltf.scene;
下添加以下操作:为 3D 模型的每一个元素(椅腿、坐垫等)启用投射和接收阴影的选项。该遍历方法会在后续再次使用。在
theModel = gltf.scene;
下方添加:这看起来比以前更糟,但起码能在地板上产生阴影!之所以不好看,是因为模型仍使用 Blender 带来的材质。下面我们将所有这些材质都替换为普通的 PhongMaterial。
在 loader 函数上方创建另一个 PhongMaterial:
这是一个不错的起始材质,灰白色和略带光泽。
虽然目前只有一种材质,但为了后续方便为椅子各个部分设置不同颜色或加载的纹理,我们将材质的数据结构声明为一个数组。
再次遍历 3D 模型(的组成元素),并使用 childID 查找椅子的不同部分,然后设置相应材质(
mtl
属性)。模型每个元素的名字都是在 Blender 中设置的,这在第一节讲到。在 loader 函数下方,添加一个参数为模型、模型的哪部分(type)和材质的函数。我们还为模型的组成元素添加了一个后续会用到的新属性
nameID
。在 loader 函数内的
scene.add(theModel)
前遍历 INITIAL_MAP 数组,并执行该函数,:最后,回到地板,将其颜色从红色(0xff0000)改为亮灰色(0xeeeeee)。
这里值得注意的是:
0xeeeeee
与背景色不同。但在光的作用下,它们看起来一致。3D Chair Customizer Tutorial - Part 1
恭喜,越来越像样了!如果你卡在某一节点,可以 fork 这个 pen 或参考它,直至找到问题所在。
Part 4:添加控制
实际上,本章节很短,这得益于第三个依赖——OrbitControls.js,让一切变得十分简单。
在声明 animate 函数上方,添加以下控制代码:
在 animate 函数内的顶部,添加:
controls
是 OrbitControls 的实例。你可以随意更改其参数,其中包括允许用户旋转椅子(上下)、禁用拖拽以使椅子保持在中心、启用了阻尼使其过渡更自然,还有自动旋转功能(根据个人情况启用与否),但目前是关闭状态。用你的鼠标或触摸屏进行体验吧!
Scrollable
Part 5:更改颜色
到现在,我们的程序还没进入主题,所以接下来会专注于更改颜色(纹理)。
在 canvas 标签下方添加:
.controls
DIV 标签吸附在视口底部,.tray
设为 100%(相对于body
),其子元素.tray__slide
作为色板,色板可根据需要进行补充。首先添加几种颜色。在 JavaScript 顶部,添加含有 5 个对象的数组,每个对象都带有
color
属性。使用这些颜色制作色板!
首先在 JavaScript 顶部引用滑块:
在 JavaScript 底部添加一个名为
buildColors
的函数,并立即调用它。上面是我们基于
colors
数组创建的色板列表!注意我们同时为它们设置了data-key
属性,这是用于查找生成材质的颜色值。在
buildColors
函数下方,为色板添加事件处理函数:点击事件的处理函数命名为
selectSwatch
。它会基于色值创建新的 PhongMaterial,并调用另一个函数来遍历 3D 模型(的组成元素),对匹配的部分更换材质!该函数通过 data-key 属性匹配颜色,并基于该颜色创建新材质。
该函数仍不能工作,需要添加
setMaterial
函数。在该函数下方,添加
setMaterial
函数:这与
initColor
函数大同小异。nameID
属性来自initColor
,若它与参数type
相等,就为它添加材质。现在我们的色板能创建新材质,并更改椅腿的颜色,快来试一试!
Swatches change the legs color!
Part 6:指定哪个部分进行更改
我们已经能更改椅腿的颜色。现在就让我们添加指定更改哪部分颜色的能力。在
body
标签内的顶部添加以下 HTML:这是带有自定义图标的按钮集合。
.option
DIV 吸附在视口一侧(另外,通过 CSS 的媒介查询还会使其随着视口大小而进行调整)。每个.option
DIV 都是白色正方形,而带有--is-active
类名的还会有红色边框。另外,还带有用于匹配 nameIDdata-option
属性。最后,image
元素拥有pointer-events
属性,即使点击了image
,点击事件的触发始终保留在其父元素。在 JavaScript 顶部添加另一个变量
activeOptions
,其默认值为legs
:回到
selectSwatch
函数,更改硬编码的legs
参数为activeOption
:现在我们需要做的是创建事件处理函数,当点击
.option
时更改activeOption
。在
const swtaches
和selectSwatch
函数上方添加:该函数会将
event.target
的data-option
值设为activeOption
,并切换--is-active
类。体验一下
Changing options
止步于此?物体全是一种材质类型时,难免乏味。下面就增加木和纺织布材质:
前两个是纹理,分别是木和牛仔布。另外,还增加了两个新属性——
size
和shininess
。size
表示重复图案的频率,所以数值越大图案越密集。现在我们要更新两个函数以支持该特性。首先将
buildColors
更新为:现在它会检查是否存在
texture
属性,若存在,则将色板的背景设为该纹理。第二个需要更新的函数是
selectSwatch
:该函数会检查当前色板是不是纹理,若是,则通过 Three.js 的 TextureLoader 方法创建新纹理,并将该纹理的
repeat
设为色板size
值。另外,还为纹理设置wrapping
(经试验后得出效果最佳的wrapping
值),然后为 PhongMaterial 的map
属性设置为当前纹理,最后设置shininess
值。如果当前色板无 texture 属性,则使用老方法。请注意,你也可以为了纯色的材质设置
shininess
值。这里带有纹理的 pen:
Texture support
Part 7:收尾工作
我曾有个项目交付给客户验收,这个项目有一个大按钮去祈求被按,甚至在 hover 时闪闪发光,然而客户及其同事(会计部的 Dave)却反馈他们不知道要按什么(去你的,Dave)。
在 canvas 标签上方添加一些号召性语句:
通过 CSS 将其放在椅子前方,用于指示用户可拖拽旋转椅子。但椅子仅仅呆滞不动?
让椅子在首次加载后进行旋转,旋转完毕后隐藏引导语。
首先在 JavaScript 上方添加
loaded
变量,并设为false
:在 JavaScript 底部添加该函数:
模型需要在 120 帧内线性旋转 360 度(约 2 秒,60fps),所以我们将在 animate 函数中运行该函数 120 次,一旦完成则将
loaded
设为true
。代码如下:我们判断
theModel
是否不等于null
且loaded
是否为false
,若符合条件,则调用该函数 120 次,然后将loaded
设为true
,使得animate
函数最终忽略它。这就拥有了自旋转的椅子。椅子停止的这一刻是删除引导语的好时机。
在 CSS 中,为引导语添加一个带有隐藏动画的类,该动画的延迟时间为 3 秒,所以,在开始旋转椅子的同时为引导语添加该类。
在 JavaScript 顶部引用引导语:
更新
animate
函数:好极了!这里有更丰富的颜色供你选择。同时,下方也提供了轻量无依赖的滑动功能(用于拖拽滑动色板列表):
在 JavaScript 底部添加 slider 函数,它将使你拥有可通过鼠标或触摸屏拖拽色板的能力。为了紧扣主题,这里就不过多研究其工作原理。
现在,将 CSS 内的
.tray__slider
小动画注释掉:剩下最后两步收尾工作就完成了!
更新
.controls
div,让其包含引导语:现在我们拥有了一个新的信息块,其包含描述如何控制应用的一些说明。
最后,增加一个 loading 遮罩层,以确保在应用加载期间页面是干净的,并在模型加载后将其删除。
在 body 内的顶部增加以下 HTML。
为了使其优先加载,我们将这些 CSS 单独放在 head 标签内,而不是链接式的 CSS 中。所以,在 head 闭合标签上方添加以下 CSS。
快好了!在加载模型后将其删除。
在 JavaScript 顶部引用它:
在
loader
函数中,在scene.add(theModel)
后放置以下代码:现在,模型会在该 DIV 背后加载:
就这样!以下就是完整的 pen,仅供参考!
See the Pen 3D Chair Customizer Tutorial - Part 4 by Kyle Wetton (@kylewetton) on CodePen.
你还可以体验托管在 Codrops 上的 案例。
感谢您的支持!
这是一篇长篇教程。如果你发现错误,请在评论告诉我。