UE5 Lightmap使用

在BasePass阶段使用

DefferredShadingRenderer:Render()

if (bRenderDeferredLighting)
	{
		RDG_GPU_STAT_SCOPE(GraphBuilder, RenderDeferredLighting);
		RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, RenderLighting);
		SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_Lighting);

		FRDGTextureRef DynamicBentNormalAOTexture = nullptr;

		RenderDiffuseIndirectAndAmbientOcclusion(
			GraphBuilder,
			SceneTextures,
			LumenFrameTemporaries,
			LightingChannelsTexture,
			bHasLumenLights,
			/* bCompositeRegularLumenOnly = */ false,
			/* bIsVisualizePass = */ false,
			AsyncLumenIndirectLightingOutputs);

		// These modulate the scenecolor output from the basepass, which is assumed to be indirect lighting
		if (bAllowStaticLighting)
		{
			RenderIndirectCapsuleShadows(GraphBuilder, SceneTextures);
		}

		// These modulate the scene color output from the base pass, which is assumed to be indirect lighting
		RenderDFAOAsIndirectShadowing(GraphBuilder, SceneTextures, DynamicBentNormalAOTexture);

		// Clear the translucent lighting volumes before we accumulate
		if ((GbEnableAsyncComputeTranslucencyLightingVolumeClear && GSupportsEfficientAsyncCompute) == false)
		{
			TranslucencyLightingVolumeTextures.Init(GraphBuilder, Views, ERDGPassFlags::Compute);
		}

#if RHI_RAYTRACING
		if (IsRayTracingEnabled())
		{
			RenderDitheredLODFadingOutMask(GraphBuilder, Views[0], SceneTextures.Depth.Target);
		}
#endif

		GraphBuilder.SetCommandListStat(GET_STATID(STAT_CLM_Lighting));
		RenderLights(GraphBuilder, SceneTextures, TranslucencyLightingVolumeTextures, LightingChannelsTexture, SortedLightSet);
		GraphBuilder.SetCommandListStat(GET_STATID(STAT_CLM_AfterLighting));

		InjectTranslucencyLightingVolumeAmbientCubemap(GraphBuilder, Views, TranslucencyLightingVolumeTextures);
		FilterTranslucencyLightingVolume(GraphBuilder, Views, TranslucencyLightingVolumeTextures);

		// Do DiffuseIndirectComposite after Lights so that async Lumen work can overlap
		RenderDiffuseIndirectAndAmbientOcclusion(
			GraphBuilder,
			SceneTextures,
			LumenFrameTemporaries,
			LightingChannelsTexture,
			bHasLumenLights,
			/* bCompositeRegularLumenOnly = */ true,
			/* bIsVisualizePass = */ false,
			AsyncLumenIndirectLightingOutputs);

		// Render diffuse sky lighting and reflections that only operate on opaque pixels
		RenderDeferredReflectionsAndSkyLighting(GraphBuilder, SceneTextures, DynamicBentNormalAOTexture);

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
		// Renders debug visualizations for global illumination plugins
		RenderGlobalIlluminationPluginVisualizations(GraphBuilder, LightingChannelsTexture);
#endif

		AddSubsurfacePass(GraphBuilder, SceneTextures, Views);

		Strata::AddStrataOpaqueRoughRefractionPasses(GraphBuilder, SceneTextures, Views);

		{
			RenderHairStrandsSceneColorScattering(GraphBuilder, SceneTextures.Color.Target, Scene, Views);
		}

	#if RHI_RAYTRACING
		if (ShouldRenderRayTracingSkyLight(Scene->SkyLight) 
			//@todo - integrate RenderRayTracingSkyLight into RenderDiffuseIndirectAndAmbientOcclusion
			&& GetViewPipelineState(Views[0]).DiffuseIndirectMethod != EDiffuseIndirectMethod::Lumen
			&& ViewFamily.EngineShowFlags.GlobalIllumination)
		{
			FRDGTextureRef SkyLightTexture = nullptr;
			FRDGTextureRef SkyLightHitDistanceTexture = nullptr;
			RenderRayTracingSkyLight(GraphBuilder, SceneTextures.Color.Target, SkyLightTexture, SkyLightHitDistanceTexture);
			CompositeRayTracingSkyLight(GraphBuilder, SceneTextures, SkyLightTexture, SkyLightHitDistanceTexture);
		}
	#endif
	}

RenderDiffuseIndirectAndAmbientOcclusion

 

