Skip to content

Instantly share code, notes, and snippets.

Last active April 30, 2021 22:13
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save Cyanilux/36dd5e3df9e7612532ab7c30a4da4342 to your computer and use it in GitHub Desktop.
Allows you to inject tessellation into SG & URP, but hacky / can be difficult to work with. Unsure if the same method can work for HDRP. Also see : Tested in v10. Could definitely break at some point, use at your own risk :)
// @Cyanilux
// Note : Also requires setting up "_TessellationUniform" Float in Blackboard
Allows you to inject tessellation into SG & URP, but hacky / can be difficult to work with.
While this works, it's maybe not as useful as you might think. I believe any vertex displacement would need to be
taken out of the graph and moved into the domain function below (since tessellation still runs after vertex shader).
I thought about using the VertexDescriptionFunction from the generated code, but sadly that's generated after the injection point
so can't be called as it's undeclared at that point.
Perhaps based on this someone can figure out a better way to handle it though, without having to edit the code a ton?
Or we just wait until official SG tessellation support comes.
// Custom Function node, have a single Float output, use String mode. Name isn't important. Body :
Out = 0;
} // ends the function defined by the node
#pragma require tessellation
#pragma hull hull
#pragma domain domain
#include "Assets/.../SGTessellation.hlsl" // change this to the path of this file
void dummy(){
// creates a dummy function for the closing bracket added by the node.
// Since it outputs 0, we can connect it anywhere to the graph by just using an Add node.
// Alternatively, use a Float/Vector input and send the same thing out.
// -----------------------------------------------------------------------------------------------
// Had to use this as Attributes/Varyings structs were defined after the injection point.
// May have changed in v10 though
struct TessellationOutput {
float4 positionCS : SV_POSITION;
float4 tex0 : TEXCOORD0;
float4 tex1 : TEXCOORD1;
//... etc
// This part (and in the domain below) needs editing to interpolate each thing the SG uses,
// which probably requires looking at the generated code.
// I guess you could just interpolate all the possible TEXCOORDs,
// but unsure if that makes the shader more expensive if some are unused?
#if defined(SHADER_API_D3D11) || defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE) || defined(SHADER_API_VULKAN) || defined(SHADER_API_METAL) || defined(SHADER_API_PSSL)
# define UNITY_domain domain
# define UNITY_partitioning partitioning
# define UNITY_outputtopology outputtopology
# define UNITY_patchconstantfunc patchconstantfunc
# define UNITY_outputcontrolpoints outputcontrolpoints
struct TessellationFactors {
float edge[3] : SV_TessFactor;
float inside : SV_InsideTessFactor;
TessellationFactors patchConstantFunction (InputPatch<TessellationOutput, 3> patch) {
TessellationFactors f;
f.edge[0] = _TessellationUniform;
f.edge[1] = _TessellationUniform;
f.edge[2] = _TessellationUniform;
f.inside = _TessellationUniform;
return f;
TessellationOutput hull (InputPatch<TessellationOutput, 3> patch, uint id : SV_OutputControlPointID) {
return patch[id];
TessellationOutput domain(TessellationFactors factors, OutputPatch<TessellationOutput, 3> patch,
float3 barycentricCoordinates : SV_DomainLocation) {
TessellationOutput v;
#define INTERPOLATE(fieldName) v.fieldName = \
patch[0].fieldName * barycentricCoordinates.x + \
patch[1].fieldName * barycentricCoordinates.y + \
patch[2].fieldName * barycentricCoordinates.z;
//... etc
return v;
// Tessellation code based on :
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment