原文:服饰3D柔性渲染调研及实践 - 2021.08.05

调研背景

当前全球服装制造的产业链中,我国的中小企业的难以参与到其中利润最高的环节比如产品的设计和研发,主要原因就是服装设计的难度和成本高,因此需要一些创新技术来减少制作成本、降低门槛。
3D服装设计就是解决方案之一,采用3D技术可以直接在虚拟模特上实现打样,并且迭代修改、交付样品也可以通过线上实时完成,相比于传统服装设计方式,大幅减少了服装出品的时间成本,并且也在一定程度上降低了上手难度和学习门槛。

天猫趋势中心-3D企划

目前在天猫趋势中心3D企划中也运用了服饰3D柔性渲染相关技术。天猫趋势中心通过全球海量数据,利用大数据AI算法,可以实现提前6个月以上预测未来趋势发展路径。其中的3D企划,是通过3D服装渲染的方式,让商家能够全方位、更直观、更细节地进行选款。

虽然目前的3D显示已经能满足一些商家进行选款的需求,但还是有些商家希望在此基础上,提供一些的定制化能力,比如更换面料、添加商家 Logo 这样上手难度比较低的功能。而这些简易功能其实就赋予了商家快速设计快速出品的能力。
不过目前线上平台中尚未开放定制化服务,为了要进一步实现定制化功能,我们对现有一些的3D服装设计产品进行了调研。

现有产品调研

3D服装设计软件,简单的理解就是将一件衣服从 CAD 版片→模拟成仿真衣服→渲染真实感效果,从而诞生一件3D数字服装。目前全球最有影响力的3D服装设计软件主要是韩国的 CLO 虚拟服饰公司开发的两款软件:Marvelous Designer 和 CLO3D,国内比较成熟的软件是由凌迪科技公司推出的 Style3D。

Marvelous Designer

Marvelous Designer 是于2009年开发的,三维服装设计行业中最知名的软件,可以实现非常精美、逼真的服装模拟效果,主要面向游戏和动画行业,很多大型游戏公司比如EA、Ubisoft中的不少工作室都是采用的这款软件进行服装设计的。

CLO3D

这家公司之后在2010年发布了第一代 CLO3D,目的是更加精准地实现虚拟服装在外观和功能上与物理服装的无缝转换。虽然和 Marverlos Designer 的核心是相同的,但 Marvelous Designer主要用于动画和游戏行业,而 CLO3D 更专注于时尚和服装行业,面向服装设计的整个链路。有一个很大的区别就是 CLO3D 导入和导出的生产资料可以直接发送给生产厂商。

Style3D

国内目前比较成熟3D服装设计软件,是目前和我们合作的凌迪科技公司推出Style3D。
Style3D主要有两款应用,一款是大型桌面软件Style3D studio,另一款是基于 Web 端的 Style3D Cloud。

Style 3D Studio

Style3D Studio是数字化建模设计软件,类似于 CLO3D,Studio 也具备服装柔性动态模拟、2D板片/3D模型同步修改、导出生产资料等能力

Style3D Cloud

Style3D Cloud 平台提供3D数字化的款式管理、研发资源库管理、企划看板、部件化设计等功能,并支持即时沟通、在线下单,帮助采购方和供应方建立高效协同,缩减产品开发周期和开发成本;

个人觉得Cloud 并不同于 Studio 主要面向设计师,而更多是面向商家和消费者进行预览、选款,其不提供服装动态建模的能力,但提供了线上的3D显示和简易的定制化能力,比如在静态模型上的面料替换、添加图案等功能。

产品对比

上述几款产品的对比如下表所示:

