Unity Metaverse(五)、Avatar数字人换装系统的实现方案

文章目录

  • 🎈 前言
  • 🎈 如何将RPM中编辑的Avatar导入到Unity
  • 🎈 如何提取模型中的Mesh网格、Material材质、及Texture贴图
  • 🎈 如何提取RPM网页中的图片资源
  • 🎈 资源配置


🎈 前言

"Avatar换装"

随着元宇宙概念的火热,数字人换装捏脸的实现方案逐渐受到更多关注,本篇内容主要介绍如何在Unity中实现数字人的换装系统,涉及的所有美术资源均来源于RPM(Ready Player Me),地址:Ready Player Me主页。

实现该系统涉及到的无非是老生常谈的几项内容:

  • Skinned Mesh Renderer - 蒙皮网格
  • Material - 材质球
  • Avatar Bone - 骨架

重要点,也是核心点,就是基于Avatar数字人的同一套骨架,也就是讲当数字人进行换装时,切换的是Skinned Mesh Renderer中的Mesh网格及Material材质球,骨架是不会去改变的。

🎈 如何将RPM中编辑的Avatar导入到Unity

本专栏的第一篇内容中有介绍RPM的使用以及将Avatar导入Unity的过程,下面简要说明。

首先要下载其SDK,地址:Ready Player Me - Unity SDK,将下载的.unitypackage包导入到Unity中,可以看到菜单栏中有了Ready Player Me的选项,Avatar Loader可以将我们自定义的Avatar模型导入到Unity中:

Avatar Loader

在RPM的Avatar Hub中,选择我们想要导入到Unity中的Avatar,通过Copy .glb URL复制链接。

Copy .glb URL
回到Unity中,将复制的链接粘贴到Avatar URL or Short Code中,点击Load Avatar

Load Avatar
下载完成后,在Resources文件夹下可以看到下载的.glb模型文件:

glb 模型
Unity中常用的模型文件格式为.fbx类型,可以通过Blender软件将.glb格式文件转换为.fbx格式文件,需要注意在导出选项里,将路径模式改为复制,并选中后面的内嵌纹理,否则导入到Unity中只是一个白模,并没有材质、贴图。

导出fbx

🎈 如何提取模型中的Mesh网格、Material材质、及Texture贴图

Mesh网格和Material材质的提取可以直接在Skinned Mesh Renderer组件中获取并通过实例化并调用AssetDatabase类中的CreateAsset来创建和保存资产:

// 摘要:
//     Creates a new asset at path.
//
// 参数:
//   asset:
//     Object to use in creating the asset.
//
//   path:
//     Filesystem path for the new asset.
[MethodImpl(MethodImplOptions.InternalCall)]
[NativeThrows]
[PreventExecutionInState(AssetDatabasePreventExecution.kGatheringDependenciesFromSourceFile, PreventExecutionSeverity.PreventExecution_ManagedException, "Assets may not be created during gathering of import dependencies")]
public static extern void CreateAsset([NotNull("ArgumentNullException")] UnityEngine.Object asset, string path);
  • asset:第一个参数为要进行保存/创建的资产;
  • path:第二个参数为该资产生成的文件夹路径。

Texture贴图资源可以通过调用AssetDatabase类中的GetDependencies方法获取材质球的依赖项文件路径:

// 摘要:
//     Returns an array of all the assets that are dependencies of the asset at the
//     specified pathName. Note: GetDependencies() gets the Assets that are referenced
//     by other Assets. For example, a Scene could contain many GameObjects with a Material
//     attached to them. In this case, GetDependencies() will return the path to the
//     Material Assets, but not the GameObjects as those are not Assets on your disk.
//
// 参数:
//   pathName:
//     The path to the asset for which dependencies are required.
//
//   recursive:
//     Controls whether this method recursively checks and returns all dependencies
//     including indirect dependencies (when set to true), or whether it only returns
//     direct dependencies (when set to false).
//
// 返回结果:
//     The paths of all assets that the input depends on.
public static string[] GetDependencies(string pathName)
{return GetDependencies(pathName, recursive: true);
}

