# Board index » delphi » Generate random 3d vectors within angle around 3d vector?

## Generate random 3d vectors within angle around 3d vector?

2005-05-12 09:30:27 AM
delphi182
Hi all,
I have tried googling about this with not much luck - lots and lots of
pages to wade through :(
Hopefully this is a 'simple' question <G>
Given a direction 3d vector, how can I generate random vectors within a
'cone' formed by some max dot product angle between the direction vector and
the other vectors?
I can do this for, lets say a vertical direction vector no worries (see code
below), but I don't know how to apply this to any arbitarily pointing 3d
vector...
Function TParticleEmitter.GenVelocity: TVector3d;
Const
d = 10;
Var
x,z,h,a,r: Single;
Begin
{
r v
--------
\ |
\ |
\ |
h \ |d
\ |
\o|
\|
o = max dot product angle around vector v
h = hypotenuse
d = some 'height' (can be anything)
r = max radius from v
}
h := d / Cos(o * PI / 180);
r := h * Sin(o * PI / 180);
a := Random * 360 * PI / 180; // random angle around circle looking down
at r length of triangle
r := Random * r; // take random radius between 0 and r
x := r * Cos(a);
z := r * Sin(a);
Result := Normalise(Point3d(x,d,z));
End;
If anyone can help me, it would be excellent :)
Cheers,
Paul.
"The plastic veneer of civilization is easily melted in the heat of the
moment" - Paul Nicholls.
XXXX@XXXXX.COM
Remove ".NOSPAM" to reply.

## Re:Generate random 3d vectors within angle around 3d vector?

to sample directions uniformly within a cone of aperture angle alpha around
a direction D:
1. Sample uniformly within the same cone, only centered around the z-axis:
- Choose a random z uniformly between 1-cos(alpha) and 1;
(it is not obvious, but this will ensure a uniform distribution on the
"cap")
- Choose a random direction in the x-y plane:
a) Generate x and y uniformly between -1 and 1;
b) Compute r2 = x^2 + y^2; if it exceeds 1, go back to step a)
- Direction is (sqrt(1-z^2) * x / sqrt(r2),
sqrt(1-z^2) * y / sqrt(r2),
z).
- For more efficiency first compute f = sqrt( (1-z^2)/r2 );
Direction is then (f*x, f*y, z).
2. Apply a transformation that moves the z-axis to direction D.
This is achieved through a 180-degree rotation about the direction
that is halfway between D and the z-axis. The matrix can be computed
as follows, defining den=1+D.z (the case where D is exactly opposite to z
should be handled separately):
((D.x*D.x)/den - 1, (D.x*D.y)/den, D.x,
(D.x*D.y)/den, (D.y*D.y)/den - 1, D.y,
D.x, D.y, D.z);
too much math. my brain hurts.
cheers,
Michael
"Paul Nicholls" <XXXX@XXXXX.COM>writes
##### Quote
Hi all,
I have tried googling about this with not much luck - lots and lots of
pages to wade through :(

Hopefully this is a 'simple' question <G>

Given a direction 3d vector, how can I generate random vectors within a
'cone' formed by some max dot product angle between the direction vector
and the other vectors?

I can do this for, lets say a vertical direction vector no worries (see
code below), but I don't know how to apply this to any arbitarily pointing
3d vector...

Function TParticleEmitter.GenVelocity: TVector3d;
Const
d = 10;
Var
x,z,h,a,r: Single;
Begin
{
r v
--------
\ |
\ |
\ |
h \ |d
\ |
\o|
\|

o = max dot product angle around vector v
h = hypotenuse
d = some 'height' (can be anything)
r = max radius from v
}
h := d / Cos(o * PI / 180);
r := h * Sin(o * PI / 180);
a := Random * 360 * PI / 180; // random angle around circle looking
down at r length of triangle

r := Random * r; // take random radius between 0 and r

x := r * Cos(a);
z := r * Sin(a);

Result := Normalise(Point3d(x,d,z));
End;

If anyone can help me, it would be excellent :)
Cheers,
Paul.

"The plastic veneer of civilization is easily melted in the heat of the
moment" - Paul Nicholls.
XXXX@XXXXX.COM

Remove ".NOSPAM" to reply.

## Re:Generate random 3d vectors within angle around 3d vector?

Hi Paul,
Probably easiest is to assume your Du-base vector is (0, 0, 1) - unit vector
along the Z-axis. You can achieve that by creating a transformation matrix
from "world" to local "base". This matrix will have as 3rd column the unit
vector of your Du, then in 2nd column and 3rd column two vectors that are
perpendicular.
Assume you have Du and Hu as vectors, which are already unified.
To find the transformation, use
Z = Du
Y = Unify ( Cross(Du, Hu) )
X = Cross(Y, Z); // order important!
Just to make sure, here's how to calculate crossproduct:
C = Cross(A, B) equals:
Cx = Ay * Bz - Az * By
Cy = Az * Bx - Bz * Ax
Cz = Ax * By - Ay * Bx
Also, Du and Hu must make an angle otherwise length of the cross vector will
become zero! (In that case you can in fact use any other random unit vector
Matrix =
[Xx Yx Zx]
[Xy Yy Zy]
[Xz Yz Zz]
You can check:
Du = Matrix * Du-base
e.g.
Dux [. . Zx] 0
Duy = [. . Zy] * 0
Duz [. . Zz] 1
Now you can use polar coordinates to represent your random vector. Let's
assume angle A that is the angle between the vertical and your vector, and
Angle B which is the azimuth in the XY plane.
Amax := arccos( (Dot(Du, Hu))
Arand := random * Amax
Brand := random * 2 * pi
Vbasez := cos(Arand)
Rxy := sqrt(1 - Vbasez^2)
Vbasex := cos(Brand) * Rxy
Vbasey := sin(Brand) * Rxy
Once you have Vbase (x, y, z) you can transform back to the world
coordinates, using
Vworld = Matrix * Vbase
That should give your unified vector, which you can then scale with the
original length of Du.
By the way, this method will uniformly distribute particles over the arc
going from the center to outside. This means that less particles will be
fired in the outer areas (less dense) because the ring is bigger there. But
I guess for firing animation this is quite good, because it mimicks gaussian
distribution over the target area.
If you instead want an equal distribution, reply and I will show how.
Hope that helps,
Nils Haeck
www.simdesign.nl
"Paul Nicholls" <XXXX@XXXXX.COM>writes
##### Quote
Hi all,
I have tried googling about this with not much luck - lots and lots of
pages to wade through :(

Hopefully this is a 'simple' question <G>

Given a direction 3d vector, how can I generate random vectors within a
'cone' formed by some max dot product angle between the direction vector
and
the other vectors?

I can do this for, lets say a vertical direction vector no worries (see
code
below), but I don't know how to apply this to any arbitarily pointing 3d
vector...

Function TParticleEmitter.GenVelocity: TVector3d;
Const
d = 10;
Var
x,z,h,a,r: Single;
Begin
{
r v
--------
\ |
\ |
\ |
h \ |d
\ |
\o|
\|

o = max dot product angle around vector v
h = hypotenuse
d = some 'height' (can be anything)
r = max radius from v
}