PN-AEN Triangles GLSL

Hi.
I’ve been doing some work regarding tessellation techniques for smoothing meshes. Plain PN Triangle was pretty easy to implement but I have quite a problem with PN-AEN Triangles. I’ve searched over the net looking for implementation in GLSL but I’ve found nothing. I hope you will help me understand if this can or cannot be done in GLSL.

I wont describe all PN-AEN T. but explain what doesn’t seems to work…

First…is it possible for TCS to pass further into pipeline only 3 vertices insteed of 9 defined in patch? I’m aware of “layout(vertices = 3) out” but from what I can tell, when I set TES to triangles it consumes all 9 vertices from patch and makes 3 triangles instead of wanting 1. I can check this by using gl_PrimitiveID in TES. I have indices like this for eg.:
1,2,3, - those I want to see as triangle
4,5,6,7,8,9, - those are control points only for calculations (end of first patch)
10,11,12, - triangle
13,14,15,16,17,18 - calculations (end of second patch)
I can see triangle (10,11,12,) only when (gl_PrimitiveID <= 3) - so 4,5,6 and 7,8,9 also make triangles (I can sometimes see them as artifacts - flying on screen)

Second… does gl_InvocationID have the same order in patches as they were send to memory? From above where second patch had verts 10,11,12,13,14,15,16,17,18 is it right to assume that the first vert in this patch: 10 will have gl_Invocation: 1, next 11 - 2, 12 - 3, and so on? If not is there other way around to make them like this? I really need this so I’ve tested it and it seems that sometimes it is not consistent - for 108 indices (12 triangles, rest are control points) it fails for 2 triangles. Like in the image.
[ATTACH=CONFIG]218[/ATTACH]

I think that code is unnecessary but if someone want to look at it here it is:
TCS


#version 400

struct CP
{
	vec3 Pos[3];
	vec3 Nor[2];
};
//------------------------------
layout(vertices = 3) out;

in vec3 vPosition[];
in vec3 vNormal[];
out CP cp[];
patch out vec3 center;

uniform float TessLevelInner;
uniform float TessLevelOuter;

#define ID gl_InvocationID

void main()
{
                // for vert ID=0 use control points 3,4 (1 ID - 5,6; 2 ID - 7,8)
		int IDnext    = (ID + 1) % 3;
		int IDadd     = (ID * 2) + 3;
		int IDaddNext = IDadd + 1;
	
		vec3 P1i = vPosition[ID];
		vec3 P2i = vPosition[IDnext];
		vec3 N1i = normalize(vNormal[ID]);
		vec3 N2i = normalize(vNormal[IDnext]);

		vec3 P1o = vPosition[IDadd];
		vec3 P2o = vPosition[IDaddNext];
		vec3 N1o = normalize(vNormal[IDadd]);
		vec3 N2o = normalize(vNormal[IDaddNext]);

		vec3 posIns;
		vec3 posOut;

		cp[ID].Pos[0] = P1i;

		posIns = (2 * P1i + P2i - dot(P2i - P1i, N1i) * N1i) / 3;
		posOut = (2 * P1o + P2o - dot(P2o - P1o, N1o) * N1o) / 3;
		cp[ID].Pos[1] = (posIns + posOut) / 2;

		posIns = (2 * P2i + P1i - dot(P1i - P2i, N2i) * N2i) / 3;
		posOut = (2 * P2o + P1o - dot(P1o - P2o, N2o) * N2o) / 3;
		cp[ID].Pos[2] = (posIns + posOut) / 2;


		float r12 = 2 * dot(P2i - P1i, N1i + N2i) / dot(P2i - P1i, P2i - P1i);
			  r12+= 2 * dot(P2o - P1o, N1o + N2o) / dot(P2o - P1o, P2o - P1o);
			  r12/=2;
		cp[ID].Nor[0] = N1i;
		cp[ID].Nor[1] = N1i + N2i - r12 * (P2i - P1i);

		gl_TessLevelOuter[ID] = TessLevelOuter;

		barrier();
		if (ID == 0)
		{
			vec3 E = (cp[0].Pos[1] + cp[0].Pos[2] + 
					  cp[1].Pos[1] + cp[1].Pos[2] + 
					  cp[2].Pos[1] + cp[2].Pos[2]) / 6;
			vec3 V = (vPosition[0] + vPosition[1] + vPosition[2]) / 3;
			center = E + (E - V) / 2;

			gl_TessLevelInner[0] = TessLevelInner;
		}
}

TES


#version 400

struct CP
{
	vec3 Pos[3];
	vec3 Nor[2];
};

layout(triangles, equal_spacing, ccw) in;
in CP cp[];
patch in vec3 center;

out vec3 tePosition;
out vec3 tePatchDistance;

uniform mat4 Projection;
uniform mat4 Modelview;

