Mass billboarding systems BEFORE geometry shaders - GPU instancing under DirectX 9?

Hello forum. I’m a long time lurker, usually finding all of my answer by browsing trough old posts, for this I thank you.

I’m currently working on creating a custom planting algorithm for placing trees and the like onto custom terrain mesh (with overhangs, caves and stuff like that not supported by a unity terrain).
I’ve managed to create a planting system that is efficient enough for handling detailed meshes of a few hundred trees continuously being planted as one traverse the landscape,
My question relates to how the built in terrain system achieve rendering of it’s massive number of plants for things like billboards and grass?

Seeing the unity built in terrain system in action there can be thousands of billboards displayed effectively giving the illusion of vast distant forest coverage or grassy meadows.
Studying code I’ve grasped how a billboard shader is achieved by cleverly shifting the vertices of a quad using a simple vertex shader.
From my understanding this will require a unique pivot for every billboard, naively implemented resulting in thousands of gameObjects, thousands of draw calls and single digit frame rates.

My own naive idea was that I could just write a vertexshader that load a mesh onto the GPU and instanced it onto every vertex of another mesh.
Trying to browse on the subject I’ve found many examples of doing just this, but they’re all using directX 11 and the new geometry shaders.
Clearly this is not what unity nor scores of older games like oblivion etc does.
So how is it actually achieved?

Reading trough the terrain shaders and the terrain.cginc files, they seem to suggest there is some kind of nesting of vertex shaders going on
doing something similar to what I originally thought. But I fail to make any sense of how it is achieved, what mesh and how it is feed into these vertex shaders
since the whole ‘terrain script’ connecting it all together is obscured from our view.

First Nvidia GPU gems (5th Printing September 2007) go into some details about this, but it somehow seem to fail to mention how the actual instancing take place:
http://http.developer.nvidia.com/GPUGems/gpugems_ch07.html

Thanks for reading, any nudge in the right direction would be much appreciated.

Seeing how I asked a new question I take the time to answer this one myself for anyone coming across this wondering.

The way it’s done, or at least one way, is by assembling meshes of thousands of quad-planes with all their 4 vertices condensed to a single point located where you want your billboard to appear relative to the meshes pivot. The vertices of each of these quad-planes are mapped to sit at each the four corners of UV space. They’re then displaced by a vertex-shader so that the U 1.0 vertices is raised by a up-vector, and the V 1.0 vertices is displaced sideways by a vector perpendicular to camera angle. This forces them to face towards the camera no matter what the view angle is.

So a finished mesh like this is loaded onto the GPU and no actual instancing takes place in the shader code, that’s only possible on directX 11 using geometry shaders.

Hi

I have been down the same path with some success but my billboards still have some perspective - they don’t appear to be perfectly facing the camera.

       // Face the vert towards the camera .
		half3 up = UNITY_MATRIX_MV[1].xyz;
		half3 eyeVector = ObjSpaceViewDir( v.vertex );
		
		// Find the sideways vector perpendicular to camera angle
		half3 right = normalize(cross(up, eyeVector));

		// Offset the vert
		half3 pos = v.vertex;
		pos += v.offsets.x * right * _Size;
		pos += v.offsets.y * up * _Size;
		
		o.pos = mul( UNITY_MATRIX_MVP, half4(pos, 1) );

Could you possibly post your solution?