产品名硬件要求(推荐配置)价格(个人版)面料仿真效果虚拟模特导出生产资料
Marvelous DesignerOS:Win/Mac;显卡:Nvidia GTX960 ;空间:20G280¥/月动态效果逼真支持虚拟角色;多种Pose
CLO3DOS:Win/Mac;显卡:Nvidia GTX1060 ;空间:20G50$/月(323¥/月)效果逼真;物理属性精确;面料库自由调整;压力提醒;
Style3D studioOS:Win;显卡:Nvidia GTX1060 ;空间:20G999¥/年提供面料扫描;高清贴图数量有限
Style3D cloud支持WebGL的浏览器;显存:1G会员199¥/月静态模型;高清贴图暂无未知

从价格上看,可以看出几款软件的使用成本是相对比较高的,所以相当于还是拉高了用户的门槛,而我们业务的需求是希望通过低门槛的产品来让更多用户体验到易上手的定制化功能,让更多的中小商家能够参与到设计的环节中来。

难点及挑战

但以我们目前的基础,要实现这样的能力仍需要面对一些难点挑战,目前调研下来,将难点和挑战大致分为三类:

  • 算法建模
  • 关键技术
  • 物料基础

算法建模

要实现逼真的服装模拟,首先要实现布料的仿真,而布料仿真一直以来都是计算机图形学中比较难的研究方向,对其需要的理论知识要求也比较高。相比于刚体,柔体布料内部作用力更复杂,并且产生碰撞时各部分形态情况都是不同的,所以分析和模拟起来就更难。

仿真过程可以大致分为两部分:

  • 布料仿真建模(也就是对布料本身的建模)
  • 运动碰撞问题(布料与其他物体/场景的碰撞检测及响应)

布料仿真建模

柔性布料的三维动态仿真自 1980 年以来就有大量学者为此研究,从学术历史上,研究模型大概分为三类:几何模型、物理模型、混合模型。

几何模型

几何模型是最早提出的,通过一系列的顶点和多边形去模拟、拟合织物、服装的形态。
其优点是设计时不考虑织物的物理特征(拉伸、弯曲),也不需要对织物物理状态的物理量求解,大大降低了计算量。
缺点是这种方法只注重织物的外观感觉,多用于静态场景,无法真正的动态显示,因此局限性很大。

物理模型(目前主流)

物理模型是从织物运动的物理规律入手,将质量、受力等物理量引入模型中来完成建模,是当前布料模拟的主流。其中质点-弹簧(Mass-Spring)模型因为简单、快捷而受到许多研究者的青睐,应用也最为广泛。

混合模型

由两种方法组合,模拟轮廓时采用几何模型,模拟细节时采用物理模型,不过从目前相关文献调研的结果看,还没有达到理想的效果。

质点-弹簧模型

质点-弹簧模型是将布料看作离散的指点,质点之间用弹簧相连,将织物的运动划分为拉伸压缩变形、相邻弹簧的剪切变形和弯曲变形,用不同类型的弹簧去约束质点各个方向的受力状态。

质点-弹簧模型动态仿真的过程简单来说就是:初始时刻在屏幕上画出所有质点和弹簧的位置状态,下一个时刻再计算所有质点和弹簧位置状态,以此类推逐时刻计算,连续起来实现动态效果。其中获得每个点的位置状态,是通过对受力、速度、加速度分析,构建对应微分方程组,再通过欧拉法等方式求解微分方程得到的。

碰撞检测算法

完成了布料的自身建模,还需要考虑布料运动碰撞检测。因为每时刻计算大量的图元状态计算量很高,所以一般会采用两阶段检测的方法,通过多个规则的几何体如球体,立方体将布料包围起来(也称作包围盒),只有当碰撞体进入到包围盒中时,才对包围盒中的布料进行逐点分析。因为简单的物体比较容易检查相互之间的重叠,所以通过用简单的包围盒形状来近似代替复杂几何体的形状,很大程度地降低了计算量。

关键技术

