找回密码
 立即注册
查看: 227|回复: 0

【虚拟仿真】Unity3D中拆分模型教程(多种类型模型拆分)

[复制链接]
发表于 2022-11-15 23:39 | 显示全部楼层 |阅读模式
推荐阅读
    CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客QQ群:1040082875
大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。
一、前言

今天有小伙伴在我这篇文章【虚拟仿真】Unity3D对物体进行拆分实现下面问我如何一秒一拆:


虽然我已经给出了思路,但是离实现还是有点思路,正好我对于我这篇文章也是不满意,就解答一下小伙伴的疑惑,然后再将文章内容进行升级。
原文章:【虚拟仿真】Unity3D对物体进行拆分实现 的思路是获取子物体跟父物体之间的距离,然后拆分的时候让子物体移动到跟父物体距离的两倍的位置上,这种方法只能拆分完全对称镜像的模型,比如这样的:


但是,其他类型的,奇奇怪怪的模型估计就不那么好用了,所以本篇文章升级了一下,可以拆分更多模型,快来看看吧。
二、实现一秒一拆

首先,解决小伙伴一秒一拆代码的实现。本小节根据【虚拟仿真】Unity3D对物体进行拆分实现这篇文章基础上进行实现。
新建个项目,模板选3D,我用的是Unity3D版本是Unity 2019.4.7f1:


搭建场景,简简单单搭一个十字模型:



将DoTween插件导入:


新建脚本SplitTest.cs,双击打开脚本,修改代码:
  1. using DG.Tweening;using System.Collections;using System.Collections.Generic;using UnityEngine;publicclassSplitTest:MonoBehaviour{privateTransform m_ParObj;//中心点private List<GameObject> m_Child;//所有子对象private List<Vector3> m_InitPoint =newList<Vector3>();//初始位置privateint m_IsSplitState =0;privatefloat m_TimeTotal =0;//总时间privatefloat m_Timecurrent =0;//当前时间privateint m_TimeDisRe =0;//时间间隔 记录privateint IndexCount =0;//计数publicint m_TimeDistance =1;//时间间隔voidStart(){
  2.         m_ParObj =GetComponent<Transform>();
  3.         m_Child =GetChild(m_ParObj);for(int i =0; i < m_Child.Count; i++){
  4.             m_InitPoint.Add(m_Child[i].transform.position);}
  5.         m_TimeTotal = m_Child.Count* m_TimeDistance;}//获取所有子对象public List<GameObject>GetChild(Transform obj){
  6.         List<GameObject> tempArrayobj =newList<GameObject>();foreach(Transform child in obj){
  7.             tempArrayobj.Add(child.gameObject);}return tempArrayobj;}voidUpdate(){if(Input.GetKeyDown(KeyCode.W)){
  8.             m_Timecurrent =0;
  9.             m_TimeDisRe =0;
  10.             IndexCount =0;
  11.             m_IsSplitState =1;}if(Input.GetKeyDown(KeyCode.S)){
  12.             m_Timecurrent =0;
  13.             m_TimeDisRe =0;
  14.             IndexCount =0;
  15.             m_IsSplitState =2;}if(m_IsSplitState ==1){//拆分SplitObject();}elseif(m_IsSplitState ==2){//合并MergeObject();}}privatevoidSplitObject(){
  16.         m_Timecurrent += Time.deltaTime;if(m_Timecurrent <= m_TimeTotal && IndexCount< m_Child.Count){if(Mathf.FloorToInt(m_Timecurrent)== m_TimeDisRe){
  17.                 m_TimeDisRe += m_TimeDistance;Vector3 tempV3 =SplitObjTest(m_ParObj.transform, m_Child[IndexCount].transform);
  18.                 m_Child[IndexCount].transform.DOMove(tempV3,1f,false);
  19.                 IndexCount++;}}}privatevoidMergeObject(){
  20.         m_Timecurrent += Time.deltaTime;if(m_Timecurrent <= m_TimeTotal && IndexCount < m_Child.Count){if(Mathf.FloorToInt(m_Timecurrent)== m_TimeDisRe){
  21.                 m_TimeDisRe += m_TimeDistance;
  22.                 m_Child[IndexCount].transform.DOMove(m_InitPoint[IndexCount],3f,false);
  23.                 IndexCount++;}}}publicVector3SplitObjTest(Transform m_ParObj,Transform _TargetObj){Vector3 tempV3;
  24.         tempV3.x =(_TargetObj.position.x - m_ParObj.position.x)*2;
  25.         tempV3.y =(_TargetObj.position.y - m_ParObj.position.y)*2;
  26.         tempV3.z =(_TargetObj.position.z - m_ParObj.position.z)*2;return tempV3;}}
复制代码
效果图:



三、对称型模型拆分

模型样例:


