代码改变世界

processTexturemapping之setuptextureMapping

2021-03-04 13:09  kk20161206  阅读(133)  评论(0编辑  收藏  举报

1. setuptextureMapping函数里会calculateTexelCorners,这个函数会光栅化每个三角形里的每个corner,

// Rasterize each triangle offset by the corner offsets
		for (int32 CornerIndex = 0; CornerIndex < NumTexelCorners; CornerIndex++)
		{
			FTriangleRasterizer<FTexelCornerRasterPolicy> TexelCornerRasterizer(FTexelCornerRasterPolicy(
				Scene,
				TexelToCornersMap,
				CornerIndex,
				bDebugThisMapping
				));

			TexelCornerRasterizer.DrawTriangle(
				V0,
				V1,
				V2,
				V0.TextureCoordinates[UVIndex] * FVector2D(TexelToCornersMap.GetSizeX(), TexelToCornersMap.GetSizeY()) + CornerOffsets[CornerIndex],
				V1.TextureCoordinates[UVIndex] * FVector2D(TexelToCornersMap.GetSizeX(), TexelToCornersMap.GetSizeY()) + CornerOffsets[CornerIndex],
				V2.TextureCoordinates[UVIndex] * FVector2D(TexelToCornersMap.GetSizeX(), TexelToCornersMap.GetSizeY()) + CornerOffsets[CornerIndex],
				false
				);
		}

  

注意这里光栅化的时候会设置texeltocorner为valid,而且得到位置、切线等信息:

void FTexelCornerRasterPolicy::ProcessPixel(int32 X, int32 Y, const InterpolantType& Vertex, bool BackFacing)
{
FTexelToCorners& TexelToCorners = TexelToCornersMap(X, Y);

#if ALLOW_LIGHTMAP_SAMPLE_DEBUGGING
if (bDebugThisMapping
&& X == Scene.DebugInput.LocalX
&& Y == Scene.DebugInput.LocalY)
{
int32 TempBreak = 0;
}
#endif

TexelToCorners.Corners[CornerIndex].WorldPosition = Vertex.WorldPosition;
TexelToCorners.WorldTangentX = Vertex.WorldTangentX;
TexelToCorners.WorldTangentY = Vertex.WorldTangentY;
TexelToCorners.WorldTangentZ = Vertex.WorldTangentZ;
TexelToCorners.bValid[CornerIndex] = true;
}

  2. 设置是否用保守的纹素光栅化,同时贴图映射为双线性滤波,

为true,则 会遍历每个三角形,x,y双重循环1到7,计算sampleOffset及sample权重然后会通过staticLightingRasterpolicy计算图素对应的顶点sample,

FTriangleRasterizer<FStaticLightingRasterPolicy> TexelMappingRasterizer(FStaticLightingRasterPolicy(
							Scene,
							TexelToVertexMap,
							SampleWeight,
							TriangleNormal,
							bDebugThisMapping,
							GeneralSettings.bUseMaxWeight
							));

						TexelMappingRasterizer.DrawTriangle(
							V0,
							V1,
							V2,
							UV0 + FVector2D(SampleXOffset, SampleYOffset),
							UV1 + FVector2D(SampleXOffset, SampleYOffset),
							UV2 + FVector2D(SampleXOffset, SampleYOffset),
							false
							);
  

光栅化得到texelTOVertex数据

void FStaticLightingRasterPolicy::ProcessPixel(int32 X,int32 Y,const InterpolantType& Interpolant,bool BackFacing)
{
	FTexelToVertex& TexelToVertex = TexelToVertexMap(X,Y);
	bool bDebugThisTexel = false;
#if ALLOW_LIGHTMAP_SAMPLE_DEBUGGING
	if (bDebugThisMapping
		&& X == Scene.DebugInput.LocalX
		&& Y == Scene.DebugInput.LocalY)
	{
		bDebugThisTexel = true;
	}
#endif

	if (bUseMaxWeight)
	{
		if (SampleWeight > TexelToVertex.MaxSampleWeight)
		{
			// Use the sample with the largest weight.  
			// This has the disadvantage compared averaging based on weight that it won't be well centered for texels on a UV seam,
			// But it has the advantage that the final position is guaranteed to be valid (ie actually on a triangle),
			// Even for split texels which are mapped to triangles in different parts of the mesh.
			TexelToVertex.MaxSampleWeight = SampleWeight;
			TexelToVertex.WorldPosition = Interpolant.Vertex.WorldPosition;
			TexelToVertex.ElementIndex = Interpolant.ElementIndex;

			for( int32 CurCoordIndex = 0; CurCoordIndex < MAX_TEXCOORDS; ++CurCoordIndex )
			{
				TexelToVertex.TextureCoordinates[ CurCoordIndex ] = Interpolant.Vertex.TextureCoordinates[ CurCoordIndex ];
			}
		}
		
		// Weighted average of normal, improves the case where the position chosen by the max weight has a different normal than the rest of the texel
		// Eg, small extrusions from an otherwise flat surface, and the texel center lies on the perpendicular extrusion
		//@todo - only average normals within the texel radius to improve the split texel case?
		TexelToVertex.WorldTangentX += Interpolant.Vertex.WorldTangentX * SampleWeight;
		TexelToVertex.WorldTangentY += Interpolant.Vertex.WorldTangentY * SampleWeight;
		TexelToVertex.WorldTangentZ += Interpolant.Vertex.WorldTangentZ * SampleWeight;
		checkSlow(!TriangleNormal.ContainsNaN());
		TexelToVertex.TriangleNormal += TriangleNormal * SampleWeight;
		TexelToVertex.TotalSampleWeight += SampleWeight;
	}
	else if (!bUseMaxWeight)
	{
		// Update the sample weight, and compute the scales used to update the sample's averages.
		const float NewTotalSampleWeight = TexelToVertex.TotalSampleWeight + SampleWeight;		
		const float OldSampleWeight = TexelToVertex.TotalSampleWeight / NewTotalSampleWeight;	
		const float NewSampleWeight = SampleWeight / NewTotalSampleWeight;						
		TexelToVertex.TotalSampleWeight = NewTotalSampleWeight;	

		// Add this sample to the mapping.
		TexelToVertex.WorldPosition = TexelToVertex.WorldPosition * OldSampleWeight + Interpolant.Vertex.WorldPosition * NewSampleWeight;
		TexelToVertex.WorldTangentX = FVector4(TexelToVertex.WorldTangentX) * OldSampleWeight + Interpolant.Vertex.WorldTangentX * NewSampleWeight;
		TexelToVertex.WorldTangentY = FVector4(TexelToVertex.WorldTangentY) * OldSampleWeight + Interpolant.Vertex.WorldTangentY * NewSampleWeight;
		TexelToVertex.WorldTangentZ = FVector4(TexelToVertex.WorldTangentZ) * OldSampleWeight + Interpolant.Vertex.WorldTangentZ * NewSampleWeight;
		TexelToVertex.TriangleNormal = TriangleNormal;
		TexelToVertex.ElementIndex = Interpolant.ElementIndex;
		
		for( int32 CurCoordIndex = 0; CurCoordIndex < MAX_TEXCOORDS; ++CurCoordIndex )
		{
			TexelToVertex.TextureCoordinates[ CurCoordIndex ] = TexelToVertex.TextureCoordinates[ CurCoordIndex ] * OldSampleWeight + Interpolant.Vertex.TextureCoordinates[ CurCoordIndex ] * NewSampleWeight;
		}
	}
}

  如果为false,则只是在纹素中心光栅化,不用考虑权重混合。如果中心不在三角形内则纹素不会被映射。

3. 最后这个函数AdjustRepresentativeSurfelForTexelsTextureMapping会设置lightmapData为是否映射,

if (LightMapData != nullptr)
				{
					// Mark the texel as mapped to some geometry in the scene
					FGatheredLightMapSample& CurrentLightSample = (*LightMapData)(X, Y);
					CurrentLightSample.bIsMapped = true;
				}

  会重新计算调整texelToVertex的坐标、tangent等信息并且检测会不会重叠,重叠的话,会进行偏移。