根据路径调用LoadAssetAtPath方法加载贴图资源:

// 摘要:
//     Returns the first asset object of type type at given path assetPath.
//
// 参数:
//   assetPath:
//     Path of the asset to load.
//
//   type:
//     Data type of the asset.
//
// 返回结果:
//     The asset matching the parameters.
[MethodImpl(MethodImplOptions.InternalCall)]
[PreventExecutionInState(AssetDatabasePreventExecution.kGatheringDependenciesFromSourceFile, PreventExecutionSeverity.PreventExecution_ManagedException, "Assets may not be loaded while dependencies are being gathered, as these assets may not have been imported yet.")]
[PreventExecutionInState(AssetDatabasePreventExecution.kDomainBackup, PreventExecutionSeverity.PreventExecution_ManagedException, "Assets may not be loaded while domain backup is running, as this will change the underlying state.")]
[NativeThrows]
[TypeInferenceRule(TypeInferenceRules.TypeReferencedBySecondArgument)]
public static extern UnityEngine.Object LoadAssetAtPath(string assetPath, Type type);public static T LoadAssetAtPath<T>(string assetPath) where T : UnityEngine.Object;

本篇内容中提取Avatar数字人相关资产的工作流如下:

  • fbx导入到Unity后,在Import Settings导入设置中将Material Location类型改为Use External Materials(Legacy),应用后编辑器会在该fbx文件所在目录下生成相应的材质和贴图资源文件夹:

Materials Location

  • 将所有法线贴图Texture Type改为Normal map,并检查法线贴图是否用在相应材质球上:
    Normal map
  • 调用自定义的编辑器方法,提取资产:

提取资产
该方法可以提取Avatar的头部、身体、上衣、裤子及鞋子的相关资产,代码如下:

using UnityEngine;
using UnityEditor;namespace Metaverse
{/// <summary>/// 用于提取ReadyPlayerMe的Avatar服装资源/// </summary>public class RPMAvatarClothingCollecter {[MenuItem("Metaverse/Ready Player Me/Avatar Clothing Collect")]public static void Execute(){//如果未选中任何物体if (Selection.activeGameObject == null) return;//弹出窗口 选择资源提取的路径string collectPath = EditorUtility.OpenFolderPanel("选择路径", Application.dataPath, null);//如果路径为空或无效 返回if (string.IsNullOrEmpty(collectPath)) return;//AssetDatabase路径collectPath = collectPath.Replace(Application.dataPath, "Assets");if (!AssetDatabase.IsValidFolder(collectPath)) return;//头部Transform head = Selection.activeGameObject.transform.Find("Wolf3D_Head");if (head != null) Collect(collectPath, head.GetComponent<SkinnedMeshRenderer>(), "head");//身体Transform body = Selection.activeGameObject.transform.Find("Wolf3D_Body");if (head != null) Collect(collectPath, body.GetComponent<SkinnedMeshRenderer>(), "body");//上衣Transform top = Selection.activeGameObject.transform.Find("Wolf3D_Outfit_Top");if (top != null) Collect(collectPath, top.GetComponent<SkinnedMeshRenderer>(), "top");//裤子Transform bottom = Selection.activeGameObject.transform.Find("Wolf3D_Outfit_Bottom");if (bottom != null) Collect(collectPath, bottom.GetComponent<SkinnedMeshRenderer>(), "bottom");//鞋子Transform footwear = Selection.activeGameObject.transform.Find("Wolf3D_Outfit_Footwear");if (footwear != null) Collect(collectPath, footwear.GetComponent<SkinnedMeshRenderer>(), "footwear");//刷新AssetDatabase.Refresh();}public static void Collect(string path, SkinnedMeshRenderer smr, string suffix){//创建Mesh网格资产AssetDatabase.CreateAsset(Object.Instantiate(smr.sharedMesh), string.Format("{0}/mesh_{1}.asset", path, suffix));//创建Material材质球资产Material material = Object.Instantiate(smr.sharedMaterial);AssetDatabase.CreateAsset(material, string.Format("{0}/mat_{1}.asset", path, suffix));//获取材质球的依赖项路径string[] paths = AssetDatabase.GetDependencies(AssetDatabase.GetAssetPath(material));//遍历依赖项路径for (int i = 0;i < paths.Length; i++){//AssetDatabase路径string p = paths[i].Replace(Application.dataPath, "Assets");//根据路径加载Texture贴图资源Texture tex = AssetDatabase.LoadAssetAtPath<Texture>(p);if (tex == null) continue;TextureImporter textureImporter = AssetImporter.GetAtPath(p) as TextureImporter;//主贴图if (textureImporter.textureType == TextureImporterType.Default){AssetDatabase.MoveAsset(p, string.Format("{0}/tex_{1}_d.jpg", path, suffix));}//法线贴图if (textureImporter.textureType == TextureImporterType.NormalMap){AssetDatabase.MoveAsset(p, string.Format("{0}/tex_{1}_n.jpg", path, suffix));}}}}
}