布料模拟只是实现来对于服装局部的模拟,而要实现对完整服装的模拟还涉及到很多关键技术,例如:

  • 裁剪缝合技术

    需要裁剪缝合技术来将一块块布料组合成完整的服装,同时要保证缝合处的细节要逼真。
    
  • 2D板片-3D模型同步

    考虑到传统的制衣方式是基于服装板片,并且最后导出的生产资料也是服装板片,所以除了能够直接对3D模型进行修改,还需要实现2D板片盒3D模型的同步修改。
    
  • 合体性检查

    制作的服装模型需要符合人的穿衣模式、穿衣状态,因此需要和合体性检查来提醒模型是否适合用户。
    
  • ...

物料基础

完成了技术难题后,要构建一款完整的产品,还需要考虑建立和收集物料。比如:

  • 服装模型库
  • 面料库
  • 虚拟模特库

因为从产品的使用上,不能让用户从0开始,从一块布开始去构建完整的服装模型。类似于前端页面开发,可以通过模板、物料方式来减少开发成本,服装设计也可以提供一些服装模型作为基础模版,或者划分为不同部位的组件、模块,让用户通过给予物料进行设计,降低了使用难度;同时因为面料决定了服装的形态,而采集面料的信息(高清贴图、物理属性)对设备要求比较高,所以提供丰富面料库可以降低了用户自行采集配置的时间成本;人物模型库,以此减少用户自己采集、录入、配置的成本;虚拟模特库可以提供不同年龄、身材的人物模型,提供精细化参数调整,以面向不同用户的需求。

技术方案实践

讨论到这里,可以看出从0开始打造一款类似 CLO3D、Style3D 这样的服装设计软件需要很多理论知识和相关技术的储备,开发的工作量也相当大,可能需要好几年才能产品成型。不过回到我们文章开始说到的业务需求,我们并不需要从0打造一款服装设计软件,因为面向的不是专业的服装设计师而是一些中小商家,所以目前需要的只是:

  • 服饰的3D渲染显示
  • 提供简易的定制化功能:面料替换、添加图案

如果仅考虑满足上述两点需求的话,其实暂时不需要提供3D服装的动态建模的功能。因为考虑到易用性,用户可以直接对建模好的模型进行操作(通过其他3D建模软件完成建模),所以需要做的只是从外部加载模型,再对模型的材质进行修改就可以了。这么分析下来其实工作量就少了很多,那接下来就说说怎么去开发一个满足上面需求的demo。

技术结构分析

目前参考了市面上的一些线上3D服装展示的平台,梳理出简化的技术结构图大致如下:

首先是下载模型,浏览器从服务器下载建模好的模型文件和贴图文件。3D模型文件的格式选择的是glTF(Graphics Language Transmission Format)格式,也是 Web 上的3D模型标准格式(glTF 基本上成为了3D模型的 JPG 格式),glTF 由 json 和外部数据构成,构成如下三部分:

  • 一个json格式的文件(.gltf):完整的场景描述,阶包括段层级结构、材质、相机以及mesh、animation等的描述信息;包含对二进制文件中不同区间与数据的映射关系;
  • 二进制文件(.bin),存储geometry、animation数据以及其他基于buffer的数据;
  • 纹理文件(.jpg, .png)

之后如果模型是压缩过的,还需要对模型进行解压。通常因为模型文件都比较大,所以都会采取先压缩再传输,以此减少传输的时间。这里可以通过一个叫做 Draco 的库来完成模型压缩和解压。Draco 是谷歌开发的一个用于3D模型压缩的库,可以大幅度降低模型的大小,便于模型的传输和浏览器的加载,提供了 JavaScript 版本和 WASM 版本的 decoder。
解压后的模型通过3D渲染框架 Three.js 提供的接口加载,最后再通过 Three.js 将模型渲染到用户界面上。Three.js 是目前最知名也是最热门的 WebGL 项目,社区强大,并且有大量的示例可以参考,比较适合用来学习。

功能分析及代码实现

接下来就采用上面的技术结构,基于 Three.js 框架来完成一个3D服装渲染的 demo,下文会对重点功能进行分析,并给出一些关键功能的代码实现。

