UE4——编辑器资源操作篇

我又来了,最近更新频率有所降低并不是我没有学到什么新的知识,只是最近工作有点忙加上 鼻炎引起发烧 然后又因为发烧引起上火口腔溃疡 什么的都来了。 所以大家工作在忙也要照顾好自己的身体

进入正题

今天我们来讲讲如何利用代码去修改我们的材质实例资源里面的参数并保存下来、创建蓝图、以代码的方式添加组件到蓝图内,首先我们来分析一下这篇博客涉及到的知识——

1.如何修改材质实例的编辑器参数
2.创建出蓝图
3.为蓝图中添加响应的组件或者是添加相应的静态网格组件
4.保存资源
5. 最后一点也是最难的一点(以上4点都在不打开编辑器的情况下去操作)

好了废话不多说,我们直接开始吧

首先分析一个点就是我们需要不打开编辑器的情况下去执行这些操作就必须让引擎识别到我们不需要打开编辑器又能运行我们的代码,这里最直接的就是使用commendlet的方式去操作了。因为commendlet的执行顺序是高于启动编辑器的。

关于commendlet的相关介绍可以看会我之前的博客有一期是有讲这个的。现在我们来写一个我们自己的commendlet

下面仅供参考——不完整示例
.h

UCLASS()
class UMyCommandlet : public UCommandlet
{
	GENERATED_UCLASS_BODY()

	/** Runs the commandlet */ //这里是我们commandlet的入口 其实和控制台应用程序一样
	virtual int32 Main(const FString& Params) override;
public:
	//示例 更改材质参数函数
	void ChangeMatParam();
	//示例创建蓝图函数
	void CreateBlueprint();
private:
	//我们自己创建一个世界
	class FPreviewScene* Scene;

.cpp

int32 UMyCommandlet ::Main(const FString& Params)
{
	ChangeMatParam();
	CreateBlueprint();
}

void ChangeMatParam()
{
	//首先我们先基于一个材质实例或者材质去创建一个材质
	//这里不创建也行直接把想要修改的材质加载上来就好了
	class UMaterialInterface* InParentMat =  LoadObject<UMaterialInterface>(NULL, TEXT("父材质的路径"), NULL, LOAD_None, NULL);
	FString NewMaterialPath = "这里是新创建的材质想保存的位置";
	
	// Make sure we have a parent
	if (!ensure(InParentMat))
	{
		return 1;
	}
	FString MaterialFullName = FPaths::GetBaseFilename(NewMaterialPath );
	
	// The material could already exist in the project
	FString BasePackageName = (FPaths::GetPath(NewMaterialPath )+TEXT("/")+MaterialFullName);

	const FString Suffix(TEXT(""));
	FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
	FString FinalPackageName;
	//这里bReplace 的作用是是否替换以存在的资源 ---这部分内容我删减掉了因为 不删减 的话太多代码了 免得你们看得眼花缭乱
	if (!bReplace) AssetToolsModule.Get().CreateUniqueAssetName(BasePackageName, Suffix, FinalPackageName, MaterialFullName);
	else FinalPackageName = BasePackageName;
	UPackage* Package = CreatePackage(NULL, *FinalPackageName);


		auto MaterialInstanceFactory = NewObject<UMaterialInstanceConstantFactoryNew>();
		MaterialInstanceFactory->InitialParent = InParentMat;
		UMaterialInstanceConstant* UnrealMaterialConstant = (UMaterialInstanceConstant*)MaterialInstanceFactory->FactoryCreateNew(UMaterialInstanceConstant::StaticClass(), Package, *MaterialFullName, RF_Standalone | RF_Public, NULL, GWarn);
		
		if (UnrealMaterialConstant != NULL)
		{
			// Notify the asset registry
			FAssetRegistryModule::AssetCreated(UnrealMaterialConstant);
			//修改贴图参数
			UnrealMaterialConstant->SetTextureParameterValueEditorOnly(FMaterialParameterInfo("参数名"), Texture);//后面是要设置的贴图
			//设置数值
			UnrealMaterialConstant->SetScalarParameterValueEditorOnly(FMaterialParameterInfo("参数名"), 1);
			//设置颜色
			UnrealMaterialConstant->SetVectorParameterValueEditorOnly(FMaterialParameterInfo("参数名"), TempColor); //tempColor 是FlinearColor
			//开关静态开关Static Switch Param
			FStaticParameterSet OutStaticParameters;
			UnrealMaterialConstant->GetStaticParameterValues(OutStaticParameters);
			for (auto& StaticSwitch : OutStaticParameters.StaticSwitchParameters)  //Iteration All Switch Param
			{
					int32 index;
					if (FieldArr.Find(StaticSwitch.ParameterInfo.Name.ToString(), index))
					{
						FString ParamName = StaticSwitch.ParameterInfo.Name.ToString(); //获取静态开关参数名称
						StaticSwitch.Value = false;//设置开关值
						StaticSwitch.bOverride = true; //这里如果修改了值一定要设置为true 这里可以理解为编辑器上每个可调节项前面的预览开关
					}
			}
			UnrealMaterialConstant->PostEditChange();
			UnrealMaterialConstant->UpdateStaticPermutation(OutStaticParameters); //一定一定要更新
			FMaterialUpdateContext MaterialUpdateContext;
			MaterialUpdateContext.AddMaterialInstance(NewMat); //一定一定要更新
	
			//保存下来
			Package->SetDirtyFlag(true);
			TArray<UPackage*> Packages;
			Packages.Add(Package); // Fully load and check out is done in UEditorLoadingAndSavingUtils::SavePackages
			// Save without a prompt
			UEditorLoadingAndSavingUtils::SavePackages(Packages, false);
		}
	
}

//上面修改材质参数的示例代码已经有了就差创建蓝图了 但是在没有打开编辑器的情况下创建蓝图保存是会报错的(不知道是不是我做法不对),所以我这里用了一个取巧的方法

具体思路 :

