Ejemplo n.º 1
0
void UnFbx::FFbxImporter::CreateUnrealMaterial(FbxSurfaceMaterial* FbxMaterial, TArray<UMaterialInterface*>& OutMaterials, TArray<FString>& UVSets)
{
	FString MaterialFullName = ANSI_TO_TCHAR(MakeName(FbxMaterial->GetName()));

	// check for a 'skinXX' suffix in the material name
	int32 MaterialNameLen = FCString::Strlen(*MaterialFullName) + 1;
	char* MaterialNameANSI = new char[MaterialNameLen];
	FCStringAnsi::Strcpy(MaterialNameANSI, MaterialNameLen, TCHAR_TO_ANSI(*MaterialFullName));
	if (FCStringAnsi::Strlen(MaterialNameANSI) > 6)
	{
		const char* SkinXX = MaterialNameANSI + FCStringAnsi::Strlen(MaterialNameANSI) - 6;
		if (FCharAnsi::ToUpper(*SkinXX) == 'S' && FCharAnsi::ToUpper(*(SkinXX+1)) == 'K' && 
			FCharAnsi::ToUpper(*(SkinXX+2)) == 'I' && FCharAnsi::ToUpper(*(SkinXX+3)) == 'N')
		{
			if (FCharAnsi::IsDigit(*(SkinXX+4)) && FCharAnsi::IsDigit(*(SkinXX+5)))
			{
				// remove the 'skinXX' suffix from the material name
				MaterialFullName = MaterialFullName.Left(MaterialNameLen - 7);
			}
		}
	}

	MaterialFullName = ObjectTools::SanitizeObjectName(MaterialFullName);

	// Make sure we have a parent
	if ( !ensure(Parent) )
	{
		return;
	}
	
	// set where to place the materials
	FString NewPackageName = FPackageName::GetLongPackagePath(Parent->GetOutermost()->GetName()) + TEXT("/") + MaterialFullName;
	NewPackageName = PackageTools::SanitizePackageName(NewPackageName);
	UPackage* Package = CreatePackage(NULL, *NewPackageName);
	
	UMaterialInterface* UnrealMaterialInterface = FindObject<UMaterialInterface>(Package,*MaterialFullName);
	// does not override existing materials
	if (UnrealMaterialInterface != NULL)
	{
		OutMaterials.Add(UnrealMaterialInterface);
		return;
	}
	
	// create an unreal material asset
	UMaterialFactoryNew* MaterialFactory = new UMaterialFactoryNew(FPostConstructInitializeProperties());
	
	UMaterial* UnrealMaterial = (UMaterial*)MaterialFactory->FactoryCreateNew(
		UMaterial::StaticClass(), Package, *MaterialFullName, RF_Standalone|RF_Public, NULL, GWarn );
	// TODO :  need this ? UnrealMaterial->bUsedWithStaticLighting = true;

	if ( UnrealMaterial != NULL )
	{
		// Notify the asset registry
		FAssetRegistryModule::AssetCreated(UnrealMaterial);

		// Set the dirty flag so this package will get saved later
		Package->SetDirtyFlag(true);
	}

	// textures and properties
	CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sDiffuse, UnrealMaterial->DiffuseColor, false, UVSets);
	CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sEmissive, UnrealMaterial->EmissiveColor, false, UVSets);
	CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sSpecular, UnrealMaterial->SpecularColor, false, UVSets);
	CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sSpecularFactor, UnrealMaterial->SpecularColor, false, UVSets); // SpecularFactor modulates the SpecularColor value if there's one
	//CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sShininess, UnrealMaterial->SpecularPower, false, UVSets);
	if (!CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sNormalMap, UnrealMaterial->Normal, true, UVSets))
	{
		CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, FbxSurfaceMaterial::sBump, UnrealMaterial->Normal, true, UVSets); // no bump in unreal, use as normal map
	}
	//CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, KFbxSurfaceMaterial::sTransparentColor, UnrealMaterial->Opacity, false, UVSets);
	//CreateAndLinkExpressionForMaterialProperty( *FbxMaterial, UnrealMaterial, KFbxSurfaceMaterial::sTransparencyFactor, UnrealMaterial->OpacityMask, false, UVSets);
	FixupMaterial( *FbxMaterial, UnrealMaterial); // add random diffuse if none exists

	// compile shaders for PC (from UPrecompileShadersCommandlet::ProcessMaterial
	// and FMaterialEditor::UpdateOriginalMaterial)

	// make sure that any static meshes, etc using this material will stop using the FMaterialResource of the original 
	// material, and will use the new FMaterialResource created when we make a new UMaterial in place
	FGlobalComponentReregisterContext RecreateComponents;
	
	// let the material update itself if necessary
	UnrealMaterial->PreEditChange(NULL);
		UnrealMaterial->PostEditChange();
	
	OutMaterials.Add(UnrealMaterial);
}
//! @brief Create an Unreal Material for the given graph-instance
UMaterial* CreateMaterial(graph_inst_t* GraphInstance,
	const FString & MaterialName,
	UObject* Outer)
{
	// create an unreal material asset
	UMaterialFactoryNew* MaterialFactory = NewObject<UMaterialFactoryNew>();

	UMaterial* UnrealMaterial = 
		(UMaterial*)MaterialFactory->FactoryCreateNew(
			UMaterial::StaticClass(),
			Substance::Helpers::CreateObjectPackage(Outer, MaterialName),
			*MaterialName, 
			RF_Standalone|RF_Public, NULL, GWarn );

	// textures and properties
	for (auto ItOut = GraphInstance->Outputs.itfront(); ItOut; ++ItOut)
	{
		output_inst_t* OutputInst = &(*ItOut);
		output_desc_t* OutputDesc = OutputInst->GetOutputDesc();

		CreateMaterialExpression(
			OutputInst,
			UnrealMaterial);
	}

	// special case: emissive only materials
	TArray<FName> ParamNames;
	TArray<FGuid> ParamIds;
	UnrealMaterial->GetAllTextureParameterNames(ParamNames, ParamIds);
	if (ParamNames.Num() == 1)
	{
		if (ParamNames[0].ToString() == TEXT("emissive"))
		{
			UnrealMaterial->SetShadingModel(MSM_Unlit);
		}
	}

	// special case: no roughness but glossiness
	if (!UnrealMaterial->Roughness.IsConnected())
	{
		for (auto ItOut = GraphInstance->Outputs.itfront(); ItOut; ++ItOut)
		{
			output_inst_t* OutputInst = &(*ItOut);
			output_desc_t* OutputDesc = OutputInst->GetOutputDesc();

			UTexture* Texture = *OutputInst->Texture;

			if (OutputDesc->Channel == CHAN_Glossiness && Texture)
			{
				// and link it to the material
				UMaterialExpressionOneMinus* OneMinus = NewObject<UMaterialExpressionOneMinus>(UnrealMaterial);

				UMaterialExpressionTextureSampleParameter2D* UnrealTextureExpression =
					CreateSampler(UnrealMaterial, Texture, OutputDesc);

				UnrealTextureExpression->MaterialExpressionEditorX -= 200;
				OneMinus->MaterialExpressionEditorX = -200;
				OneMinus->MaterialExpressionEditorY = UnrealTextureExpression->MaterialExpressionEditorY;
				
				UnrealTextureExpression->ConnectExpression(OneMinus->GetInput(0), 0);
				UnrealMaterial->Roughness.Expression = OneMinus;
				
				UnrealMaterial->Expressions.Add(UnrealTextureExpression);
				UnrealMaterial->Expressions.Add(OneMinus);
			}
		}
	}

	// let the material update itself if necessary
	UnrealMaterial->PreEditChange(NULL);
	UnrealMaterial->PostEditChange();
	
	return UnrealMaterial;
}