Files
FunnyGirl/Plugins/VRM4U/Source/VRM4ULoader/Private/VrmConvertTexture.cpp
T
2026-05-19 13:42:41 +07:00

1392 lines
43 KiB
C++

// VRM4U Copyright (c) 2021-2024 Haruyoshi Yamamoto. This software is released under the MIT License.
#include "VrmConvertTexture.h"
#include "VrmConvert.h"
#include "VrmUtil.h"
#include "Materials/MaterialExpressionTextureSampleParameter2D.h"
#include "Modules/ModuleManager.h"
#include "IImageWrapper.h"
#include "IImageWrapperModule.h"
#include "PixelFormat.h"
#include "RenderUtils.h"
#include "Engine/Texture.h"
#include "Engine/Texture2D.h"
#include "Materials/Material.h"
#include "Engine/SubsurfaceProfile.h"
#include "Materials/MaterialInstanceConstant.h"
#include "VrmAssetListObject.h"
#include "Async/ParallelFor.h"
#include "UObject/UObjectHash.h"
#include "Misc/FileHelper.h"
#include "Misc/Paths.h"
#if WITH_EDITOR
#include "Factories.h"
#include "Factories/TextureFactory.h"
#endif
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/mesh.h>
#include <assimp/postprocess.h>
#include <assimp/material.h>
#include <assimp/GltfMaterial.h>
#include <assimp/vrm/vrmmeta.h>
#if UE_VERSION_OLDER_THAN(4,23,0)
#define TRACE_CPUPROFILER_EVENT_SCOPE(a)
#else
#endif
namespace {
bool bDefaultVrmMaterial = false;
bool LocalIsOriginalVrmMaterial() {
return bDefaultVrmMaterial;
}
void LocalSetOriginalVrmMaterial(bool b) {
bDefaultVrmMaterial = b;
}
void LocalMaterialSetParent(UMaterialInstanceConstant *material, UMaterialInterface *parent) {
#if WITH_EDITOR
if (VRMConverter::IsImportMode()) {
material->SetParentEditorOnly(parent);
} else {
material->Parent = parent;
}
FMaterialUpdateContext UpdateContext(FMaterialUpdateContext::EOptions::Default, GMaxRHIShaderPlatform);
UpdateContext.AddMaterialInstance(material);
#else
material->Parent = parent;
#endif
}
void LocalTextureSet(UMaterialInstanceConstant *dm, FName name, UTexture2D * tex) {
#if WITH_EDITOR
if (VRMConverter::IsImportMode()) {
dm->SetTextureParameterValueEditorOnly(name, tex);
}else{
FTextureParameterValue *v = new (dm->TextureParameterValues) FTextureParameterValue();
v->ParameterInfo.Index = INDEX_NONE;
v->ParameterInfo.Name = name;
v->ParameterInfo.Association = EMaterialParameterAssociation::GlobalParameter;
v->ParameterValue = tex;
}
#else
FTextureParameterValue *v = new (dm->TextureParameterValues) FTextureParameterValue();
v->ParameterInfo.Index = INDEX_NONE;
v->ParameterInfo.Name = name;
v->ParameterInfo.Association = EMaterialParameterAssociation::GlobalParameter;
v->ParameterValue = tex;
#endif
}
void LocalScalarParameterSet(UMaterialInstanceConstant *dm, FName name, float f) {
bool bSet = false;
#if WITH_EDITOR
if (VRMConverter::IsImportMode()) {
dm->SetScalarParameterValueEditorOnly(name, f);
bSet = true;
}
#endif
if (bSet == false) {
FScalarParameterValue *v = nullptr;
for (auto &a : dm->ScalarParameterValues) {
if (a.ParameterInfo.Name == name) {
v = &a;
}
}
if (v == nullptr) {
v = new (dm->ScalarParameterValues) FScalarParameterValue();
}
v->ParameterInfo.Index = INDEX_NONE;
v->ParameterInfo.Name = name;
v->ParameterInfo.Association = EMaterialParameterAssociation::GlobalParameter;
v->ParameterValue = f;
}
}
void LocalVectorParameterSet(UMaterialInstanceConstant *dm, FName name, FLinearColor c) {
bool bSet = false;
#if WITH_EDITOR
if (VRMConverter::IsImportMode()) {
dm->SetVectorParameterValueEditorOnly(name, c);
bSet = true;
}
#endif
if (bSet == false) {
FVectorParameterValue *v = nullptr;
for (auto &a : dm->VectorParameterValues) {
if (a.ParameterInfo.Name == name) {
v = &a;
}
}
if (v == nullptr) {
v = new (dm->VectorParameterValues) FVectorParameterValue();
}
v->ParameterInfo.Index = INDEX_NONE;
v->ParameterInfo.Name = name;
v->ParameterInfo.Association = EMaterialParameterAssociation::GlobalParameter;
v->ParameterValue = c;
}
}
void LocalMaterialFinishParam(UMaterialInstanceConstant *material) {
#if WITH_EDITOR
if (VRMConverter::IsImportMode()) {
material->PreEditChange(NULL);
material->PostEditChange();
} else {
material->PostLoad();
}
#else
material->PostLoad();
#endif
}
void createSmallThumbnail(UVrmAssetListObject *vrmAssetList, const aiScene *aiData) {
#if WITH_EDITORONLY_DATA
UTexture2D *src = nullptr;
VRM::VRMMetadata *meta = reinterpret_cast<VRM::VRMMetadata*>(aiData->mVRMMeta);
if (meta == nullptr) {
return;
}
int TextureID = -1;
for (int i = 0; i < meta->license.licensePairNum; ++i) {
auto &p = meta->license.licensePair[i];
if (FString(TEXT("texture")) == p.Key.C_Str()) {
int t = FCString::Atoi(*FString(p.Value.C_Str()));
if (t >= 0 && t < vrmAssetList->Textures.Num()) {
src = vrmAssetList->Textures[t];
TextureID = t;
break;
}
}
}
if (src == nullptr) {
// todo small texture vrm1license
}
if (src == nullptr) {
return;
}
const int W = src->GetSurfaceWidth();
const int H = src->GetSurfaceHeight();
int dW = FMath::Min(256, W);
int dH = FMath::Min(256, H);
vrmAssetList->SmallThumbnailTexture = src;
if (W == dW && H == dH) {
return;
}
if (W != H) {
return;
}
if (TextureID < 0 || TextureID >= (int)aiData->mNumTextures) {
return;
}
if (aiData->mTextures[TextureID] == nullptr) {
return;
}
TArray<uint8> sData;
sData.SetNum(W * H * 4);
TArray<uint8> dData;
dData.SetNum(256*256 * 4);
FString baseName = (src->GetFName()).ToString();
baseName += TEXT("_small");
{
VRMUtil::FImportImage img;
auto *a = aiData->mTextures[TextureID];
if (VRMLoaderUtil::LoadImageFromMemory(a->pcData, a->mWidth, img) == false) {
return;
}
if (img.RawData.GetData() == nullptr) {
return;
}
FMemory::Memcpy(sData.GetData(), img.RawData.GetData(), img.RawData.Num());
}
auto* pkg = vrmAssetList->Package;
if (VRMConverter::Options::Get().IsSingleUAssetFile() == false) {
pkg = VRM4U_CreatePackage(vrmAssetList->Package, *baseName);
}
UTexture2D* NewTexture2D = VRMLoaderUtil::CreateTexture(W, H, baseName, pkg);
// scale texture
{
ParallelFor(dH, [&](int32 y){
//for (int32 y = 0; y < dH; y++){
float s = (float)H / dH;
for (int32 x = 0; x < dW; x++){
int32 xx = (s * (0.5f + x));
int32 yy = (s * (0.5f + y));
uint8* dp = &dData[(y * dW + x) * sizeof(uint8) * 4];
int c = 0;
int tmp[4] = {};
int n = (float)W / dW / 2;
for (int ry = yy - n; ry <= yy + n; ry++) {
for (int rx = xx - n; rx <= xx + n; rx++) {
if (rx < 0 || ry < 0) continue;
if (rx >= W || ry >= H) continue;
const uint8* rp = &sData[(ry * W + rx) * sizeof(uint8) * 4];
tmp[0] += rp[0];
tmp[1] += rp[1];
tmp[2] += rp[2];
tmp[3] += rp[3];
++c;
}
}
dp[0] = tmp[0] / c;
dp[1] = tmp[1] / c;
dp[2] = tmp[2] / c;
dp[3] = tmp[3] / c;
}
});
// Set options
NewTexture2D->SRGB = true;// bUseSRGB;
NewTexture2D->CompressionSettings = TC_Default;
NewTexture2D->AddressX = TA_Wrap;
NewTexture2D->AddressY = TA_Wrap;
NewTexture2D->CompressionNone = false;
NewTexture2D->DeferCompression = true;
if (VRMConverter::Options::Get().IsMipmapGenerateMode() && FMath::IsPowerOfTwo(dW) && FMath::IsPowerOfTwo(dH)) {
NewTexture2D->MipGenSettings = TMGS_FromTextureGroup;
} else {
NewTexture2D->MipGenSettings = TMGS_NoMipmaps;
}
NewTexture2D->Source.Init(dW, dH, 1, 1, ETextureSourceFormat::TSF_BGRA8, dData.GetData());
//NewTexture2D->Source.Compress();
// Update the remote texture data
NewTexture2D->UpdateResource();
NewTexture2D->PostEditChange();
vrmAssetList->SmallThumbnailTexture = NewTexture2D;
}
#endif
}
bool createAndAddMaterial(UMaterialInstanceConstant *dm, int matIndex, UVrmAssetListObject *vrmAssetList, const VRMConverter *vc,
const TArray<int> &TextureTypeToIndex
) {
auto i = matIndex;
// default set function
auto SetLocalParamsForVector = [](auto* dm) {
LocalVectorParameterSet(dm, TEXT("mtoon_Color"), FLinearColor(1, 1, 1, 1));
LocalVectorParameterSet(dm, TEXT("mtoon_ShadeColor"), FLinearColor(1, 1, 1, 1));
LocalVectorParameterSet(dm, TEXT("mtoon_OutlineColor"), FLinearColor(0, 0, 0, 1));
};
auto SetLocalParamsForScaler = [](auto* dm) {
LocalScalarParameterSet(dm, TEXT("mtoon_BumpScale"), 1.f);
LocalScalarParameterSet(dm, TEXT("mtoon_NormalScale"), 1.f);
LocalScalarParameterSet(dm, TEXT("mtoon_ReceiveShadowRate"), 1.f);
LocalScalarParameterSet(dm, TEXT("mtoon_OutlineLightingMix"), 1.f);
LocalScalarParameterSet(dm, TEXT("mtoon_OutlineWidth"), 0.1f);
LocalScalarParameterSet(dm, TEXT("mtoon_OutlineWidthMode"), 1.f);
};
// default for not vrm material
if (dm) {
if (LocalIsOriginalVrmMaterial() == false) {
SetLocalParamsForVector(dm);
SetLocalParamsForScaler(dm);
}
}
// VRM1
if (VRMConverter::Options::Get().IsVRM10Model()) {
LocalScalarParameterSet(dm, TEXT("bVRM10Mode"), 1.f);
}
VRM::VRMMaterial vrmMat;
if (vc->GetMatParam(vrmMat, i) == false) {
return false;
}
{
struct TT {
FString key;
float* value;
};
TT tableParam[] = {
{TEXT("_Color"), vrmMat.vectorProperties._Color},
{TEXT("_ShadeColor"), vrmMat.vectorProperties._ShadeColor},
{TEXT("_MainTex"), vrmMat.vectorProperties._MainTex},
{TEXT("_ShadeTexture"), vrmMat.vectorProperties._ShadeTexture},
{TEXT("_BumpMap"), vrmMat.vectorProperties._BumpMap},
{TEXT("_ReceiveShadowTexture"), vrmMat.vectorProperties._ReceiveShadowTexture},
{TEXT("_ShadingGradeTexture"), vrmMat.vectorProperties._ShadingGradeTexture},
{TEXT("_RimColor"), vrmMat.vectorProperties._RimColor},
{TEXT("_RimTexture"), vrmMat.vectorProperties._RimTexture},
{TEXT("_SphereAdd"), vrmMat.vectorProperties._SphereAdd},
{TEXT("_EmissionColor"), vrmMat.vectorProperties._EmissionColor},
{TEXT("_EmissionMap"), vrmMat.vectorProperties._EmissionMap},
{TEXT("_OutlineWidthTexture"), vrmMat.vectorProperties._OutlineWidthTexture},
{TEXT("_OutlineColor"), vrmMat.vectorProperties._OutlineColor},
{TEXT("_UvAnimMaskTexture"), vrmMat.vectorProperties._UvAnimMaskTexture},
};
for (auto &t : tableParam) {
LocalVectorParameterSet(dm, *(TEXT("mtoon") + t.key), FLinearColor(t.value[0], t.value[1], t.value[2], t.value[3]));
}
// default for not vrm material
if (LocalIsOriginalVrmMaterial() == false) {
SetLocalParamsForVector(dm);
}
}
{
struct TT {
FString key;
float& value;
};
TT tableParam[] = {
{TEXT("_Cutoff"), vrmMat.floatProperties._Cutoff},
{TEXT("_BumpScale"), vrmMat.floatProperties._BumpScale},
{TEXT("_NormalScale"), vrmMat.floatProperties._BumpScale}, // VRM4U Custom
{TEXT("_ReceiveShadowRate"), vrmMat.floatProperties._ReceiveShadowRate},
{TEXT("_ShadeShift"), vrmMat.floatProperties._ShadeShift},
{TEXT("_ShadeToony"), vrmMat.floatProperties._ShadeToony},
{TEXT("_LightColorAttenuation"), vrmMat.floatProperties._LightColorAttenuation},
{TEXT("_IndirectLightIntensity"), vrmMat.floatProperties._IndirectLightIntensity},
{TEXT("_RimLightingMix"), vrmMat.floatProperties._RimLightingMix},
{TEXT("_RimFresnelPower"), vrmMat.floatProperties._RimFresnelPower},
{TEXT("_RimLift"), vrmMat.floatProperties._RimLift},
{TEXT("_OutlineWidth"), vrmMat.floatProperties._OutlineWidth},
{TEXT("_OutlineScaledMaxDistance"), vrmMat.floatProperties._OutlineScaledMaxDistance},
{TEXT("_OutlineLightingMix"), vrmMat.floatProperties._OutlineLightingMix},
{TEXT("_UvAnimScrollX"), vrmMat.floatProperties._UvAnimScrollX},
{TEXT("_UvAnimScrollY"), vrmMat.floatProperties._UvAnimScrollY},
{TEXT("_UvAnimRotation"), vrmMat.floatProperties._UvAnimRotation},
{TEXT("_MToonVersion"), vrmMat.floatProperties._MToonVersion},
{TEXT("_DebugMode"), vrmMat.floatProperties._DebugMode},
{TEXT("_BlendMode"), vrmMat.floatProperties._BlendMode},
{TEXT("_OutlineWidthMode"), vrmMat.floatProperties._OutlineWidthMode},
{TEXT("_OutlineColorMode"), vrmMat.floatProperties._OutlineColorMode},
{TEXT("_CullMode"), vrmMat.floatProperties._CullMode},
{TEXT("_OutlineCullMode"), vrmMat.floatProperties._OutlineCullMode},
{TEXT("_SrcBlend"), vrmMat.floatProperties._SrcBlend},
{TEXT("_DstBlend"), vrmMat.floatProperties._DstBlend},
{TEXT("_ZWrite"), vrmMat.floatProperties._ZWrite},
};
for (auto &t : tableParam) {
LocalScalarParameterSet(dm, *(TEXT("mtoon") + t.key), t.value);
}
// default for not vrm material
if (LocalIsOriginalVrmMaterial() == false) {
SetLocalParamsForScaler(dm);
}
//if (vrmMat.floatProperties._CullMode == 0.f) {
// dm->BasePropertyOverrides.bOverride_TwoSided = true;
// dm->BasePropertyOverrides.TwoSided = 1;
//}
if (vrmMat.floatProperties._Cutoff != 0.f) {
dm->BasePropertyOverrides.bOverride_OpacityMaskClipValue = true;
dm->BasePropertyOverrides.OpacityMaskClipValue = vrmMat.floatProperties._Cutoff;
}
{
switch ((int)(vrmMat.floatProperties._BlendMode)) {
case 0:
case 1:
break;
case 2:
case 3:
//dm->BasePropertyOverrides.bOverride_BlendMode = true;
//dm->BasePropertyOverrides.BlendMode = EBlendMode::BLEND_Translucent;
break;
}
}
}
{
struct TT {
FString key;
int value;
};
TT tableParam[] = {
{TEXT("mtoon_tex_MainTex"), vrmMat.textureProperties._MainTex},
{TEXT("mtoon_tex_ShadeTexture"), vrmMat.textureProperties._ShadeTexture},
{TEXT("mtoon_tex_Shade"), vrmMat.textureProperties._ShadeTexture}, // vrm1
{TEXT("mtoon_tex_BumpMap"), vrmMat.textureProperties._BumpMap},
{TEXT("mtoon_tex_ReceiveShadowTexture"), vrmMat.textureProperties._ReceiveShadowTexture},
{TEXT("mtoon_tex_ShadingGradeTexture"), vrmMat.textureProperties._ShadingGradeTexture},
{TEXT("mtoon_tex_RimTexture"), vrmMat.textureProperties._RimTexture},
{TEXT("mtoon_tex_RimMultiply"), vrmMat.textureProperties._RimTexture}, // vrm1
{TEXT("mtoon_tex_SphereAdd"), vrmMat.textureProperties._SphereAdd},
{TEXT("mtoon_tex_MatCap"), vrmMat.textureProperties._SphereAdd}, // vrm1
{TEXT("mtoon_tex_EmissionMap"), vrmMat.textureProperties._EmissionMap},
{TEXT("mtoon_tex_Emissive"), vrmMat.textureProperties._EmissionMap}, // vrm1
{TEXT("mtoon_tex_OutlineWidthTexture"), vrmMat.textureProperties._OutlineWidthTexture},
{TEXT("mtoon_tex_OutlineWidthMultiply"), vrmMat.textureProperties._OutlineWidthTexture}, // vrm1
{TEXT("mtoon_tex_UvAnimMaskTexture") , vrmMat.textureProperties._UvAnimMaskTexture},
{TEXT("mtoon_tex_UvAnimationMask"), vrmMat.textureProperties._UvAnimMaskTexture}, // vrm1
};
if (VRMConverter::Options::Get().IsVRM10Model()) {
FSoftObjectPath r(TEXT("/VRM4U/MaterialUtil/T_DummyBlack.T_DummyBlack"));
UObject* u = r.TryLoad();
if (u) {
auto r2 = Cast<UTexture2D>(u);
if (r2) {
LocalTextureSet(dm, "mtoon_tex_EmissionMap", r2);
}
}
}
// default texture
{
auto n = TextureTypeToIndex[aiTextureType_DIFFUSE];
if (n >= 0) {
LocalTextureSet(dm, TEXT("mtoon_tex_MainTex"), vrmAssetList->Textures[n]);
LocalTextureSet(dm, TEXT("gltf_tex_diffuse"), vrmAssetList->Textures[n]);
LocalTextureSet(dm, TEXT("mtoon_tex_Shade"), vrmAssetList->Textures[n]);
}
}
// mtoon texture
int count = 0;
for (auto &t : tableParam) {
++count;
if (t.value < 0 || t.value >= vrmAssetList->Textures.Num()) {
continue;
}
LocalTextureSet(dm, *t.key, vrmAssetList->Textures[t.value]);
if (count == 1) {
// main => shade tex
LocalTextureSet(dm, *tableParam[1].key, vrmAssetList->Textures[t.value]);
LocalTextureSet(dm, *tableParam[2].key, vrmAssetList->Textures[t.value]);
}
//FTextureParameterValue *v = new (dm->TextureParameterValues) FTextureParameterValue();
//v->ParameterInfo.Index = INDEX_NONE;
//v->ParameterInfo.Name = *t.key;
//v->ParameterInfo.Association = EMaterialParameterAssociation::GlobalParameter;
//v->ParameterValue = vrmAssetList->Textures[t.value];
}
// gltf default texture
{
auto n = TextureTypeToIndex[aiTextureType_NORMALS];
if (0 <= n && n < vrmAssetList->Textures.Num()) {
vrmAssetList->Textures[n]->SRGB = false;
vrmAssetList->Textures[n]->CompressionSettings = TC_Normalmap;
vrmAssetList->Textures[n]->UpdateResource();
LocalTextureSet(dm, TEXT("mtoon_tex_Normal"), vrmAssetList->Textures[n]);
}
}
{
auto n = TextureTypeToIndex[aiTextureType_EMISSIVE];
if (0 <= n && n < vrmAssetList->Textures.Num()) {
LocalTextureSet(dm, TEXT("mtoon_tex_Emissive"), vrmAssetList->Textures[n]);
}
}
}
return true;
}
UMaterial* CreateDefaultMaterial(UVrmAssetListObject *vrmAssetList) {
#if UE_VERSION_OLDER_THAN(4,20,0)
UMaterial* UnrealMaterial = VRM4U_NewObject<UMaterial>(vrmAssetList->Package, TEXT("M_BaseMaterial"), RF_Standalone | RF_Public);
#else
UMaterial* UnrealMaterial = nullptr;
if (vrmAssetList->Package == GetTransientPackage()) {
UnrealMaterial = VRM4U_NewObject<UMaterial>(GetTransientPackage(), NAME_None, EObjectFlags::RF_Public | RF_Transient, nullptr);
}
else {
UnrealMaterial = VRM4U_NewObject<UMaterial>(vrmAssetList->Package, TEXT("M_BaseMaterial"), RF_Standalone | RF_Public, nullptr);
}
#endif
if (UnrealMaterial != NULL)
{
//UnrealMaterialFinal = UnrealMaterial;
// Notify the asset registry
//FAssetRegistryModule::AssetCreated(UnrealMaterial);
if(true)
{
bool bNeedsRecompile = true;
UnrealMaterial->GetMaterial()->SetMaterialUsage(bNeedsRecompile, MATUSAGE_SkeletalMesh);
UnrealMaterial->GetMaterial()->SetMaterialUsage(bNeedsRecompile, MATUSAGE_MorphTargets);
}
// Set the dirty flag so this package will get saved later
//Package->SetDirtyFlag(true);
// textures and properties
{
#if WITH_EDITORONLY_DATA
UMaterialExpressionTextureSampleParameter2D* UnrealTextureExpression = NewObject<UMaterialExpressionTextureSampleParameter2D>(UnrealMaterial);
#if UE_VERSION_OLDER_THAN(5,1,0)
UnrealMaterial->Expressions.Add(UnrealTextureExpression);
#else
UnrealMaterial->GetEditorOnlyData()->ExpressionCollection.Expressions.Add(UnrealTextureExpression);
#endif
UnrealTextureExpression->SamplerType = SAMPLERTYPE_Color;
UnrealTextureExpression->ParameterName = TEXT("gltf_tex_diffuse");
#if UE_VERSION_OLDER_THAN(5,1,0)
UnrealMaterial->BaseColor.Expression = UnrealTextureExpression;
#else
UnrealMaterial->GetEditorOnlyData()->BaseColor.Expression = UnrealTextureExpression;
#endif
#endif
}
UnrealMaterial->BlendMode = BLEND_Masked;
UnrealMaterial->SetShadingModel(MSM_DefaultLit);
}
return UnrealMaterial;
}
bool isSameMaterial(const UMaterialInterface *mi1, const UMaterialInterface *mi2) {
const UMaterialInstanceConstant *m1 = Cast<UMaterialInstanceConstant>(mi1);
const UMaterialInstanceConstant *m2 = Cast<UMaterialInstanceConstant>(mi2);
if (m1 == nullptr || m2 == nullptr) {
return false;
}
// tex
{
if (m1->TextureParameterValues.Num() != m2->TextureParameterValues.Num()) {
return false;
}
for (int i = 0; i < m1->TextureParameterValues.Num(); ++i) {
if (m1->TextureParameterValues[i].ParameterValue != m2->TextureParameterValues[i].ParameterValue) {
return false;
}
if (m1->TextureParameterValues[i].ParameterInfo.Name != m2->TextureParameterValues[i].ParameterInfo.Name) {
return false;
}
}
}
// scalar
{
if (m1->ScalarParameterValues.Num() != m2->ScalarParameterValues.Num()) {
return false;
}
for (int i = 0; i < m1->ScalarParameterValues.Num(); ++i) {
if (m1->ScalarParameterValues[i].ParameterValue != m2->ScalarParameterValues[i].ParameterValue) {
return false;
}
if (m1->ScalarParameterValues[i].ParameterInfo.Name != m2->ScalarParameterValues[i].ParameterInfo.Name) {
return false;
}
}
}
// vector
{
if (m1->VectorParameterValues.Num() != m2->VectorParameterValues.Num()) {
return false;
}
for (int i = 0; i < m1->VectorParameterValues.Num(); ++i) {
if (m1->VectorParameterValues[i].ParameterValue != m2->VectorParameterValues[i].ParameterValue) {
return false;
}
if (m1->VectorParameterValues[i].ParameterInfo.Name != m2->VectorParameterValues[i].ParameterInfo.Name) {
return false;
}
}
}
if (m1->BasePropertyOverrides != m2->BasePropertyOverrides) {
return false;
}
#define VRM4U_TMP_COMPARE(a) if (m1->a != m2->a) return false;
VRM4U_TMP_COMPARE(OpacityMaskClipValue);
VRM4U_TMP_COMPARE(BlendMode);
VRM4U_TMP_COMPARE(TwoSided);
VRM4U_TMP_COMPARE(DitheredLODTransition);
VRM4U_TMP_COMPARE(bCastDynamicShadowAsMasked);
#if UE_VERSION_OLDER_THAN(4,23,0)
VRM4U_TMP_COMPARE(GetShadingModel());
#else
VRM4U_TMP_COMPARE(GetShadingModels());
#endif
#undef VRM4U_TMP_COMPARE
return true;
}
}// namespace
bool VRMConverter::ConvertTextureAndMaterial(UVrmAssetListObject *vrmAssetList) {
if (vrmAssetList == nullptr || aiData == nullptr) {
return false;
}
if (VRMConverter::Options::Get().IsNoMesh()) {
return true;
}
const bool bGenerateMips = VRMConverter::Options::Get().IsMipmapGenerateMode();
// skip for preload
// skip vrmAssetList->Textures.Reset(0);
vrmAssetList->Materials.Reset(0);
vrmAssetList->OutlineMaterials.Reset(0);
TArray<bool> NormalBoolTable;
NormalBoolTable.SetNum(aiData->mNumTextures);
TArray<bool> MaskBoolTable;
MaskBoolTable.SetNum(aiData->mNumTextures);
TArray<UMaterialInterface*> matArray;
TArray<bool> matFlagTranslucentArray;
TArray<bool> matFlagTwoSidedArray;
TArray<bool> matFlagOpaqueArray;
TArray<EVRMImportTextureCompressType> textureCompressTypeArray;
{
const VRM::VRMMetadata *meta = static_cast<const VRM::VRMMetadata*>(aiData->mVRMMeta);
if (meta) {
for (int i = 0; i < meta->materialNum; ++i) {
int t = 0;
t = meta->material[i].textureProperties._BumpMap;
if (NormalBoolTable.IsValidIndex(t)){
NormalBoolTable[t] = true;
}
t = meta->material[i].textureProperties._OutlineWidthTexture;
if (MaskBoolTable.IsValidIndex(t)){
MaskBoolTable[t] = true;
}
}
}
}
{
if (aiData->HasTextures() && vrmAssetList->Textures.Num() != aiData->mNumTextures) {
TArray<UTexture2D*> texArray;
texArray.Reserve(aiData->mNumTextures);
// Note: PNG format. Other formats are supported
for (uint32_t i = 0; i < aiData->mNumTextures; ++i) {
auto& t = *aiData->mTextures[i];
int Width = t.mWidth;
int Height = t.mHeight;
FString baseName = VRMConverter::NormalizeFileName(t.mFilename.C_Str());
if (baseName.Len() == 0) {
baseName = TEXT("texture") + FString::FromInt(i);
}
bool bNormalGreenFlip = NormalBoolTable[i];
if (bNormalGreenFlip) {
baseName += TEXT("_N");
}
FString name = FString(TEXT("T_")) + baseName;
auto* pkg = vrmAssetList->Package;
if (VRMConverter::Options::Get().IsSingleUAssetFile() == false) {
pkg = VRM4U_CreatePackage(vrmAssetList->Package, *name);
}
UTexture2D* NewTexture2D = VRMLoaderUtil::CreateTextureFromImage(name, pkg, t.pcData, t.mWidth, bGenerateMips, NormalBoolTable[i], bNormalGreenFlip&&(VRMConverter::IsImportMode()==false));
#if WITH_EDITOR
NewTexture2D->DeferCompression = false;
#endif
bool bIsBC7 = false;
// Set options
if (NormalBoolTable[i]) {
NewTexture2D->SRGB = 0;
#if WITH_EDITOR
NewTexture2D->CompressionNoAlpha = true;
if (VRMConverter::IsImportMode()) {
NewTexture2D->bFlipGreenChannel = true;
}
#endif
} else {
if (VRMConverter::Options::Get().IsBC7Mode()) {
NewTexture2D->CompressionSettings = TC_BC7;
bIsBC7 = true;
}
}
if (MaskBoolTable[i]) {
// comment for material warning...
//NewTexture2D->SRGB = 0;
}
if (bIsBC7) {
textureCompressTypeArray.Add(EVRMImportTextureCompressType::VRMITC_BC7);
} else {
textureCompressTypeArray.Add(EVRMImportTextureCompressType::VRMITC_DXT1);
}
NewTexture2D->UpdateResource();
#if WITH_EDITOR
NewTexture2D->PostEditChange();
#endif
if (NormalBoolTable[i]) {
// UE5.5�ŃN���b�V�������̂� update���ɍēx�X�V
NewTexture2D->CompressionSettings = TC_Normalmap;
NewTexture2D->UpdateResource();
#if WITH_EDITOR
NewTexture2D->PostEditChange();
#endif
}
texArray.Push(NewTexture2D);
}
vrmAssetList->Textures = texArray;
// small thumbnail
{
createSmallThumbnail(vrmAssetList, aiData);
}
}
} // texture
TArray<FString> pmxTexNameList;
if (Options::Get().IsPMXModel()) {
TArray<UTexture2D*> texArray;
int MatNum = aiData->mNumMaterials;
vrmAssetList->Materials.SetNum(MatNum);
for (int32_t iMat = 0; iMat < MatNum; ++iMat) {
auto& aiMat = *aiData->mMaterials[iMat];
//
aiString ais;
if (aiMat.Get(AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0), ais) != AI_SUCCESS) {
continue;
}
FString TextureFullPath = FPaths::GetPath(vrmAssetList->FileFullPathName) + TEXT("/") + UTF8_TO_TCHAR(ais.C_Str());
FString baseName = FPaths::GetBaseFilename(UTF8_TO_TCHAR(ais.C_Str()));
baseName = TEXT("T_") + FPaths::GetBaseFilename(baseName);
baseName = NormalizeFileName(baseName);
if (pmxTexNameList.Find(baseName) >= 0) {
continue;
}
pmxTexNameList.Push(baseName);
TArray<uint8> RawFileData;
if (FFileHelper::LoadFileToArray(RawFileData, *TextureFullPath)){
auto* pkg = vrmAssetList->Package;
if (VRMConverter::Options::Get().IsSingleUAssetFile() == false) {
pkg = VRM4U_CreatePackage(vrmAssetList->Package, *baseName);
}
UTexture2D* NewTexture2D = VRMLoaderUtil::CreateTextureFromImage(baseName, pkg, RawFileData.GetData(), RawFileData.Num(), bGenerateMips);
texArray.Push(NewTexture2D);
}
}
vrmAssetList->Textures = texArray;
}
if (aiData->HasMaterials()) {
//TArray<FString> MatNameList;
TMap<FString, int> MatNameList;
int MatNum = FMath::Max(1, (int)aiData->mNumMaterials);
// lastmaterial = gltf default material
if (Options::Get().IsVRMModel()) {
MatNum = FMath::Max(1, (int)aiData->mNumMaterials - 1);
}
vrmAssetList->Materials.SetNum(MatNum);
for (int32_t iMat = 0; iMat < MatNum; ++iMat) {
auto &aiMat = *aiData->mMaterials[iMat];
UMaterialInterface *baseM = nullptr;
UVrmImportMaterialSet *mset = nullptr;
bool bMToon = false;
{
FString ShaderName = aiMat.mShaderName.C_Str();
auto MaterialType = Options::Get().GetMaterialType();
vrmAssetList->ImportMode = MaterialType;
// native mtoon model ?
LocalSetOriginalVrmMaterial(false);
if (ShaderName.Find(TEXT("MToon")) >= 0) {
// native
LocalSetOriginalVrmMaterial(true);
}
if (VRMConverter::Options::Get().IsVRM10Model()) {
// native
LocalSetOriginalVrmMaterial(true);
}
if (Options::Get().GetMaterialType() == EVRMImportMaterialType::VRMIMT_Auto) {
// default unlit
MaterialType = EVRMImportMaterialType::VRMIMT_Unlit;
if (ShaderName.Find(TEXT("MToon")) >= 0) {
MaterialType = EVRMImportMaterialType::VRMIMT_MToonUnlit;
}
if (Options::Get().IsPMXModel()) {
MaterialType = EVRMImportMaterialType::VRMIMT_MToonUnlit;
}
if (Options::Get().IsVRM10Model()) {
MaterialType = EVRMImportMaterialType::VRMIMT_MToonUnlit;
}
}
// select materialset
switch (MaterialType) {
case EVRMImportMaterialType::VRMIMT_MToon:
mset = vrmAssetList->MtoonLitSet;
bMToon = true;
break;
case EVRMImportMaterialType::VRMIMT_MToonUnlit:
mset = vrmAssetList->MtoonUnlitSet;
bMToon = true;
break;
case EVRMImportMaterialType::VRMIMT_SSS:
mset = vrmAssetList->SSSSet;
bMToon = true; // MTOON TRUE!
break;
case EVRMImportMaterialType::VRMIMT_SSSProfile:
mset = vrmAssetList->SSSProfileSet;
bMToon = true; // MTOON TRUE!
break;
case EVRMImportMaterialType::VRMIMT_Unlit:
mset = vrmAssetList->UnlitSet;
bMToon = false;
break;
case EVRMImportMaterialType::VRMIMT_glTF:
mset = vrmAssetList->GLTFSet;
bMToon = false;
break;
case EVRMImportMaterialType::VRMIMT_UEFNUnlit:
mset = vrmAssetList->UEFNUnlitSet;
bMToon = false;
break;
case EVRMImportMaterialType::VRMIMT_UEFNLit:
mset = vrmAssetList->UEFNLitSet;
bMToon = false;
break;
case EVRMImportMaterialType::VRMIMT_UEFNSSSProfile:
mset = vrmAssetList->UEFNSSSProfileSet;
bMToon = false;
break;
case EVRMImportMaterialType::VRMIMT_Custom:
mset = vrmAssetList->CustomSet;
bMToon = false;
break;
case EVRMImportMaterialType::VRMIMT_Auto:
default:
break;
}
if (mset == nullptr) {
continue;
}
bool bTwoSided = false;
bool bTranslucent = false;
bool bOpaque = false;
{
aiString alphaMode;
aiReturn result = aiMat.Get(AI_MATKEY_GLTF_ALPHAMODE, alphaMode);
FString alpha = alphaMode.C_Str();
if (alpha == TEXT("BLEND")) {
// check also _ZWrite
bTranslucent = true;
}
if (alpha == TEXT("MASK")) {
}
if (alpha == TEXT("OPAQUE")) {
bOpaque = true;
if (vrmAssetList->MaterialHasAlphaCutoff.IsValidIndex(iMat)) {
if (vrmAssetList->MaterialHasAlphaCutoff[iMat]) {
// force mask mode
bOpaque = false;
}
}
}
bool b = false;
aiReturn ret = aiMat.Get(AI_MATKEY_TWOSIDED, b);
if (ret == AI_SUCCESS) {
if (b) bTwoSided = true;
}
}
if (ShaderName.Find(TEXT("MToon")) >= 0) {
const VRM::VRMMetadata *meta = static_cast<const VRM::VRMMetadata*>(aiData->mVRMMeta);
if (meta) {
if ((int)iMat < meta->materialNum) {
auto &vrmMat = meta->material[iMat];
if (vrmMat.floatProperties._CullMode == 0.f || vrmMat.floatProperties._CullMode== 1.f) {
bTwoSided = true;
}
if (vrmMat.floatProperties._ZWrite == 1.f) {
bTranslucent = false;
}
}
}
}else{
if (ShaderName.Find(TEXT("UnlitTexture")) >= 0) {
}
if (ShaderName.Find(TEXT("UnlitTransparent")) >= 0) {
bTranslucent = true;
}
}
if (Options::Get().IsForceOpaque()) {
bTranslucent = false;
}
if (Options::Get().IsForceTwoSided()) {
bTwoSided = true;
}
// material set
if (bMToon) {
// opaque/translucent, twoside
UMaterialInterface *table_param[2][2] = {
{
mset->Opaque,
mset->OpaqueTwoSided,
},
{
mset->Translucent,
mset->TranslucentTwoSided,
},
};
int c[2] = {
bTranslucent ? 1 : 0,
bTwoSided ? 1 : 0,
};
baseM = table_param[c[0]][c[1]];
if (matArray.Num() == matFlagTranslucentArray.Num()) {
matFlagTranslucentArray.Add(c[0] != 0);
matFlagTwoSidedArray.Add(c[1] != 0);
matFlagOpaqueArray.Add(bOpaque);
}
}else{
// not mtoon
baseM = mset->Opaque;
if (bTranslucent){
baseM = mset->Translucent;
}
}
}
if (baseM == nullptr) {
continue;
}
TArray<int> TextureTypeToIndex;
{
TextureTypeToIndex.SetNum(AI_TEXTURE_TYPE_MAX);
for (auto& a : TextureTypeToIndex) {
a = -1;
}
TArray<aiString> texName;
texName.SetNum(AI_TEXTURE_TYPE_MAX);
for (uint32_t t = 0; t < AI_TEXTURE_TYPE_MAX; ++t) {
uint32_t n = aiMat.GetTextureCount((aiTextureType)t);
for (uint32_t y = 0; y < FMath::Min((uint32_t)1, n); ++y) {
aiMat.GetTexture((aiTextureType)t, y, &texName[t]);
}
}
for (uint32_t i = 0; i < aiData->mNumTextures; ++i) {
for (int32_t t = 0; t < texName.Num(); ++t) {
if (aiData->mTextures[i]->mFilename == texName[t]) {
TextureTypeToIndex[t] = i;
break;
}
}
}
}
for (uint32_t t = 0; t < AI_TEXTURE_TYPE_MAX; ++t) {
aiString path;
aiReturn r = aiMat.GetTexture(aiTextureType(t), 0, &path);
if (r == AI_SUCCESS) {
std::string s = path.C_Str();
s = s.substr(s.find_last_of('*') + 1);
TextureTypeToIndex[t] = atoi(s.c_str());
if (Options::Get().IsPMXModel()) {
for (int i = 0; i < pmxTexNameList.Num(); ++i) {
FString baseName = FPaths::GetBaseFilename(UTF8_TO_TCHAR(path.C_Str()));
baseName = TEXT("T_") + FPaths::GetBaseFilename(baseName);
baseName = NormalizeFileName(baseName);
if (pmxTexNameList[i] == baseName) {
TextureTypeToIndex[t] = i;
break;
}
}
}
}
}
//UMaterialInstanceDynamic* dm = UMaterialInstanceDynamic::Create(baseM, vrmAssetList, m.GetName().C_Str());
//UMaterialInstanceDynamic* dm = UMaterialInstance::Create(baseM, vrmAssetList, m.GetName().C_Str());
//MaterialInstance->TextureParameterValues
//set paramater with Set***ParamaterValue
//DynMaterial->SetScalarParameterValue("MyParameter", myFloatValue);
//MyComponent1->SetMaterial(0, DynMaterial);
//MyComponent2->SetMaterial(0, DynMaterial);
// ALL!! no texture material.
//if (indexDiffuse >= 0 && indexDiffuse < vrmAssetList->Textures.Num()) {
//if (indexDiffuse >= 0) {
{
UMaterialInstanceConstant* dm = nullptr;
{
const FString origname = (FString(TEXT("MI_")) + NormalizeFileName(aiMat.GetName().C_Str()));
FString name = origname;
if (MatNameList.Find(origname)) {
name += FString::Printf(TEXT("_%03d"), MatNameList[name]);
}
MatNameList.FindOrAdd(origname)++;
if (vrmAssetList->Package == GetTransientPackage()) {
dm = VRM4U_NewObject<UMaterialInstanceConstant>(GetTransientPackage(), NAME_None, EObjectFlags::RF_Public | RF_Transient);
} else {
TArray<UObject*> ret;
GetObjectsWithOuter(vrmAssetList->Package, ret);
for (auto *a : ret) {
auto s = a->GetName().ToLower();
if(s.IsEmpty()) continue;
if (s == name.ToLower()) {
//a->ClearFlags(EObjectFlags::RF_Standalone);
//a->SetFlags(EObjectFlags::RF_Public | RF_Transient);
//a->ConditionalBeginDestroy();
static int ccc = 0;
++ccc;
a->Rename(*(FString(TEXT("need_reload_tex_VRM"))+FString::FromInt(ccc)), GetTransientPackage(), REN_DontCreateRedirectors | REN_NonTransactional | REN_ForceNoResetLoaders);
break;
}
}
dm = VRM4U_NewObject<UMaterialInstanceConstant>(vrmAssetList->Package, *name, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone);
vrmAssetList->MaterialNameOrigToAsset.Add(NormalizeFileName(aiMat.GetName().C_Str()), name);
}
}
LocalMaterialSetParent(dm, baseM);
if (dm) {
{
FVectorParameterValue *v = new (dm->VectorParameterValues) FVectorParameterValue();
v->ParameterInfo.Index = INDEX_NONE;
v->ParameterInfo.Name = TEXT("gltf_basecolor");
v->ParameterInfo.Association = EMaterialParameterAssociation::GlobalParameter;
aiColor4D col(1.f, 1.f, 1.f, 1.f);
aiReturn result = aiMat.Get(AI_MATKEY_BASE_COLOR, col);
if (result == 0) {
}
v->ParameterValue = FLinearColor(col.r, col.g, col.b, col.a);
}
{
float f[2] = { 1,1 };
aiReturn result0 = aiMat.Get(AI_MATKEY_ROUGHNESS_FACTOR, f[0]);
aiReturn result1 = aiMat.Get(AI_MATKEY_METALLIC_FACTOR, f[1]);
if (result0 == AI_SUCCESS || result1 == AI_SUCCESS) {
f[0] = (result0 == AI_SUCCESS) ? f[0] : 1;
f[1] = (result1 == AI_SUCCESS) ? f[1] : 1;
if (f[0] == 0 && f[1] == 0) {
f[0] = f[1] = 1.f;
}
FVectorParameterValue *v = new (dm->VectorParameterValues) FVectorParameterValue();
v->ParameterInfo.Index = INDEX_NONE;
v->ParameterInfo.Name = TEXT("gltf_RM");
v->ParameterInfo.Association = EMaterialParameterAssociation::GlobalParameter;;
v->ParameterValue = FLinearColor(f[0], f[1], 0, 0);
}
}
int indexDiffuse = TextureTypeToIndex[aiTextureType::aiTextureType_DIFFUSE];
if (indexDiffuse >= 0 && indexDiffuse < vrmAssetList->Textures.Num()) {
LocalTextureSet(dm, TEXT("gltf_tex_diffuse"), vrmAssetList->Textures[indexDiffuse]);
{
FString str = TEXT("mtoon_tex_ShadeTexture");
bool bFindShadeTex = false;
for (auto &t : dm->TextureParameterValues) {
if (str.Compare(t.ParameterInfo.Name.ToString(), ESearchCase::IgnoreCase) == 0) {
if (t.ParameterValue) {
bFindShadeTex = true;
if (IsValid(vrmAssetList->Textures[indexDiffuse]) == false) {
#if UE_VERSION_OLDER_THAN(5,0,0)
UTexture2D *tmp = Cast<UTexture2D>(t.ParameterValue);
#else
UTexture2D* tmp = Cast<UTexture2D>(t.ParameterValue.Get());
#endif
if (tmp) {
LocalTextureSet(dm, TEXT("gltf_tex_diffuse"), tmp);
}
}
}
}
}
if (bFindShadeTex == false) {
LocalTextureSet(dm, *str, vrmAssetList->Textures[indexDiffuse]);
}
}
} else {
if (Options::Get().IsDefaultGridTextureMode() == false) {
// set white texture for default
UTexture2D* tex = LoadObject<UTexture2D>(nullptr, TEXT("/VRM4U/MaterialUtil/T_DummyWhite.T_DummyWhite"));
if (tex) {
LocalTextureSet(dm, TEXT("gltf_tex_diffuse"), tex);
LocalTextureSet(dm, TEXT("mtoon_tex_ShadeTexture"), tex);
LocalTextureSet(dm, TEXT("mtoon_tex_Shade"), tex);
}
}
}
if (bMToon == false){
{
aiString alphaMode;
aiReturn result = aiMat.Get(AI_MATKEY_GLTF_ALPHAMODE, alphaMode);
FString alpha = alphaMode.C_Str();
if (alpha == TEXT("BLEND")) {
if (Options::Get().IsForceOpaque() == false) {
dm->BasePropertyOverrides.bOverride_BlendMode = true;;
dm->BasePropertyOverrides.BlendMode = EBlendMode::BLEND_Translucent;
}
}
}
}
// mtoon
if (bMToon || VRMConverter::Options::Get().IsVRM10Model()) {
createAndAddMaterial(dm, iMat, vrmAssetList, this, TextureTypeToIndex);
if (matFlagOpaqueArray.IsValidIndex(iMat)) {
if (matFlagOpaqueArray[iMat]) {
LocalScalarParameterSet(dm, TEXT("bOpaque"), 1.f);
}
}
if (vrmAssetList->MaterialHasMToon.IsValidIndex(iMat)) {
if (vrmAssetList->MaterialHasMToon[iMat] == false) {
for (auto& a : dm->VectorParameterValues) {
if (a.ParameterInfo.Name == TEXT("mtoon_Color")) {
auto c = a.ParameterValue;
LocalVectorParameterSet(dm, TEXT("mtoon_ShadeColor"), c);
break;
}
}
}
}
} else {
// gltf texture
TArray<FString> materialParamName;
materialParamName.SetNum(AI_TEXTURE_TYPE_MAX);
materialParamName[aiTextureType::aiTextureType_DIFFUSE] = TEXT("gltf_tex_diffuse");
materialParamName[aiTextureType::aiTextureType_NORMALS] = TEXT("gltf_tex_normal");
materialParamName[aiTextureType::aiTextureType_EMISSIVE] = TEXT("gltf_tex_Emission");
materialParamName[aiTextureType::aiTextureType_BASE_COLOR] = TEXT("gltf_tex_diffuse");
materialParamName[aiTextureType::aiTextureType_EMISSION_COLOR] = TEXT("gltf_tex_Emission");
materialParamName[aiTextureType::aiTextureType_METALNESS] = TEXT("gltf_tex_metalness");
materialParamName[aiTextureType::aiTextureType_DIFFUSE_ROUGHNESS] = TEXT("gltf_tex_roughness");
for (uint32_t t = 0; t < AI_TEXTURE_TYPE_MAX; ++t) {
if (materialParamName[t] == "") continue;
int index = TextureTypeToIndex[t];
if (index < 0) continue;
if (vrmAssetList->Textures.IsValidIndex(index) == false) continue;
if (IsValid(vrmAssetList->Textures[index]) == false) continue;
LocalTextureSet(dm, *(materialParamName[t]), vrmAssetList->Textures[index]);
}
}
LocalMaterialFinishParam(dm);
//dm->InitStaticPermutation();
matArray.Add(dm);
if (matArray.Num() != matFlagTranslucentArray.Num()) {
matFlagTranslucentArray.SetNumZeroed(matArray.Num());
matFlagTwoSidedArray.SetNumZeroed(matArray.Num());
matFlagOpaqueArray.SetNumZeroed(matArray.Num());
}
TArray<FString> t;
if (vrmAssetList->MaterialNameOrigToAsset.Num()) {
vrmAssetList->MaterialNameOrigToAsset.GenerateValueArray(t);
vrmAssetList->MaterialNameAssetToMatNo.Add(t[t.Num() - 1], matArray.Num() - 1);
}
}
}
}
if (VRMConverter::Options::Get().IsBC7Mode()) {
vrmAssetList->Texture_CompressType = EVRMImportTextureCompressType::VRMITC_BC7;
}
vrmAssetList->Texture_CompressTypeList = textureCompressTypeArray;
if (Options::Get().IsMergeMaterial() == false) {
vrmAssetList->Materials = matArray;
vrmAssetList->MaterialFlag_Translucent = matFlagTranslucentArray;
vrmAssetList->MaterialFlag_TwoSided = matFlagTwoSidedArray;
vrmAssetList->MaterialFlag_Opaque = matFlagOpaqueArray;
} else {
TArray<UMaterialInterface*> tmp;
TArray<bool> tmpTranslucent;
TArray<bool> tmpTwoSided;
TArray<bool> tmpOpaque;
vrmAssetList->MaterialMergeTable.Reset();
for (int i = 0; i < matArray.Num(); ++i) {
vrmAssetList->MaterialMergeTable.Add(i, 0);
bool bFind = false;
for (int j = 0; j < tmp.Num(); ++j) {
if (isSameMaterial(matArray[i], tmp[j]) == false) {
continue;
}
bFind = true;
vrmAssetList->MaterialMergeTable[i] = j;
matArray[i]->Rename(nullptr, GetTransientPackage(), REN_DontCreateRedirectors | REN_NonTransactional | REN_ForceNoResetLoaders);
break;
}
if (bFind == false) {
int t = tmp.Add(matArray[i]);
vrmAssetList->MaterialMergeTable[i] = t;
tmpTranslucent.Add(matFlagTranslucentArray[i]);
tmpTwoSided.Add(matFlagTwoSidedArray[i]);
tmpOpaque.Add(matFlagOpaqueArray[i]);
}
}
vrmAssetList->Materials = tmp;
vrmAssetList->MaterialFlag_Translucent = tmpTranslucent;
vrmAssetList->MaterialFlag_TwoSided = tmpTwoSided;
vrmAssetList->MaterialFlag_Opaque = tmpOpaque;
for (auto& a : vrmAssetList->MaterialNameAssetToMatNo) {
a.Value = vrmAssetList->MaterialMergeTable[a.Value];
}
}
// ouline Material
if (VRMConverter::Options::Get().IsGenerateOutlineMaterial()) {
if (vrmAssetList->OptMToonOutlineMaterial){
for (const auto aa : vrmAssetList->Materials) {
const UMaterialInstanceConstant *a = Cast<UMaterialInstanceConstant>(aa);
FString s = a->GetName() + TEXT("_outline");
//UMaterialInstanceConstant *m = Cast<UMaterialInstanceConstant>(StaticDuplicateObject(a->GetOuter(), a, *s, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone, UMaterialInstanceConstant::StaticClass()));
UMaterialInstanceConstant *m = VRM4U_NewObject<UMaterialInstanceConstant>(vrmAssetList->Package, *s, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone);
if (m) {
LocalMaterialSetParent(m, vrmAssetList->OptMToonOutlineMaterial);
m->VectorParameterValues = a->VectorParameterValues;
m->ScalarParameterValues = a->ScalarParameterValues;
m->TextureParameterValues = a->TextureParameterValues;
LocalMaterialFinishParam(m);
//m->InitStaticPermutation();
vrmAssetList->OutlineMaterials.Add(m);
}
}
}
}
{
UPackage* package = GetTransientPackage();
if (vrmAssetList) {
package = vrmAssetList->Package;
}
auto sp = VRM4U_NewObject<USubsurfaceProfile>(package, *(FString(TEXT("SP_")) + vrmAssetList->BaseFileName), EObjectFlags::RF_Public | EObjectFlags::RF_Standalone);
#if UE_VERSION_OLDER_THAN(5,0,0)
sp->Settings.ScatterRadius = 50.f;
#else
// default
#endif
#if WITH_EDITORONLY_DATA
vrmAssetList->SSSProfile = sp;
#endif
for (auto& a : vrmAssetList->Materials) {
a->SubsurfaceProfile = sp;
auto* c = Cast<UMaterialInstance>(a);
if (c) {
c->bOverrideSubsurfaceProfile = true;
}
}
}
}
return true;
}
VrmConvertTexture::VrmConvertTexture()
{
}
VrmConvertTexture::~VrmConvertTexture()
{
}