Game Development Community

dev|Pro Game Development Curriculum

Plan for Doyoon Kim

by Doyoon Kim · 08/02/2002 (8:36 am) · 17 comments

Ok, I started experimenting with adding grass (or little shrubs) to Torque. This is just one way from my tests, so I don't want to stop anyone else from doing grass (melv and phil :).

Here's the scene with no grass:
No grass test
Now with some grass:
1 grass per triangle
grass test1
20 grass per triangle
grass test2
50
grass test3
100
grass test4
200
grass test6

Each grass blade is individually rendered as a single translucent opengl triangle. Here's how. All grass rendering is done in TerrainRender::renderBlock(). It goes through each triangle and finds any number of random points within the triangle to represent each grass blade. Finding a random point within a triangle is simple:

for (U32 i = 0; i < gTerrainGrassPerTriangle; i++) {
// lets find a random point within polygon (triangle)
F32 x = sgRandom.randF(0.0, 1.0);
F32 y = sgRandom.randF(0.0, 1.0);
F32 z;
if (x+y > 1.0) {
x = 1 - x;
y = 1 - y;
}
z = 1 - x - y;

GrassPoint randPoint;
randPoint.x = (x * point1.x) + (y * point2.x) + (z * point3.x);
randPoint.y = (x * point1.y) + (y * point2.y) + (z * point3.y);
randPoint.z = (x * point1.z) + (y * point2.z) + (z * point3.z);

Now that we have a random point, we store it in an array of grass points that we render later. For the random seed, I just use the IndexCount of the triangle strip so it'll select the same set of random points every time. There are lots of problems though such as with sorting (mine aren't yet), speed, and depth buffer issues. Another problem is that it effects the whole terrain globally.

Also, looping through every triangle in the terrain is too much so I also test the terrain chunk (square) distance to flag each chunk to render grass or not (same way detail textures are handled for terrain).

And the code isn't optimized. It just spits out opengl vertices for every grass blade.

Here are some more test shots:

Textured triangle
textured grass test1
Grass option dialog box, settings can be changed in real time
textured grass test2

Textured alpha blended quad:
quad test1
If I set the detail levels low, I can get decent frame rates
quad test2

Overkill test shots:
200 grass blades per triangle
overkill test 1
High grass stress test1
overkill test 2
High grass stress test2
overkill test 3

All shots were taken on an Athlon 1800+ XP and Geforce 1 card. If I ever get anywhere with it, I'll post the code.

#1
08/02/2002 (8:43 am)
Nice, would I be right in saying there would be some possibly substantial fps hits from having to render that many objects so closely together?
#2
08/02/2002 (8:47 am)
Yup, but it would work ok if you have a few shrubs here and there like in the 'quad test2' shot instead of a millions grass polys. You can check out the fps value (upper left) in the screenshots.
#3
08/02/2002 (9:39 am)
They looks cool tho even if there is a fps hit.
grass donuts bubblegum nuts? ha ha

I don't suppose you'd be interested in posting the code for your "material tests" too :) I checked out your firing range demo. Nice! I love how you got the glass working. Goes through multiple pains etc. I also noticed your decals seem much more "solid" then I have (from resource here) or that were in Tribes2. Meaning they don't seem to flicker. The multiple sfx is great too of course.

Anyway, good luck with your new ventures. CrimeWars was starting to come along pretty well it looked like. Maybe you'll still find a modeler or two.

-Sabrecyd
#4
08/02/2002 (10:20 am)
For the "material test", it's just a matter of finding what texture name you collided with. Here's the code I used to find the material name of the collision point:

// only works for interiors right now
const char * GetMaterialName(SceneObject *collisionObject, U32 face)
{
      // interior:
      InteriorInstance * instance = dynamic_cast<InteriorInstance*>(collisionObject);

      if((instance && (face != -1)))
      {  
         Interior * interior = instance->getDetailLevel(0);
         AssertFatal(interior, "GetMaterialName(): invalid interior");
         AssertFatal(face < interior->getSurfaceCount(), "GetMaterialName: invalid surface");

         const Interior::Surface & surface = interior->getSurface(face);

			U32 textureIndex = surface.textureIndex;
			
			const char * matName = interior->getMaterialName(textureIndex);
//			Con::printf("Texture = %s", matName);
			return matName;

		}
		else
			return NULL;
}




if (gServerContainer.castRay(bulletStart, end, mask, &rInfo) == true) {
	ret = rInfo.object->getId();
	const char * matName = GetMaterialName(rInfo.object, rInfo.face);

	if( (rInfo.object->getTypeMask() & InteriorObjectType) ||
                 (rInfo.object->getTypeMask() & StaticTSObjectType)) {
		if( rInfo.t <= 1.0) {
			const char * matName = GetMaterialName(rInfo.object, rInfo.face);
		}
	}

}

Now that you have the name, it's up to you on what decals to place, sounds, etc. For bullets going through objects, I just create a new bullet at the exit point.

For the decals to stop flickering, just use the glPolygonOffset() function in OpenGL. Something like this before it draws the decal:

offset = -1;
glPolygonOffset(offset, -1);