RenderDeferredReflectionsAndSkyLighting

Final Image :

 

基础结构

struct VTPageTableResult
{
	float2 UV;
	float2 dUVdx;
	float2 dUVdy;
	uint4 PageTableValue[2];
	uint PackedRequest;
};

struct FLightmapSceneData
{
	float4 StaticShadowMapMasks;
	float4 InvUniformPenumbraSizes;
	float4 LightMapCoordinateScaleBias;
	float4 ShadowMapCoordinateScaleBias;
	float4 LightMapScale[2];
	float4 LightMapAdd[2];
	uint4 LightmapVTPackedPageTableUniform[2];
	uint4 LightmapVTPackedUniform[5];
};

Shader测具体过程:

BasePathPixelShader.usf

void GetPrecomputedIndirectLightingAndSkyLight(
	FMaterialPixelParameters MaterialParameters, 
	FVertexFactoryInterpolantsVSToPS Interpolants,
	FBasePassInterpolantsVSToPS BasePassInterpolants,
	VTPageTableResult LightmapVTPageTableResult,
	bool bEvaluateBackface,
	float3 DiffuseDir,
	float3 VolumetricLightmapBrickTextureUVs,
	out float3 OutDiffuseLighting,
	out float3 OutSubsurfaceLighting,
	out float OutIndirectIrradiance)
{
	OutIndirectIrradiance = 0;
	OutDiffuseLighting = 0;
	OutSubsurfaceLighting = 0;
	LightmapUVType SkyOcclusionUV = (LightmapUVType)0;
	uint SkyOcclusionDataIndex = 0u;


	// High quality texture lightmaps
	#elif HQ_TEXTURE_LIGHTMAP
		LightmapUVType LightmapUV0, LightmapUV1;
		uint LightmapDataIndex;
		GetLightMapCoordinates(Interpolants, LightmapUV0, LightmapUV1, LightmapDataIndex);
		SkyOcclusionUV = LightmapUV0;
		SkyOcclusionDataIndex = LightmapDataIndex;
		GetLightMapColorHQ(LightmapVTPageTableResult, LightmapUV0, LightmapUV1, LightmapDataIndex, DiffuseDir, MaterialParameters.SvPosition.xy, bEvaluateBackface, OutDiffuseLighting, OutSubsurfaceLighting);

	// Low quality texture lightmaps
	#elif LQ_TEXTURE_LIGHTMAP
		LightmapUVType LightmapUV0, LightmapUV1;
		uint LightmapDataIndex;
		GetLightMapCoordinates(Interpolants, LightmapUV0, LightmapUV1, LightmapDataIndex);
		GetLightMapColorLQ(LightmapVTPageTableResult, LightmapUV0, LightmapUV1, LightmapDataIndex, DiffuseDir, bEvaluateBackface, OutDiffuseLighting, OutSubsurfaceLighting, OutIndirectIrradiance);

	#endif

	// Apply indirect lighting scale while we have only accumulated lightmaps
	OutDiffuseLighting *= View.PrecomputedIndirectLightingColorScale;
	OutSubsurfaceLighting *= View.PrecomputedIndirectLightingColorScale;

	float3 SkyDiffuseLighting;
	float3 SkySubsurfaceLighting;
	GetSkyLighting(MaterialParameters, LightmapVTPageTableResult, bEvaluateBackface, DiffuseDir, SkyOcclusionUV, SkyOcclusionDataIndex, VolumetricLightmapBrickTextureUVs, SkyDiffuseLighting, SkySubsurfaceLighting);

	OutSubsurfaceLighting += SkySubsurfaceLighting;

	// Sky lighting must contribute to IndirectIrradiance for ReflectionEnvironment lightmap mixing
	OutDiffuseLighting += SkyDiffuseLighting;

	#if HQ_TEXTURE_LIGHTMAP || LQ_TEXTURE_LIGHTMAP || CACHED_VOLUME_INDIRECT_LIGHTING || CACHED_POINT_INDIRECT_LIGHTING || PRECOMPUTED_IRRADIANCE_VOLUME_LIGHTING
		OutIndirectIrradiance = Luminance(OutDiffuseLighting);
	#endif
}


