Metahuman - Assembly quality presets

I would like to have better control over the metahuman Assembly quality presets.

Is there any way I could define what LODs from source I would like to set as an output for example or create new custom presets?

Does any documentation for this exists?

Zbynek

[Attachment Removed]

Hi,

At the moment, this level of customisation is unfortunately not supported. It is a common request, and we recognise the need to have greater control over the assembly process to optimize characters for different platforms.

As such, it is an area that we’re investigating how to expose in the future, although I am not able to put a timeframe on this at the moment. You mention defining LODs; what areas of the character would you like to be able to control during assembly?

Some level of customisation is possible after the characters have been assembled, as you can modified the blueprint etc, although we do not have documentation for specific scenarios.

Mark.

[Attachment Removed]

Hi,

Heads are the main focus.

i.e. I would like to be able to assemble output mesh composed from custom selection of LODs

Target - MH HD source

LOD0 - LOD1

LOD1 - LOD4

LOD2 - LOD5

LOD3 - LOD7

[Attachment Removed]

As Mark said, this isn’t something you can easily do out of the box, but if you want to look into it yourself I can give some hints to get you started.

The face and body LODs for a quality level are controlled by a set of blueprints under /MetaHumanCharacter/BuildPipeline, e.g. the settings for High quality are in BP_DefaultLegacyPipeline_High. There’s no way to add a custom quality level (yet), but you can modify one of the existing quality levels for your purposes.

If you open BP_DefaultLegacyPipeline_High and look at the Editor Pipeline -> LODs -> LOD Properties category, you can see there are properties that control which face and body LODs are used and their LOD settings. You can modify these if you’re comfortable with modifying engine content. The High BP uses the original body LODs, but you can look at the Medium blueprint for an example of how to use a reduced set of body LODs.

After you’ve modified these properties, you’ll also need to adjust the LOD Sync component setup in the actor blueprint to select the correct groom and clothing LODs. You can find the template actor blueprints for the different quality levels in the same folder, e.g. BP_MetaHuman_Legacy_High is the template for High.

Note that in the full quality, cinematic MetaHuman, each body LOD has two corresponding face LODs where the neck seam will match perfectly, e.g. body LOD 0 matches face LODs 0 and 1. In your LOD mapping, you have two face LODs (4 and 5) that map to the same body LOD (body LOD 2). None of our quality levels are set up like this, so you won’t have an example to copy from, but it should work if you set up the pipeline BP to generate body LODs 0, 2 and 3, and then in the LOD Sync Component make a Custom LOD Mapping entry for the Body component to map LODs 0-4 to body LODs 0, 1, 1, 2.

I hope this makes sense. I haven’t tested your specific setup with this method, but as far as I know it should work, and if not you should be able to debug it by putting a breakpoint in UMetaHumanDefaultEditorPipelineBase::BuildCollection.

Hope this helps!

[Attachment Removed]

Thanks for the hints. I’ll test.

In the mean time I have a question regarding DNA and LODs.

If the exported asset will start with higher LOD, will that affect the complexity of DNA data? My goal is also to optimize DNA as well.

[Attachment Removed]

You’re welcome.

Any LODs removed from the mesh will be removed from the DNA as well. This happens in FMetaHumanCharacterEditorBuild::StripLODsFromMesh, and you can see that it uses FDNACalibSetLODsCommand to remove the LODs from the DNA.

[Attachment Removed]

What is the expected additional memory usage when using the DNA Assets together with Mutable? It seems by our approximate measurements (based on the buffer size) that it can be around 3.5 MB per each CustomizableObject Skeletal Mesh, and the Total Used Memory of the game raises around +300 MBs. The memory is not reported together with Skeletal Meshes and cannot be seen in memreports/labelem in LLM (unless we are missing something), but the raise seems to be there for sure.

[Attachment Removed]

I don’t have any specific stats for that, but it sounds high if it’s per mesh. It’s certainly possible that not all of the memory is tagged for LLM.

Is that 300MB for 1 MetaHuman? What quality level are you using when you assemble the MetaHuman?