🎈 如何提取RPM网页中的图片资源

提取网页中的图片资源可以使用ImageAssistant图片助手,一款Chrome浏览器中用于嗅探、分析网页图片、图片筛选、下载等功能的扩展程序,当然也可以在Edge浏览器中去使用,地址:Image Assistant

图片助手

选中想要下载的图片资源并开始下载:

下载图片

🎈 资源配置

正常开发工作中,建议构建出不同服装资源的AB(AssetsBundle)包,通过加载AB包来实现各种服装的切换,本篇内容中通过Scriptable Object配置各种服装资源来实现Demo,首先编写外观数据类:

using System;
using UnityEngine;namespace Metaverse
{/// <summary>/// Avatar外观数据/// </summary>[Serializable]    public class AvatarOutlookData{/// <summary>/// 头部网格/// </summary>public Mesh headMesh;/// <summary>/// 头部材质/// </summary>public Material headMaterial;/// <summary>/// 身体网格/// </summary>public Mesh bodyMesh;/// <summary>/// 身体材质/// </summary>public Material bodyMaterial;/// <summary>/// 上衣网格/// </summary>public Mesh topMesh;/// <summary>/// 上衣材质/// </summary>public Material topMaterial;/// <summary>/// 裤子网格/// </summary>public Mesh bottomMesh;/// <summary>/// 裤子材质/// </summary>public Material bottomMaterial;/// <summary>/// 鞋子网格/// </summary>public Mesh footwearMesh;/// <summary>/// 鞋子材质/// </summary>public Material footwearMaterial;/// <summary>/// 缩略图/// </summary>public Sprite thumb;}
}

编写配置类如下,实现后创建一个新的配置表并配置数据:

using UnityEngine;namespace Metaverse
{/// <summary>/// Avatar服装配置/// </summary>[CreateAssetMenu(menuName = "Metaverse/Avatar Clothing Config")]public class AvatarClothingConfig : ScriptableObject{public AvatarOutlookData[] data = new AvatarOutlookData[0];}
}

数据配置

测试脚本如下:

using UnityEngine;public class Example : MonoBehaviour
{[SerializeField] private SkinnedMeshRenderer head;[SerializeField] private SkinnedMeshRenderer body;[SerializeField] private SkinnedMeshRenderer top;[SerializeField] private SkinnedMeshRenderer bottom;[SerializeField] private SkinnedMeshRenderer footwear;[SerializeField] private Metaverse.AvatarOutlookConfig config;private void OnGUI(){if (GUILayout.Button("服装一", GUILayout.Width(200f), GUILayout.Height(50f))) Apply(0);if (GUILayout.Button("服装二", GUILayout.Width(200f), GUILayout.Height(50f))) Apply(1);if (GUILayout.Button("服装三", GUILayout.Width(200f), GUILayout.Height(50f))) Apply(2);}private void Apply(int index){head.sharedMesh = config.data[index].headMesh;head.sharedMaterial = config.data[index].headMaterial;body.sharedMesh = config.data[index].bodyMesh;body.sharedMaterial = config.data[index].bodyMaterial;top.sharedMesh = config.data[index].topMesh;top.sharedMaterial = config.data[index].topMaterial;bottom.sharedMesh = config.data[index].bottomMesh;bottom.sharedMaterial = config.data[index].bottomMaterial;footwear.sharedMesh = config.data[index].footwearMesh;footwear.sharedMaterial = config.data[index].footwearMaterial;}
}