void GetLightMapColorHQ( VTPageTableResult LightmapVTPageTableResult, LightmapUVType LightmapUV0, LightmapUVType LightmapUV1, uint LightmapDataIndex, half3 WorldNormal, float2 SvPositionXY, bool bEvaluateBackface, out half3 OutDiffuseLighting, out half3 OutSubsurfaceLighting )
{
	OutSubsurfaceLighting = 0;

	half4 Lightmap0;
	half4 Lightmap1;
#if LIGHTMAP_VT_ENABLED
	Lightmap0 = SampleLightmapVT( LightmapVTPageTableResult, 0u, LightmapDataIndex, LightmapResourceCluster.VTLightMapTexture, LightmapResourceCluster.LightMapSampler); 
	Lightmap1 = SampleLightmapVT( LightmapVTPageTableResult, 1u, LightmapDataIndex, LightmapResourceCluster.VTLightMapTexture_1, LightmapResourceCluster.LightMapSampler); 
#else
	Lightmap0 = Texture2DSample( LightmapResourceCluster.LightMapTexture, LightmapResourceCluster.LightMapSampler, LightmapUV0 );
	Lightmap1 = Texture2DSample( LightmapResourceCluster.LightMapTexture, LightmapResourceCluster.LightMapSampler, LightmapUV1 );
#endif

	half LogL = Lightmap0.w;

	// Add residual
	LogL += Lightmap1.w * (1.0 / 255) - (0.5 / 255);

	// Range scale LogL
	LogL = LogL * GetLightmapData(LightmapDataIndex).LightMapScale[0].w + GetLightmapData(LightmapDataIndex).LightMapAdd[0].w;
		
	// Range scale UVW
	half3 UVW = Lightmap0.rgb * Lightmap0.rgb * GetLightmapData(LightmapDataIndex).LightMapScale[0].rgb + GetLightmapData(LightmapDataIndex).LightMapAdd[0].rgb;

	// LogL -> L
	const half LogBlackPoint = 0.01858136;
	half L = exp2( LogL ) - LogBlackPoint;

#if USE_LM_DIRECTIONALITY
	// Range scale SH. Alpha doesn't matter, will scale with zero
	float4 SH = Lightmap1 * GetLightmapData(LightmapDataIndex).LightMapScale[1] + GetLightmapData(LightmapDataIndex).LightMapAdd[1];

	// Sample SH with normal
	half Directionality = max( 0.0, dot( SH, float4(WorldNormal.yzx, 1) ) );

	#if SHADINGMODEL_REQUIRES_BACKFACE_LIGHTING
	if (bEvaluateBackface)
	{
		half SubsurfaceDirectionality = max(0.0, dot(SH, float4(-WorldNormal.yzx, 1)));
		OutSubsurfaceLighting = L * SubsurfaceDirectionality * UVW;
	}
	#endif
#else
	half Directionality = 0.6;

	#if SHADINGMODEL_REQUIRES_BACKFACE_LIGHTING
	if (bEvaluateBackface)
	{
		OutSubsurfaceLighting = L * Directionality * UVW;
	}
	#endif
#endif

	half Luma = L * Directionality;
	half3 Color = Luma * UVW;

	OutDiffuseLighting = Color;
}

	VTPageTableResult LightmapVTPageTableResult = (VTPageTableResult)0.0f;
#if LIGHTMAP_VT_ENABLED
	{
		LightmapUVType LightmapUV0, LightmapUV1;
		uint LightmapDataIndex;
		GetLightMapCoordinates(Interpolants, LightmapUV0, LightmapUV1, LightmapDataIndex);
		LightmapVTPageTableResult = LightmapGetVTSampleInfo(LightmapUV0, LightmapDataIndex, In.SvPosition.xy);
	}
#endif

#if NEEDS_LIGHTMAP_COORDINATE
void GetLightMapCoordinates(FVertexFactoryInterpolantsVSToPS Interpolants, out float2 LightmapUV0, out float2 LightmapUV1, out uint LightmapDataIndex)
{
	LightmapUV0 = Interpolants.LightMapCoordinate.xy * float2( 1, 0.5 );
	LightmapUV1 = LightmapUV0 + float2( 0, 0.5 );

#if VF_USE_PRIMITIVE_SCENE_DATA && NEEDS_LIGHTMAP_COORDINATE
	LightmapDataIndex = Interpolants.LightmapDataIndex;
#else
	LightmapDataIndex = 0;
#endif
}