[Attachment Removed]

It’s around 40-50 MetaHuman Head Skeletal Meshes that are customized via the mutable system and the DNA data is copied to them via `URigLogicMutableExtension::OnSkeletalMeshCreated`.

[Attachment Removed]

OK, 300MB doesn’t sound too crazy for 40-50 MetaHumans, although it would be nice if it was lower.

I recommend running the console command “obj list class=DNAAsset” in a cooked build to check how many DNAs you have in memory, and make sure that you don’t have any unexpected copies.

I would also try assembling the MetaHumans at a lower quality level, just as a test, and make sure the DNA memory usage goes down. If it doesn’t, the unused LODs may not be being pruned from the DNA as expected.

[Attachment Removed]

Here is an excerpt of the command.

Obj List: class=DNAAsset
Objects:
                                                                                                                                      Object     NumKB      MaxKB   ResExcKB  ResExcDedSysKB  ResExcDedVidKB     ResExcUnkKB
                                                                      DNAAsset /Engine/Transient.SK_MCOR_M_NPC_Head_3318225225_71:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                                DNAAsset /Engine/Transient.SK_MCOR_F_NPC_Head_164:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                     DNAAsset /Game/Art/Characters/Mutable/MCOR_F_NPC/_Generated_/MCOR_F_NPC_SE_8.MCOR_F_NPC_SE_8:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                     DNAAsset /Engine/Transient.SK_MCOR_M_NPC_Head_3600922032_162:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                     DNAAsset /Engine/Transient.SK_MCOR_M_NPC_Head_2428319526_160:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                     DNAAsset /Engine/Transient.SK_MCOR_M_NPC_Head_2214340074_158:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                                DNAAsset /Engine/Transient.SK_MCOR_M_NPC_Head_156:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                                DNAAsset /Engine/Transient.SK_MCOR_F_NPC_Head_154:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                     DNAAsset /Engine/Transient.SK_MCOR_F_NPC_Head_3834853620_151:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                                DNAAsset /Engine/Transient.SK_MCOR_F_NPC_Head_149:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                     DNAAsset /Engine/Transient.SK_MCOR_M_NPC_Head_2285745731_147:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                     DNAAsset /Engine/Transient.SK_MCOR_M_NPC_Head_2281319440_145:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                     DNAAsset /Engine/Transient.SK_MCOR_M_NPC_Head_4114919928_143:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
                                                                                DNAAsset /Engine/Transient.SK_MCOR_M_NPC_Head_141:DNAAsset_7      0.34       0.36       0.00            0.00            0.00            0.00
[....]
                                                                                                Class    Count      NumKB      MaxKB   ResExcKB  ResExcDedSysKB  ResExcDedVidKB     ResExcUnkKB
                                                                                             DNAAsset       98      33.69      35.22       0.00            0.00            0.00            0.00

Basically all the original DNAAssets are loaded, as well as the transient copies created by the URigLogicMutableExtension::OnSkeletalMeshCreated which duplicates the UObject (which results in ~50ms spikes every time a new Mutable is created).

[Attachment Removed]

Yeah, that makes sense. Because a DNAAsset is AssetUserData, it has to be a subobject of the mesh, so we have to duplicate it for each mesh.

There’s a change coming in 5.8 that moves the DNA to its own standalone asset type called simply “DNA”, which will allow DNA to be shared between meshes. Once you have that change it would be possible to modify the Mutable extension to have the Customizable Object reference a DNA asset instead of hosting the DNA data in the CO itself, then it could simply pass that reference on to any skeletal meshes it generates and avoid copying the DNA.

Until then I can’t see an easy way to avoid copying the DNA. It may be possible to do the copy on a background thread to avoid the 50ms stall, but I haven’t looked into this.

[Attachment Removed]

I just had another idea. Mutable has recently introduced the concept of “passthrough” meshes that aren’t modified by Mutable. If a passthrough mesh has DNA, this would simply be passed through to the final result without copying, so that could be an option depending on your exact needs. I think this feature was in 5.7 but I’m not 100% sure.

