Skip to content

Instantly share code, notes, and snippets.

@Eideren
Created October 21, 2020 16:31
Show Gist options
  • Save Eideren/d85cd767917beffbc9031eba20aaf9f2 to your computer and use it in GitHub Desktop.
Save Eideren/d85cd767917beffbc9031eba20aaf9f2 to your computer and use it in GitHub Desktop.
Stride, charly's tessellation issues
#ifndef InputControlPointCount
# define InputControlPointCount 3
#endif
#ifndef OutputControlPointCount
# define OutputControlPointCount 3
#endif
shader TessCustom : ShaderBase, TransformationBase, MaterialDomainStream, Camera, Transformation, NormalBase
{
cbuffer PerMaterial
{
[Link("Tessellation.DesiredTriangleSize")]
stage float DesiredTriangleSize = 12.0f;
}
patchstream float tessFactor[3] : SV_TessFactor;
patchstream float insideTessFactor : SV_InsideTessFactor;
[maxvertexcount(18)]
stage void GSMain(triangle Input input [3], inout TriangleStream<Output> triangleStream)
{
for (int i = 0; i < 6; ++i)
{
for (int j = 0; j < 3; ++j)
{
streams = input[j];
streams.ShadingPosition = streams.Position; // Replace this garbage
triangleStream.Append(streams);
}
triangleStream.RestartStrip();
}
}
[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("HSConstantMain")]
void HSMain(InputPatch<Input, InputControlPointCount> input, out Output output, uint uCPID : SV_OutputControlPointID)
{
const uint NextCPID = uCPID < 2 ? uCPID + 1 : 0;
streams = input[uCPID];
TessellateHull(input, uCPID, NextCPID);
// Compute screen space position of current control point and next one
// TODO: Reuse ShadingPosition?
// However, not sure if we can do tessellation directly through ShadingPosition interpolation (in which case we wouldn't need to do it in domain shader either)
float2 screenPosition0 = GetScreenSpacePosition(input[uCPID].PositionWS, ViewSize.x, ViewSize.y);
float2 screenPosition1 = GetScreenSpacePosition(input[NextCPID].PositionWS, ViewSize.x, ViewSize.y);
// Screen space tessellation based on desired triangle size
streams.oppositeEdgeLOD = distance(screenPosition0, screenPosition1) / DesiredTriangleSize;
output = streams;
}
void HSConstantMain(InputPatch<Input, InputControlPointCount> input, const OutputPatch<Input2, 3> output, out Constants constants)
{
constants.tessFactor[0] = output[1].oppositeEdgeLOD;
constants.tessFactor[1] = output[2].oppositeEdgeLOD;
constants.tessFactor[2] = output[0].oppositeEdgeLOD;
constants.insideTessFactor = 0.33f * (constants.tessFactor[0] + constants.tessFactor[1] + constants.tessFactor[2]);
TessellateHullConstant(input, output, constants);
if (ComputeClipping(input, output, constants))
{
constants.tessFactor[0] = 0.0f;
constants.tessFactor[1] = 0.0f;
constants.tessFactor[2] = 0.0f;
constants.insideTessFactor = 0.0f;
}
}
[domain("tri")]
void DSMain(const OutputPatch<Input, OutputControlPointCount> input, out Output output, in Constants constants, float3 f3BarycentricCoords : SV_DomainLocation)
{
InterpolateBarycentric(input, constants, f3BarycentricCoords);
this.BaseTransformDS();
output = streams;
}
stage override void BaseTransformVS()
{
this.PreTransformPosition();
}
stage void BaseTransformDS()
{
this.TransformPosition();
this.PostTransformPosition();
}
stage override void TransformPosition()
{
base.TransformPosition();
// Apply tessellation map, etc...
TessellateDomain();
}
float2 GetScreenSpacePosition(
float4 f3Position, // View space position of patch control point
float fScreenWidth, // Screen width
float fScreenHeight // Screen height
)
{
float4 f4ProjectedPosition = this.ComputeShadingPosition(f3Position);
float2 f2ScreenPosition = f4ProjectedPosition.xy / f4ProjectedPosition.w;
f2ScreenPosition = ( f2ScreenPosition + 1.0f ) * 0.5f * float2( fScreenWidth, -fScreenHeight );
return f2ScreenPosition;
}
stage void TessellateHull(InputPatch<Input, InputControlPointCount> input, uint uCPID, uint NextCPID) {}
stage void TessellateHullConstant(InputPatch<Input, InputControlPointCount> input, const OutputPatch<Input2, 3> output, inout Constants constants) {}
stage void TessellateDomain() {}
override stage void GenerateNormal_VS()
{
base.GenerateNormal_VS();
// Ensure that normal is normalized at every steps of the tessellation.
streams.normalWS = normalize(streams.normalWS);
}
float ComputeClipping(InputPatch<Input, InputControlPointCount> input, const OutputPatch<Input2, 3> output, inout Constants constants)
{
return ComputeClippingGroup3(input[0].PositionWS, input[1].PositionWS, input[2].PositionWS);
}
float ComputeClippingGroup3(float4 f3Position1, float4 f3Position2, float4 f3Position3)
{
float4 clipPos1 = this.ComputeShadingPosition(float4(f3Position1.xyz, 1.0f));
float4 clipPos2 = this.ComputeShadingPosition(float4(f3Position2.xyz, 1.0f));
float4 clipPos3 = this.ComputeShadingPosition(float4(f3Position3.xyz, 1.0f));
float3 clipPos1P = sign(clipPos1.xyz + clipPos1.www);
float3 clipPos1M = sign(clipPos1.xyz - clipPos1.www);
float3 clipPos2P = sign(clipPos2.xyz + clipPos2.www);
float3 clipPos2M = sign(clipPos2.xyz - clipPos2.www);
float3 clipPos3P = sign(clipPos3.xyz + clipPos3.www);
float3 clipPos3M = sign(clipPos3.xyz - clipPos3.www);
float3 planeTests = abs(clipPos1P + clipPos1M + clipPos2P + clipPos2M + clipPos3P + clipPos3M);
return all(planeTests != 6.0f) ? 0.0 : 1.0;
}
void InterpolateBarycentric(const OutputPatch<Input, 3> input, in Constants constants, float3 f3BarycentricCoords)
{
//streams = input[0] * fU + input[1] * fV + input[2] * fW;
float fU = f3BarycentricCoords.x;
float fV = f3BarycentricCoords.y;
float fW = f3BarycentricCoords.z;
streams = input[0] * fU + input[1] * fV + input[2] * fW;
}
};
namespace %YOUR_PROJECT_NAMESPACE_GOES_HERE.RENDERING_MAYBE?
{
using Stride.Core;
using Stride.Rendering;
using Stride.Rendering.Materials;
using Stride.Shaders;
[DataContract("TessCustomFeature")]
[Display("Custom Tessellation")]
public class TessCustomFeature : MaterialTessellationBaseFeature
{
public override void GenerateShader(MaterialGeneratorContext context)
{
base.GenerateShader(context);
if (hasAlreadyTessellationFeature)
return;
// set the tessellation method used enumeration
context.MaterialPass.TessellationMethod |= StrideTessellationMethod.Flat;
// create and affect the shader source
var tessellationShader = new ShaderMixinSource();
tessellationShader.Mixins.Add(new ShaderClassSource("TessCustom"));
context.Parameters.Set(MaterialKeys.TessellationShader, tessellationShader);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment