Jump to content
  • Advertisement
Sign in to follow this  
terryeverlast

Subdividing using the geometry shader and applying texture.

This topic is 1079 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Im trying to subdivide a icosahedron. I can subdivide it one time withi this code:

void Subdivide(VertexOut inVerts[3], out VertexOut outVerts[6])
{
	//			1
	//			*
	//		   / \
	//		  /   \
	//	   m0*-----*m1
	//	    / \	  /	\
	//     /   \ /   \
	//    *-----*-----*
	//   0     m2     2

	VertexOut m[3];

	inVerts[0].PosL = normalize(inVerts[0].PosL);
inVerts[1].PosL = normalize(inVerts[1].PosL);
inVerts[2].PosL = normalize(inVerts[2].PosL);
// compute edge midpoints
m[0].PosL = 0.5f * (inVerts[0].PosL + inVerts[1].PosL);
m[1].PosL = 0.5f * (inVerts[1].PosL + inVerts[2].PosL);
m[2].PosL = 0.5f * (inVerts[2].PosL + inVerts[0].PosL);
m[0].PosL = normalize(m[0].PosL);
m[1].PosL = normalize(m[1].PosL);
m[2].PosL = normalize(m[2].PosL);

	// derive normals
	m[0].NormalL = m[0].PosL;
	m[1].NormalL = m[1].PosL;
	m[2].NormalL = m[2].PosL;

	// interpolate texture coordinates
	m[0].Tex = 0.5f * (inVerts[0].Tex + inVerts[1].Tex);
	m[1].Tex = 0.5f * (inVerts[1].Tex + inVerts[2].Tex);
	m[2].Tex = 0.5f * (inVerts[2].Tex + inVerts[0].Tex);

	outVerts[0] = inVerts[0];
	outVerts[1] = m[0];
	outVerts[2] = m[2];
	outVerts[3] = m[1];
	outVerts[4] = inVerts[2];
	outVerts[5] = inVerts[1];
}

void OutputSubdivision(VertexOut v[6], inout TriangleStream<GeoOut> stream)
{
	GeoOut gout[6];

	[unroll]
	for(int i = 0; i < 6; ++i)
	{
		// Transform to World Space
		gout[i].PosW = mul(float4(v[i].PosL, 1.0f), gWorld).xyz;
		gout[i].NormalW = mul(v[i].NormalL, (float3x3)gWorldInvTranspose);

		// Transform to homogeneous clip space
		gout[i].PosH = mul(float4(v[i].PosL, 1.0f), gWorldViewProj);
		
		gout[i].Tex = v[i].Tex;
	}

	//			1
	//			*
	//		   / \
	//		  /   \
	//	   m0*-----*m1
	//	    / \	  /	\
	//     /   \ /   \
	//    *-----*-----*
	//   0     m2     2

	// We can draw the subdivision in two strips:
	// strip 1: bottom three triangles
	// strip 2: top triangle

	[unroll]
	for(int j = 0; j < 5; ++j)
	{
		stream.Append(gout[j]);
	}
	stream.RestartStrip();

	stream.Append(gout[1]);
	stream.Append(gout[5]);
	stream.Append(gout[3]);

		}

[maxvertexcount(8)]
void GS(triangle VertexOut gin[3], inout TriangleStream<GeoOut> stream)
{	
	VertexOut v[6];
	Subdivide(gin, v);
	OutputSubdivision(v, stream);

}

How can I divide it twice? I tried recursion, didn't work! btw..I have to do it in the geometry shader, my book says

Edited by terryeverlast

Share this post


Link to post
Share on other sites
Advertisement
[Sorry, post deleted: I didn't read the last part of the topic and suggested using tessellation instead. Moderators may delete my post.]

Share this post


Link to post
Share on other sites

If you want to do recursive GS tessellation, which I'm pretty sure you probably don't really want to do and your book is making you do something weird, you divide it twice by setting the stream out VB as the input VB. You call deviceContext->Draw twice.

 

Alternatively you can output a crap-ton of triangles out of your geometry shader but there's no reason to do this.

 

Make sure you recurse on object-space vertices. In your example you're outputting projected vertices, you don't want to recurse on those.

 

This whole thing is really slow and the whole point of using a GPU is to make things fast. One obvious problem with this type of tessellation is that the GS is way more flexible than you need it to be for this particular task. You know exactly how many output vertices you're going to get. You could actually do this analytically and generate an icosohedron with just a vertex shader, switch based on vertex ID, and write to a UAV.

Edited by Dingleberry

Share this post


Link to post
Share on other sites
you divide it twice by setting the stream out VB as the input VB

 

What is a vb. I think you mean Vertex Buffer right? what part of the code do I edit to replace the out vb as the input vb?

 

thx

Edited by terryeverlast

Share this post


Link to post
Share on other sites


what part of the code do I edit to replace the out vb as the input vb?

 

Pretty sure he means running the C++ code that uses the shader twice, using stream output to not draw the vertices output from the GS but rather store them in a temporary vertex buffer, which is then used as input during the second draw-call. You're trying to do something really custom that isn't a common use-case, so there won't be any simple answers.

Read the documentation for geometry shaders and stream output and experiment and you can surely make it happen anyway if you really want to...

Share this post


Link to post
Share on other sites

I once implemented recursive tessellation using multi-pass GS (when the tessellator stage was not yet available for D3D). While it worked quite well and did allow - albeit coarsely - dynamic tessellation factors and a custom domain function, it was very slow when run in hardware. This is because each draw call costs some time and this scenario represents the worst case in which all the inputs of the subsequent passes depend on the previous pass (which causes pipeline stall).

 

Also, GS generally trades flexibility for speed. As Dingleberry said, it is best to use hardware features in scenarios where they actually reduce processing time.

 

One of the good scenarios for GS is particle ampilification. You'd throw in particle attributes as single vertices and get out quads, triangles, snowflakes, paper aeroplanes or whatever you can make from about 0-10 primitives - max amount depending on the output vertex complexity. GS flexibility allows you to perform final transform during the amplification, so your particles could, for example, rotate about their own center for practically free (think snowflakes).

 

An another good scenario is shadow volume extrusion. In this case, only the edges that lie on the tangent boundary of the mesh with regard to the light direction vector are amplified, while others are discarded. This is quite efficient to do on GS as generally, waterproof alternatives need at least one more draw call and extra memory consumption and work on the CPU side.

Edited by Nik02

Share this post


Link to post
Share on other sites

Ok i got a icosahedron subdivided twice with a geometric approach. But my only problem is putting the texture on it.

How do i interpolate a triangle that has vertices like the one below to put a texture on to it?

 

8vxjjo.png

Its possible right??

 

Currently the sphere looks like

 

2a6qatf.jpg

Edited by terryeverlast

Share this post


Link to post
Share on other sites

Create the texture coordinates from the position on the sphere. You can turn 3D sphere coordinates into polar coordinates pretty easily, or use a cube map. Those are the most basic solutions. 

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!