149 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			149 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								# 前言
							 | 
						|||
| 
								 | 
							
								继承关系:BP_XXX_Base -> BP_Idol_Base -> TsIdolActor -> AVCharacter -> ACharacter 。
							 | 
						|||
| 
								 | 
							
								主要逻辑位于TsIdolActor中,文件路径为`Script/LiveDirector/Character/TsIdolActor.ts`
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# 添加新衣服流程
							 | 
						|||
| 
								 | 
							
								1. 在Content/Character/XXX中创建继承自BP_XXX_Base的蓝图。
							 | 
						|||
| 
								 | 
							
								2. 设置SkeletalMesh。并且确保勾选了**Dynamic InsetShadow**。
							 | 
						|||
| 
								 | 
							
								3. 添加PhysicalAsset,并且保证胶囊体大致包裹模型,否则阴影会出现被裁剪的问题。
							 | 
						|||
| 
								 | 
							
								4. 添加对应的OutlineMaterial。
							 | 
						|||
| 
								 | 
							
								5. 在DressName中输入新衣服的显示名称。
							 | 
						|||
| 
								 | 
							
								6. 添加Prop标签。
							 | 
						|||
| 
								 | 
							
									1. Idol.XXX
							 | 
						|||
| 
								 | 
							
									2. Prop.Dress(第一件衣服需要设置成Prop.Dress.Default)
							 | 
						|||
| 
								 | 
							
									3. Prop.MountPoint.Body
							 | 
						|||
| 
								 | 
							
								7. ***脚本扫描***:点击编辑器的嘉然头像->角色道具配置全量生成 or 角色道具配置增量生成。会往IdolPropAssetConfig.json添加对应衣服或者道具配置数据。
							 | 
						|||
| 
								 | 
							
								# 添加新角色流程笔记
							 | 
						|||
| 
								 | 
							
								1. 添加一个Idol.xxx标签。
							 | 
						|||