VTPageTableResult LightmapGetVTSampleInfo(float2 UV, uint LightmapDataIndex, float2 SvPositionXY)
{
	UV = ScaleLightmapUV(UV, float2(1.0f, 2.0f)); // Undo transform used to pack 2 lightmap coeffs in 1 texture for the non-VT default case

	return TextureLoadVirtualPageTable(LightmapResourceCluster.LightmapVirtualTexturePageTable0, LightmapResourceCluster.LightmapVirtualTexturePageTable1,
		VTPageTableUniform_Unpack(GetLightmapData(LightmapDataIndex).LightmapVTPackedPageTableUniform[0], GetLightmapData(LightmapDataIndex).LightmapVTPackedPageTableUniform[1]),
		UV, LIGHTMAP_VTADDRESSMODE, LIGHTMAP_VTADDRESSMODE, 0, SvPositionXY);
}

VTPageTableResult TextureLoadVirtualPageTable(
	Texture2D<uint4> PageTable0, Texture2D<uint4> PageTable1,
	VTPageTableUniform PageTableUniform,
	float2 UV, uint AddressU, uint AddressV,
	MaterialFloat MipBias, float2 SvPositionXY)
{
	VTPageTableResult Result = (VTPageTableResult)0;
	UV = UV * PageTableUniform.UVScale;
	int vLevel = GetGlobalVirtualTextureMipBias();
#if PIXELSHADER
	vLevel = TextureComputeVirtualMipLevel(Result, ddx(UV), ddy(UV), MipBias, SvPositionXY, PageTableUniform);
#endif // PIXELSHADER
	UV = ApplyAddressMode(UV, AddressU, AddressV);
	TextureLoadVirtualPageTableInternal(Result, PageTable0, PageTable1, PageTableUniform, UV, vLevel);
	return Result;
}

void TextureLoadVirtualPageTableInternal(
	in out VTPageTableResult OutResult,
	Texture2D<uint4> PageTable0, Texture2D<uint4> PageTable1,
	VTPageTableUniform PageTableUniform,
	float2 UV, int vLevel)
{
	OutResult.UV = UV * PageTableUniform.SizeInPages;

	const uint vLevelClamped = clamp(vLevel, 0, int(PageTableUniform.MaxLevel));
	const uint vPageX = (uint(OutResult.UV.x) + PageTableUniform.XOffsetInPages) >> vLevelClamped;
	const uint vPageY = (uint(OutResult.UV.y) + PageTableUniform.YOffsetInPages) >> vLevelClamped;

	OutResult.PageTableValue[0] = PageTable0.Load(int3(vPageX, vPageY, vLevelClamped));
	OutResult.PageTableValue[1] = PageTable1.Load(int3(vPageX, vPageY, vLevelClamped));

	// PageTableID packed in upper 4 bits of 'PackedPageTableUniform', which is the bit position we want it in for PackedRequest as well, just need to mask off extra bits
	OutResult.PackedRequest = PageTableUniform.ShiftedPageTableID;
	OutResult.PackedRequest |= vPageX;
	OutResult.PackedRequest |= vPageY << 12;

	// Feedback always encodes vLevel+1, and subtracts 1 on the CPU side.
	// This allows the CPU code to know when we requested a negative vLevel which indicates that we don't have sufficient virtual texture resolution.
	const uint vLevelPlusOneClamped = clamp(vLevel + 1, 0, int(PageTableUniform.MaxLevel + 1));
	OutResult.PackedRequest |= vLevelPlusOneClamped << 24;
}

FLightmapSceneData GetLightmapData(uint LightmapDataIndex) 
{
	// Note: layout must match FLightmapSceneShaderData in C++
	// Relying on optimizer to remove unused loads

	FLightmapSceneData LightmapData;
	uint LightmapDataBaseOffset = LightmapDataIndex * LIGHTMAP_SCENE_DATA_STRIDE;
	LightmapData.StaticShadowMapMasks = LoadLightmapDataElement(LightmapDataBaseOffset + 0);
	LightmapData.InvUniformPenumbraSizes = LoadLightmapDataElement(LightmapDataBaseOffset + 1);
	LightmapData.LightMapCoordinateScaleBias = LoadLightmapDataElement(LightmapDataBaseOffset + 2);
	LightmapData.ShadowMapCoordinateScaleBias = LoadLightmapDataElement(LightmapDataBaseOffset + 3);
	LightmapData.LightMapScale[0] = LoadLightmapDataElement(LightmapDataBaseOffset + 4);
	LightmapData.LightMapScale[1] = LoadLightmapDataElement(LightmapDataBaseOffset + 5);
	LightmapData.LightMapAdd[0] = LoadLightmapDataElement(LightmapDataBaseOffset + 6);
	LightmapData.LightMapAdd[1] = LoadLightmapDataElement(LightmapDataBaseOffset + 7);
	LightmapData.LightmapVTPackedPageTableUniform[0] = asuint(LoadLightmapDataElement(LightmapDataBaseOffset + 8));
	LightmapData.LightmapVTPackedPageTableUniform[1] = asuint(LoadLightmapDataElement(LightmapDataBaseOffset + 9));

	UNROLL
	for (uint i = 0u; i < 5u; ++i)
	{
		LightmapData.LightmapVTPackedUniform[i] = asuint(LoadLightmapDataElement(LightmapDataBaseOffset + 10 + i));
	}

	return LightmapData;
}

