ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

字体渲染过程及合批研究

2022-06-11 20:36:09  阅读:167  来源: 互联网

标签:GlyphAtlasData const 渲染 ++ float 字体 DrawElement 及合批 FSlateDrawElement


---恢复内容开始---

ElementBatcher.cpp文件 AddTextElement函数里调用了 BuildFontGeometry函数,如下 · 345678 通过fontInfo得到CharacterList,

FSlateFontTextureRHI

FSlateFontTextureRHI

 

if (FontAtlasTexture == nullptr || GlyphAtlasData.TextureIndex != FontTextureIndex)
					{
						// Font has a new texture for this glyph. Refresh the batch we use and the index we are currently using
						FontTextureIndex = GlyphAtlasData.TextureIndex;

						FontAtlasTexture = FontCache.GetSlateTextureResource(FontTextureIndex);
						check(FontAtlasTexture);

						FontShaderResource = ResourceManager.GetFontShaderResource(FontTextureIndex, FontAtlasTexture, FontMaterial);
						check(FontShaderResource);

						ElementBatch = &FindBatchForElement(InLayer, FShaderParams(), FontShaderResource, ESlateDrawPrimitive::TriangleList, ESlateShader::Font, InDrawEffects, ESlateBatchDrawFlag::None, DrawElement.GetClippingIndex(), DrawElement.GetSceneIndex());

  FSlateDataPayload

FSlateFontTextureRHIResource

 

FontCache.cpp

bool FSlateFontCache::AddNewEntry( const FCharacterRenderData InRenderData, uint8& OutTextureIndex, uint16& OutGlyphX, uint16& OutGlyphY, uint16& OutGlyphWidth, uint16& OutGlyphHeight )
{
	const uint64 LastFlushRequestFrameDelta = GFrameCounter - FrameCounterLastFlushRequest;
……
}

  将renderData拷贝到Slot

void FSlateTextureAtlas::CopyDataIntoSlot( const FAtlasedTextureSlot* SlotToCopyTo, const TArray<uint8>& Data )
{
	// Copy pixel data to the texture
	uint8* Start = &AtlasData[SlotToCopyTo->Y*AtlasWidth*BytesPerPixel + SlotToCopyTo->X*BytesPerPixel];
	
	// Account for same padding on each sides
	const uint32 Padding = GetPaddingAmount();
	const uint32 AllPadding = Padding*2;

	// Make sure the actual slot is not zero-area (otherwise padding could corrupt other images in the atlas)
	check(SlotToCopyTo->Width > AllPadding);
	check(SlotToCopyTo->Height > AllPadding);

	// The width of the source texture without padding (actual width)
	const uint32 SourceWidth = SlotToCopyTo->Width - AllPadding; 
	const uint32 SourceHeight = SlotToCopyTo->Height - AllPadding;
……
}

  

 

 

void FSlateElementBatcher::AddElementsInternal(const TArray<FSlateDrawElement>& DrawElements, const FVector2D& ViewportSize)
{
	checkSlow(DrawLayer);

	for ( int32 DrawElementIndex = 0; DrawElementIndex < DrawElements.Num(); ++DrawElementIndex )
	{
		const FSlateDrawElement& DrawElement = DrawElements[DrawElementIndex];

		// Determine what type of element to add
		switch ( DrawElement.GetElementType() )
		{
		case FSlateDrawElement::ET_Box:
			ElmementStat_Boxes++;
			DrawElement.IsPixelSnapped() ? AddBoxElement<ESlateVertexRounding::Enabled>(DrawElement) : AddBoxElement<ESlateVertexRounding::Disabled>(DrawElement);
			break;
		case FSlateDrawElement::ET_Border:
			ElmementStat_Borders++;
			DrawElement.IsPixelSnapped() ? AddBorderElement<ESlateVertexRounding::Enabled>(DrawElement) : AddBorderElement<ESlateVertexRounding::Disabled>(DrawElement);
			break;
		case FSlateDrawElement::ET_Text:
			ElmementStat_Text++;
			DrawElement.IsPixelSnapped() ? AddTextElement<ESlateVertexRounding::Enabled>(DrawElement) : AddTextElement<ESlateVertexRounding::Disabled>(DrawElement);
			break;
		case FSlateDrawElement::ET_ShapedText:
			ElmementStat_ShapedText++;
			DrawElement.IsPixelSnapped() ? AddShapedTextElement<ESlateVertexRounding::Enabled>(DrawElement) : AddShapedTextElement<ESlateVertexRounding::Disabled>(DrawElement);
			break;
		case FSlateDrawElement::ET_Line:
			ElmementStat_Line++;
			DrawElement.IsPixelSnapped() ? AddLineElement<ESlateVertexRounding::Enabled>(DrawElement) : AddLineElement<ESlateVertexRounding::Disabled>(DrawElement);
			break;
		case FSlateDrawElement::ET_DebugQuad:
			ElmementStat_Other++;
			DrawElement.IsPixelSnapped() ? AddQuadElement<ESlateVertexRounding::Enabled>(DrawElement) : AddQuadElement<ESlateVertexRounding::Disabled>(DrawElement);
			break;
		case FSlateDrawElement::ET_Spline:
			// Note that we ignore pixel snapping here; see implementation for more info.
			ElmementStat_Other++;
			AddSplineElement(DrawElement);
			break;
		case FSlateDrawElement::ET_Gradient:
			ElmementStat_Other++;
			DrawElement.IsPixelSnapped() ? AddGradientElement<ESlateVertexRounding::Enabled>(DrawElement) : AddGradientElement<ESlateVertexRounding::Disabled>(DrawElement);
			break;
		case FSlateDrawElement::ET_Viewport:
			ElmementStat_Other++;
			DrawElement.IsPixelSnapped() ? AddViewportElement<ESlateVertexRounding::Enabled>(DrawElement) : AddViewportElement<ESlateVertexRounding::Disabled>(DrawElement);
			break;
		case FSlateDrawElement::ET_Custom:
			ElmementStat_Other++;
			AddCustomElement(DrawElement);
			break;
		case FSlateDrawElement::ET_CustomVerts:
			ElmementStat_Other++;
			AddCustomVerts(DrawElement);
			break;
		case FSlateDrawElement::ET_Layer:
			ElmementStat_Other++;
			AddLayer(DrawElement);
			break;
		case FSlateDrawElement::ET_CachedBuffer:
			ElmementStat_CachedBuffer++;
			AddCachedBuffer(DrawElement);
			break;
		case FSlateDrawElement::ET_PostProcessPass:
			ElmementStat_Other++;
			AddPostProcessPass(DrawElement, ViewportSize);
			break;
		default:
			checkf(0, TEXT("Invalid element type"));
			break;
		}
	}
}

  这个函数根据类型DrawElement类型调用不同的函数,当类型为text时,调用AddTextElement函数;

当类型为ShapedTextElement时,调用AddShapedTextElement,(void FSlateElementBatcher::AddShapedTextElement( const FSlateDrawElement& DrawElement ))它里面的

auto BuildFontGeometry = [&](const FFontOutlineSettings& InOutlineSettings, const FColor& InTint, const UObject* FontMaterial, int32 InLayer, int32 InHorizontalOffset)
	{
		FVector2D TopLeft(0, 0);

		const float PosX = TopLeft.X+InHorizontalOffset;
		float PosY = TopLeft.Y;

		float LineX = PosX;
		float LineY = PosY;

		int32 FontTextureIndex = -1;
		FSlateShaderResource* FontAtlasTexture = nullptr;
		FSlateShaderResource* FontShaderResource = nullptr;

		FSlateElementBatch* ElementBatch = nullptr;
		FSlateVertexArray* BatchVertices = nullptr;
		FSlateIndexArray* BatchIndices = nullptr;

		uint32 VertexOffset = 0;
		uint32 IndexOffset = 0;

		float InvTextureSizeX = 0;
		float InvTextureSizeY = 0;

		const bool bIsFontMaterial = FontMaterial != nullptr;

		// Optimize by culling
		bool bEnableCulling = false;
		float LocalClipBoundingBoxLeft = 0;
		float LocalClipBoundingBoxRight = 0;
		if (GlyphsToRender.Num() > 200)
		{
			int16 ClippingIndex = DrawElement.GetClippingIndex();
			if (ClippingStates && ClippingStates->IsValidIndex(ClippingIndex))
			{
				const FSlateClippingState& ClippingState = (*ClippingStates)[ClippingIndex];
				if (ClippingState.ScissorRect.IsSet() && ClippingState.ScissorRect->IsAxisAligned() && RenderTransform.GetMatrix().IsIdentity())
				{
					bEnableCulling = true;
					const FSlateRect LocalClipBoundingBox = TransformRect(RenderTransform.Inverse(), ClippingState.ScissorRect->GetBoundingBox());
					LocalClipBoundingBoxLeft = LocalClipBoundingBox.Left;
					LocalClipBoundingBoxRight = LocalClipBoundingBox.Right;
				}
			}
		}

		const int32 NumGlyphs = GlyphsToRender.Num();
		for (int32 GlyphIndex = 0; GlyphIndex < NumGlyphs; ++GlyphIndex)
		{
			const FShapedGlyphEntry& GlyphToRender = GlyphsToRender[GlyphIndex];

			if (GlyphToRender.bIsVisible)
			{
				const FShapedGlyphFontAtlasData GlyphAtlasData = FontCache.GetShapedGlyphFontAtlasData(GlyphToRender, InOutlineSettings);
    				 ……
			    //


}

  

里面调用了FontCache.GetShapedGlyphFontAtlasData(GlyphToRender, InOutlineSettings)

 许多地方都可能调到这个地方,比如:

 

 

bool FSlateFontCache::AddNewEntry(const FShapedGlyphEntry& InShapedGlyph, const FFontOutlineSettings& InOutlineSettings, FShapedGlyphFontAtlasData& OutAtlasData)
{
	// Render the glyph
	FCharacterRenderData RenderData;
	const bool bDidRender = FontRenderer->GetRenderData(InShapedGlyph, InOutlineSettings, RenderData);

	OutAtlasData.Valid = bDidRender && AddNewEntry(RenderData, OutAtlasData.TextureIndex, OutAtlasData.StartU, OutAtlasData.StartV, OutAtlasData.USize, OutAtlasData.VSize);
	if (OutAtlasData.Valid)
	{
		OutAtlasData.VerticalOffset = RenderData.MeasureInfo.VerticalOffset;
		OutAtlasData.HorizontalOffset = RenderData.MeasureInfo.HorizontalOffset;
	}

	return OutAtlasData.Valid;
}

  里面的GetRenderData函数

bool FSlateFontRenderer::GetRenderData(const FShapedGlyphEntry& InShapedGlyph, const FFontOutlineSettings& InOutlineSettings, FCharacterRenderData& OutRenderData) const
{
#if WITH_FREETYPE
	SCOPE_CYCLE_COUNTER(STAT_FreetypeRenderGlyph);

	FFreeTypeFaceGlyphData FaceGlyphData;
	FaceGlyphData.FaceAndMemory = InShapedGlyph.FontFaceData->FontFace.Pin();
	FaceGlyphData.GlyphIndex = InShapedGlyph.GlyphIndex;
	FaceGlyphData.GlyphFlags = InShapedGlyph.FontFaceData->GlyphFlags;

	if (FaceGlyphData.FaceAndMemory.IsValid())
	{
		check(FaceGlyphData.FaceAndMemory->IsValid());

		FT_Error Error = FreeTypeUtils::LoadGlyph(FaceGlyphData.FaceAndMemory->GetFace(), FaceGlyphData.GlyphIndex, FaceGlyphData.GlyphFlags, InShapedGlyph.FontFaceData->FontSize, InShapedGlyph.FontFaceData->FontScale);
		check(Error == 0);

		OutRenderData.Char = 0;
		return GetRenderDataInternal(FaceGlyphData, InShapedGlyph.FontFaceData->FontScale, InOutlineSettings, OutRenderData);
	}
#endif // WITH_FREETYPE
	return false;
}

  LoadGlyph获得字体的大小,scale矩阵。GetRenderDataInternal获得要渲染的像素长宽,填充像素。

然后AddNewEntry函数又调用了另一个重载的AddNewEntry函数,这个函数主要作用是:根据上面求出的RenderData的数据,将Character加到AtlasedTextureSlot里。然后将这个图集贴图Slot加到图集里。得到这个字母的x, y, 宽,高值。

 

bool FSlateFontCache::AddNewEntry( const FCharacterRenderData InRenderData, uint8& OutTextureIndex, uint16& OutGlyphX, uint16& OutGlyphY, uint16& OutGlyphWidth, uint16& OutGlyphHeight )
{
	const uint64 LastFlushRequestFrameDelta = GFrameCounter - FrameCounterLastFlushRequest;

	// Will this entry fit within any atlas texture?
	if (InRenderData.MeasureInfo.SizeX > FontAtlasFactory->GetAtlasSize().X || InRenderData.MeasureInfo.SizeY > FontAtlasFactory->GetAtlasSize().Y)
	{
		TSharedPtr<ISlateFontTexture> NonAtlasedTexture = FontAtlasFactory->CreateNonAtlasedTexture(InRenderData.MeasureInfo.SizeX, InRenderData.MeasureInfo.SizeY, InRenderData.RawPixels);
		if (NonAtlasedTexture.IsValid())
		{
			INC_DWORD_STAT_BY(STAT_SlateNumFontNonAtlasedTextures, 1);

			UE_LOG(LogSlate, Warning, TEXT("SlateFontCache - Glyph texture is too large to store in the font atlas, so we're falling back to a non-atlased texture for this glyph. This may have SERIOUS performance implications. Atlas page size: { %d, %d }. Glyph render size: { %d, %d }"),
				FontAtlasFactory->GetAtlasSize().X, FontAtlasFactory->GetAtlasSize().Y,
				InRenderData.MeasureInfo.SizeX, InRenderData.MeasureInfo.SizeY
				);

			NonAtlasedTextures.Add(NonAtlasedTexture.ToSharedRef());
			OutTextureIndex = AllFontTextures.Add(NonAtlasedTexture.ToSharedRef());
			OutGlyphX = 0;
			OutGlyphY = 0;
			OutGlyphWidth = InRenderData.MeasureInfo.SizeX;
			OutGlyphHeight = InRenderData.MeasureInfo.SizeY;

			if (NonAtlasedTextures.Num() > CurrentMaxNonAtlasedTexturesBeforeFlushRequest && !bFlushRequested)
			{
				// The InitialMaxNonAtlasedTexturesBeforeFlushRequest may have changed since last flush,
				// so double check that we're below the current max or initial, if we're under it,
				// update the current to the initial.
				if (NonAtlasedTextures.Num() <= InitialMaxNonAtlasedTexturesBeforeFlushRequest)
				{
					CurrentMaxNonAtlasedTexturesBeforeFlushRequest = InitialMaxNonAtlasedTexturesBeforeFlushRequest;
				}
				// If we grew back up to this number of non-atlased textures within the same or next frame of the previous flush request, then we likely legitimately have 
				// a lot of font data cached. We should update CurrentMaxNonAtlasedTexturesBeforeFlushRequest to give us a bit more flexibility before the next flush request
				else if (LastFlushRequestFrameDelta <= GrowFontNonAtlasFrameWindow)
				{
					CurrentMaxNonAtlasedTexturesBeforeFlushRequest = NonAtlasedTextures.Num();
					UE_LOG(LogSlate, Warning, TEXT("SlateFontCache - Setting the threshold to trigger a flush to %d non-atlased textures as there is a lot of font data being cached."), CurrentMaxNonAtlasedTexturesBeforeFlushRequest);
				}
				else
				{
					// We've grown beyond our current stable limit - try and request a flush
					RequestFlushCache(FString::Printf(TEXT("Large glyph font atlases out of space; %d/%d Textures; frames since last flush: %llu"), NonAtlasedTextures.Num(), CurrentMaxNonAtlasedTexturesBeforeFlushRequest, LastFlushRequestFrameDelta));
				}
			}

			return true;
		}

		UE_LOG(LogSlate, Warning, TEXT("SlateFontCache - Glyph texture is too large to store in the font atlas, but we cannot support rendering such a large texture. Atlas page size: { %d, %d }. Glyph render size: { %d, %d }"),
			FontAtlasFactory->GetAtlasSize().X, FontAtlasFactory->GetAtlasSize().Y,
			InRenderData.MeasureInfo.SizeX, InRenderData.MeasureInfo.SizeY
			);
		return false;
	}

	auto FillOutputParamsFromAtlasedTextureSlot = [&](const FAtlasedTextureSlot& AtlasedTextureSlot)
	{
		OutGlyphX = AtlasedTextureSlot.X + AtlasedTextureSlot.Padding;
		OutGlyphY = AtlasedTextureSlot.Y + AtlasedTextureSlot.Padding;
		OutGlyphWidth = AtlasedTextureSlot.Width - (2 * AtlasedTextureSlot.Padding);
		OutGlyphHeight = AtlasedTextureSlot.Height - (2 * AtlasedTextureSlot.Padding);
	};

	for( OutTextureIndex = 0; OutTextureIndex < FontAtlases.Num(); ++OutTextureIndex ) 
	{
		// Add the character to the texture
		const FAtlasedTextureSlot* NewSlot = FontAtlases[OutTextureIndex]->AddCharacter(InRenderData);
		if( NewSlot )
		{
			FillOutputParamsFromAtlasedTextureSlot(*NewSlot);
			return true;
		}
	}

	TSharedRef<FSlateFontAtlas> FontAtlas = FontAtlasFactory->CreateFontAtlas();

	// Add the character to the texture
	const FAtlasedTextureSlot* NewSlot = FontAtlas->AddCharacter(InRenderData);
	if( NewSlot )
	{
		FillOutputParamsFromAtlasedTextureSlot(*NewSlot);
	}

	FontAtlases.Add( FontAtlas );
	OutTextureIndex = AllFontTextures.Add(FontAtlas);

	INC_DWORD_STAT_BY( STAT_SlateNumFontAtlases, 1 );

	if( FontAtlases.Num() > CurrentMaxAtlasPagesBeforeFlushRequest && !bFlushRequested )
	{
		// The InitialMaxNonAtlasedTexturesBeforeFlushRequest may have changed since last flush,
		// so double check that we're below the current max or initial, if we're under it,
		// update the current to the initial.
		if (FontAtlases.Num() <= InitialMaxAtlasPagesBeforeFlushRequest)
		{
			CurrentMaxAtlasPagesBeforeFlushRequest = InitialMaxAtlasPagesBeforeFlushRequest;
		}
		// If we grew back up to this number of atlas pages within the same or next frame of the previous flush request, then we likely legitimately have 
		// a lot of font data cached. We should update MaxAtlasPagesBeforeFlushRequest to give us a bit more flexibility before the next flush request
		else if (LastFlushRequestFrameDelta <= GrowFontAtlasFrameWindow)
		{
			CurrentMaxAtlasPagesBeforeFlushRequest = FontAtlases.Num();
			UE_LOG(LogSlate, Warning, TEXT("SlateFontCache - Setting the threshold to trigger a flush to %d atlas pages as there is a lot of font data being cached."), CurrentMaxAtlasPagesBeforeFlushRequest);
		}
		else
		{
			// We've grown beyond our current stable limit - try and request a flush
			RequestFlushCache(FString::Printf(TEXT("Font Atlases Full; %d/%d Pages; frames since last flush: %llu"), FontAtlases.Num(), CurrentMaxAtlasPagesBeforeFlushRequest, LastFlushRequestFrameDelta));
		}
	}

	return NewSlot != nullptr;
}

  通过这个AddMewEntry,就把这个字母相关的渲染数据写入到图集贴图里了。

后面在ElementBatcher.cpp文件中,AddShapedTextElement函数中,BuildFontGeometry函数就会用到图集信息

if (bOutlineFont)
	{
		// Build geometry for the outline
		BuildFontGeometry(OutlineSettings, PackVertexColor(DrawElementPayload.GetOutlineTint()), OutlineFontMaterial, Layer, 0);
		
		//The fill area was measured without an outline so it must be shifted by the scaled outline size
		float HorizontalOffset = FMath::RoundToFloat(OutlineSize * FontScale);

		// Build geometry for the base font which is always rendered on top of the outline 
		BuildFontGeometry(FFontOutlineSettings::NoOutline, BaseTint, BaseFontMaterial, Layer+1, HorizontalOffset);
	}
	else
	{
		// No outline
		BuildFontGeometry(FFontOutlineSettings::NoOutline, BaseTint, BaseFontMaterial, Layer, 0);
	}

  shapedText的 AddShapedTextElement里的BuildFontGeometry函数:

auto BuildFontGeometry = [&](const FFontOutlineSettings& InOutlineSettings, const FColor& InTint, const UObject* FontMaterial, int32 InLayer, int32 InHorizontalOffset)
	{
		FVector2D TopLeft(0, 0);

		const float PosX = TopLeft.X+InHorizontalOffset;
		float PosY = TopLeft.Y;

		float LineX = PosX;
		float LineY = PosY;

		int32 FontTextureIndex = -1;
		FSlateShaderResource* FontAtlasTexture = nullptr;
		FSlateShaderResource* FontShaderResource = nullptr;

		FSlateElementBatch* ElementBatch = nullptr;
		FSlateVertexArray* BatchVertices = nullptr;
		FSlateIndexArray* BatchIndices = nullptr;

		uint32 VertexOffset = 0;
		uint32 IndexOffset = 0;

		float InvTextureSizeX = 0;
		float InvTextureSizeY = 0;

		const bool bIsFontMaterial = FontMaterial != nullptr;

		// Optimize by culling
		bool bEnableCulling = false;
		float LocalClipBoundingBoxLeft = 0;
		float LocalClipBoundingBoxRight = 0;
		if (GlyphsToRender.Num() > 200)
		{
			int16 ClippingIndex = DrawElement.GetClippingIndex();
			if (ClippingStates && ClippingStates->IsValidIndex(ClippingIndex))
			{
				const FSlateClippingState& ClippingState = (*ClippingStates)[ClippingIndex];
				if (ClippingState.ScissorRect.IsSet() && ClippingState.ScissorRect->IsAxisAligned() && RenderTransform.GetMatrix().IsIdentity())
				{
					bEnableCulling = true;
					const FSlateRect LocalClipBoundingBox = TransformRect(RenderTransform.Inverse(), ClippingState.ScissorRect->GetBoundingBox());
					LocalClipBoundingBoxLeft = LocalClipBoundingBox.Left;
					LocalClipBoundingBoxRight = LocalClipBoundingBox.Right;
				}
			}
		}

		const int32 NumGlyphs = GlyphsToRender.Num();
		for (int32 GlyphIndex = 0; GlyphIndex < NumGlyphs; ++GlyphIndex)
		{
			const FShapedGlyphEntry& GlyphToRender = GlyphsToRender[GlyphIndex];

			if (GlyphToRender.bIsVisible)
			{
				const FShapedGlyphFontAtlasData GlyphAtlasData = FontCache.GetShapedGlyphFontAtlasData(GlyphToRender, InOutlineSettings);
				 
				if (GlyphAtlasData.Valid)
				{
					const float X = LineX + GlyphAtlasData.HorizontalOffset + GlyphToRender.XOffset;
					// Note PosX,PosY is the upper left corner of the bounding box representing the string.  This computes the Y position of the baseline where text will sit

					if (bEnableCulling)
					{
						if (X + GlyphAtlasData.USize < LocalClipBoundingBoxLeft)
						{
							LineX += GlyphToRender.XAdvance;
							LineY += GlyphToRender.YAdvance;
							continue;
						}
						else if (X > LocalClipBoundingBoxRight)
						{
							break;
						}
					}

					if (FontAtlasTexture == nullptr || GlyphAtlasData.TextureIndex != FontTextureIndex)
					{
						// Font has a new texture for this glyph. Refresh the batch we use and the index we are currently using
						FontTextureIndex = GlyphAtlasData.TextureIndex;

						FontAtlasTexture = FontCache.GetSlateTextureResource(FontTextureIndex);
						check(FontAtlasTexture);

						FontShaderResource = ResourceManager.GetFontShaderResource(FontTextureIndex, FontAtlasTexture, FontMaterial);
						check(FontShaderResource);

						ElementBatch = &FindBatchForElement(InLayer, FShaderParams(), FontShaderResource, ESlateDrawPrimitive::TriangleList, ESlateShader::Font, InDrawEffects, ESlateBatchDrawFlag::None, DrawElement.GetClippingIndex(), DrawElement.GetSceneIndex());

						BatchVertices = &BatchData->GetBatchVertexList(*ElementBatch);
						BatchIndices = &BatchData->GetBatchIndexList(*ElementBatch);

						VertexOffset = BatchVertices->Num();
						IndexOffset = BatchIndices->Num();

						InvTextureSizeX = 1.0f / FontAtlasTexture->GetWidth();
						InvTextureSizeY = 1.0f / FontAtlasTexture->GetHeight();
					}


					const float Y = LineY - GlyphAtlasData.VerticalOffset + GlyphToRender.YOffset + MaxHeight + TextBaseline;
					const float U = GlyphAtlasData.StartU * InvTextureSizeX;
					const float V = GlyphAtlasData.StartV * InvTextureSizeY;
					const float SizeX = GlyphAtlasData.USize;
					const float SizeY = GlyphAtlasData.VSize;
					const float SizeU = GlyphAtlasData.USize * InvTextureSizeX;
					const float SizeV = GlyphAtlasData.VSize * InvTextureSizeY;

					{
						FSlateVertexArray& BatchVerticesRef = *BatchVertices;
						FSlateIndexArray& BatchIndicesRef = *BatchIndices;

						const FVector2D UpperLeft(X, Y);
						const FVector2D UpperRight(X + SizeX, Y);
						const FVector2D LowerLeft(X, Y + SizeY);
						const FVector2D LowerRight(X + SizeX, Y + SizeY);

						// Add four vertices for this quad
						BatchVerticesRef.AddUninitialized(4);
						// Add six indices for this quad
						BatchIndicesRef.AddUninitialized(6);

						// The start index of these vertices in the index buffer
						uint32 IndexStart = VertexOffset;

						float Ut = 0.0f, Vt = 0.0f, UtMax = 0.0f, VtMax = 0.0f;
						if (bIsFontMaterial)
						{
							float DistAlpha = (float)GlyphIndex / NumGlyphs;
							float DistAlphaNext = (float)(GlyphIndex + 1) / NumGlyphs;

							// This creates a set of UV's that goes from 0-1, from left to right of the string in U and 0-1 baseline to baseline top to bottom in V
							Ut = FMath::Lerp(0.0f, 1.0f, DistAlpha);
							Vt = FMath::Lerp(0.0f, 1.0f, UpperLeft.Y / MaxHeight);

							UtMax = FMath::Lerp(0.0f, 1.0f, DistAlphaNext);
							VtMax = FMath::Lerp(0.0f, 1.0f, LowerLeft.Y / MaxHeight);
						}

						// Add four vertices to the list of verts to be added to the vertex buffer
						BatchVerticesRef[VertexOffset++] = FSlateVertex::Make<Rounding>(RenderTransform, UpperLeft,								FVector4(U, V, Ut, Vt),							FVector2D(0.0f, 0.0f), InTint );
						BatchVerticesRef[VertexOffset++] = FSlateVertex::Make<Rounding>(RenderTransform, FVector2D(LowerRight.X, UpperLeft.Y),	FVector4(U + SizeU, V, UtMax, Vt),				FVector2D(1.0f, 0.0f), InTint );
						BatchVerticesRef[VertexOffset++] = FSlateVertex::Make<Rounding>(RenderTransform, FVector2D(UpperLeft.X, LowerRight.Y),	FVector4(U, V + SizeV, Ut, VtMax),				FVector2D(0.0f, 1.0f), InTint );
						BatchVerticesRef[VertexOffset++] = FSlateVertex::Make<Rounding>(RenderTransform, LowerRight,							FVector4(U + SizeU, V + SizeV, UtMax, VtMax),	FVector2D(1.0f, 1.0f), InTint );

						BatchIndicesRef[IndexOffset++] = IndexStart + 0;
						BatchIndicesRef[IndexOffset++] = IndexStart + 1;
						BatchIndicesRef[IndexOffset++] = IndexStart + 2;
						BatchIndicesRef[IndexOffset++] = IndexStart + 1;
						BatchIndicesRef[IndexOffset++] = IndexStart + 3;
						BatchIndicesRef[IndexOffset++] = IndexStart + 2;
					}
				}
			}

			LineX += GlyphToRender.XAdvance;
			LineY += GlyphToRender.YAdvance;
		}
	};

 普通text的AddTextElement,跟ShapedText不同。 根据characterList得到characterEntry,这个entry上有textureindex,从而获得图集贴图,联合材质球构成shaderResource。然后获得顶点和索引,uv。

两者跟outline相关的地方:

FCharacterList& CharacterList = FontCache.GetCharacterList(DrawElementPayload.GetFontInfo(), FontScale, InOutlineSettings);

const FShapedGlyphFontAtlasData GlyphAtlasData = FontCache.GetShapedGlyphFontAtlasData(GlyphToRender, InOutlineSettings);

 先看第二个,返回的是FShapedGlyphFontAtlasData数据,从AddNewEntry(InShapedGlyph, InOutlineSettings, *NewAtlasData);获取到的。上面说过了。

然后看看顶点属性

template<ESlateVertexRounding Rounding>
	static FSlateVertex Make(const FSlateRenderTransform& RenderTransform, const FVector2D& InLocalPosition, const FVector4& InTexCoords, const FVector2D& InMaterialTexCoords, const FColor& InColor)
	{
		FSlateVertex Vertex;
		Vertex.TexCoords[0] = InTexCoords.X;
		Vertex.TexCoords[1] = InTexCoords.Y;
		Vertex.TexCoords[2] = InTexCoords.Z;
		Vertex.TexCoords[3] = InTexCoords.W;
		Vertex.MaterialTexCoords = InMaterialTexCoords;
		Vertex.InitCommon<Rounding>(RenderTransform, InLocalPosition, InColor);

		return Vertex;
	}

  因为看到祖龙的龙族幻想里面,同样坐标的顶点出现了两次,只有InAttribute3这个属性不一样。如下

VTX	 IDX	 in_ATTRIBUTE0.x	 in_ATTRIBUTE0.y	 in_ATTRIBUTE0.z	 in_ATTRIBUTE0.w	 in_ATTRIBUTE1.x	 in_ATTRIBUTE1.y	 in_ATTRIBUTE2.x	 in_ATTRIBUTE2.y	 in_ATTRIBUTE2.z	 in_ATTRIBUTE3.x	 in_ATTRIBUTE3.y	 in_ATTRIBUTE3.z	 in_ATTRIBUTE3.w
2	2	0.16113	0.06152	0	0	0	1	1962.7439	208.84578	0.99947	0	0	0	0.4
104	70	0.25684	0.06152	0	0	0	1	1962.7439	208.84578	0.99947	0.83922	0.94118	0.60392	1

  输出的,颜色和var_texcoord1不一样。

 

half3 sRGBToLinear( half3 Color )
{
Color = max(6.10352e-5, Color); // minimum positive non-denormal (fixes black problem on DX11 AMD and NV)
return Color > 0.04045 ? pow( Color * (1.0 / 1.055) + 0.0521327, 2.4 ) : Color * (1.0 / 12.92);
}

half3 sRGBToLinear( half3 Color )
{
Color = max(6.10352e-5, Color); // minimum positive non-denormal (fixes black problem on DX11 AMD and NV)
return pow( Color * (1.0 / 1.055) + 0.0521327, 2.4 );
}

 

FindBatchForElement这个函数会查找,是否有能跟当前text合批的text,首先查找这个layer,找到了,则将这个element加到batch。如果没有,则创建一个新的batch:
FSlateElementBatch& FSlateElementBatcher::FindBatchForElement(
	uint32 Layer, 
	const FShaderParams& ShaderParams, 
	const FSlateShaderResource* InTexture, 
	ESlateDrawPrimitive::Type PrimitiveType,
	ESlateShader::Type ShaderType, 
	ESlateDrawEffect DrawEffects, 
	ESlateBatchDrawFlag DrawFlags,
	int32 ClippingIndex,
	int32 SceneIndex)
{

	SCOPE_CYCLE_COUNTER( STAT_SlateFindBatchForElement );
	FElementBatchMap& LayerToElementBatches = DrawLayer->GetElementBatchMap();

	// See if the layer already exists.
	TUniqueObj<FElementBatchArray>* ElementBatches = LayerToElementBatches.Find( Layer );
	if( !ElementBatches )
	{
		// The layer doesn't exist so make it now
		ElementBatches = &LayerToElementBatches.Add( Layer );
	}

	checkSlow( ElementBatches );

	// Create a temp batch so we can use it as our key to find if the same batch already exists
	FSlateElementBatch TempBatch( InTexture, ShaderParams, ShaderType, PrimitiveType, DrawEffects, DrawFlags, ClippingIndex, *ClippingStates, 0, 0, nullptr, SceneIndex );

	FSlateElementBatch* ElementBatch = (*ElementBatches)->FindByKey( TempBatch );
	if( !ElementBatch )
	{
		// No batch with the specified parameter exists.  Create it from the temp batch.
		int32 Index = (*ElementBatches)->Add( TempBatch );
		ElementBatch = &(**ElementBatches)[Index];

		BatchData->AssignVertexArrayToBatch(*ElementBatch);
		BatchData->AssignIndexArrayToBatch(*ElementBatch);
	}
	check( ElementBatch );

	// Increment the number of elements in the batch.
	++ElementBatch->NumElementsInBatch;
	return *ElementBatch;
}

  

标签:GlyphAtlasData,const,渲染,++,float,字体,DrawElement,及合批,FSlateDrawElement
来源: https://www.cnblogs.com/Shaojunping/p/11543391.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有