|
|
|
@@ -0,0 +1,471 @@
|
|
|
|
|
/*
|
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
|
|
|
associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
|
|
|
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
|
|
|
subject to the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
|
|
|
portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
|
|
|
|
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
|
|
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
|
|
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
//=================================================================================================================================
|
|
|
|
|
// Microsoft D3D11 Fixed Function Tessellator Reference - May 7, 2012
|
|
|
|
|
// amar.patel@microsoft.com
|
|
|
|
|
//
|
|
|
|
|
// CHWTessellator demonstrates what is expected of hardware in the D3D11 fixed function Tessellator stage. Hardware
|
|
|
|
|
// implementers need only look at this class.
|
|
|
|
|
//
|
|
|
|
|
// CHLSLTessellator is a wrapper for CHWTessellator, representing the effect of shader code that will
|
|
|
|
|
// be autogenerated by HLSL in the Hull Shader, both for plumbing data around, and to precondition TessFactor values before they
|
|
|
|
|
// are passed to the hardware (such as deriving inside TessFactors from edge TessFactors). The algorithms used
|
|
|
|
|
// in CHLSLTessellator are subject to change, but since they represent shader code auto-generated by the HLSL compiler,
|
|
|
|
|
// CHLSLTessellator has no effect on hardware design at all. Note the HLSL compiler will expose all the raw hardware
|
|
|
|
|
// control illustrated by CHWTessellator for those who don't need the helper functionality illustrated by CHLSLTessellator.
|
|
|
|
|
//
|
|
|
|
|
// Usage: (1) Create either a CHLSLTessellator or CHWTessellator object, depending on which you want to verify.
|
|
|
|
|
// (2) Call C*Tessellator::Init()
|
|
|
|
|
// (3) Call C*Tessellator::Tessellate[IsoLine|Tri|Quad]Domain()
|
|
|
|
|
// - Here you pass in TessFactors (how much to tessellate)
|
|
|
|
|
// (4) Call C*Tessellator::GetPointCount(), C*Tessellator::GetIndexCount() to see how much data was generated.
|
|
|
|
|
// (5) Call C*Tessellator::GetPoints() and C*Tessellator::GetIndices() to get pointers to the data.
|
|
|
|
|
// The pointers are fixed for the lifetime of the object (storage for max tessellation),
|
|
|
|
|
// so if you ::Tessellate again, the data in the buffers is overwritten.
|
|
|
|
|
// (6) There are various other Get() methods to retrieve TessFactors that have been processed from
|
|
|
|
|
// what you passed in at step 3. You can retrieve separate TessFactors that the tessellator
|
|
|
|
|
// produced after clamping but before rounding, and also after rounding (say in pow2 mode).
|
|
|
|
|
// These numbers can be useful information if you are geomorphing displacement maps.
|
|
|
|
|
// (7) Goto Step 2 or 3 if you want to animate TessFactors or tessellate a different patch
|
|
|
|
|
//
|
|
|
|
|
// Code implementation details:
|
|
|
|
|
//
|
|
|
|
|
// There is lots of headroom to make this code run faster on CPUs. It was written merely as a reference for
|
|
|
|
|
// what results hardware should produce, with CPU performance not a consideration. It is nice that this implementation
|
|
|
|
|
// only generates the exact number of vertices needed (no duplicates) in the output vertex buffer. Also, the number
|
|
|
|
|
// of calculations done for each U/V domain coordinate is minimized by doing some precalculation of some patch or edge
|
|
|
|
|
// invariant numbers (see TESS_FACTOR_CONTEXT). All the vertex coordinate calculations could be computed with as much
|
|
|
|
|
// parallelism as you like. Similarly the calculation of connectivity itself is highly parallelizable, and can also
|
|
|
|
|
// be done independent of the vertex calculations.
|
|
|
|
|
//
|
|
|
|
|
//=================================================================================================================================
|
|
|
|
|
|
|
|
|
|
#define D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR 1
|
|
|
|
|
#define D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR 63
|
|
|
|
|
#define D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR 2
|
|
|
|
|
#define D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR 64
|
|
|
|
|
|
|
|
|
|
#define D3D11_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR 1
|
|
|
|
|
#define D3D11_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR 64
|
|
|
|
|
|
|
|
|
|
#define D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR 64 // max of even and odd tessFactors
|
|
|
|
|
|
|
|
|
|
#define MAX_POINT_COUNT ((D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR+1)*(D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR+1))
|
|
|
|
|
#define MAX_INDEX_COUNT (D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR*D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR*2*3)
|
|
|
|
|
|
|
|
|
|
//=================================================================================================================================
|
|
|
|
|
// Data types for the caller
|
|
|
|
|
//=================================================================================================================================
|
|
|
|
|
enum D3D11_TESSELLATOR_PARTITIONING
|
|
|
|
|
{
|
|
|
|
|
D3D11_TESSELLATOR_PARTITIONING_INTEGER,
|
|
|
|
|
D3D11_TESSELLATOR_PARTITIONING_POW2,
|
|
|
|
|
D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD,
|
|
|
|
|
D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum D3D11_TESSELLATOR_REDUCTION
|
|
|
|
|
{
|
|
|
|
|
D3D11_TESSELLATOR_REDUCTION_MIN,
|
|
|
|
|
D3D11_TESSELLATOR_REDUCTION_MAX,
|
|
|
|
|
D3D11_TESSELLATOR_REDUCTION_AVERAGE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum D3D11_TESSELLATOR_QUAD_REDUCTION_AXIS
|
|
|
|
|
{
|
|
|
|
|
D3D11_TESSELLATOR_QUAD_REDUCTION_1_AXIS,
|
|
|
|
|
D3D11_TESSELLATOR_QUAD_REDUCTION_2_AXIS
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum D3D11_TESSELLATOR_OUTPUT_PRIMITIVE
|
|
|
|
|
{
|
|
|
|
|
D3D11_TESSELLATOR_OUTPUT_POINT,
|
|
|
|
|
D3D11_TESSELLATOR_OUTPUT_LINE,
|
|
|
|
|
D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW,
|
|
|
|
|
D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CCW,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef struct DOMAIN_POINT
|
|
|
|
|
{
|
|
|
|
|
float u;
|
|
|
|
|
float v; // for tri, w = 1 - u - v;
|
|
|
|
|
} DOMAIN_POINT;
|
|
|
|
|
|
|
|
|
|
//=================================================================================================================================
|
|
|
|
|
// CHWTessellator: D3D11 Tessellation Fixed Function Hardware Reference
|
|
|
|
|
//=================================================================================================================================
|
|
|
|
|
typedef unsigned int FXP; // fixed point number
|
|
|
|
|
|
|
|
|
|
class CHWTessellator
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
public:
|
|
|
|
|
void Init( D3D11_TESSELLATOR_PARTITIONING partitioning,
|
|
|
|
|
D3D11_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive);
|
|
|
|
|
|
|
|
|
|
void TessellateIsoLineDomain( float TessFactor_V_LineDensity,
|
|
|
|
|
float TessFactor_U_LineDetail );
|
|
|
|
|
|
|
|
|
|
void TessellateTriDomain( float TessFactor_Ueq0,
|
|
|
|
|
float TessFactor_Veq0,
|
|
|
|
|
float TessFactor_Weq0,
|
|
|
|
|
float TessFactor_Inside );
|
|
|
|
|
|
|
|
|
|
void TessellateQuadDomain( float TessFactor_Ueq0,
|
|
|
|
|
float TessFactor_Veq0,
|
|
|
|
|
float TessFactor_Ueq1,
|
|
|
|
|
float TessFactor_Veq1,
|
|
|
|
|
float TessFactor_InsideU,
|
|
|
|
|
float TessFactor_InsideV );
|
|
|
|
|
|
|
|
|
|
int GetPointCount();
|
|
|
|
|
int GetIndexCount();
|
|
|
|
|
|
|
|
|
|
DOMAIN_POINT* GetPoints(); // Get CHWTessellator owned pointer to vertices (UV values).
|
|
|
|
|
// Pointer is fixed for lifetime of CHWTessellator object.
|
|
|
|
|
int* GetIndices(); // Get CHWTessellator owned pointer to vertex indices.
|
|
|
|
|
// Pointer is fixed for lifetime of CHWTessellator object.
|
|
|
|
|
|
|
|
|
|
#define ALLOW_XBOX_360_COMPARISON // Different vertex splitting order. This is NOT D3D11 behavior, just available here for comparison.
|
|
|
|
|
// Setting this define true just allows the XBox split style to be enabled via
|
|
|
|
|
// SetXBox360Mode() below, but by default this XBox360 mode still always starts off DISABLED.
|
|
|
|
|
// The XBox360 always splits from the center of an edge (D3D11 uses ruler function). Splitting
|
|
|
|
|
// from the center causes sliver triangles in transition areas, which cause numerous problems.
|
|
|
|
|
// Note the XBox360 only supports adaptive tessellation via fractional_even partitioning,
|
|
|
|
|
// though this #define lets you try the XBox vertex splitting order with any of the
|
|
|
|
|
// partitioning modes: even, odd, integer or pow2.
|
|
|
|
|
#ifdef ALLOW_XBOX_360_COMPARISON
|
|
|
|
|
void SetXBox360Mode(bool bXboxMode) {m_bXBox360Mode = bXboxMode;}
|
|
|
|
|
#endif
|
|
|
|
|
CHWTessellator();
|
|
|
|
|
~CHWTessellator();
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
//=============================================================================================================================
|
|
|
|
|
// Some defines so that numbers are usually self commenting
|
|
|
|
|
//=============================================================================================================================
|
|
|
|
|
static const int U = 0; // points on a tri patch
|
|
|
|
|
static const int V = 1;
|
|
|
|
|
static const int W = 2;
|
|
|
|
|
static const int Ueq0 = 0; // edges on a tri patch
|
|
|
|
|
static const int Veq0 = 1;
|
|
|
|
|
static const int Weq0 = 2;
|
|
|
|
|
|
|
|
|
|
static const int Ueq1 = 2; // edges on a quad patch: Ueq0, Veq0, Ueq1, Veq1
|
|
|
|
|
static const int Veq1 = 3;
|
|
|
|
|
|
|
|
|
|
static const int QUAD_AXES = 2;
|
|
|
|
|
static const int QUAD_EDGES = 4;
|
|
|
|
|
static const int TRI_EDGES = 3;
|
|
|
|
|
//=============================================================================================================================
|
|
|
|
|
|
|
|
|
|
enum TESSELLATOR_PARITY // derived from D3D11_TESSELLATOR_PARTITIONING
|
|
|
|
|
{ // (note: for integer tessellation, both parities are used)
|
|
|
|
|
TESSELLATOR_PARITY_EVEN,
|
|
|
|
|
TESSELLATOR_PARITY_ODD
|
|
|
|
|
};
|
|
|
|
|
private:
|
|
|
|
|
TESSELLATOR_PARITY m_originalParity; // user chosen parity
|
|
|
|
|
TESSELLATOR_PARITY m_parity; // current parity: if allowing mix of even/odd during discrete
|
|
|
|
|
// tessellation, this can vary from the user defined parity
|
|
|
|
|
D3D11_TESSELLATOR_PARTITIONING m_originalPartitioning; // user chosen partitioning
|
|
|
|
|
D3D11_TESSELLATOR_PARTITIONING m_partitioning; // current partitioning. IsoLines overrides for line density
|
|
|
|
|
D3D11_TESSELLATOR_OUTPUT_PRIMITIVE m_outputPrimitive;
|
|
|
|
|
DOMAIN_POINT* m_Point; // array where we will store u/v's for the points we generate
|
|
|
|
|
int* m_Index; // array where we will store index topology
|
|
|
|
|
int m_NumPoints;
|
|
|
|
|
int m_NumIndices;
|
|
|
|
|
#ifdef ALLOW_XBOX_360_COMPARISON
|
|
|
|
|
bool m_bXBox360Mode;
|
|
|
|
|
#endif
|
|
|
|
|
// PlacePointIn1D below is the workhorse for all position placement.
|
|
|
|
|
// It is code that could run as preamble in a Domain Shader, so the tessellator itself
|
|
|
|
|
// doesn't necessarily need to have floating point.
|
|
|
|
|
// Some per-TessFactor fixed context is needed, and that can be computed wherever
|
|
|
|
|
// the TessFactor reduction is done, perhaps as Hull Shader postamble - this is shared
|
|
|
|
|
// for all point evaluation.
|
|
|
|
|
typedef struct TESS_FACTOR_CONTEXT
|
|
|
|
|
{
|
|
|
|
|
FXP fxpInvNumSegmentsOnFloorTessFactor;
|
|
|
|
|
FXP fxpInvNumSegmentsOnCeilTessFactor;
|
|
|
|
|
FXP fxpHalfTessFactorFraction;
|
|
|
|
|
int numHalfTessFactorPoints;
|
|
|
|
|
int splitPointOnFloorHalfTessFactor;
|
|
|
|
|
} TESS_FACTOR_CONTEXT;
|
|
|
|
|
void ComputeTessFactorContext( FXP fxpTessFactor, TESS_FACTOR_CONTEXT& TessFactorCtx );
|
|
|
|
|
void PlacePointIn1D( const TESS_FACTOR_CONTEXT& TessFactorCtx, int point, FXP& fxpLocation );
|
|
|
|
|
|
|
|
|
|
int NumPointsForTessFactor(FXP fxpTessFactor);
|
|
|
|
|
|
|
|
|
|
// Tessellation parity control
|
|
|
|
|
bool Odd() {return (m_parity == TESSELLATOR_PARITY_ODD) ? true : false;}
|
|
|
|
|
void SetTessellationParity(TESSELLATOR_PARITY parity) {m_parity = parity;}
|
|
|
|
|
|
|
|
|
|
// HWIntegerPartitioning() - hardware doesn't care about what pow2 partitioning is - the query below is true for
|
|
|
|
|
// both integer and pow2.
|
|
|
|
|
bool HWIntegerPartitioning() {return ((m_partitioning == D3D11_TESSELLATOR_PARTITIONING_INTEGER)||
|
|
|
|
|
(m_partitioning == D3D11_TESSELLATOR_PARTITIONING_POW2)) ? true : false;}
|
|
|
|
|
|
|
|
|
|
// Tesselation Partitioning control
|
|
|
|
|
void RestorePartitioning() {m_partitioning = m_originalPartitioning;};
|
|
|
|
|
void OverridePartitioning(D3D11_TESSELLATOR_PARTITIONING partitioning) {m_partitioning = partitioning;} //isoline uses this for density
|
|
|
|
|
|
|
|
|
|
// Call these to generate new points and indices. Max TessFactor storage is already allocated.
|
|
|
|
|
int DefinePoint(FXP u, FXP v, int pointStorageOffset);
|
|
|
|
|
void DefineIndex(int index, int indexStorageOffset);
|
|
|
|
|
void DefineClockwiseTriangle(int index0, int index1, int index2, int indexStorageBaseOffset);
|
|
|
|
|
|
|
|
|
|
// Couple of trivial ways to generate index data just given points and no other connectivity.
|
|
|
|
|
void DumpAllPoints(); // Make point indices for point rendering mode -
|
|
|
|
|
// redundant, but just here for orthogonality.
|
|
|
|
|
void DumpAllPointsAsInOrderLineList(); // A debug visualization of all the points connected
|
|
|
|
|
// in the order they were generated.
|
|
|
|
|
// Asking to draw line topology on a tri or quad patch will do this
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The structures below define the data that is derived given input TessFactors and which
|
|
|
|
|
// is used by point generation and connectivity generation steps (each of which are independent)
|
|
|
|
|
typedef struct PROCESSED_TESS_FACTORS_ISOLINE
|
|
|
|
|
{
|
|
|
|
|
TESSELLATOR_PARITY lineDensityParity;
|
|
|
|
|
TESSELLATOR_PARITY lineDetailParity;
|
|
|
|
|
TESS_FACTOR_CONTEXT lineDensityTessFactorCtx;
|
|
|
|
|
TESS_FACTOR_CONTEXT lineDetailTessFactorCtx;
|
|
|
|
|
bool bPatchCulled;
|
|
|
|
|
int numPointsPerLine;
|
|
|
|
|
int numLines;
|
|
|
|
|
} PROCESSED_TESS_FACTORS_ISOLINE;
|
|
|
|
|
typedef struct PROCESSED_TESS_FACTORS_TRI
|
|
|
|
|
{
|
|
|
|
|
FXP outsideTessFactor[TRI_EDGES];
|
|
|
|
|
FXP insideTessFactor;
|
|
|
|
|
TESSELLATOR_PARITY outsideTessFactorParity[TRI_EDGES];
|
|
|
|
|
TESSELLATOR_PARITY insideTessFactorParity;
|
|
|
|
|
TESS_FACTOR_CONTEXT outsideTessFactorCtx[TRI_EDGES];
|
|
|
|
|
TESS_FACTOR_CONTEXT insideTessFactorCtx;
|
|
|
|
|
bool bJustDoMinimumTessFactor;
|
|
|
|
|
bool bPatchCulled;
|
|
|
|
|
// Stuff below is just specific to the traversal order
|
|
|
|
|
// this code happens to use to generate points/lines
|
|
|
|
|
int numPointsForOutsideEdge[TRI_EDGES];
|
|
|
|
|
int numPointsForInsideTessFactor;
|
|
|
|
|
int insideEdgePointBaseOffset;
|
|
|
|
|
} PROCESSED_TESS_FACTORS_TRI;
|
|
|
|
|
typedef struct PROCESSED_TESS_FACTORS_QUAD
|
|
|
|
|
{
|
|
|
|
|
FXP outsideTessFactor[QUAD_EDGES];
|
|
|
|
|
FXP insideTessFactor[QUAD_AXES];
|
|
|
|
|
TESSELLATOR_PARITY outsideTessFactorParity[QUAD_EDGES];
|
|
|
|
|
TESSELLATOR_PARITY insideTessFactorParity[QUAD_AXES];
|
|
|
|
|
TESS_FACTOR_CONTEXT outsideTessFactorCtx[QUAD_EDGES];
|
|
|
|
|
TESS_FACTOR_CONTEXT insideTessFactorCtx[QUAD_AXES];
|
|
|
|
|
bool bJustDoMinimumTessFactor;
|
|
|
|
|
bool bPatchCulled;
|
|
|
|
|
// Stuff below is just specific to the traversal order
|
|
|
|
|
// this code happens to use to generate points/lines
|
|
|
|
|
int numPointsForOutsideEdge[QUAD_EDGES];
|
|
|
|
|
int numPointsForInsideTessFactor[QUAD_AXES];
|
|
|
|
|
int insideEdgePointBaseOffset;
|
|
|
|
|
} PROCESSED_TESS_FACTORS_QUAD;
|
|
|
|
|
|
|
|
|
|
// These are the workhorse functions for tessellation:
|
|
|
|
|
// (1) Process input TessFactors
|
|
|
|
|
// (2) Generate points
|
|
|
|
|
// (3) Generate connectivity (can be done in parallel to (2))
|
|
|
|
|
void IsoLineProcessTessFactors( float TessFactor_V_LineDensity, float TessFactor_U_LineDetail, PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors );
|
|
|
|
|
void IsoLineGeneratePoints( const PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors );
|
|
|
|
|
void IsoLineGenerateConnectivity( const PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors );
|
|
|
|
|
void TriProcessTessFactors( float tessFactor_Ueq0, float TessFactor_Veq0, float TessFactor_Weq0, float insideTessFactor, PROCESSED_TESS_FACTORS_TRI& processedTessFactors );
|
|
|
|
|
void TriGeneratePoints( const PROCESSED_TESS_FACTORS_TRI& processedTessFactors );
|
|
|
|
|
void TriGenerateConnectivity( const PROCESSED_TESS_FACTORS_TRI& processedTessFactors );
|
|
|
|
|
void QuadProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,
|
|
|
|
|
float insideTessFactor_U, float insideTessFactor_V, PROCESSED_TESS_FACTORS_QUAD& processedTessFactors );
|
|
|
|
|
void QuadGeneratePoints( const PROCESSED_TESS_FACTORS_QUAD& processedTessFactors );
|
|
|
|
|
void QuadGenerateConnectivity( const PROCESSED_TESS_FACTORS_QUAD& processedTessFactors );
|
|
|
|
|
|
|
|
|
|
// Stitching
|
|
|
|
|
// ---------
|
|
|
|
|
// Given pointers to the beginning of 2 parallel rows of points, and TessFactors for each, stitch them.
|
|
|
|
|
// The assumption is the stitch is symmetric.
|
|
|
|
|
void StitchTransition(int baseIndexOffset, int insideEdgePointBaseOffset, int insideNumHalfTessFactorPoints,
|
|
|
|
|
TESSELLATOR_PARITY insideEdgeTessFactorParity,
|
|
|
|
|
int outsideEdgePointBaseOffset, int outsideNumHalfTessFactorPoints,
|
|
|
|
|
TESSELLATOR_PARITY outsideEdgeTessFactorParity );
|
|
|
|
|
// The interior can just use a simpler stitch.
|
|
|
|
|
enum DIAGONALS
|
|
|
|
|
{
|
|
|
|
|
DIAGONALS_INSIDE_TO_OUTSIDE,
|
|
|
|
|
DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE,
|
|
|
|
|
DIAGONALS_MIRRORED
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void StitchRegular(bool bTrapezoid, DIAGONALS diagonals, int baseIndexOffset, int numInsideEdgePoints,
|
|
|
|
|
int insideEdgePointBaseOffset, int outsideEdgePointBaseOffset);
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
// Index Patching
|
|
|
|
|
// --------------
|
|
|
|
|
// The code below patches index values produces during triangulation, so triangulation doesn't have to know
|
|
|
|
|
// where points should go. I happened to never produce duplicate vertices, but the patching would
|
|
|
|
|
// be simpler if some duplicate vertices were introduced in practice. During point rendering mode however,
|
|
|
|
|
// it is not permitted for duplicate points to show up.
|
|
|
|
|
|
|
|
|
|
// Since the points are generated in concentric rings, most of the time, the point locations are
|
|
|
|
|
// sequentially increasing in memory for each side of a ring, which the stitch can take advantage of.
|
|
|
|
|
// However, there are exceptions where the points are not sequentially increasing, such as
|
|
|
|
|
// the 4th row in a given ring, where the last point on the outside of each row is actually the beginning
|
|
|
|
|
// point.
|
|
|
|
|
// So we let the stitching code think it sees sequential vertices, and when it emits a vertex index,
|
|
|
|
|
// we patch it to be the real location.
|
|
|
|
|
int PatchIndexValue(int index);
|
|
|
|
|
typedef struct INDEX_PATCH_CONTEXT
|
|
|
|
|
{
|
|
|
|
|
int insidePointIndexDeltaToRealValue;
|
|
|
|
|
int insidePointIndexBadValue;
|
|
|
|
|
int insidePointIndexReplacementValue;
|
|
|
|
|
int outsidePointIndexPatchBase;
|
|
|
|
|
int outsidePointIndexDeltaToRealValue;
|
|
|
|
|
int outsidePointIndexBadValue;
|
|
|
|
|
int outsidePointIndexReplacementValue;
|
|
|
|
|
} INDEX_PATCH_CONTEXT;
|
|
|
|
|
void SetUsingPatchedIndices(bool bUsingPatchedIndices) {m_bUsingPatchedIndices = bUsingPatchedIndices;}
|
|
|
|
|
|
|
|
|
|
// A second index patch we have to do handles the leftover strip of quads in the middle of an odd quad patch after
|
|
|
|
|
// finishing all the concentric rings.
|
|
|
|
|
// This also handles the leftover strip of points in the middle of an even quad
|
|
|
|
|
// patch, when stitching the row of triangles up the left side (V major quad) or bottom (U major quad) of the
|
|
|
|
|
// inner ring
|
|
|
|
|
typedef struct INDEX_PATCH_CONTEXT2
|
|
|
|
|
{
|
|
|
|
|
int baseIndexToInvert;
|
|
|
|
|
int indexInversionEndPoint;
|
|
|
|
|
int cornerCaseBadValue;
|
|
|
|
|
int cornerCaseReplacementValue;
|
|
|
|
|
} INDEX_PATCH_CONTEXT2;
|
|
|
|
|
void SetUsingPatchedIndices2(bool bUsingPatchedIndices) {m_bUsingPatchedIndices2 = bUsingPatchedIndices;}
|
|
|
|
|
bool m_bUsingPatchedIndices;
|
|
|
|
|
bool m_bUsingPatchedIndices2;
|
|
|
|
|
INDEX_PATCH_CONTEXT m_IndexPatchContext;
|
|
|
|
|
INDEX_PATCH_CONTEXT2 m_IndexPatchContext2;
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//=================================================================================================================================
|
|
|
|
|
// CHLSLTessellator: D3D11 Tessellation HLSL Tessellator Interface
|
|
|
|
|
// Demonstrates TessFactor preconditioning code auto-generated by HLSL. Subject to change, but this
|
|
|
|
|
// just represents the effect of shader code the HLSL compiler will generate in the Hull Shader,
|
|
|
|
|
// so it does not affect hardware design at all.
|
|
|
|
|
//=================================================================================================================================
|
|
|
|
|
class CHLSLTessellator : public CHWTessellator
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
void Init( D3D11_TESSELLATOR_PARTITIONING partitioning,
|
|
|
|
|
D3D11_TESSELLATOR_REDUCTION insideTessFactorReduction,
|
|
|
|
|
D3D11_TESSELLATOR_QUAD_REDUCTION_AXIS quadInsideTessFactorReductionAxis,
|
|
|
|
|
D3D11_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive);
|
|
|
|
|
|
|
|
|
|
void TessellateIsoLineDomain( float TessFactor_V_LineDensity,
|
|
|
|
|
float TessFactor_U_LineDetail );
|
|
|
|
|
|
|
|
|
|
void TessellateTriDomain( float tessFactor_Ueq0,
|
|
|
|
|
float TessFactor_Veq0,
|
|
|
|
|
float TessFactor_Weq0,
|
|
|
|
|
float insideTessFactorScale /*[0..1]*/ );
|
|
|
|
|
|
|
|
|
|
void TessellateQuadDomain( float TessFactorUeq0,
|
|
|
|
|
float TessFactorVeq0,
|
|
|
|
|
float TessFactorUeq1,
|
|
|
|
|
float TessFactorVeq1,
|
|
|
|
|
float insideTessFactorScaleU /*[0..1]*/,
|
|
|
|
|
float insideTessFactorScaleV /*[0..1]*/ );
|
|
|
|
|
|
|
|
|
|
int GetPointCount() {return CHWTessellator::GetPointCount();};
|
|
|
|
|
int GetIndexCount() {return CHWTessellator::GetIndexCount();}
|
|
|
|
|
|
|
|
|
|
DOMAIN_POINT* GetPoints() {return CHWTessellator::GetPoints();} // Get CHLSLTessellator owned pointer to vertices (UV values).
|
|
|
|
|
// Pointer is fixed for lifetime of CHLSLTessellator object.
|
|
|
|
|
int* GetIndices() {return CHWTessellator::GetIndices();} // Get CHLSLTessellator owned pointer to vertex indices.
|
|
|
|
|
// Pointer is fixed for lifetime of CHLSLTessellator object.
|
|
|
|
|
|
|
|
|
|
// Retrieve TessFactors actually used by the "hardware"
|
|
|
|
|
// This includes clamping to valid range, and more interestingly
|
|
|
|
|
// if integer or pow2 partitioning is being done, the rounded TessFactors can be retrieved.
|
|
|
|
|
// Getting the rounded TessFactors can be useful for geomorphing of displacement maps.
|
|
|
|
|
float GetIsoLineDensityTessFactor() {return m_LastComputedTessFactors[0];}
|
|
|
|
|
float GetIsoLineDetailTessFactor() {return m_LastComputedTessFactors[1];}
|
|
|
|
|
float GetTriUeq0TessFactor() {return m_LastComputedTessFactors[0];}
|
|
|
|
|
float GetTriVeq0TessFactor() {return m_LastComputedTessFactors[1];}
|
|
|
|
|
float GetTriWeq0TessFactor() {return m_LastComputedTessFactors[2];}
|
|
|
|
|
float GetTriInsideTessFactor() {return m_LastComputedTessFactors[3];}
|
|
|
|
|
float GetQuadUeq0TessFactor() {return m_LastComputedTessFactors[0];}
|
|
|
|
|
float GetQuadVeq0TessFactor() {return m_LastComputedTessFactors[1];}
|
|
|
|
|
float GetQuadUeq1TessFactor() {return m_LastComputedTessFactors[2];}
|
|
|
|
|
float GetQuadVeq1TessFactor() {return m_LastComputedTessFactors[3];}
|
|
|
|
|
float GetQuadInsideUTessFactor() {return m_LastComputedTessFactors[4];}
|
|
|
|
|
float GetQuadInsideVTessFactor() {return m_LastComputedTessFactors[5];}
|
|
|
|
|
float GetUnRoundedIsoLineDensityTessFactor() {return m_LastUnRoundedComputedTessFactors[0];}
|
|
|
|
|
float GetUnRoundedIsoLineDetailTessFactor() {return m_LastUnRoundedComputedTessFactors[1];}
|
|
|
|
|
float GetUnRoundedTriUeq0TessFactor() {return m_LastUnRoundedComputedTessFactors[0];}
|
|
|
|
|
float GetUnRoundedTriVeq0TessFactor() {return m_LastUnRoundedComputedTessFactors[1];}
|
|
|
|
|
float GetUnRoundedTriWeq0TessFactor() {return m_LastUnRoundedComputedTessFactors[2];}
|
|
|
|
|
float GetUnRoundedTriInsideTessFactor() {return m_LastUnRoundedComputedTessFactors[3];}
|
|
|
|
|
float GetUnRoundedQuadUeq0TessFactor() {return m_LastUnRoundedComputedTessFactors[0];}
|
|
|
|
|
float GetUnRoundedQuadVeq0TessFactor() {return m_LastUnRoundedComputedTessFactors[1];}
|
|
|
|
|
float GetUnRoundedQuadUeq1TessFactor() {return m_LastUnRoundedComputedTessFactors[2];}
|
|
|
|
|
float GetUnRoundedQuadVeq1TessFactor() {return m_LastUnRoundedComputedTessFactors[3];}
|
|
|
|
|
float GetUnRoundedQuadInsideUTessFactor() {return m_LastUnRoundedComputedTessFactors[4];}
|
|
|
|
|
float GetUnRoundedQuadInsideVTessFactor() {return m_LastUnRoundedComputedTessFactors[5];}
|
|
|
|
|
|
|
|
|
|
CHLSLTessellator();
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
private:
|
|
|
|
|
TESSELLATOR_PARITY m_originalParity; // user chosen parity
|
|
|
|
|
TESSELLATOR_PARITY m_parity; // current parity: if allowing mix of even/odd during discrete
|
|
|
|
|
// tessellation, this can vary from the user defined parity
|
|
|
|
|
D3D11_TESSELLATOR_PARTITIONING m_originalPartitioning; // user chosen partitioning
|
|
|
|
|
D3D11_TESSELLATOR_PARTITIONING m_partitioning; // current partitioning. IsoLines overrides for line density
|
|
|
|
|
D3D11_TESSELLATOR_OUTPUT_PRIMITIVE m_outputPrimitive;
|
|
|
|
|
D3D11_TESSELLATOR_REDUCTION m_insideTessFactorReduction;
|
|
|
|
|
D3D11_TESSELLATOR_QUAD_REDUCTION_AXIS m_quadInsideTessFactorReductionAxis;
|
|
|
|
|
float m_LastComputedTessFactors[6]; // TessFactors used for last tessellation
|
|
|
|
|
float m_LastUnRoundedComputedTessFactors[6]; // TessFactors used for last tessellation (before they were rounded)
|
|
|
|
|
bool IntegerPartitioning() {return (m_partitioning == D3D11_TESSELLATOR_PARTITIONING_INTEGER) ? true : false;}
|
|
|
|
|
bool Pow2Partitioning() {return (m_partitioning == D3D11_TESSELLATOR_PARTITIONING_POW2)? true : false;}
|
|
|
|
|
void ClampTessFactor(float& TessFactor);
|
|
|
|
|
void RoundUpTessFactor(float& TessFactor);
|
|
|
|
|
void CleanupFloatTessFactor(float& input); // clamp float to [1.0f... +INF] (incl NaN->1.0f)
|
|
|
|
|
void ClampFloatTessFactorScale(float& input); // clamp float to [0.0f... +INF] (incl NaN->0.0f)
|
|
|
|
|
|
|
|
|
|
// Tessellation parity control
|
|
|
|
|
bool Odd() {return (m_parity == TESSELLATOR_PARITY_ODD) ? true : false;}
|
|
|
|
|
void SetTessellationParity(TESSELLATOR_PARITY parity) {m_parity = parity;}
|
|
|
|
|
|
|
|
|
|
// Tesselation Partitioning control
|
|
|
|
|
void RestorePartitioning() {m_partitioning = m_originalPartitioning;};
|
|
|
|
|
void OverridePartitioning(D3D11_TESSELLATOR_PARTITIONING partitioning) {m_partitioning = partitioning;} //isoline uses this for density
|
|
|
|
|
|
|
|
|
|
void IsoLineHLSLProcessTessFactors( float TessFactor_V_LineDensity, float TessFactor_U_LineDetail );
|
|
|
|
|
void TriHLSLProcessTessFactors( float tessFactor_Ueq0, float TessFactor_Veq0, float TessFactor_Weq0, float insideTessFactor );
|
|
|
|
|
void QuadHLSLProcessTessFactors( float TessFactor_Ueq0, float TessFactor_Veq0, float TessFactor_Ueq1, float TessFactor_Veq1,
|
|
|
|
|
float insideTessFactor_U, float insideTessFactor_V );
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|