I have, to my knowledge, properly implemented the phong tessellation code, as presented in http://www.klayge.org/material/4_0/PhongTess/PhongTessellation.pdf
Despite that, when I use a shape factor of 1 on an icosphere from blender, I don't get any change in shape. It remains a flat sided icosphere instead of deforming towards a sphere based on the shape factor.
I'm posting my vertex, hull, and domain shader code that is relevant to phong tessellation in hope that someone can figure out why it isn't becoming a sphere.
Vertex:
VertexShaderOutput output;
output.position = float4(input.position, 1.0f);
output.wPos = mul(output.position, world);
output.position = mul(output.position, mul(mul(world, view), projection));
output.normal = mul(float4(input.normal, 0.0f), world);
return output;
Hull:
float CalcTessFactor(float3 v0WPos, float3 v1WPos)
{
float edgeLen = distance(v0WPos, v1WPos);
float edgeCamDist = distance((v0WPos+v1WPos)/2, camPos.xyz);
return clamp((edgeLen*576) / (edgeCamDist*50), 1.0f, 63.0f);
}
HullShaderConstDataOutput CalcHSPatchConstants(InputPatch<HullShaderInput, NUM_CONTROL_POINTS> ip)
{
HullShaderConstDataOutput output;
if (ShouldPatchBeClipped(ip[0].position, ip[1].position, ip[2].position))
{ output.EdgeTessFactor[0] = output.EdgeTessFactor[1] = output.EdgeTessFactor[2] = output.InsideTessFactor = 0; }
else
{
[unroll] for (int i=0; i<NUM_CONTROL_POINTS; i++) {output.EdgeTessFactor[i] = CalcTessFactor(ip[(i+1)%3].wPos.xyz, ip[(i+2)%3].wPos.xyz);}
output.InsideTessFactor = (output.EdgeTessFactor[0] + output.EdgeTessFactor[1] + output.EdgeTessFactor[2]) / 3;
}
return output;
}
[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("CalcHSPatchConstants")]
HullShaderOutput main(InputPatch<HullShaderInput, NUM_CONTROL_POINTS> ip, uint i : SV_OutputControlPointID)
{ return ip[i]; }
Domain:
#define NUM_CONTROL_POINTS 3
#define BARYCENTRIC_INTERPOLATE(structVar) u*patch[0].structVar + v*patch[1].structVar + w*patch[2].structVar
float3 OrtoProject(float3 q, float3 p, float3 n)
{
return q - dot((q - p), n) * n;
}
[domain("tri")]
DomainShaderOutput main
( DomainShaderConstDataInput input, float3 barycentric : SV_DomainLocation,
const OutputPatch<DomainShaderInput, NUM_CONTROL_POINTS> patch )
{
DomainShaderOutput output;
float u = barycentric.x, v = barycentric.y, w = barycentric.z;
float3 Puv = BARYCENTRIC_INTERPOLATE(wPos.xyz);
float shapeFactor = 1;
output.wPos = float4((1 - shapeFactor)*Puv + shapeFactor * float3
(
u*OrtoProject(Puv, patch[0].wPos.xyz, patch[0].normal) +
v*OrtoProject(Puv, patch[1].wPos.xyz, patch[1].normal) +
w*OrtoProject(Puv, patch[2].wPos.xyz, patch[2].normal)
), 1.0f);
output.position = mul(mul(output.wPos, view), projection);
output.normal = BARYCENTRIC_INTERPOLATE(normal);
Alright, so it turns out that the icosphere that I took from blender has the normals be in the same direction as the triangle faces, meaning the object will only ever remain flat, as there is no change in normal angle for the tessellated triangles to adapt to. If I wanted to fix this, I'd have to combine all shared points' normals, and turn them into point specific outward pointing normals that aren't orthogonal to the triangle planes, but rather the edges of the object, such that interpolating between them will allow for a curve.
Edit: After finding out how to get an icosphere with the right normals, that hlsl much like other programming languages truncates at integer-integer division, as to make the result an integer as well, which made it so 3/4 became equal to 0, which made the ico sphere that could be phong tessellated become flat shaded much like the improper model.