  1. 首先在项目工程内创建一个空的蓝图并保存下来
  2. 在命令行中加载之前保存下来的蓝图进行复制一份 然后修改父类 并往里面添加静态网格数据

看着好像很简单就两条,但是想要创建想要往蓝图内添加静态网格就必须创建一个静态网格组件并将这个组件附加挂载到Actor上。 但是问题又来了,我们连关卡都没加载哪里来的世界 给我们去创建actor

这里我们自己来创建一个世界 具体看下面示例代码

void CreateBlueprint()
{
	//创建我们自己的场景
	Scene = new FPreviewScene();
	
	//创建一个Actor 
	FActorSpawnParameters Spawnparam;
	Spawnparam.bAllowDuringConstructionScript = true;
	AActor* TempActor = Scene->GetWorld()->SpawnActor<AActor>(AActor::StaticClass(), FTransform::Identity, Spawnparam);
	//添加根组件
	USceneComponent* Component = NewObject<USceneComponent>(TempActor ,FName("RootComponent"));
	TempActor ->AddOwnedComponent(Component);
	TempActor ->AddInstanceComponent(Component);
	Component->RegisterComponent();
	TempActor ->SetRootComponent(Component);
	//添加静态网格
	UStaticMesh* Mesh = LoadObject<UStaticMesh>(NULL, "静态网格路径", NULL, LOAD_None, NULL);
	UStaticMeshComponent* Component = NewObject<UStaticMeshComponent>(TempActor , FName(*UKismetSystemLibrary::GetObjectName(Mesh)));
	FVector RelativeLoction = FVector::ZeroVector;
	TempActor ->AddOwnedComponent(Component);
	TempActor ->AddInstanceComponent(Component);
	Component->RegisterComponent();
	if (Mesh) Component->SetStaticMesh(Mesh);
	Component->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
	Component->SetCollisionProfileName(FName("BlockAllDynamic"));
	//附加上去
	Component->AttachToComponent(TempActor ->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
	//加载空蓝图
	UBlueprint* TempBlueprint = LoadObject<UBlueprint>(NULL, TEXT("蓝图路径"), NULL, LOAD_None, NULL);

	FString NEWBlueprintPath = "新蓝图准备存放的包路径";
	
	TArray<UObject*> ObjtoCopy;
	ObjtoCopy.Add(TempBlueprint); //将空蓝图加到预复制数组内 
	TArray<UObject*> NewObjects; //新复制出来的对象
	FString Desc = "目标路径";
	ObjectTools::DuplicateObjects(ObjtoCopy, TEXT(""), Desc, /*bOpenDialog=*/false, &NewObjects);

	for (auto temp: NewObjects)
	{
		//下面我们修改一下新蓝图的名称不然的话还是用的空蓝图的名称
		FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
		TArray<FAssetRenameData> AssetsAndNames;
		const FString PackagePath = FPackageName::GetLongPackagePath(temp->GetOutermost()->GetName());
		new(AssetsAndNames) FAssetRenameData(temp, PackagePath, "想要修改成的名字");
		AssetToolsModule.Get().RenameAssets(AssetsAndNames);

		//temp->Rename(*CurrentPakName);
		UBlueprint* InBlueprint = Cast<UBlueprint>(temp);
		//往新蓝图内添加组件//添加的组件来自我们刚刚创建的Actor 内的组件
		FKismetEditorUtilities::AddComponentsToBlueprint(InBlueprint, TempActor ->GetComponents().Array());

		PackageToSave.Add(temp->GetOutermost());
	}
	//保存资源
	UEditorLoadingAndSavingUtils::SavePackages(PackageToSave, false);
}

好了大体上内容都完成了,今天的代码量有点多,但是已经删减了很多内容了。以上内容全部是平时研究出来的,中间趟了好多坑,希望可以大家参考一下。文中有什么不好的或者是有什么建议都可以写在评论区

最后的最后,写博客不易。虽然内容不是很高质量,如需转发请注明出处谢谢。

上一篇:VR制作中必须踩的坑365之014(oculus2、UE4、UE5、VR记录一年的踩坑之旅)金币的制作UE4 - Tutorial - Coin Mesh Particles!


下一篇:UE4中使用URL图片