换装

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/63576.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【互动多媒体】应用形式(二)体感换装/虚拟试衣

应用描述 体感换装/虚拟试衣就是让用户能够通过简单的操作&#xff0c;看到显示设备重的自己&#xff0c;虚拟地穿上了衣服、装备&#xff0c;以求品牌价值传递或是服饰的试穿体验。 体感换装放在第二项去说&#xff0c;主要是因为它一方面和互动拍照是相关联的&#xff0c;另…

豆瓣网电影信息的抓取

分析 通过上面两张图片可以发现 第一页url&#xff1a;https://movie.douban.com/top250?start0&filter 第二页url&#xff1a;https://movie.douban.com/top250?start25&filter 由此类推 第n页url https://movie.douban.com/top250?startn-1然后25&filter 代…

豆瓣电影简单评分模型-从收集数据到建模分析

思路&#xff1a; 从豆瓣上抓取数据【主要是评分&#xff0c;只是那个人数的百分比和最终评分&#xff0c;不过够用了】 一、收集数据 起始URL&#xff1a;https://movie.douban.com/j/new_search_subjects?sortU&range0,10&tags&start0 【注&#xff0c;爬取的对…

抓取豆瓣的电影排行榜TOP100

1 #!/usr/bin/env python2 # -*- coding:utf-8 -*-3 """4 一个简单的Python爬虫, 用于抓取豆瓣电影Top前100的电影的名称5 Anthor: Andrew Liu6 Version: 0.0.17 Date: 2014-12-048 Language: Python2.7.89 Editor: Sublime Text2 10 Operate: 具体操作请看READ…

爬取豆瓣电影Top250影片信息

爬取豆瓣电影Top250影片信息 查看影片的详细信息爬取过程需安装的包确定爬取地址发送请求头解析数据保存数据完整代码 查看影片的详细信息 进入豆瓣电影Top250&#xff0c;选择某一影片&#xff0c;右击&#xff0c;选择“检查元素”。 爬取过程 需安装的包 安装requests、…

豆瓣电影详情数据爬取

这次的爬虫我们来看url携带多个参数的页面爬取 打开豆瓣电影排行榜官网&#xff0c;这里我选择了喜剧类型&#xff0c;发现只要将鼠标下滚翻到该页面最底部&#xff0c;滚轮就会重新跳到中间&#xff0c;相当于浏览器又发送了请求&#xff0c;重新加载一个页面&#xff0c;对应…

豆瓣电影top250信息爬取

摘要 python的网络爬虫可以方便抓取网页的消息&#xff0c;本文以豆瓣网站为例&#xff0c;实现了python网络爬虫抓取豆瓣电影排行榜top250的过程&#xff0c;以及其中遇到的问题和解决过程。 1&#xff0e;引言 网络爬虫又称网络蜘蛛&#xff0c;或网络机器人。是一种按照一…

基于Python的豆瓣中文影评差评分析

资源下载地址&#xff1a;https://download.csdn.net/download/sheziqiong/86773473 资源下载地址&#xff1a;https://download.csdn.net/download/sheziqiong/86773473 1. NLP NLP&#xff08;Natural Language Processing&#xff09;是指自然语言处理&#xff0c;他的目的…

基于电影《少年的你》豆瓣影评数据的爬取与分析

目标网站&#xff1a;豆瓣电影 目标网址&#xff1a;https://movie.douban.com/subject/30166972/comments?statusP 目标数据&#xff1a;&#xff08;1&#xff09;评价 &#xff08;2&#xff09;日期 &#xff08;3&#xff09;评论 &#xff08;4&#xff09;评论点赞 …