[Attachment Removed]

Is it just the CL 49280991, or is something else dependent on it as well?

I am trying currently to estimate how possible it would be to backport the changes to 5.6, because since the current state is far from production ready for our case (in both memory and processing time during runtime), we will either need to backport the 5.8 changes, or choose a completely different solution for facial animations.

As for reducing the MetaHuman during creation in UE, we are using LOD3 as LOD0 for polycount, but it has always around 600 bones for LOD0 in any case.

[Attachment Removed]

I’ve spoken to the author of that change and they said it should have everything in it.

What quality level are you assembling the MetaHuman at? If you’re using Optimized High, that would give you about 600 bones in LOD 0 and 41 bones in LOD 3. LOD 3 of Optimized High corresponds to LOD 7 of Cine though, and only has 356 polys, so I’m guessing that’s not what you’re using for your top LOD.

If you assemble at a lower quality, so that LOD 0 is the one you want to use, that should definitely make the DNA smaller and faster to copy.

[Attachment Removed]

I would like to ask for some hints as the process of assembly is little bit confusing.

I’ve attempt to adjust the BP_DefaultLegacyPipeline_High setting as follows

[Image Removed].. the output SK mesh asset matches defined LODs, but not in terms of bones. I’m getting the same amount of bones in LOD0 (LOD3 original) as with original LOD0, after assembly process. I can see that the skinning is different, but the amount of bones is identical.

[Image Removed]

I would expect the same result of LOD0 after assembly as if I would select Quality:Medium for the assembly process.

[Image Removed]How to get correctly assembled meshes for the LODs if customizing the BP_DefaultLegacyPipeline_High or get 4 LODs with BP_DefaultLegacyPipeline_Medium , please?

[Attachment Removed]

I did a quick test with the same setup and I think it’s working correctly.

[Image Removed]The bones over the top of the head aren’t used at this LOD. You can see that they’re greyed out, so AFAIK their positions are not important.

If you enable the Detailed mesh stats, you can see how many bones are used by each LOD and I found that LOD 0 does approximately match the cinematic LOD 3 as expected.

[Image Removed]

[Attachment Removed]

The fact there are extra bones, even not skinned … what effect it has on DNA data? Are those not skinned excluded?

Why with Medium preset is the mesh “clean” ? Is there any way to achieve the same result?

What functionality has LODsettings asset in the process of assembly in terms of bone count?

[Attachment Removed]

Those additional bones are defined in the skeleton asset, which is separate from the DNA. If they’re not skinned they should have almost no performance or memory impact.

Can you explain what you mean by clean? Are you talking about the positions of the unskinned bones? Unless they’re causing a problem, such as animation artifacts, you can safely ignore them.

I did some experiments with LODSettings to be able to answer your question, and I discovered that:

  • For LOD 0, the mesh seems to contain information about which bones are used, and the RequiredBones array that determines which bones are animated is populated only with these, so this is already a minimal set of bones for the LOD. This applies even if the current LOD 0 was previously a lower LOD, as in your case. I didn’t trace back far enough to see where this information originates from, but I’m satisfied that it will be present and correct in your case.
  • For lower LODs, the Bone List in the LODSettings determines which bones are animated, so this must be set correctly for the LOD.

This means that when you’re setting custom LODs in the Face LODs array in the blueprint, you should also create a new LODSettings asset with the correct setup for those LODs, especially the Bone List. You can copy the Bone List for your source LODs from the cinematic LOD settings found in the MetaHuman Creator plugin content here: /MetaHumanCharacter/Face/Face_LODSettings.

Once you’ve done this, only the bones that are needed will be updated for each LOD, in both the Unreal animation and rendering systems and in RigLogic.

[Attachment Removed]

Hi Henry.

By “clean” I meant result as with [Medium [Content removed] , the extra bones are “not used” by LOD0 (LOD3 original source).

I’m writing “not used” as that is what tooltip says when you hover over the bone “This bone is used by the current mesh, but has no vertices weighted against it”

Are you sure they are not transformed by the animation when in this state?

[Attachment Removed]