r.SkinCache.AllowDupedVertsForRecomputeTangents

r.SkinCache.AllowDupedVertsForRecomputeTangents

#Overview

name: r.SkinCache.AllowDupedVertsForRecomputeTangents

This variable is created as a Console Variable (cvar).

It is referenced in 6 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of r.SkinCache.AllowDupedVertsForRecomputeTangents is to control how vertices at the same position are treated during tangent recomputation in the GPU Skin Cache system of Unreal Engine 5.

This setting variable is primarily used in the rendering system, specifically within the GPU Skin Cache subsystem. It’s part of the Engine module, as evidenced by its location in the GPUSkinCache.cpp file.

The value of this variable is set through the Unreal Engine console variable system. It’s initialized to 0 (off) by default, but can be changed at runtime.

This variable interacts directly with its associated C++ variable GAllowDupedVertsForRecomputeTangents. They share the same value and are used interchangeably in the code.

Developers must be aware that enabling this variable (setting it to 1) will force vertices at the same position to be treated differently during tangent recomputation. This has the potential to cause seams when vertices are split, which could affect the visual quality of skinned meshes.

Best practices when using this variable include:

  1. Keeping it disabled (0) by default to avoid potential seam issues.
  2. Only enabling it when absolutely necessary for specific use cases where different treatment of vertices at the same position is required.
  3. Thoroughly testing the visual results when enabled, particularly looking for seams or other artifacts in skinned meshes.

Regarding the associated variable GAllowDupedVertsForRecomputeTangents:

This is an internal C++ variable that directly corresponds to the console variable. It’s used throughout the GPU Skin Cache code to determine the behavior of vertex treatment during tangent recomputation. The variable affects various parts of the tangent recomputation process, including shader selection and dispatch parameters. When disabled, it also triggers the use of additional buffers (DuplicatedIndices and DuplicatedIndicesIndices) to handle duplicated vertices properly.

Developers working directly with the C++ code should be aware of this variable and its effects on the GPU Skin Cache system, especially when modifying or extending the tangent recomputation functionality.

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GPUSkinCache.cpp:153

Scope: file

Source code excerpt:

static int32 GAllowDupedVertsForRecomputeTangents = 0;
FAutoConsoleVariableRef CVarGPUSkinCacheAllowDupedVertesForRecomputeTangents(
	TEXT("r.SkinCache.AllowDupedVertsForRecomputeTangents"),
	GAllowDupedVertsForRecomputeTangents,
	TEXT("0: off (default)\n")
	TEXT("1: Forces that vertices at the same position will be treated differently and has the potential to cause seams when verts are split.\n"),
	ECVF_RenderThreadSafe
);

#Associated Variable and Callsites

This variable is associated with another variable named GAllowDupedVertsForRecomputeTangents. They share the same value. See the following C++ source code.

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GPUSkinCache.cpp:151

Scope: file

Source code excerpt:

);

static int32 GAllowDupedVertsForRecomputeTangents = 0;
FAutoConsoleVariableRef CVarGPUSkinCacheAllowDupedVertesForRecomputeTangents(
	TEXT("r.SkinCache.AllowDupedVertsForRecomputeTangents"),
	GAllowDupedVertsForRecomputeTangents,
	TEXT("0: off (default)\n")
	TEXT("1: Forces that vertices at the same position will be treated differently and has the potential to cause seams when verts are split.\n"),
	ECVF_RenderThreadSafe
);

int32 GRecomputeTangentsParallelDispatch = 0;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GPUSkinCache.cpp:250

Scope (from outer to inner):

file
function     bool GPUSkinCacheNeedsDuplicatedVertices

Source code excerpt:

	return true;
#else
	return GAllowDupedVertsForRecomputeTangents == 0;
#endif
}

// determine if during DispatchUpdateSkinning caching should occur
enum class EGPUSkinCacheDispatchFlags
{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GPUSkinCache.cpp:930

Scope (from outer to inner):

file
class        class FBaseRecomputeTangentsPerTriangleShader : public FGlobalShader
function     void SetParameters

Source code excerpt:

		SetShaderValue(BatchedParameters, IntermediateAccumBufferOffset, GRecomputeTangentsParallelDispatch * DispatchData.IntermediateAccumulatedTangentBufferOffset);

        if (!GAllowDupedVertsForRecomputeTangents)
        {
		    SetSRVParameter(BatchedParameters, DuplicatedIndices, DispatchData.DuplicatedIndices);
            SetSRVParameter(BatchedParameters, DuplicatedIndicesIndices, DispatchData.DuplicatedIndicesIndices);
        }
	}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GPUSkinCache.cpp:1141

Scope (from outer to inner):

file
function     void FGPUSkinCache::DispatchUpdateSkinTangents

Source code excerpt:

			if (bFullPrecisionUV)
			{
				if (GAllowDupedVertsForRecomputeTangents) Shader = ComputeShader01;
				else Shader = ComputeShader11;
			}
			else
			{
				if (GAllowDupedVertsForRecomputeTangents) Shader = ComputeShader00;
				else Shader = ComputeShader10;
			}

			check(Shader.IsValid());

			uint32 NumTriangles = DispatchData.NumTriangles;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/GPUSkinCache.cpp:1158

Scope (from outer to inner):

file
function     void FGPUSkinCache::DispatchUpdateSkinTangents

Source code excerpt:

				*RayTracingTag , *GetSkeletalMeshObjectName(Entry->GPUSkin), LODIndex, SectionIndex, DispatchData.IndexBufferOffsetValue, DispatchData.NumTriangles, Entry->BoneInfluenceType, bFullPrecisionUV);

			if (!GAllowDupedVertsForRecomputeTangents)
			{
#if WITH_EDITOR
				check(LodData.RenderSections[SectionIndex].DuplicatedVerticesBuffer.DupVertData.Num() && LodData.RenderSections[SectionIndex].DuplicatedVerticesBuffer.DupVertIndexData.Num());
#endif
				DispatchData.DuplicatedIndices = LodData.RenderSections[SectionIndex].DuplicatedVerticesBuffer.DuplicatedVerticesIndexBuffer.VertexBufferSRV;
				DispatchData.DuplicatedIndicesIndices = LodData.RenderSections[SectionIndex].DuplicatedVerticesBuffer.LengthAndIndexDuplicatedVerticesIndexBuffer.VertexBufferSRV;