爬取豆瓣电影前十页的好评一般差评

分析一波 爬取的地址&#xff1a;https://movie.douban.com/subject/26588308/comments 分别找出好评、一般、差评的评论&#xff1a; 通过地址栏分析&#xff0c;评论的类型和percent_type有关&#xff1a; 好评为h一般为m差评为l 但是我们想找的是在全部里面寻找好评一般和差…

豆瓣电影当中的电影详情数据

打开豆瓣电影&#xff0c;点击当中的排行榜&#xff0c;相应的类型选择为喜剧类型&#xff0c;当前的数据如果不使用数据解析来实现的话&#xff0c;会不会通过阿贾克斯请求来请求到json形式相应的电影数据呢&#xff1f; 当滚轮拖动到底部的时候&#xff0c;发现滚轮很快就变动…

针对豆瓣TOP前250电影做的简单的数据分析~

~~~~~~内容参考如下使用python抓取豆瓣top250电影数据进行分析 - 简书 https://www.jianshu.com/p/720b193a5c2b #导入库&#xff0c;三大常用数据分析库 import numpy as np import pandas as pd import matplotlib.pyplot as plt import matplotlib#读取保存本地的excel文件…

电影评分数据集的分析

目录 数据集的获得使用工具项目流程 数据集的获得 进入该网址&#xff1a;https://grouplens.org/datasets/movielens/ 找到如下part&#xff1a; 点击ml-100k.zip进行数据集的下载 在本地解压后&#xff0c;将会看到如下内容&#xff1a; 但我们目前只需要三个文件&#…

爬取豆瓣电影的评论

好久没有爬虫了&#xff0c;今天突然叫爬豆瓣&#xff0c;有点懵了&#xff0c;不过看了看以前爬的&#xff0c;一葫芦画瓢整了一个这个。bs4和requests yyds&#xff01; 分析一波 爬取的地址&#xff1a;https://movie.douban.com/subject/26588308/comments 每次翻页可以看到…

2020 豆瓣电影榜单出炉,直接在豆瓣上看电影吧

公众号后台回复“图书“&#xff0c;了解更多号主新书内容 作者&#xff1a;苏生不惑 来源&#xff1a;苏生不惑 一晃又到了年底&#xff0c;2020年就要结束了&#xff08;你的小目标完成了吗&#xff09;&#xff0c;一年一度的豆瓣电影榜单也出炉了https://movie.douban.com/…

豆瓣Top250电影数据分析报告

我的其他数据分析报告:求职指南——数据分析职位解析 【Python3】Requests+正则表达式+multiprocessing爬虫并存入MySQL数据库 一、分析背景及目的 豆瓣对Top250电影的定义: 豆瓣用户每天都在对“看过”的电影进行“很差”到“力荐”的评价,豆瓣根据每部影片看过的人数以及…

爬取豆瓣电影分类排行榜

确定目标网址&#xff1a;豆瓣电影排行榜 使用Google浏览器打开目标网址&#xff0c;右侧选择分类“传记”&#xff0c;按F12打开开发者工具&#xff0c;会打开如下界面&#xff1a;左侧是数据内容&#xff0c;右侧是网页源代码信息。注&#xff1a;由于该页面是动态的&#x…

豆瓣top250电影数据分析

分析背景及目的 豆瓣电影 Top 250定义:豆瓣用户每天都在对“看过”的电影进行“很差”到“力荐”的评价,豆瓣根据每部影片看过的人数以及该影片所得的评价等综合数据,通过算法分析产生豆瓣电影 Top 250。 本文对于"好评电影"(豆瓣电影top250)的影片评分,上映…

Python对豆瓣电影Top250并进行数据分析

由于CSDN审核机制&#xff0c;导致原文章无法发出&#xff0c;故修改了相关词汇&#xff0c;并改为两篇问章发布。 数据获取 翻页操作 观察可知&#xff0c;我们只需要修改start参数即可 headers字段 headers中有很多字段&#xff0c;这些字段都有可能会被对方服务器拿过来进…