ue4.26 CustomPrimitiveData导致staticmesh editor预览变黑解法

发布时间 2023-10-31 01:05:24作者: wantnon

一,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);

将其改为:

for (int i = 0; i < FCustomPrimitiveData::NumCustomPrimitiveDataFloat4s; i++)
{
Result.CustomPrimitiveData[i].Set(1, 1, 1, 1);
}

即可。

改完后重新编译引擎(由于是比较底层的代码,重编文件较多)。

则staticmesh editor预览不再变黑: