前言
🏄️陆地冲浪板,简称陆冲板,可以在地面上模拟海浪的效果,站上滑板,即可一直滑行了!
前期调研
前期是收集资料阶段,看看有哪些品牌,哪些可以定制的地方。主要搜索渠道知乎、淘宝、B站等。从知乎上了解品牌、陆冲板结构、实用人群等,然后去淘宝看实际商品,B站看看教程!
收集资料
- 【2023陆冲入门推荐指南】新人初学者如何选择自己的第一块陆冲板/陆地冲浪板 - 知乎 (zhihu.com)
- 【小白入坑必看】陆地冲浪板入坑扫盲,各品牌已亲测 - 知乎 (zhihu.com)
- 【图片】国产陆地冲浪板(桥)的选择及防踩雷知识 首先,说一下国内目前陆地冲浪板的情况,淘宝上买的国产板子大概都在300到1000元这个区间内_陆地冲浪板吧_百度贴吧 (baidu.com)
- 国产陆地冲浪板的特点与选购 - 知乎 (zhihu.com)
- ...
陆冲板的主要品牌有...... 嗯,这里选的是国产品牌 - 牛匠 来作为参考对象!逛一逛淘宝~
从图中我们可以看到
- 陆冲板有不同的板型
- 板型有不同尺寸之分
- 板面的贴图不同
- 轮子颜色也有不同
- 和其他品牌相比,在材料、做工、支架等方面也有区别。
这里的定制主要考虑的是板型、板面和轮子颜色✔️
数据收集
模型制作的前期是数据收集阶段。
收集的信息有:
- 陆冲板的不同板型 - 来自淘宝,选取了五款板型🥚
- 陆冲板的不同板面 - 来自百度,选取了合适的图片风格🖼️
- 陆冲板轮子的颜色 - 来自颜色表网站,从中选取颜色~🎨
陆冲板图片
- 来自淘宝,下载的图片
支架图片参考
- 来自知乎和百度搜索的图片
板面图片来源
- www.zmtc.com/bizhi/324.h…
- www.bizhizu.cn/bizhi/64648…
- 搜索内容 - 手机壁纸(考虑到滑板是竖着的,和手机壁纸很配~)
图片处理
PS使用网站
图片处理操作主要是陆冲板的板面素材,因为它们可能不是一样大的,这样直接贴到模型上,会有问题!用PS软件,将这些图片处理成统一大小(尺寸)💯,修改图片的名字,方便程序点击切换图片!
我们共收集了五种板型,为了方便操作和选取,用PS的钢笔工具绘制出板型的形状,也是方便切换板型,这里共绘制了五张png透明图片,程序实现时,将图片顺时针旋转45°✏️,倾斜角度,更有运动效果~
模型制作
模型建立
进入正题!模型制作用的是Blender,先前收集的版式图,先导入到Blender中,然后将他们放大到同一大小,这样制作处理的模型,不会差距太大。
导入图片🖼️
框选出来的,就是要导入的图片,可以看到它们的板头、板尾、外形等有所不同,这就是我们要实现的切换效果。
调整比例,这一步,保证了制作模型的大小,不会相差太大,对比标准是图片中滑板的宽度,先保证宽度一致!有了参考图,之后就是依据参考图进行模型制作,因为模型是立体的,还需要其他角度的参考图一起参考!
建立模型,模型主要由三部分组成,板面、支架和轮子,其中支架和轮子可以重复使用,只需要建立板面(5个)的模型即可。建立平面,依据参考图的样子创建板面,整体完成效果如下。
看一下细节部分,为什么要分为两个部分?因为我们切换的部分有板面和板型,切换板面会直接将材质替换,侧边的材质是木纹,不需要替换。同样,切换板型的时候,侧边也需要一起变化,所以分为两个部分。这个在程序中很好实现,一起显示即可!
来一张爆炸图💣💥,主要结构部分~
模型贴图
模型贴图,主要是在模型中查看实际效果(大小、位置等效果),我们导出的时候,并不需要导出贴图(在程序中实现,初始化加载一张图片即可),重点是查看板面的贴图效果!
关于板面贴图,我们最主要的任务就是确定模型的UV位置!因为我们切换贴图的时候,贴图的位置、缩放比例就是UV(2维坐标系)决定的!最后导出模型的时候也需要这个坐标系!
什么是UV贴图?
看看板型4的UV
板型5的UV
这里的UV展开方式是从视角展开,从顶视图的角度(俯视)。我们使用一张图来测试模型贴图效果,再根据不同板面模型,调整不同的位置,切换其他图片(先前我们处理过了,把所有图片都设置为同样大小),可以实现同样的效果,就算完成板面切换的功能了!
其他的材质,就好整了,调一下粗糙度、颜色即可!
- 粗糙度🧔🏽可以决定模型表面光滑程度,轮子的粗糙度调低了一些,可以反射部分光线,符合塑料材质特点!
模型导出
模型导出,将板面的贴图删除,其他部分材质保留(因为不需要改变),即可导出贴图了,导出的格式为gltf,方便后续程序处理(轮子颜色切换、板面贴图切换等)
因为我们要实现切换效果,所以需要每个部件单独导出!共计12次。。。最后的输出内容如下。。
代码部分
环境搭建
主要是模型环境和操作界面
模型加载使用的是Three.js(参考官方案例加载gltf模型部分,修改模型路径即可)
- scene
- camera
- renderer
- gltfLoader
- orbitControls
操作界面使用幽灵按钮👻,点击展开侧边页面,考虑到不同尺寸设备下的用户体验,使用百分比布局(50%),在小尺寸下,宽度变小,图片变大,有利于操作。
可选内容有板型、板面、和轮滑,分为三部分,多出部分可以滑动,主色调为红色,选中状态添加红色边框,红色是生命的象征❤️,结合滑板,更有运动风格~ 在文字部分添加icon,更直观展现文字内容。
代码细节部分,我们展开部分占据页面整体宽度的50%,在Three.js的场景部分也要进行相应的调整,这样模型就会显示在画面中间!我们使用个变量 - isCustomize,如果点击按钮,即是进入定制效果,相应的它的绘制窗口就缩小一半。
window.addEventListener("resize", resize);
function resize() {
(camera.aspect =
window.innerWidth / (state.isCustomize ? 2 : 1) / window.innerHeight),
camera.updateProjectionMatrix();
renderer.setSize(
window.innerWidth / (state.isCustomize ? 2 : 1),
window.innerHeight
);
}
板型切换
主要使用排他法💨,点击的显示,其他模型隐藏。
在切换板型的img上,添加data属性,点击时候对模型进行查找即可!
// 可选版型
surfBodys.forEach((item) => {
item.addEventListener("click", (e) => {
audio.play();
surfBodys.forEach((item) => {
item.classList.remove("active");
});
item.classList.add("active");
// 加载对应的模型。。
state.handleSurfBodyIndex = e.target.dataset.surfbodyindex;
// 分两次查找,因为我们有板面的主体和侧边。。(body,side)
// 显示为true,其他为false
Object.entries(theModel.surfBodys).forEach((value) => {
value[1].visible = false;
if (e.target.dataset.surfbodyindex === value[0]) {
value[1].visible = true;
handleSurfBodyMtl(value[1]);
}
});
Object.entries(theModel.surfSides).forEach((value) => {
value[1].visible = false;
if (e.target.dataset.surfbodyindex === value[0]) {
value[1].visible = true;
}
});
});
});
板面切换
切换板面,主要是切换它的贴图!我们直接传递图片的src地址即可!
我们写一个处理贴图的方法,修改贴图🖼️
function handleSurfBodyMtl(gltf) {
// 这里设置传进来的贴图 - state.handleSurfBodyMtl这个就是图片地址。。
// 设置水平垂直平铺。
let txt = new THREE.TextureLoader().load(state.handleSurfBodyMtl);
txt.wrapS = THREE.RepeatWrapping;
txt.wrapT = THREE.RepeatWrapping;
// 设置后,图片不会出现模糊效果
txt.anisotropy = 16;
// 调试过程中,出现的问题(查看源码得知。。。)
// 为什么图像会反转,这里要设置 flipY 为false!!!
// txt.rotation = Math.PI;
txt.flipY = false;
// OK,把设置好的图片放到模型上!
gltf.traverse((item) => {
if (item.isMesh) {
item.material = new THREE.MeshPhongMaterial({
map: txt,
});
}
});
}
滑轮切换
轮滑的颜色修改需要作用在它本身的材质上(我们在Blender中设置过了!)我们打印一下!
这是轮子模型加载后打印出来的!可以看到它的材质以及颜色!我们要做的就是修改它的颜色!
定义一个theModel对象,将每次获取到的模型都放进去(板面、板型、轮子等,前面用的也是同样的方法,可以这样理解,这个theModel就是实际在场景中展示的部分,我们切换模型,修改的也是theModel中存储的模型,前面我们创建的模型都是在获取模型时候用的,然后放入theModel中!)
加载轮子模型,放到theModel中了!
// wheels
loader.load( path + models.wheels, (gltf) => {
theModel.wheels = gltf.scene;
scene.add(gltf.scene);
});
修改轮子颜色🎨!
// 定义轮子颜色
const wheelsColor = [
"#CD5C5C", //红
"#F08080",
"#FF0000",
"#ADFF2F", //绿
"#00FF00",
"#98FB98",
"#FF4500", //黄
"#FFA500",
"#FFFF00",
"#D8BFD8", //粉
"#DA70D6",
"#FF00FF",
"#00BFFF", //蓝
"#0000FF",
"#191970",
"#DCDCDC", //灰
"#778899",
"#000000",
];
// 添加到dom,添加data属性
// 可选颜色
let wheelsContent = "";
wheelsColor.forEach((item, index) => {
wheelsContent += `<li class="itemBox ${
index === wheelsColor.length - 1 ? "active" : ""
}" style='background: ${item}' data-color='${item}'></li>`;
});
// 修改轮子颜色!
wheelsItems.forEach((item) => {
item.addEventListener("click", (e) => {
// 改变轮子颜色!
wheelsItems.forEach((item) => {
item.classList.remove("active");
});
item.classList.add("active");
audio.play();
// 这是引用 - 直接就修改了!!!
console.log(theModel.wheels.children[0].material, 'wheel----')
const wheelsMtl = theModel.wheels.children[0].material;
wheelsMtl.color = new THREE.Color(e.target.dataset.color);
});
});
码上掘金
最后就是上线了~ 模型先放到github上,用于获取模型,图片放在掘金的草稿箱里,,,可以获取图片。。。
最终的效果如下😎~
总结
思考过程经历了前期调研 - 数据收集 - 图片处理 - 模型制作 - 代码部分 - 上线,很像产品生产过程,总结一下还是很有收获的。
- 前期调研考虑到了从网站获取用户及产品的信息资料,了解可以定制的内容以及关于陆地冲浪板的基本介绍
- 数据收集方面,利用淘宝平台获取图片信息,分析板面的应用风格,收集对应的素材图片。利用百度、知乎等,获取模型相关的细节图片,将素材分为不同的文件夹,方便浏览
- 图片处理阶段应用了PS,考虑到图片与模型的应用细节,提前处理图片大小和命名
- 模型的分层导出,是本次最主要的收获,将主体和侧边分为两个部分,可以更好的完成交互任务
- 代码部分和上线最大的收获是,掘金也可以当图库。。。
- 借助Blender和Threejs实现了陆冲板的定制效果还是很😎的,继续练习Blender和JS~。
带着我们的滑板一起溜达溜达~~
执念的鱼 提着灯闯过远洋的甄选 继续下潜 无需誓言