Page 1 of 1

problem: directional billboarding

Posted: 04 Aug 2007, 20:31
by jK
i am writting a particle system in lua and trying to convert the simpleparticle class to use shaders.

now i have a problem with the "directional" feature of csimpleparticle.
first what it does: it rotates the quad (it is still billboarded) so it points to the speed vector, i.e. an effect that start in a point and the particles escaping from it -> all quads would point away from the start point.
the code that does this is in worldspace:

Code: Select all

float3 dif(particles[i].pos-camera->pos);
float camDist=dif.Length();
dif/=camDist;
float3 dir1(dif.cross(particles[i].speed));
dir1.Normalize();
float3 dir2(dif.cross(dir1));
(dir1 is the up vector and dir2 the right vector)

now i can't copy this code, cuz i use the a vertex shader to billboard my quads. so i have to rotate the quads in eyespace, but all my tries (>4 different codes) don't worked at all or only if the speed vector directly points to the sky (in worldspace coord) :(

my concept is:
  • convert the speed vector into eyespace coord: vec3( gl_ModelViewMatrix * vec4(speed,0.0) )
  • calculate the 2d angle between the eyespace up vector and the eyespace speed vector. i tried many codes to do so, but none worked :(
    Image
    (please note the speed vector still has a z coord, but i only want the up and right components of the speed vector)
  • rotate the quad with: mat2 rotation = mat2( cos(alpha), -sin(alpha), sin(alpha), cos(alpha) )
anyone has a idea, how i can the angle between the speed vector and the eyespace up vector or if there is a much easier way to rotate a billboarded quad in the vertex shader?

Posted: 04 Aug 2007, 22:09
by AlfaSub
Mathematically speaking, the angle between two vectors a and b is:

arccos( (a dot b)/(|a||b|) )

(a dot b) is the dot product (a1b1+a2b2+a3b3 etc), and |x| is the magnitude function (the length of the vector, sqrt(x1^2+x2^2+x3^2...)

So for your two-dimensional example, the angle between the vectors <x1,y1> and <x2,y2> would be:

arccos( (x1y1+x2y2)/( sqrt(x1^2+y1^2)sqrt(x2^2+y2^2) ) )


http://en.wikipedia.org/wiki/Dot_product (it's near the middle)

Posted: 04 Aug 2007, 22:48
by jK
yeah, i know how to calculate the angle between two vectors, but the problem is how do i get only the eye up and eye right components of the speedvector?
i tried to use Gram-Schmidt to orthogonalize (without normalizing) the speedvector to the eye forward and eye up vector to get the eye right component (of the speed vector) and then the same only this time orthonoalized to eye forward and eye right vector to get the up component, but it didn't worked :(

Posted: 04 Aug 2007, 23:16
by Kloot
Transform both the speed-vector V and an up-vector T [0, 1, 0] to eye-space. Then take the (normalized) crossproduct of the transformed speed- and up-vectors V' and T' to get the eye-right component R. Next calculate the (also normalized) crossproduct of V' and R to get the eye-up component U. From there you can easily find the angle between U and the eye-space up-vector (unless I've misunderstood you and that's not what you want to do ;)).

Posted: 05 Aug 2007, 03:03
by jK
still doesn't work :(
the rotation angle is now constant 45degree

my code is now the following:

Code: Select all

vec3 eyeup    = vec3( gl_ModelViewMatrix * vec4(0.0,1.0,0.0,0.0) );
vec3 eyespeed = vec3( gl_ModelViewMatrix * vec4(speedv,0.0) );
vec3 R = normalize( cross(eyeup,eyespeed) );
vec3 U = normalize( cross(eyespeed,R) );

float cosf = dot(normalize(U+R), normalize(eyeup)); //here is a problem it should be between -1.0 and 1.0, but it is abs(cosf)>1

float alpha = acos( cosf );
mat2 rotation = mat2( cos(alpha), -sin(alpha), sin(alpha), cos(alpha) );

gl_Position.xy += rotation * (gl_MultiTexCoord1.zw * size);
(gl_MultiTexCoord1.zw saves the offsets per vertex from the center point of the quad)