Thanks. And yes, too bad for CrimeWars. :)
#5
08/02/2002 (10:30 am)
A GeForce1 is a little weak for Torque. I'd like to see how it performs on a GeForce3 or GeForce4--I'll bet that it won't be half bad at all.

The Quad renders look really cool, as do the overkills--awesome work! I think you should definitely make this available when you're done, since most of our projects will be done when a GeForce3/Radeon 8500 will be standard cards.
#6
08/02/2002 (10:38 am)
Hey thanks, very nice. I'll have to give those things a try.

Yeah I didn't notice at first you went from 50fps to 5fps on the overkill shots. That is a lot, but like Steve said I wonder what a GeForce3 or 4 would do because the shots do look very cool with all that grass.
#7
08/02/2002 (1:34 pm)
Looks like we have a 3 way race! well, not exactly a race anymore since you posted already.. but a 3 way grass fest!

Nice work. Lets see if we can get the same thing at a reasonable framerate!

Phil.
#8
08/02/2002 (1:41 pm)
Very nice! Looks like August is going to be officially known as 'Month of the Grass' for us Torquers.

mmm..weed...mmm

- LightWave Dave
#9
08/02/2002 (2:08 pm)
You're right about my Geforce 1 not being able to handle it very well. I noticed for the high grass tests, fill rate was a huge problem. (I also had trilinear filter on :).

So, I lowered my resolution to 640x480, tried some normal grass, ~150 grass blades per triangle, and at a reasonable short distance and got around 30 fps. Here's the pic:

www.crimeforce.com/grass/grass_low_res_test.jpg
which isn't too bad, but still slow.

I checked out the Planetside screenshots and noticed their grass is only rendered at short distances so I'm aiming for something similar.

Planetside grass pic

Yes, the grass fest is on!
#10
08/02/2002 (3:52 pm)
Doyoon, what they do is alpha out the grass as it gets past a certain distance. So you only need to draw your grass reasonbly close up and it still looks smooth if youre grass an grass texture match quite well.

Another thing would be to mix the grass types youre drawing to give more variety.

John Ratcliff of planetside had a reasonable chat on one of the comp.graphics.algorithms aobut his implmentation. I'd suggest following that up.

Next thing would be to try and generate tri strips of grass rather than single tri's or quads. Try and make a bunch of quads that roughly form a v or some other continuous shape and see if it can draw that at the same rate.

I'm planning on using a TSStatic mesh to render, but render it X times in one pass (after setting the renderstate up once). Theoretically TSStatics should be pretty fast to render (theyre stripified afaik and should be rendered to a VB or CVA).

Phil.
#11
08/02/2002 (5:26 pm)
Yeah Phil, I'll try doing some optimizations and add some variety. I already calculate the alpha based on distance so it's smooth when moving forward (but sometimes it looks weird having grass magically grow in front of your eyes).

I'll also try making some strips like you suggested. It'll probably work best though for medium/far distances since I still have to deal with the fill-rate up close.

Hmmm, I couldn't find the John Ratcliff thingy.

And yeah, rendering TSStatic meshes in one render state for all the trees and plants would be way cool if you can pull it off.

Found another pic of planetside:
planetside pic
I'm assuming all those plants are blended at a short distance?

Oh and here's another inspirational pic
planetside again
#12
08/03/2002 (1:02 am)
Hey Doyoon, I have an Athlon 2100 with a GF3 Ti 500, i woould love to do testing with your code and give you data on how it preforms on a more higher end system. Drop me a line at strife@project-51.com or post here if you want any help.
#13
08/03/2002 (1:20 am)
Hehe, yeah, the race is on! Very nice, Doyoon, would be really interesting to test the fps on a highend machine...
S.T.A.L.K.E.R has some nice foliage stuff, too!
Also check out these picks... russobit-m.ru/eng/games/oblivion/shoots.shtml#. The Planetside picks don't work for me btw., I get a "Forbidden" error... :/
#14
08/03/2002 (2:50 am)
Another thing Ive noticed. Most of these games have high noise textures on the ground which closely match the plants thier using for foliage.

I guess that helps quite a bit.

Phil.
#15
08/03/2002 (9:38 am)
I would try an alpha blend just infront of the player leading into the grass, and one out a ways blending the grass back into the terrain. This will help on your fps and also it won't look as goofy when you look towards the ground where you are standing. Also if you use a nice detail map on the grass beneith you, it should look nice all around.
#16
08/23/2002 (9:53 am)
If I may suggest something ?
I understand the problem of rendering grass further than a certain distance, but remember one thing : if you dont render the grass past a certain distance, then enemies afar wont be covered by the vegetation.
This leads to problems like in Delta Force where the voxel rendering looks cool, but where you can spot your enemies from a mile away because they appear clearly unmasked by the background.

I would suggest something similar to what you get in a cartoon : only render grass a certain radius around moving characters (whatever their distance from the viewer).
As long as the grass do get drawn over your enemies it should look pretty cool.
Just imagine having your enemies disappear because they just decided to lay on the ground among the grass ! I know I'd like to see that :)
#17
09/24/2002 (4:07 am)
I think I might fire randomly at the middle of the patch of grass :)