#define LIGHTMAP_SCENE_DATA_STRIDE 15

#if USE_GLOBAL_GPU_LIGHTMAP_DATA
StructuredBuffer<float4> GPUSceneLightmapData;
#endif

float4 LoadLightmapDataElement(uint Index)
{
#if USE_GLOBAL_GPU_LIGHTMAP_DATA
	checkStructuredBufferAccessSlow(GPUSceneLightmapData, Index);
	return GPUSceneLightmapData[Index];
#else
	checkStructuredBufferAccessSlow(View.LightmapSceneData, Index);
	return View.LightmapSceneData[Index];
#endif
}

C++测具体过程:

GPUScene.cpp

template<typename FUploadDataSourceAdapter>
void FGPUScene::UpdateBufferState(FRDGBuilder& GraphBuilder, FScene& Scene, const FUploadDataSourceAdapter& UploadDataSourceAdapter)
{
	LLM_SCOPE_BYTAG(GPUScene);

	ensure(bInBeginEndBlock);
	ensure(bIsEnabled == UseGPUScene(GMaxRHIShaderPlatform, Scene.GetFeatureLevel()));
	ensure(NumScenePrimitives == Scene.Primitives.Num());

	// Multi-GPU support : Updating on all GPUs is inefficient for AFR. Work is wasted
	// for any primitives that update on consecutive frames.
	RDG_GPU_MASK_SCOPE(GraphBuilder, FRHIGPUMask::All());

	constexpr int32 InitialBufferSize = 256;


	const uint32 LightMapDataBufferSize = FMath::RoundUpToPowerOfTwo(FMath::Max(LightmapDataAllocator.GetMaxSize(), InitialBufferSize));
	BufferState.LightmapDataBuffer = ResizeStructuredBufferIfNeeded(GraphBuilder, LightmapDataBuffer, LightMapDataBufferSize * sizeof(FLightmapSceneShaderData::Data), TEXT("GPUScene.LightmapData"));
	BufferState.LightMapDataBufferSize = LightMapDataBufferSize;

	ShaderParameters.GPUSceneInstanceSceneData = GraphBuilder.CreateSRV(BufferState.InstanceSceneDataBuffer);
	ShaderParameters.GPUSceneInstancePayloadData = GraphBuilder.CreateSRV(BufferState.InstancePayloadDataBuffer);
	ShaderParameters.GPUScenePrimitiveSceneData = GraphBuilder.CreateSRV(BufferState.PrimitiveBuffer);
	ShaderParameters.GPUSceneLightmapData = GraphBuilder.CreateSRV(BufferState.LightmapDataBuffer);
	ShaderParameters.InstanceDataSOAStride = InstanceSceneDataSOAStride;
	ShaderParameters.NumScenePrimitives = NumScenePrimitives;
	ShaderParameters.NumInstances = InstanceSceneDataAllocator.GetMaxSize();
	ShaderParameters.GPUSceneFrameNumber = GetSceneFrameNumber();
}

GPUScene.h