模型加载

笔者是在3D展示平台sketchfab上下载的 glTF 格式开源模型,Three.js 提供了相应导入glTF 格式模型的接口,可以直接加载:

// 初始化相关参数
let modelObj;
let scene = new THREE.Scene();
...

// 导入外部GLTF模型
function loadGLTFModel(modelPath, modelName) {
  const loader = new GLTFLoader();
  // 可选: 如果模型是draco压缩过的,这里需要加上dracoLoader
  const dracoLoader = new DRACOLoader();
  dracoLoader.setDecoderPath( '/examples/js/libs/draco/' );
  loader.setDRACOLoader( dracoLoader );
  
  loader.load(modelPath, function (gltf) {
    // 外部模型场景加入当前场景
    scene.add(gltf.scene);
    // 获取衣服模型
    modelObj = scene.getObjectByName(modelName);
  });
}

模型渲染

服装模型加载后如何通过 Three.js 渲染出来的(以下是个人的理解,不会太深入的去说),这里要先说下three.js中的基本单位:顶点,三个顶点可以构建一个三角面。在 Three.js 中的几何体 geometry 除了点、和线以外基本都是由一系列的顶点和三角面构成的.其中顶点具有两个重要的属性:

  • 位置坐标(x, y, z)
  • 纹理坐标(u, v)

位置坐标决定了顶点在三维空间中的位置;而纹理坐标决定了三维空间中的点与二维的纹理图的映射关系,也就是决定了纹理图是怎么映射到模型上的,如下图:

Geometry 只是决定了几何体的空间位置和结构,而几何体最终呈现在屏幕上的状态是还需要加上另外一个重要的材质 Material 共同决定,材质的设置会影响几何体在光照下的效果,比如透明程度,反光程度等等。材质除了通过参数设置外,也可以导入外部的 Texture 纹理文件来设置,通常纹理文件会分成颜色纹理、法向纹理等等。Geometry 和 Material 组成了 Mesh 网格模型,再由多个 Mesh 组成完整的模型。最后再加上背景环境、光照等元素一起组成为场景 Scene,场景在相机 Camera 的拍摄下最终呈现在用户的屏幕上。

面料替换

通过刚才分析,面料替换功能实现其实比较简单,因为纹理映射关系是存在模型的 Geometry 中的,所以如果模型是已经建模好了的就不需要手动去设置映射关系,只需要替换纹理图片就可以实现面料替换,并且 Three.js 提供的函数可以实现对纹理进行一些变换,比如重复、旋转等。

// 初始化相关参数
let modelObj;
...

// 替换模型纹理
function changeTexture(texturePath) {
  let ImageLoader = new THREE.ImageLoader();
  // load方法回调函数,按照路径加载图片
  ImageLoader.load(
    texturePath,
    function (image) {
      // 将衣服模型的所有mesh替换纹理图
      modelObj.children.forEach((mesh) => {
        mesh.material.map.image = image;
        mesh.material.map.needsUpdate = true;
      });
    }
  );
}

添加图案

添加图案功能相对来说复杂一些,因为图案根据鼠标位置来添加的,所以首先需要建立屏幕上的鼠标位置和模型三维坐标对应关系;Three.js 中提供了光线投射THREE.Raycaster的方法来捕捉我们鼠标选择的模型的点和面。获得了鼠标选中的模型的点面,还需要把图案添加到模型上去,如果这里采用原生实现,需要自己写计算相交算法取相交面,会比较麻烦;好在 Three.js 封装了这个过程,提供了一个叫THREE.DecalGeometry(贴花几何体)的类,只需要传入相交的面、相交的位置、贴花的大小和方向就能创建贴合在模型上的图案。

相交检测

// 初始化相关参数
let modelObj, selectedMesh;
const raycaster = new THREE.Raycaster();
// 设置相交面参数
const intersection = {
  intersects: false,
  point: new THREE.Vector3(),
  normal: new THREE.Vector3(),
};
const mouse = new THREE.Vector2();
const intersects = [];

