as for grass rendering I read a post of Yann L somewhere
he said he creates one VBO where he puts the grass geometry into it
and in order to render it over a curved patch he does the vertex transformation in the vertex shader just translating the quads/triangles
thus you need only a single VBO to render the same grass type this should also work with trees and other things like stones ....
just use the control points of your patch and a cubic interpolation function to calculate the transformation offsets for the grass quads
I hope that helps, basically you only need the code inside the 2nd for loop
Heres the code:
cubic interpolation function
//cubic weight function float cubic(float a, float b, float c, float d, float fact) { float s0,s1,s2,s3,m; m = fact*fact; s0 = (d-c)-(a-b); s1 = (a-b)-s0; s2 = c-a; s3 = b; return (s0*m*fact+s1*m+s2*fact+s3); };
here is the bicubic interpolation function from my perlin noise library
which can easily be taken as a foundation for a decent vertex shader implementation *I suggest using the CG toolkit for API independence*
//sample image up( powers of 2) template<class U, class W> void sample_bicubic(const U& s, W& d) { uint32 i,j; int32 is,js; float x,y,dx,dy; int32 XCoords[4]; int32 YCoords[4]; float weights[4]; dx = dy = static_cast<float>(U::MAP_SIZE)/ static_cast<float>(W::MAP_SIZE); for(i=0;i<W::MAP_SIZE;i++) { //calculate source coordinates x = i*dy; is = static_cast<int32>(x); x = x - (is); XCoords[0] = (is-1 + U::MAP_SIZE)%U::MAP_SIZE; XCoords[1] = (is + U::MAP_SIZE)%U::MAP_SIZE; XCoords[2] = (is+1 + U::MAP_SIZE)%U::MAP_SIZE; XCoords[3] = (is+2 + U::MAP_SIZE)%U::MAP_SIZE; for(j=0;j<W::MAP_SIZE;j++) { //calculate source coordinates y = j*dy; js = static_cast<int32>(y); y = y - (js); YCoords[0] = (js-1 + U::MAP_SIZE)%U::MAP_SIZE; YCoords[1] = (js + U::MAP_SIZE)%U::MAP_SIZE; YCoords[2] = (js+1 + U::MAP_SIZE)%U::MAP_SIZE; YCoords[3] = (js+2 + U::MAP_SIZE)%U::MAP_SIZE; //interpolate the y axis weights[0] = cubicweight2( s.m_Map[XCoords[0]][YCoords[0]], s.m_Map[XCoords[0]][YCoords[1]], s.m_Map[XCoords[0]][YCoords[2]], s.m_Map[XCoords[0]][YCoords[3]], y); weights[1] = cubicweight2( s.m_Map[XCoords[1]][YCoords[0]], s.m_Map[XCoords[1]][YCoords[1]], s.m_Map[XCoords[1]][YCoords[2]], s.m_Map[XCoords[1]][YCoords[3]], y); weights[2] = cubicweight2( s.m_Map[XCoords[2]][YCoords[0]], s.m_Map[XCoords[2]][YCoords[1]], s.m_Map[XCoords[2]][YCoords[2]], s.m_Map[XCoords[2]][YCoords[3]], y); weights[3] = cubicweight2( s.m_Map[XCoords[3]][YCoords[0]], s.m_Map[XCoords[3]][YCoords[1]], s.m_Map[XCoords[3]][YCoords[2]], s.m_Map[XCoords[3]][YCoords[3]], y); //interpolate the x axis d.m_Map[j] = cubicweight2(weights[0],weights[1],weights[2],weights[3],x); } } };
Big thanks goes to outrider for presenting the correct weight factors
The bicubic interpolation thread