How to go with billboarding geometries inside a vertex shader?

It’s not even that hard. Send a quad but set all of its corners to the appropriate points.

As said, if you show me the code for how you are making your quads and geometries then I will show you how to make them work with what we’ve been talking about. But that’s the third time I’ve asked that so it is the last time. Feel free to pursue other paths but I don’t think I will be helping with them.

LOL yes I’m so sorry, I simply forgot that yesterday :smiley: I do understand how frustating it can be to try and help people that do not cooperate XD I’m sorry for this, I didn’t mean to hide things from you.

So here’s what I think is relevant from my code (still have not modified anything regarding the new scenario described above) but if you need anything else, just ask.

Some variables are not defined in this scope, but you know it’s randomization at this point.

[java]
// Setup
Node flowerLayer = new Node(“Flower Layer”);

// Create approx 1000 flowers
for(int i = 0; i < heightmap.length; i++){
Node flowerPatch = new Node();
Quad faceShape = new Quad(selectedSizeVariation, selectedSizeVariation); // <— OF COURSE this will become a point instead
Geometry face = new Geometry(“face”,faceShape);
flowerPatch.attachChild(face);
flowerPatch.setLocalTranslation(location);
flowerPatch.move(r2 * 5f, -selectedSizeVariation/4.5f, r3 * 5f);
}

// Batch optimization
GeometryBatchFactory.optimize(flowerLayer);
rootNode.attachChild(flowerLayer);

// Materialize those flowers
Texture tex = this.getApplication().getAssetManager().loadTexture(“Textures/daisy.png”);
Material mat = new Material(this.getApplication().getAssetManager(), “Shaders/Grass/grassBase.j3md”);
mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
mat.setTextureParam(“ColorMap”,VarType.Texture2D,tex);
mat.setBoolean(“VertexLighting”,true);
mat.setVector2(“Wind”, new Vector2f(1,0));
mat.setFloat(“AlphaThreshold”, 0.5f);
// <------ Are you implying I define the quad’s width/height here and update the material each frame? (No I guess!)
rootNode.getChild(“Flower Layer”).setMaterial(mat);
[/java]

For the shader part, I already understand everything, but I’m not sure how to pass the width/height to the shader somewhere in the JME3 Java code above…

Thx :smiley:

You can’t use zuegg’s code without geometry shader support which JME doesn’t support yet. It’s also potentially slower and not really needed in your case. As I’ve said like 10 times now, you just need to provide all of the necessary information in the vertex itself.

The nice thing is that Quads are really easy to work with because the vertex buffer is just four points and it’s easy to remember their orientation.

To get the code I posted earlier to work, all you have to do is change the quad a little.
[java]
// Your original creation is fine
Quad faceShape = new Quad(selectedSizeVariation, selectedSizeVariation);

// And then just modify the vertexes to center over 0,0,0 in x.
faceShape.setBuffer(Type.Position, 3, new float[]{0, 0, 0,
0, 0, 0,
0, selectedSizeVariation, 0,
0, selectedSizeVariation, 0
});
[/java]

You don’t even really have to update the bounding shape.

Maybe this image will help… or maybe it will be more confusing. Here are two pictures of a quad. One is the standard way (if you pretend width and height are 1, 1)

Not coincidentally, the texture coordinates are the same as what I’ve put as position.

The second image is what we’ve done by making all of the X values the same. The green arrows represent what will be done in the shader. Note: the texture coordinates have not changed so we can use those to determine which corner the vertex is… which is what the previous code I posted does.

1 Like

Actually, it occurs to me that you could get the same effect just by creating the quad with width 0… but we don’t learn as much from that. :slight_smile:

If you ever want things like a texture atlas or whatever then you may need to mess with the texture coordinates and use something else to determine corners/offsets and it’s useful to know how to punch this stuff directly into an already created Quad.

Paul, thank you for this, I gave you +1 as it adds very useful information regarding the situation. Tough, I never implied I’d use a geometry shader to begin with so I totally agree on this. I understand the vertex emitting is only done in a geometry shader and that it’s faster to let the GPU handle rotation matrices in parallel instead of asking a core to procedurally output 4 vertices one by one. I’ve read in the couple last months from different sources that it was slower for this technique because of this. So the vertex shader method is exactly where I’ve been headed from the start. THIS is the only piece of information I was missing to implement my billboard vertex shader: the VBO hacking part and you pointed the exact thing I was looking for:

@pspeed said: [java] // And then just modify the vertexes to center over 0,0,0 in x. faceShape.setBuffer(Type.Position, 3, new float[]{0, 0, 0, 0, 0, 0, 0, selectedSizeVariation, 0, 0, selectedSizeVariation, 0 }); [/java]

I have a question regarding your second post:

@pspeed said: Actually, it occurs to me that you could get the same effect just by creating the quad with width 0...