这种规则的,对称的,镜像的,正方形的,都可以使用下面的代码。
新建脚本SplitCube.cs,修改代码:
  1. using DG.Tweening;using System.Collections;using System.Collections.Generic;using UnityEngine;publicclassSplitCube:MonoBehaviour{privateTransform m_ParObj;//中心点private List<GameObject> m_Child;//所有子对象private List<Vector3> m_InitPoint =newList<Vector3>();//初始位置privatevoidStart(){
  2.         m_ParObj = transform;
  3.         m_Child =GetChild(m_ParObj);//获取所有子对象for(int i =0; i < m_Child.Count; i++){
  4.             m_InitPoint.Add(m_Child[i].transform.position);}}//获取所有子对象public List<GameObject>GetChild(Transform obj){
  5.         List<GameObject> tempArrayobj =newList<GameObject>();foreach(Transform child in obj){
  6.             tempArrayobj.Add(child.gameObject);}return tempArrayobj;}privatevoidUpdate(){if(Input.GetKeyDown(KeyCode.W)){//拆分SplitObject();}if(Input.GetKeyDown(KeyCode.S)){//合并MergeObject();}}privatevoidSplitObject(){for(int i =0; i < m_Child.Count; i++){Vector3 tempV3 =SplitObjTest(m_ParObj, m_Child[i].transform);
  7.             m_Child[i].transform.DOMove(tempV3,3f,false);}}privatevoidMergeObject(){for(int i =0; i < m_InitPoint.Count; i++){
  8.             m_Child[i].transform.DOMove(m_InitPoint[i],3f,false);}}publicVector3SplitObjTest(Transform m_ParObj,Transform _TargetObj){Vector3 tempV3;
  9.         tempV3.x =(_TargetObj.position.x - m_ParObj.position.x)*2;
  10.         tempV3.y =(_TargetObj.position.y - m_ParObj.position.y)*2;
  11.         tempV3.z =(_TargetObj.position.z - m_ParObj.position.z)*2;return tempV3;}}
复制代码
效果图:




四、不规则形状模型拆分

搭建一个不规则的模型:


如果还用原来的代码就会有些问题:


那么就可以使用预先拆分法来拆分模型。
先把原模型复制一份出来,然后将零件移动到想要的位置上:


新建脚本SplitAnomaly.cs,修改脚本:
  1. using DG.Tweening;using System.Collections;using System.Collections.Generic;using UnityEngine;publicclassSplitAnomaly:MonoBehaviour{publicTransform m_ChildPointParent;//要移动的子对象的父物体private List<GameObject> m_Child;//所有子对象private List<Vector3> m_InitPoint =newList<Vector3>();//初始位置publicTransform m_TargetPointParent;//目标点对象的父物体private List<GameObject> m_TargetChild;//目标点所有子对象private List<Vector3> m_TargetPoint =newList<Vector3>();//要移动的位置privatevoidStart(){
  2.         m_Child =GetChild(transform);//获取所有子对象for(int i =0; i < m_Child.Count; i++){
  3.             m_InitPoint.Add(m_Child[i].transform.position);}
  4.         m_TargetChild =GetChild(m_TargetPointParent);//获取所有目标点子对象for(int i =0; i < m_TargetChild.Count; i++){
  5.             m_TargetPoint.Add(m_TargetChild[i].transform.position);}}//获取所有子对象public List<GameObject>GetChild(Transform obj){
  6.         List<GameObject> tempArrayobj =newList<GameObject>();foreach(Transform child in obj){
  7.             tempArrayobj.Add(child.gameObject);}return tempArrayobj;}privatevoidUpdate(){if(Input.GetKeyDown(KeyCode.W)){//拆分SplitObject();}if(Input.GetKeyDown(KeyCode.S)){//合并MergeObject();}}privatevoidSplitObject(){for(int i =0; i < m_Child.Count; i++){
  8.             m_Child[i].transform.DOMove(m_TargetPoint[i],3f,false);}}privatevoidMergeObject(){for(int i =0; i < m_InitPoint.Count; i++){
  9.             m_Child[i].transform.DOMove(m_InitPoint[i],3f,false);}}}
复制代码
给任意对象添加上SplitAnomaly 脚本组件,将对象对象拖入卡槽中:


效果图:



五、总结

再来总结一下实现的思路,首先获取到子对象到父对象的距离,将这个距离乘以2,然后将子对象移动到这个位置就实现了拆分。
但是,这在面对复杂模型的时候就不太好用了,这时候就可以使用第二种,不规则形状模型的拆分方法,也就是预拆法,先拆好,然后将子对象移动到要拆分的位置就可以了。
最后:
本篇文章的代码都是博主思考一遍遍调试修改来的,付出了不少心血。
如果这篇文章对你有帮助,受累一键三连。


博主还有跟多宝藏文章等待你的发掘哦:
专栏方向简介
Unity3D开发小游戏小游戏开发教程分享一些使用Unity3D引擎开发的小游戏,分享一些制作小游戏的教程。
Unity3D从入门到进阶入门从自学Unity中获取灵感,总结从零开始学习Unity的路线,有C#和Unity的知识。
Unity3D之UGUIUGUIUnity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。
Unity3D之读取数据文件读取使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。
Unity3D之数据集合数据集合数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。
Unity3D之VR/AR(虚拟仿真)开发虚拟仿真总结博主工作常见的虚拟仿真需求进行案例讲解。
Unity3D之插件插件主要分享在Unity开发中用到的一些插件使用方法,插件介绍等
Unity3D之日常开发日常记录主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等
Unity3D之日常BUG日常记录记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 22:33 , Processed in 0.088210 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表