void main()
{
	if(gl_PrimitiveID % 3 == 0)
	{
		float u = gl_TessCoord.x;
		float v = gl_TessCoord.y;
		float w = gl_TessCoord.z;

		vec3 pos = cp[0].Pos[0]*w*w*w   + cp[1].Pos[0]*u*u*u   + cp[2].Pos[0]*v*v*v   +
				   cp[0].Pos[1]*w*w*u*3 + cp[0].Pos[2]*w*u*u*3 + cp[1].Pos[1]*u*u*v*3 +
				   cp[1].Pos[2]*u*v*v*3 + cp[2].Pos[1]*v*v*w*3 + cp[2].Pos[2]*v*w*w*3 +
				   center * u*v*w*6;

		tePatchDistance = gl_TessCoord;
		tePosition = pos;
		gl_Position = Projection * Modelview * vec4(tePosition, 1);
	}
	else
		gl_Position = vec4(0);
}

by if(gl_PrimitiveID % 3 == 0) I can prevent (control points) triangles from showing.

OK i spend two whole days to find a tiny mistake. I even implemented it on DirectX to test it out. Basically I forgot to change patch size to 9 :D.

If I could I would edit or delete previous post but this option disappeared so let me clear things out.

Yes it’s possible and “layout(vetices=#)” works fine (which is great!)

Yes seems like it (which was kind of obvious).

So the answer to the main question…

… is also YES, here is the proof:
TCS


#version 400

struct CP
{
	vec3 Pos[3];
	vec3 Nor[2];
};

layout(vertices = 3) out;
in vec3 vPosition[];
in vec3 vNormal[];
out CP cp[];
patch out vec3 center;

uniform float TessLevelInner;
uniform float TessLevelOuter;

#define ID gl_InvocationID

void main()
{
		int IDnext    = (ID + 1) % 3;
		int IDadd     = (ID * 2) + 3;
		int IDaddNext = IDadd + 1;
	
		vec3 P1i = vPosition[ID];
		vec3 P2i = vPosition[IDnext];
		vec3 N1i = normalize(vNormal[ID]);
		vec3 N2i = normalize(vNormal[IDnext]);

		vec3 P1o = vPosition[IDadd];
		vec3 P2o = vPosition[IDaddNext];
		vec3 N1o = normalize(vNormal[IDadd]);
		vec3 N2o = normalize(vNormal[IDaddNext]);

		vec3 posIns;
		vec3 posOut;

		cp[ID].Pos[0] = P1i;

		posIns = (2 * P1i + P2i - dot(P2i - P1i, N1i) * N1i) / 3;
		posOut = (2 * P1o + P2o - dot(P2o - P1o, N1o) * N1o) / 3;
		cp[ID].Pos[1] = (posIns + posOut) / 2;

		posIns = (2 * P2i + P1i - dot(P1i - P2i, N2i) * N2i) / 3;
		posOut = (2 * P2o + P1o - dot(P1o - P2o, N2o) * N2o) / 3;
		cp[ID].Pos[2] = (posIns + posOut) / 2;

		float r12 = 2 * dot(P2i - P1i, N1i + N2i) / dot(P2i - P1i, P2i - P1i);

		cp[ID].Nor[0] = N1i;
		cp[ID].Nor[1] = N1i + N2i - r12 * (P2i - P1i);

		gl_TessLevelOuter[ID] = TessLevelOuter;

		barrier();
		if (ID == 1)
		{
			vec3 E = (cp[0].Pos[1] + cp[0].Pos[2] + 
					  cp[1].Pos[1] + cp[1].Pos[2] + 
					  cp[2].Pos[1] + cp[2].Pos[2]) / 6;
			vec3 V = (cp[0].Pos[0] + cp[1].Pos[0] + cp[2].Pos[0]) / 3;
			center = E + (E - V) / 2;

			gl_TessLevelInner[0] = TessLevelInner;
		}
}

for some reasons “gl_TessLevelOuter[gl_InvocationID] = TessLevelOuter;” doesnt seem to work in my 6XXX mobile radeon (but works in 5XXX). Maybe it’s something with ‘gl_InvocationID’. If you have similar problem just put there real numbers 0,1,2 and move it to ‘if’ body.

TES


#version 400

struct CP
{
	vec3 Pos[3];
	vec3 Nor[2];
};

layout(triangles, equal_spacing, ccw) in;
in CP cp[];
patch in vec3 center;

precise out vec4 P;
precise out vec3 N;
precise out vec3 E;

uniform mat4 MProjection;
uniform mat4 MModelview;
uniform mat3 MNormal;

void main()
{
	float u = gl_TessCoord.x;
	float v = gl_TessCoord.y;
	float w = gl_TessCoord.z;

	precise vec3 pos = cp[0].Pos[0]*w*w*w   + cp[1].Pos[0]*u*u*u   + cp[2].Pos[0]*v*v*v   +
			   cp[0].Pos[1]*w*w*u*3 + cp[0].Pos[2]*w*u*u*3 + cp[1].Pos[1]*u*u*v*3 +
			   cp[1].Pos[2]*u*v*v*3 + cp[2].Pos[1]*v*v*w*3 + cp[2].Pos[2]*v*w*w*3 +
			   center * u*v*w*6;
			   
	precise vec3 nor = cp[0].Nor[0]*w*w + cp[1].Nor[0]*u*u + cp[2].Nor[0]*v*v + 
			   cp[0].Nor[1]*w*u + cp[1].Nor[1]*u*v + cp[2].Nor[1]*v*w;

    P = MProjection * MModelview * vec4(pos, 1);
    E = -(MModelview * vec4(pos,1)).xyz;
    N = MNormal * nor;
}

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.