ue5 小知识点 CreateDynamicMaterialInstance 和 USkeletalMeshComponent::SetSkeletalMesh 细节

 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);
}

猜你喜欢

转载自blog.csdn.net/opk8848/article/details/130567290