What do you mean by this tough? My quads are not square BTW… were you implying they were? If so, I understand why you posted this, but they’re not, so I’m not sure if I’m missing a point about your statement.

I’m learning you know, so some stuff is really chinese for me at the moment, but I do learn by reading your thoughts on the matter. Thank you guys.

The quad code you posted was for square quads. They had the same width and height.

I just meant that my example of setting the vertexes manually is no different than new Quad(0, selectedSizeVariation)

…but the manually setting way is more educational.

If you need quads of varying widths (which your code did not show and I can only really deal with what is provided) then you will need a slightly different solution.

OH… sorry, I have read my post again and you’re right, I’ve not provided an example of different width/height, but in reality, I have different kinds of flowers and they’re not all square size textures. That’s why I was surprised of that assumption.

But I figure I could simply pass another float: the width/height proportion. For instance if my flower is tall, this float would be like 0.5f meaning for every 1f wide unit, it would be 2f units tall (X/Y) no?

Anyhow, I have PLENTY of information now to make this work. Let me play with my code and see if I can come up with something optimized and working fine.

I’ll post again here with screenshots later today or tomorrow when I finally complete this.

Thanks again so much for all your time.

Hi again guys!

So for future reference and to WHOEVER searched and found nothing concerning the VERTEX SHADER BILLBOARDING WITH SCALING, here is what I did to accomplish my GeometryBatchFactory’ed thousands of textured quads of different size billboarding via the GPU using solely a vertex shader and a little VBO hacking:

(Please note that my texture DAISY.PNG is a SQUARE texture, 512x512, this won’t work with non-square textures, but it could work with little adaptation tough and also note that I stripped the randomization process to lighten the code)

In JME3 Java code, I created my thousands of quads like this:

[java]
// Setup
Node flowerLayer = new Node(“Flower Layer”);

// Create a layer of 2000 flowers
for(int i = 0; i < 2000; i++){
// Random size and position
float s = 2.5f // Imagine a random size here
Vector3f location = new Vector3f(1,2,3); // Imagine a random position here

Node flowerPatch = new Node();
Quad faceShape = new Quad(s, s);

// Billboarding flat vegetation
faceShape.setBuffer(Type.Position, 3, new float[]{0, 0, 0,
0, 0, 0,
0, s, 0,
0, s, 0});

faceShape.setBuffer(Type.TexCoord2, 2, new float[]{s, 0, // ANYBODY SEES A BETTER WAY TO COMPRESS THIS?
s, 0,
s, 0,
s, 0});

Geometry face = new Geometry(“face”,faceShape);
flowerPatch.attachChild(face);
flowerPatch.setLocalTranslation(location);
}

// Batch optimization
GeometryBatchFactory.optimize(flowerLayer);
rootNode.attachChild(flowerLayer);

// Materialize those flowers
Texture tex = this.getApplication().getAssetManager().loadTexture(“Textures/daisy.png”);
Material mat = new Material(this.getApplication().getAssetManager(), “Shaders/Grass/grassBase.j3md”);
mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
mat.setTextureParam(“ColorMap”,VarType.Texture2D,tex);
mat.setBoolean(“VertexLighting”,true);
mat.setVector2(“Wind”, new Vector2f(1,0));
mat.setFloat(“AlphaThreshold”, 0.5f);

// Attach my flower layer (the thousands of quads)
rootNode.getChild(“Flower Layer”).setMaterial(mat);
[/java]

<br />

EDIT: BTW, see on line 19 above, does anybody see an optimization instead of pushing 8 floats (for a quad) only for ONE float (my desired quad width) is there any other buffer I could use that would only use 4 floats or even better: is there a way to compress it inside the position buffer or some other buffer that is constantly pushed in the VBO?

<br /> <br /> <br />

Now I used this in my vertex shader:

(You’ll notice I do this: if(inTexCoord2.x > 0) to isolate the billboarding code because this vertex shader is also used on non-billboarded quads that are crossed in X shape to give a fake depth, like you can see in @vvishmaster’s original and very good grassBase.j3md shader)

[java]
// ---------- Billboarding effect ----------
if(inTexCoord2.x > 0){
// Convert vertex location to world-view space, ie: camera-relative space
pos = g_WorldViewMatrix * pos;

    // Figure out how to offset it in camera space
    float offset = texCoord.x - 0.5;  // (make it -0.5 to 0.5)
    pos.x += offset * inTexCoord2.x;
}
// -----------------------------------------

#ifdef SWAYING
float angle = (g_Time + pos.x*m_SwayData.y) * m_SwayData.x;
pos.xz += 0.1*m_Wind*inTexCoord.y*sin(angle);
#endif

if(inTexCoord2.x &gt; 0){
    // Billboarding effect projection matrix
    gl_Position = g_ProjectionMatrix * pos;
}
else{
    // NOT billboarding effect projection matrix
    gl_Position = g_WorldViewProjectionMatrix * pos;
}

