UPrimitiveComponent::CreateDynamicMaterialInstance字面意思是创建了一个,内含了并且赋给了自己。
如果自己身上的材质已经是动态材质实例了就直接返回。
如果不是,就创建,注意,并且赋给自己。
UMaterialInstanceDynamic* UPrimitiveComponent::CreateDynamicMaterialInstance(int32 ElementIndex, class UMaterialInterface* SourceMaterial, FName OptionalName)
{
if (SourceMaterial)
{
SetMaterial(ElementIndex, SourceMaterial);
}
UMaterialInterface* MaterialInstance = GetMaterial(ElementIndex);
UMaterialInstanceDynamic* MID = Cast<UMaterialInstanceDynamic>(MaterialInstance);
if (MaterialInstance && !MID)
{
// Create and set the dynamic material instance.
//创建动态材质实例并且 setmaterial了,注意这个细节,并不仅仅是创建了,还set自己的了
MID = UMaterialInstanceDynamic::Create(MaterialInstance, this, OptionalName);
SetMaterial(ElementIndex, MID);
}
else if (!MaterialInstance)
{
#if !(UE_BUILD_TEST || UE_BUILD_SHIPPING)
UE_LOG(LogPrimitiveComponent, Warning, TEXT("CreateDynamicMaterialInstance on %s: Material index %d is invalid."), *GetPathName(), ElementIndex);
#endif
}
return MID;
}
---------------------------------------------------------------
不看代码常理来说,set新的mesh了 是不是材质也是新的mesh的材质?
但是从代码上看,SetSkeletalMesh并没有替换新的材质,只是标记了material parameter names dirty,所以这个也是一个注意的细节。USkeletalMeshComponen替换mesh并不替换材质。
void USkeletalMeshComponent::SetSkeletalMesh(USkeletalMesh* InSkelMesh, bool bReinitPose)
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_SetSkeletalMesh);
SCOPE_CYCLE_UOBJECT(NewSkelMesh, InSkelMesh);
if (InSkelMesh == GetSkeletalMeshAsset())
{
// do nothing if the input mesh is the same mesh we're already using.
return;
}
// Update property alias
//#if WITH_EDITORONLY_DATA // TODO: Re-add these guards once the MovieScene getters/setters are working, so that we can get rid of this redundant pointer in all cooked builds
PRAGMA_DISABLE_DEPRECATION_WARNINGS
SkeletalMeshAsset = InSkelMesh;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
//#endif
// We may be doing parallel evaluation on the current anim instance
// Calling this here with true will block this init till that thread completes
// and it is safe to continue
const bool bBlockOnTask = true; // wait on evaluation task so it is safe to continue with Init
const bool bPerformPostAnimEvaluation = true;
HandleExistingParallelEvaluationTask(bBlockOnTask, bPerformPostAnimEvaluation);
UPhysicsAsset* OldPhysAsset = GetPhysicsAsset();
{
FRenderStateRecreator RenderStateRecreator(this);
// The SetSkeletalMesh base implementation is being phased out of USkinnedMeshComponent, and SetSkinnedAssetAndUpdate replaces it,
// but the SetSkeletalMesh function will remain to provide continuity and a more convenient USkeletalMesh based API avoiding the uncertainty of the Cast to USkeletalMesh.
// Also, since USkeletalMeshComponent::SetSkinnedAssetAndUpdate now calls USkeletalMeshComponent::SetSkeletalMesh, and since SetSkinnedAssetAndUpdate is virtual,
// the Super keyword is necessary to make sure that the correct USkinnedMeshComponent base function is called and prevent a recursive call loop.
Super::SetSkinnedAssetAndUpdate(InSkelMesh, bReinitPose);
#if WITH_EDITOR
ValidateAnimation();
#endif
if(IsPhysicsStateCreated())
{
if(GetPhysicsAsset() == OldPhysAsset && OldPhysAsset && Bodies.Num() == OldPhysAsset->SkeletalBodySetups.Num()) //Make sure that we actually created all the bodies for the asset (needed for old assets in editor)
{
UpdateBoneBodyMapping();
}
else
{
RecreatePhysicsState();
}
}
UpdateHasValidBodies();
ClearMorphTargets();
// Make sure that required bones are invalidated as we have just changed our mesh
// RecalcRequiredBones will be called by InitAnim below
bRequiredBonesUpToDate = false;
InitAnim(bReinitPose);
RecreateClothingActors();
}
// Mark cached material parameter names dirty
MarkCachedMaterialParameterNameIndicesDirty();
// Update this component streaming data.
IStreamingManager::Get().NotifyPrimitiveUpdated(this);
}