# Vertex to cube using geometry shader

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

## Recommended Posts

Hi all,
While playing around/ experimenting with geometry shaders, I tried to "expand" a point/ vertex (input) to rendering a cube (output). I managed to do this like this:

- create 14 vertices in the GS
- give them all their correct normals and own UV's
- output all vertices as one big triangle strip

Functionally this gives the aimed result.
Although I'm curious if there are better/ other to achieve this with a geometry shader, for example by using a triangle list (indices) or some other way.

Let me know what you think.

##### Share on other sites

I'd actually advice against a geometry shader here and use hardware instancing. Not only is it simpler and allows for other geometry without changing the shaders it will also be likely much faster (Edit: Wrong! See MJP's link below, instancing can turn out bad for low vertex count). One can also only do triangle strips and no indexed drawing with a geo shader (at least not without going through other hoops like stream-out).

PS: I'm still curious how you pulled that off with 14 vertices only

##### Share on other sites

PS: I'm still curious how you pulled that off with 14 vertices only

Theoretically, one only need render the 3 faces visible to the camera...

##### Share on other sites

PS: I'm still curious how you pulled that off with 14 vertices only

14 tristrip cube in the vertex shader using only vertex ID (no UVs or normals):
b = 1 << i;
x = (0x287a & b) != 0;
y = (0x02af & b) != 0;
z = (0x31e3 & b) != 0;
Edited by Matias Goldberg

Nice bithackery

##### Share on other sites

The bithackery is a bridge too far for me :)

Thanks all, I agree that isn't the 'ideal' situation to achieve what I'm doing, but I'm just trying out Geometry shaders, to understand them.

I thought I had it, but I didn't or just broke it.

While trying to fix it, I think I've found a problem with the approach, some vertices are shared in faces, which causes a problem with the normals.

Resulting in 'half a cube' being visible.

Here's the code and the result:

	float3 gNormals[14] =
{
float3(0.0f, 0.0f, -1.0f),
float3(0.0f, 0.0f, -1.0f),
float3(0.0f, 0.0f, -1.0f),
float3(0.0f, 0.0f, -1.0f),

float3(1.0f, 0.0f,  0.0f),
float3(1.0f, 0.0f,  0.0f),
float3(1.0f, 0.0f,  0.0f),

float3(-1.0f, 0.0f,  0.0f),
float3(-1.0f, 0.0f,  0.0f),
float3(-1.0f, 0.0f,  0.0f),
float3(-1.0f, 0.0f,  0.0f),

float3(0.0f, 0.0f,  1.0f),
float3(0.0f, 0.0f,  1.0f),
float3(0.0f, 0.0f,  1.0f)
};

float4 boxv[14];
boxv[0] = float4(gin[0].CenterW.x	-halfWidth, gin[0].CenterW.y	+halfHeight, gin[0].CenterW.z	-halfDepth, 1.0f);
boxv[1] = float4(gin[0].CenterW.x	+halfWidth, gin[0].CenterW.y	+halfHeight, gin[0].CenterW.z	-halfDepth, 1.0f);
boxv[2] = float4(gin[0].CenterW.x	-halfWidth, gin[0].CenterW.y	-halfHeight, gin[0].CenterW.z	-halfDepth, 1.0f);
boxv[3] = float4(gin[0].CenterW.x	+halfWidth, gin[0].CenterW.y	-halfHeight, gin[0].CenterW.z	-halfDepth, 1.0f);
boxv[4] = float4(gin[0].CenterW.x	+halfWidth, gin[0].CenterW.y	-halfHeight, gin[0].CenterW.z	+halfDepth, 1.0f);
boxv[5] = float4(gin[0].CenterW.x	+halfWidth, gin[0].CenterW.y	+halfHeight, gin[0].CenterW.z	-halfDepth, 1.0f);
boxv[6] = float4(gin[0].CenterW.x	+halfWidth, gin[0].CenterW.y	+halfHeight, gin[0].CenterW.z	+halfDepth, 1.0f);
boxv[7] = float4(gin[0].CenterW.x	-halfWidth, gin[0].CenterW.y	+halfHeight, gin[0].CenterW.z	-halfDepth, 1.0f);
boxv[8] = float4(gin[0].CenterW.x	-halfWidth, gin[0].CenterW.y	+halfHeight, gin[0].CenterW.z	+halfDepth, 1.0f);
boxv[9] = float4(gin[0].CenterW.x	-halfWidth, gin[0].CenterW.y	-halfHeight, gin[0].CenterW.z	-halfDepth, 1.0f);
boxv[10] = float4(gin[0].CenterW.x	-halfWidth, gin[0].CenterW.y	-halfHeight, gin[0].CenterW.z	+halfDepth, 1.0f);
boxv[11] = float4(gin[0].CenterW.x	+halfWidth, gin[0].CenterW.y	-halfHeight, gin[0].CenterW.z	+halfDepth, 1.0f);
boxv[12] = float4(gin[0].CenterW.x	-halfWidth, gin[0].CenterW.y	+halfHeight, gin[0].CenterW.z	+halfDepth, 1.0f);
boxv[13] = float4(gin[0].CenterW.x	+halfWidth, gin[0].CenterW.y	+halfHeight, gin[0].CenterW.z	+halfDepth, 1.0f);

int index[14] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};

GeoOut gout;
[unroll]
for(int i=0;i<14;++i)
{
gout.PosH     = mul(boxv[index[i]], gViewProj);
gout.PosW     = boxv[index[i]].xyz;
gout.NormalW  = gNormals[index[i]];
gout.Tex      = gTexC[index[i]];
gout.PrimID   = primID;

triStream.Append(gout);
}



I might be able to fix it, by adding additional vertices and coming to 6 faces * 4 vertices = 24 vertices.

Any other ideas?

##### Share on other sites
Not really, that's why I was stumped. I don't think you can get any better, IIRC 24 vertices is the minimal amount if you need normals (and tex-coords for that matter). For the geo shader also a restart-strip after every quad.

One could probably play merging the tex-coords somehow, but I expect some (undesired?) mirroring or something. And you can generate the normals in the pixel shader if you pass along a position (using gradients):

normal = normalize(cross(ddx(pos), ddy(pos)));

It may be a good exercise, but that's really too complicated for a simple cube IMO.

##### Share on other sites
Thanks. For practice I'll go for 24 vertices and restart strip per quad. Then I'll call it enough for practice.
Update: besides the normals/ UV's it actualy did work, I just didn't change the max vertices output of the GS from 8 to 14.

The actual exercise was making a cylinder without caps, but I wanted to play around first and see if a cube was possible. Edited by cozzie

##### Share on other sites
Thanks, interesting and clearly related.
Also good to see that he also achieved it with 14 vertices (probably accepting the overlapping normals and UV issue).

1. 1
2. 2
Rutin
17
3. 3
4. 4
5. 5

• 26
• 11
• 9
• 9
• 11
• ### Forum Statistics

• Total Topics
633702
• Total Posts
3013449
×