ue4.26 CustomPrimitiveData导致staticmesh editor预览变黑解法
一,customPrimitiveData用法 及 导致staticmesh editor预览变黑
材质里这样连:
actor上设置custom primitive data数据,则模型呈现相应颜色:
但此时若打开staticmesh editor,会发现预览变黑:
那是因为staticmesh editor中没有custom primitive data数据,因为会采用默认值0
二,解法
只要把custom primitive data的默认值改为1即可。
为此在源码中搜索CustomPrimitiveData相关的代码。
可以搜到界面上对应的变量为:
不过这个用处不大,因为我们是希望传到材质里的CustomPrimitiveData的默认值为1。custom primitive data应该是通过uniform buffer传到材质(shader)里的。
可搜到PrimitiveUniformShaderParameters.h中:
可见CustomPrimitiveData是作为FPrimitiveUniformShaderParameters的一个成员传入shader的。
在FPrimitiveUniformShaderParameters下面紧接着就是其初始化函数代码:
/** Initializes the primitive uniform shader parameters. */ inline FPrimitiveUniformShaderParameters GetPrimitiveUniformShaderParameters( const FMatrix& LocalToWorld, const FMatrix& PreviousLocalToWorld, FVector ActorPosition, const FBoxSphereBounds& WorldBounds, const FBoxSphereBounds& LocalBounds, const FBoxSphereBounds& PreSkinnedLocalBounds, bool bReceivesDecals, bool bHasDistanceFieldRepresentation, // Currently unused bool bHasCapsuleRepresentation, bool bUseSingleSampleShadowFromStationaryLights, bool bUseVolumetricLightmap, bool bDrawsVelocity, uint32 LightingChannelMask, float LpvBiasMultiplier, uint32 LightmapDataIndex, int32 SingleCaptureIndex, bool bOutputVelocity, const FCustomPrimitiveData* CustomPrimitiveData, bool bCastContactShadow = true ) { FPrimitiveUniformShaderParameters Result; Result.LocalToWorld = LocalToWorld; Result.WorldToLocal = LocalToWorld.Inverse(); Result.PreviousLocalToWorld = PreviousLocalToWorld; Result.PreviousWorldToLocal = PreviousLocalToWorld.Inverse(); Result.ObjectWorldPositionAndRadius = FVector4(WorldBounds.Origin, WorldBounds.SphereRadius); Result.ObjectBounds = WorldBounds.BoxExtent; Result.LocalObjectBoundsMin = LocalBounds.GetBoxExtrema(0); // 0 == minimum Result.LocalObjectBoundsMax = LocalBounds.GetBoxExtrema(1); // 1 == maximum Result.PreSkinnedLocalBoundsMin = PreSkinnedLocalBounds.GetBoxExtrema(0); // 0 == minimum Result.PreSkinnedLocalBoundsMax = PreSkinnedLocalBounds.GetBoxExtrema(1); // 1 == maximum Result.ObjectOrientation = LocalToWorld.GetUnitAxis( EAxis::Z ); Result.ActorWorldPosition = ActorPosition; Result.LightingChannelMask = LightingChannelMask; Result.LpvBiasMultiplier = LpvBiasMultiplier; { // Extract per axis scales from LocalToWorld transform FVector4 WorldX = FVector4(LocalToWorld.M[0][0],LocalToWorld.M[0][1],LocalToWorld.M[0][2],0); FVector4 WorldY = FVector4(LocalToWorld.M[1][0],LocalToWorld.M[1][1],LocalToWorld.M[1][2],0); FVector4 WorldZ = FVector4(LocalToWorld.M[2][0],LocalToWorld.M[2][1],LocalToWorld.M[2][2],0); float ScaleX = FVector(WorldX).Size(); float ScaleY = FVector(WorldY).Size(); float ScaleZ = FVector(WorldZ).Size(); Result.NonUniformScale = FVector4(ScaleX,ScaleY,ScaleZ,0); Result.InvNonUniformScaleAndDeterminantSign = FVector4( ScaleX > KINDA_SMALL_NUMBER ? 1.0f/ScaleX : 0.0f, ScaleY > KINDA_SMALL_NUMBER ? 1.0f/ScaleY : 0.0f, ScaleZ > KINDA_SMALL_NUMBER ? 1.0f/ScaleZ : 0.0f, FMath::FloatSelect(LocalToWorld.RotDeterminant(),1,-1) ); } Result.DecalReceiverMask = bReceivesDecals ? 1 : 0; Result.PerObjectGBufferData = (2 * (int32)bHasCapsuleRepresentation + (int32)bCastContactShadow) / 3.0f; Result.UseSingleSampleShadowFromStationaryLights = bUseSingleSampleShadowFromStationaryLights ? 1.0f : 0.0f; Result.UseVolumetricLightmapShadowFromStationaryLights = bUseVolumetricLightmap && bUseSingleSampleShadowFromStationaryLights ? 1.0f : 0.0f; Result.DrawsVelocity = bDrawsVelocity ? 1 : 0; Result.LightmapDataIndex = LightmapDataIndex; // If SingleCaptureIndex is invalid, set it to 0 since there will be a default cubemap at that slot Result.SingleCaptureIndex = FMath::Max(SingleCaptureIndex, 0); Result.OutputVelocity = (bOutputVelocity) ? 1 : 0; // Clear to 0 FMemory::Memzero(Result.CustomPrimitiveData);
// If this primitive has custom primitive data, set it if (CustomPrimitiveData) { // Copy at most up to the max supported number of dwords for safety FMemory::Memcpy(&Result.CustomPrimitiveData, CustomPrimitiveData->Data.GetData(), CustomPrimitiveData->Data.GetTypeSize() * FMath::Min(CustomPrimitiveData->Data.Num(), FCustomPrimitiveData::NumCustomPrimitiveDataFloats)); } return Result; }
其中:
// Clear to 0 FMemory::Memzero(Result.CustomPrimitiveData);
就是将CustomPrimitiveData初始化为0的代码(初始化)。
而后面的:
// If this primitive has custom primitive data, set it if (CustomPrimitiveData) { // Copy at most up to the max supported number of dwords for safety FMemory::Memcpy(&Result.CustomPrimitiveData, CustomPrimitiveData->Data.GetData(), CustomPrimitiveData->Data.GetTypeSize() * FMath::Min(CustomPrimitiveData->Data.Num(), FCustomPrimitiveData::NumCustomPrimitiveDataFloats)); }
是将FCustomPrimitiveData类型变量CustomPrimitiveData的Data成员填充到FPrimitiveUniformShaderParameters类型变量Result的CustomPrimitiveData成员的过程(赋值)。
我们只需在
FMemory::Memzero(Result.CustomPrimitiveData);
后面加:
#if WITH_EDITOR
for (int i = 0; i < FCustomPrimitiveData::NumCustomPrimitiveDataFloat4s; i++)
{
Result.CustomPrimitiveData[i].Set(1, 1, 1, 1);
}
#endif
即可。
注:上面循环写法是参考的PrimitiveUniformShaderParameters.cpp中的Setup函数中这段:
改完后重新编译引擎(由于是比较底层的代码,要重编3000多个文件)。
则staticmesh editor预览不再变黑:
---补充:
ue4.26 CustomPrimitiveData导致staticmesh editor预览变黑解法 - 知乎 (zhihu.com)