| 
								 | 
							
								2. 修改下面相关文件[[#含有角色标签的文件]]。
							 | 
						|||
| 
								 | 
							
								3. 添加对应的蓝图与文件结构。
							 | 
						|||
| 
								 | 
							
									1. Content/Character
							 | 
						|||
| 
								 | 
							
										1. 在Idol_Base中添加[[#BP_XXX_Base]]。
							 | 
						|||
| 
								 | 
							
										2. 设置衣服、头发的SkeletalMesh。并且确保勾选了**Dynamic InsetShadow**。
							 | 
						|||
| 
								 | 
							
										3. 添加角色、衣服、头发的PhysicalAsset,并且保证胶囊体大致包裹模型,否则阴影会出现被裁剪的问题。
							 | 
						|||
| 
								 | 
							
									2. Content/ResArt/CharacterArt:放置角色与服装,按照
							 | 
						|||
| 
								 | 
							
										1. 动画蓝图中的***FullBody节点需要设置角色标签***。
							 | 
						|||
| 
								 | 
							
								1. 指定用于修型的PostProcess动画蓝图。
							 | 
						|||
| 
								 | 
							
								2. 添加Prop标签。
							 | 
						|||
| 
								 | 
							
									1. Idol.XXX
							 | 
						|||
| 
								 | 
							
									2. Prop.Dress
							 | 
						|||
| 
								 | 
							
									3. Prop.MountPoint.Body
							 | 
						|||
| 
								 | 
							
								3. ***脚本扫描***:点击编辑器的嘉然头像->角色道具配置全量生成 or 角色道具配置增量生成。会往IdolPropAssetConfig.json添加对应衣服或者道具配置数据。
							 | 
						|||
| 
								 | 
							
								4. 设置道具挂载信息数据表:ResArt/MountPointConfig/DT_MountPointConfig:用于设置道具挂载时的相对偏移。
							 | 
						|||
| 
								 | 
							
								5. ***材质相关操作***:
							 | 
						|||
| 
								 | 
							
									1. 在ResArt/CommonMaterial/Functions/CameraLightCollection中添加对应角色的属性。
							 | 
						|||
| 
								 | 
							
									2. 在ResArt/CommonMaterial/Functions/MF_CharacterMainLightIntensity中添加对应RoleID。
							 | 
						|||
| 
								 | 
							
									3. 在ResArt/CommonMaterial/Functions/MF_CharacterRimLightIntensity中添加对应RoleID。
							 | 
						|||
| 
								 | 
							
									4. 在对应角色的基础材质中设置RoleID数值。
							 | 
						|||
| 
								 | 
							
									5. 调用Python脚本制作Dissolve材质。LiveDirector/Editor/MaterialMigration/MakeDissolveMaterials.py
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## 含有角色标签的文件
							 | 
						|||
| 
								 | 
							
								1. [x] TsCharacterItem.ts `Script/LiveDirector/Character/View/TsCharacterItem.ts`
							 | 
						|||
| 
								 | 
							
									1. 3级角色控制界面相关的UI操作。
							 | 
						|||
| 
								 | 
							
								2. [x] TsCharacterMocapViewTmp.ts :这个是MotionProcess的UI,继承控件`/Content/UIAssets/Character/Mocap/WBP_CharacterMocapViewTmp`
							 | 
						|||
| 
								 | 
							
									1. 在MotionProcess专用地图中创建对应的Idol。
							 | 
						|||
| 
								 | 
							
								3. [x] TsPropMocapItemTmp.ts
							 | 
						|||
| 
								 | 
							
									1. 在MotionProcess专用地图中控制道具Attach到对应Idol(UI逻辑)
							 | 
						|||
| 
								 | 
							
								4. [x] TsDirectorConsoleCommandHandler.ts
							 | 
						|||
| 
								 | 
							
									1. 快捷命令 Motion同步相关 GetMotionOffset
							 | 
						|||
| 
								 | 
							
									2. 快捷命令 快速创建4个角色 IdolCostume
							 | 
						|||
| 
								 | 
							
								5. [x] TsSpawnPointSettingItem.ts
							 | 
						|||
| 
								 | 
							
									1. IdolItemUI,继承控件`/Content/UIAssets/Character/WBP_SpawnPointSettingItem`
							 | 
						|||
| 
								 | 
							
								6. [x] TsIdolPropManagerComponent.ts
							 | 
						|||
| 
								 | 
							
									1. 没有思诺与心怡
							 | 
						|||
| 
								 | 
							
									2. 需要搞清楚。
							 | 
						|||
| 
								 | 
							
								7. [x] ~~TsSimpleLevelManager.ts~~
							 | 
						|||
| 
								 | 
							
									1. SwitchLiveArea()中调用,只调用了Idol.BeiLa,属于容错语句。
							 | 
						|||
| 
								 | 
							
								8. ~~CameraDebug.cpp ~~(这个不需求)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## BP_XXX_Base
							 | 
						|||
| 
								 | 
							
								1. 指定动画蓝图。
							 | 
						|||
| 
								 | 
							
								2. 指定LiveLinkName。
							 | 
						|||
| 
								 | 
							
								3. 指定OutlineMaterial。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# AVCharacter
							 | 
						|||
| 
								 | 
							
								主要实现了`virtual void OnRep_AttachmentReplication() override;`,声明了若干BlueprintNativeEvent:
							 | 
						|||
| 
								 | 
							
								- bool CanSyncRelativeTransform();  
							 | 
						|||
| 
								 | 
							
								- void BeforeAttachToNewParent();  
							 | 
						|||
| 
								 | 
							
								- void AfterAttachToNewParent();
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
								## OnRep_AttachmentReplication()
							 | 
						|||
| 
								 | 
							
								注释:
							 | 
						|||
| 
								 | 
							
								>// 动捕模式下,CanSync=false. 各端自行计算Actor Location, client无需使用Server计算结果  
							 | 
						|||
| 
								 | 
							
								  // 自由行走模式下, CanSync=true,client需要同步server的transform信息。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								同步Attachment行为。在AActor::OnRep_AttachmentReplication()的基础上添加:
							 | 
						|||
| 
								 | 
							
								- 判断CanSync标记,以此来决定是否同步Transform
							 | 
						|||
| 
								 | 
							
								- 未Attach组件=>Attch组件前后添加BeforeAttachToNewParent()、AfterAttachToNewParent()
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								auto CanSync = CanSyncRelativeTransform(); //获取Sync标记,具体的逻辑位于TsIdolActor.ts中
							 | 
						|||
| 
								 | 
							
								if (attachmentReplication.AttachParent)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									if (RootComponent)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										USceneComponent* AttachParentComponent = (attachmentReplication.AttachComponent ? attachmentReplication.AttachComponent : attachmentReplication.AttachParent->GetRootComponent());
							 | 
						|||
| 
								 | 
							
										if (AttachParentComponent)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											if(CanSync)//增加判断Sync判断,只有在自由行走模式下才会同步Transform。
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												RootComponent->SetRelativeLocation_Direct(attachmentReplication.LocationOffset);
							 | 
						|||
| 
								 | 
							
												RootComponent->SetRelativeRotation_Direct(attachmentReplication.RotationOffset);
							 | 
						|||
| 
								 | 
							
												RootComponent->SetRelativeScale3D_Direct(attachmentReplication.RelativeScale3D);
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
											
							 | 
						|||
| 
								 | 
							
											// If we're already attached to the correct Parent and Socket, then the update must be position only.
							 | 
						|||
| 
								 | 
							
											// AttachToComponent would early out in this case.
							 | 
						|||
| 
								 | 
							
											// Note, we ignore the special case for simulated bodies in AttachToComponent as AttachmentReplication shouldn't get updated
							 | 
						|||
| 
								 | 
							
											// if the body is simulated (see AActor::GatherMovement).
							 | 
						|||
| 
								 | 
							
											const bool bAlreadyAttached = (AttachParentComponent == RootComponent->GetAttachParent() && attachmentReplication.AttachSocket == RootComponent->GetAttachSocketName() && AttachParentComponent->GetAttachChildren().Contains(RootComponent));
							 | 
						|||
| 
								 | 
							
											if (bAlreadyAttached)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												// Note, this doesn't match AttachToComponent, but we're assuming it's safe to skip physics (see comment above).
							 | 
						|||
| 
								 | 
							
												if(CanSync)
							 | 
						|||
| 
								 | 
							
												{
							 | 
						|||
| 
								 | 
							
													RootComponent->UpdateComponentToWorld(EUpdateTransformFlags::SkipPhysicsUpdate, ETeleportType::None);
							 | 
						|||
| 
								 | 
							
												}
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
											else
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												BeforeAttachToNewParent();//增加BlueprintNativeEvent
							 | 
						|||
| 
								 | 
							
												RootComponent->AttachToComponent(AttachParentComponent, FAttachmentTransformRules::KeepRelativeTransform, attachmentReplication.AttachSocket);
							 | 
						|||
| 
								 | 
							
												AfterAttachToNewParent();//增加BlueprintNativeEvent
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# TsIdolActor.ts
							 | 
						|||
| 
								 | 
							
								## VirtualOverrider
							 | 
						|||
| 
								 | 
							
								CanSyncRelativeTransform()
							 | 
						|||
| 
								 | 
							
								- 不需要同步Transform的情况
							 | 
						|||
| 
								 | 
							
									- AI控制的ACao角色不需要同步。
							 | 
						|||
| 
								 | 
							
									- 使用TsIdolMovementComponent并且勾选了ManulMovement的情况不需要同步。
							 | 
						|||
| 
								 | 
							
									- 动画蓝图中使用了**AnimGraphNode_Fullbody**节点,并且bGetMotionData为true的情况不需要同步。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								具体代码如下:
							 | 
						|||
| 
								 | 
							
								```typescript
							 | 
						|||
| 
								 | 
							
								CanSyncRelativeTransform(): boolean {
							 | 
						|||
| 
								 | 
							
									if (Utils.HasTag(this.PropTags, new UE.GameplayTag("Idol.AIACao"))) {
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									if(this.MovementComp && this.MovementComp.ManulMovement){
							 | 
						|||
| 
								 | 
							
										return false
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									var animInstance = this.Mesh.GetAnimInstance() as UE.IdolAnimInstance
							 | 
						|||
| 
								 | 
							
									let fullbodyNode = Reflect.get(animInstance, 'AnimGraphNode_Fullbody') as UE.AnimNode_FullBody
							 | 
						|||
| 
								 | 
							
									return !(fullbodyNode && fullbodyNode.bGetMotionData)
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# Prop.Dress.Default
							 | 
						|||
| 
								 | 
							
								1. TsIdolPropManagerComponent.ts ServerLoadProp()
							 | 
						|||
| 
								 | 
							
								2. DoLoadProp()
							 | 
						|||
| 
								 | 
							
								3. ServerDoLoadPropPreset()
							 | 
						|||
| 
								 | 
							
								4. GetPropPreset()
							 | 
						|||
| 
								 | 
							
								5. GetDefaultDress():取得DefaultDress标签字符串。
							 | 
						|||
| 
								 | 
							
								6. GetPropAssetConfigsByTags(tags):根据标签取得对应的资产配置(UPropAssetConfig)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								扫描所有资产:TsPropAssetManager.ts CollectAllAssets()
							 |