[/java]

I must say that I did not invent anything here, it’s all other people’s work combined and even after staring at the screen for more than 1 hour, I still couldn’t QUITE understand why pos.x += offset does the trick, but I guess it’s all a matter of PROJECTION. It’s just maths I’m not used to AT ALL, but in the end I must say I feel SO GOOD to finally see it working! It’s flawless! :stuck_out_tongue: LOOK AT THOSE DAISIES. LOOK AT THEM! ISN’T THAT WONDERFUL?! I have to go to bed now, but I swear tomorrow morning I shalln’t resist and I’ll be downloading dozens of transparent PNG’s and make all kinds of flowers pop everywhere on the infinite terrain like crazy. Different colors, different sizes, it’s just… it’s a wonderful feeling! :stuck_out_tongue: ok enough.

Can’t wait to get crazy with the flowers popping :stuck_out_tongue: Off to bed now! XD

Thx again @pspeed and a little @zzuegg too for geometric shader even if I did not use it, it’s always good to read and try to learn stuff from others and get all those points of view. I like being led by example, it’s much easier.

[java]
faceShape.setBuffer(Type.TexCoord2, 2, new float[]{s, 0, // ANYBODY SEES A BETTER WAY TO COMPRESS THIS?
s, 0,
s, 0,
s, 0});
[/java]

Instead you could do:
[java]
faceShape.setBuffer(Type.Size, 1, new float[]{-s, s, s, -s});
[/java]

Note that I’ve given the sizes signs so that they identify the corners. This would let you use a texture atlas even since now the regular texture coordinates can be 100% independent of the ‘size’.

Use inSize in the shader for the value… then just wvPos.x += inSize * 0.5;

1 Like

Wow, incredibly efficient. I did not go to bed. :stuck_out_tongue: Man, I have to get off the computer now. It’s like… WTF I’m so addicted to this! :stuck_out_tongue: Thx again Paul! Very useful tricks. Gave you +1 again.

Nice stuff :). Just to clarify i did not make grassBase.j3md i used it from theForester beta plugin. :slight_smile:

O’RLY. But it’s still because of your post that I discovered it tough :stuck_out_tongue:

There is btw one other possibility for doing this,
useing point meshes and a fragment shader can create the same result. But might be slower due to additional calculations required.

Interesting, but looks even more complicated tough. What would be the advantage of doing it in the fragment shader? Isn’t the whole idea to displace VERTICES?

@Empire Phoenix said: There is btw one other possibility for doing this, useing point meshes and a fragment shader can create the same result. But might be slower due to additional calculations required.

If you mean by using point sprites then they have the limitation that on about half the cards there is a maximum on-screen size (64 pixels in many cases). Also, I never found a way to do anything but screen oriented sprites.

If you mean something else then I’m interested too.

Well basically you create a screenorientation to correctposition matrix, and pipe all texturecoordinates used trough it. The pro is, that it is only done for visible fragments, and that no calculation is necessarly for all not visible/occluded ones(talking about real graficcards here not intel stuff), so you can do way larger batches this way. Also a point vertex buffer is faster to upload.

Are the cards with that limit anywhere near current gamining graficcards?

@Empire Phoenix said: Well basically you create a screenorientation to correctposition matrix, and pipe all texturecoordinates used trough it. The pro is, that it is only done for visible fragments, and that no calculation is necessarly for all not visible/occluded ones(talking about real graficcards here not intel stuff), so you can do way larger batches this way. Also a point vertex buffer is faster to upload.

Are the cards with that limit anywhere near current gamining graficcards?

Yep. Many many ATI cards, I think. Some nVidia cards, too. Mostly I see it in the ATI cards. I don’t know exact counts.

Enough that I will completely abandon point sprites for anything other than small stuff.

Also, ATI cards seem to not draw the sprite if the point is off the screen nVidia will still draw them in my experience.

Regarding the size thing, there’s an OpenGL thing you can query to see what the size is but JME doesn’t expose this.

A little bit of googling shows:

With:


One serious limitation to the use of point sprites is that their size is limited by the range of aliased point sizes (this was discussed in Chapter 3, “Drawing in Space: Geometric Primitives and Buffers”). You can quickly determine this implementation-dependent range with the following two lines of code:

GLfloat fSizes[2];
GLGetFloatfv(GL_ALIASED_POINT_SIZE_RANGE, fSizes);

Following this, the array fSizes will contain the minimum and maximum sizes supported for point sprites, and regular aliased points.

Also, I see just as many “doesn’t work on nVidia” hits but they seem to be older. All of my nVidia cards rendered them just fine and I didn’t notice the issue until others tried my water fall effect from a long time ago that used large point sprites. After that I noticed that Mythruna’s old fire looked like little bubbles on some cards which prompted me to completely rewrite that effect.