template<typename FUploadDataSourceAdapter>
void FGPUScene::UploadGeneral(FRDGBuilder& GraphBuilder, FScene& Scene, FRDGExternalAccessQueue& ExternalAccessQueue, const FUploadDataSourceAdapter& UploadDataSourceAdapter)
{
	LLM_SCOPE_BYTAG(GPUScene);

	ensure(bIsEnabled == UseGPUScene(GMaxRHIShaderPlatform, Scene.GetFeatureLevel()));
	ensure(NumScenePrimitives == Scene.Primitives.Num());

	const int32 NumPrimitiveDataUploads = UploadDataSourceAdapter.NumPrimitivesToUpload();

	if (!NumPrimitiveDataUploads)
	{
		return;
	}

	const bool bExecuteInParallel = GGPUSceneParallelUpdate != 0 && FApp::ShouldUseThreadingForPerformance();
	const bool bNaniteEnabled = DoesPlatformSupportNanite(GMaxRHIShaderPlatform);

	SCOPED_NAMED_EVENT(UpdateGPUScene, FColor::Green);

	// Multi-GPU support : Updating on all GPUs is inefficient for AFR. Work is wasted
	// for any primitives that update on consecutive frames.
	RDG_GPU_MASK_SCOPE(GraphBuilder, FRHIGPUMask::All());
	RDG_EVENT_SCOPE(GraphBuilder, "UpdateGPUScene NumPrimitiveDataUploads %u", NumPrimitiveDataUploads);

	struct FTaskContext
	{
		TArray<FPrimitiveUploadInfoHeader, FSceneRenderingArrayAllocator> PrimitiveUploadInfos;

		FRDGScatterUploader* PrimitiveUploader = nullptr;
		FRDGScatterUploader* InstancePayloadUploader = nullptr;
		FRDGScatterUploader* InstanceSceneUploader = nullptr;
		FRDGScatterUploader* InstanceBVHUploader = nullptr;
		FRDGScatterUploader* LightmapUploader = nullptr;

		TStaticArray<FNaniteMaterialCommands::FUploader*, ENaniteMeshPass::Num> NaniteMaterialUploaders{ InPlace, nullptr };

		int32 NumPrimitiveDataUploads = 0;
		int32 NumLightmapDataUploads = 0;
		int32 NumInstanceSceneDataUploads = 0;
		int32 NumInstancePayloadDataUploads = 0; // Count of float4s

		uint32 InstanceSceneDataSOAStride = 1;

		bool bUseNaniteMaterialUploaders = false;
	};

	FTaskContext& TaskContext = *GraphBuilder.AllocObject<FTaskContext>();

	TaskContext.NumPrimitiveDataUploads = NumPrimitiveDataUploads;
	TaskContext.InstanceSceneDataSOAStride = BufferState.InstanceSceneDataSOAStride;
	TaskContext.PrimitiveUploadInfos.SetNumUninitialized(NumPrimitiveDataUploads);

	for (int32 ItemIndex = 0; ItemIndex < NumPrimitiveDataUploads; ++ItemIndex)
	{
		FPrimitiveUploadInfoHeader& UploadInfo = TaskContext.PrimitiveUploadInfos[ItemIndex];
		UploadDataSourceAdapter.GetPrimitiveInfoHeader(ItemIndex, UploadInfo);

		TaskContext.NumLightmapDataUploads += UploadInfo.LightmapUploadCount; // Not thread safe
		TaskContext.NumInstanceSceneDataUploads += UploadInfo.NumInstanceUploads; // Not thread safe
		TaskContext.NumInstancePayloadDataUploads += UploadInfo.NumInstancePayloadDataUploads; // Not thread safe
	}

	TaskContext.PrimitiveUploader = PrimitiveUploadBuffer.Begin(GraphBuilder, BufferState.PrimitiveBuffer, UploadDataSourceAdapter.GetItemPrimitiveIds().Num(), sizeof(FPrimitiveSceneShaderData::Data), TEXT("PrimitiveUploadBuffer"));

	if (TaskContext.NumLightmapDataUploads > 0)
	{
		TaskContext.LightmapUploader = LightmapUploadBuffer.Begin(GraphBuilder, BufferState.LightmapDataBuffer, TaskContext.NumLightmapDataUploads, sizeof(FLightmapSceneShaderData::Data), TEXT("LightmapUploadBuffer"));
	}

	if (UploadDataSourceAdapter.bUpdateNaniteMaterialTables && bNaniteEnabled)
	{
		for (int32 NaniteMeshPassIndex = 0; NaniteMeshPassIndex < ENaniteMeshPass::Num; ++NaniteMeshPassIndex)
		{
			TaskContext.NaniteMaterialUploaders[NaniteMeshPassIndex] = Scene.NaniteMaterials[NaniteMeshPassIndex].Begin(GraphBuilder, Scene.Primitives.Num(), NumPrimitiveDataUploads);
		}

		TaskContext.bUseNaniteMaterialUploaders = true;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值