...
// 判断相交面
function checkIntersection(x, y) {
  if (!modelObj) return;
  // 转换鼠标坐标
  mouse.x = (x / window.innerWidth) * 2 - 1;
  mouse.y = -(y / window.innerHeight) * 2 + 1;
  // 通过鼠标位置和相机设置射线
  raycaster.setFromCamera(mouse, camera);
  // 计算射线与衣服模型相交的面
  raycaster.intersectObjects(modelObj.children, false, intersects);

  // 若存在相交面
  if (intersects.length > 0) {
    let res = intersects.filter((res) => {
      return res && res.object;
    })[0];
    selectedMesh = res.object;
    // 获得相交点的位置
    const point = intersects[0].point;
    intersection.point.copy(point);
    intersection.normal.copy(intersects[0].face.normal);
    intersection.intersects = true;
    intersects.length = 0;
  } else {
    intersection.intersects = false;
  }
}

添加贴花

// 设置纹理loader
const textureLoader = new THREE.TextureLoader();
// 设置纹理贴图地址
const decalTexturePath = '/path/to/texture/';
// 设置贴花(图案)的纹理图案
const decalDiffuse = textureLoader.load(decalTexturePath);
// 设置贴花(图案)的材质
const decalMaterial = new THREE.MeshPhongMaterial({
  map: decalDiffuse,
  normalScale: new THREE.Vector2(1, 1),
  shininess: 30,
  transparent: true,
  depthTest: true,
  depthWrite: false,
  polygonOffset: true,
  polygonOffsetFactor: -4,
  wireframe: false,
  side: THREE.FrontSide,
});
// 贴花数组
const decals = [];
// 贴花参数初始化
const decalParams = {
  position: new THREE.Vector3(),
  orientation: new THREE.Euler(),
  minScale: 0.1,
  maxScale: 0.2,
  size: new THREE.Vector3(10, 10, 10),
};
...

// 添加贴花
function addDecal() {
  // 设置贴花的位置
  decalParams.position.copy(intersection.point);
  decalParams.orientation.copy(mouseHelper.rotation);
  // 随机贴花的尺寸
  decalParams.scale =
    decalParams.minScale +
    Math.random() * (decalParams.maxScale - decalParams.minScale);
  decalParams.size.set(decalParams.scale, decalParams.scale, decalParams.scale);
  // 拷贝材质避免修改原始的数据
  const material = decalMaterial.clone();
  // 获得贴花模型
  const decal = new THREE.Mesh(
    new DecalGeometry(
      selectedMesh,
      decalParams.position,
      decalParams.orientation,
      decalParams.size
    ),
    material
  );
  // 添加贴花模型到场景中
  decals.push(decal);
  scene.add(decal);
}

// 移除所有贴花
function removeDecals() {
  decals.forEach((decal) => {
    scene.remove(decal);
  });
  decals.length = 0;
}

总结与展望

本文从天猫趋势中心3D企划的业务出发,调研了当前3D服装柔性渲染的背景、相关产品,以及实现需要面临哪些难点和挑战,最后基于 Three.js 实现了一个具有面料替换、添加图案的3D服装渲染的 demo。因为篇幅限制,涉及到的很多点比如现有的其他3D渲染引擎、物理引擎,或者一些布料模拟框架 NvCloth 等等没有详细介绍,感兴趣的朋友可以去了解下~
下一步会基于 demo 持续完善,进一步实现工程化、产品化。未来希望通过3D服装柔性渲染技术,赋能商家快速选款、定制、出款能力,让更多中小商家参与到设计、定制的环节中来;同时3D服装渲染也可以运用在消费者端,比如虚拟试衣、提醒用户是否合身、用户自定义服装款式等等。

参考资料

Last modification:November 24th, 2021 at 07:15 pm