# Getting circle quarter based on Vector3 direction

This topic is 1709 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm trying to get quarter of the circle based on a certain direction (velocity)

The number that I want should be between -D3DX_PI and D3DX_PI, How do I determine it based on the velocity direction?

Example:

Lets say I have the velocity of: (X: 0, Y: 10, Z: 0), in this case the velocity is pointing at the upper direction, so the numbers between -D3DX_PI and D3DX_PI that I should get are based on the upper quarter of the circle.

So, I want to determine which quarter of the circle the velocity is pointing at.

##### Share on other sites

Reading between the lines it sounds like maybe you want to extract heading (aka yaw) and elevation (aka pitch) values from your direction vector.

Rather than deriving them I google "direction vector to euler angles" and landed on this gamedev post: http://www.gamedev.net/topic/399701-convert-vector-to-euler-cardan-angles/

Which contained the following snippet (which I modified seeing as in your case Y is up):

"A direction vector can be turned into a pitch and yaw (two Euler angles) thusly:

double yaw = Math.Atan2(ds.X, ds.Z);
double pitch = Math.Atan2(ds.Y, Math.Sqrt((ds.X * ds.X) + (ds.Z * ds.Z)));"

##### Share on other sites

Reading between the lines it sounds like maybe you want to extract heading (aka yaw) and elevation (aka pitch) values from your direction vector.

If your reading is correct, I would say heading is "longitude" and elevation is "latitude", and what he needs is a conversion from Cartesian to spherical coordinates. That happens to have the exact same equations you posted. Edited by Álvaro

##### Share on other sites

Let me make it more clear

I have this function:

D3DXVECTOR3 GetRandomVector(D3DXVECTOR3 velocity)
{
D3DXVECTOR3 vVector;

// Pick a random Z between -1.0f and 1.0f.
vVector.z = GetRandMinMax( -1.0f, 1.0f );

// Get radius of this circle
float radius = (float)sqrt(1 - vVector.z * vVector.z);

// Pick a random point on a circle.
float t = GetRandMinMax( -D3DX_PI, D3DX_PI ); // I THINK THIS LINE SHOULD BE MODIFIED TO PICK A POINT LIMITED TO QUARTER OF THE CIRCLE (According to the direction of D3DXVECTOR3 velocity)

// Compute matching X and Y for our Z.

return vVector;
}


In the above method, the random vector is anywhere on the circle between (-D3DX_PI, D3DX_PI) I want to limit the random number to be only quarter of the circle based on the direction of D3DXVECTOR3 velocity.

##### Share on other sites

Define "quarter of the circle". Is that based on standard quadrants (0..90, 90..180, 180..270 and 270..0) picking the one said vector is located in, or is it a cone of some given width centered on the vector? (and if the latter, what width? and what distribution?)

##### Share on other sites

If I give a velocity of (0, 10, 0) I want to get A and B accordingly.

0, 10, 0 direction is UP so the result should be the upper quarter.

[attachment=15796:circle.png]

I should change the following line:

float t = GetRandMinMax( -D3DX_PI, D3DX_PI );

To:

float t = GetRandMinMax( A, B );


How do I calculate A and B based on the velocity (direction)?

##### Share on other sites

So a quarter centered on the velocity vector. In that case, you need to get the angle the vector is pointing towards (the above answers answer this part, depending on which axis you want the quarter circle in), call it theta. From your code, it seems you want the angle in the XY plane, so theta = atan2(velocity.y, velocity.x). Once you have this angle, you just go:

float t = GetRandMinMax(theta - D3DX_PI / 4, theta + D3DX_PI / 4)


That is, from theta - 45 degrees to theta + 45 degrees. As you can see, you get a random angle within the desired quarter, and can create a new vector with it.

That said, you seem to be creating a random 3D vector. In this case, would it not be better to choose the cone centered on the velocity vector rather than the quarter circle? I'm afraid with the above modification, you won't get the effect I think you are looking for.

##### Share on other sites

I'm trying to create random vector that points at the velocity (for particles)

So I have:

D3DXVECTOR3 velocity;

float velocity_var;

According to the above variables I want to make the particles generate to move according to the "velocity", however, velocity_var should determine how much the particles will spread.

Example 1:

Velocity: 0.0f, 10.0f, 0.0f

velocity_var: 4.0f

End Point

\        /

\      /

\    /

\  /

Start

Example 2:

Velocity: 0.0f, 10.0f, 0.0f

velocity_var: 0.0f

End Point

|

|

|

|

Start

The above works perfectly, however, since my particles are lines, the lines are not pointed at the velocity when generated and that's what I'm trying to fix.

##### Share on other sites

Assuming this is a continuation of http://www.gamedev.net/topic/643188-sparks-animation/#entry5062421 then the solution is purely vector based.  The code I provided before had a bias as I didn't do the full proper solution, but in general it still works, you just have to change the manner of calculation to remove the biasing.  Using the following as reference:

[attachment=15797:Reference.jpg]

In that image the white line is your chosen axis of emission, the blue line is a reference "up" (or side, just something at a right angle) vector and the red circle is the radius of the cone of emission.  What you want is to make an offset vector which falls within the red circle like the grey radius line, but you want to adjust the length of the offset and direction to be anywhere in that circle.  The easiest method of doing this is to generate two values; an angle and a radius.

Assuming that the right angle vector is 1 in length and the plane of the red circle is at +1 along the emission axis it becomes simple math to do the conversions.  First, to compute the radius, is very simple, tan( angle ).  Second, take the right angle vector (blue) and scale it to the resulting radius times the randomly generated radius.  Rotate the result about the emission vector by 2pi times the generated 0-1 angle.  Add that to the emission vector and normalize.  You have a nice little random vector around the emission vector.

There are likely more ways to do this, possibly even easier methods.  Hopefully though this gives you a reasonably understandable starting point.

##### Share on other sites

Can you provide a little bit of code so I can understand you better?

Here is how I generate a new particle:

void generateNewParticle()
{
// ...
D3DXVECTOR3 randVec = GetRandomVector();
particle.velocity += randVec * velocity_var;
particle.position = particle.velocity;
// Code to add the particle to the list here...
}

D3DXVECTOR3 GetRandomVector()
{
D3DXVECTOR3 vVector;

// Pick a random Z between -1.0f and 1.0f.
vVector.z = GetRandMinMax( -1.0f, 1.0f );

// Get radius of this circle
float radius = (float)sqrt(1 - vVector.z * vVector.z);

// Pick a random point on a circle.
float t = GetRandMinMax( -D3DX_PI, D3DX_PI );

// Compute matching X and Y for our Z.

return vVector;
}

Here is how I draw the sparks every frame:

RenderSingleLine( particle.position, particle.position - particle.velocity * lineLength );

I'm not really good in mathematics.

Now, I'm trying to change the code to make the spark lines look at the moving direction instantly after they get generated.

##### Share on other sites

Can you provide a little bit of code so I can understand you better?

Let's see if I can modify your code (trying to remember D3DX, forgive any goofs please. ):

D3DXVECTOR3 GetRandomVector()

{
// Set these to normalized vectors as appropriate.
// We'll use +z as direction and +y as up vector.
D3DXVECTOR3 dirVec( 0.0f, 0.0f, 1.0f );
D3DXVECTOR3 upVec( 0.0f, 1.0f, 0.0f );

D3DXVECTOR3 vVector;

const float  angleRange = D3DX_PI/2.0f; // 45 degree's.

float angle  = GetRandMinMax( 0.0f, 2.0f * D3DX_PI );  // Anywhere in the full circle.
float range = GetRandMinMax( 0.0f, tan( angleRange ) );

D3DXVECTOR3 offset = upVector * range;

// Hmm.  No D3DX for vector around vector rotation.  Bah..
float s = sin( angle );
float c = cos( angle );
D3DXVECTOR3 temp(
offset.x*(dirVec.x*dirVec.x*(1-c)+c) + offset.y * (dirVec.x*dirVec.y*(1-c)-dirVec.z*s) + offset.z*(dirVec.x*dirVec.z*(1-c)+dirVec.y*s),
offset.x*(dirVec.x*dirVec.y*(1-c)+dirVec.z*s) + offset.y*(dirVec.y*dirVec.y*(1-c)+c) + offset.z*(dirVec.y*dirVec.z*(1-c_-dirVec.x*s),
offset.x*(dirVec.x*dirVec.z*(1-c)-dirVec.y*s) + offset.y*(dirVec.y*dirVec.z*(1-c)+dirVec.x*s)+offset.z*(dirVec.z*dirVec.z*(1-c)+c)
);

temp += dirVec;
D3DXVec3Normalize( vVector, &temp );

return vVector;

}


I probably goofed something up in there but it should be pretty close.

In general though, you really should learn the math bits a better, it takes time but everything you do is going to be math related eventually.

Edited by Hiwas

##### Share on other sites

The variable "axis" is not defined.

Do you mean the velocity?

I tried giving axis a value of (0, 10, 0) to make the particles move up, but they still start looking down then moving up.

##### Share on other sites

Oops, typo converting from my library.  Fixed it.

##### Share on other sites

I still see the undefined variable 'axis':

offset.x*(dirVec.x*dirVec.y*(1-c)+axis.z*s)

offset.x*(dirVec.x*dirVec.z*(1-c)-axis.y*s)

##### Share on other sites

Just replace them with dirVec, I'll go correct it.  I translated the code from my library though obviously missed a couple things. :)

##### Share on other sites

That means dirVec should be the velocity (0, 10, 0)?

If yes, I tried that but the particles are moving straight in down direction.

D3DXVECTOR3 dirVec = velocity; // velocity = 0, 10, 0
D3DXVECTOR3 upVec( 0.0f, 1.0f, 0.0f );


Edited by Medo3337

##### Share on other sites

The presented code supplies a random unit vector (assuming no more bugs) within the directional cone.  In order to apply your velocity, take the result vector and multiply by the desired velocity "scalar".  In other words:

D3DXVECTOR3 randVec = GetRandomVector() * 10.0f;

// randVec is a random unit vector.  Scale it by a given velocity scalar.  I.e. you say "0, 10, 0", just multiply by 10.

##### Share on other sites

D3DXVECTOR3 randVec = GetRandomVector() * scalar;

How do I determine the direction? a scalar value is not enough to determine the direction, sometimes the sparks will move down, sometimes will move up, sometimes will move to the left, it all depends on the gravity (D3DXVECTOR3 gravity).

So here is what I want to do instead:

D3DXVECTOR3 randVec = GetRandomVector(gravity) * scalar;

##### Share on other sites

Replace (or pass in):

D3DXVECTOR3 dirVec( 0.0f, 0.0f, 1.0f );
D3DXVECTOR3 upVec( 0.0f, 1.0f, 0.0f );

With an appropriate set of vectors.  dirVec is the emission direction and you need the right angle 'upVec' as a reference.  As I mentioned in the other thread, you need a point and at least 2 vectors to fully define the emission of a particle system.  Without the pair of vectors, the math won't work, I just chose two easy ones.

##### Share on other sites

There is something I'm unsure about.

All I have is "D3DXVECTOR3 gravity", how do I get dirVec and upVec from gravity?

##### Share on other sites

There is something I'm unsure about.

All I have is "D3DXVECTOR3 gravity", how do I get dirVec and upVec from gravity?

Gravity is a particle effector, it has nothing to do with the dirVec and upVec which are part of the emitter.  I don't know if there is a language barrier here or if you just really don't understand the very basic bits of vector math, either way I suggest you should be able to figure this out on your own.  I'll simply describe how I would write things and then leave it to you to figure out the rest:

Emitter

Vector3f  Position

Vector3f  Direction  // dirVec

Vector3f  Up            // upVec

float         EmissionAngle  // Radians, I don't do degree's...

float         EmissionVelocity

Initialize the emitter (source and target are points in space, source is where the particles start, target is the direction they move towards initially)

emitter.Position = source.

emitter.EmissionVelocity = 10.0f;

emitter.Direction = Normalize( target - source );

// Check for a valid reference axis, can't be the same as +-direction vector.

if( Abs( Dot( emitter.Direction, Vector3f( 0, 1, 0 ) ) ) < 0.001f )

emitter.Up = Normalize( Cross( emitter.Direction, Cross( emitter.Direction, Vector3f( 1, 0, 0 ) ) )

else

emitter.Up = Normalize( Cross( emitter.Direction, Cross( emitter.Direction, Vector3f( 0, 1, 0 ) ) )

Particle

Vector3f  Position

Vector3f  Velocity

Effectors

Vector3f  Gravity

Initialize a particle:

particle.Position = Emitter.Position;

// Replace dirVec and upVec in the function with references to the emitter data.

particle.Velocity = GetRandomVector( emitter ) * emitter.EmissionVelocity;

Update a particle:

particle.Position += particle.Velocity * deltat;

particle.Velocity += effectors.Gravity;

At this point, you should be able to figure this all out using basic vector math.  If you can't figure out the basic vector math being performed here you really need to go learn some of the basics or nothing is going to help you very much further until you do that.  Particles are all about vector math so I can't help further if this is a math problem.  If it is just language, hopefully the above will explain any miss communications.

##### Share on other sites

Well, I'm not native English speaker, here is what I have done so far, still didn't get it to work, is there is anything wrong in the following code?

Generate a new particle:

D3DXVECTOR3 direction = gravity - position; // The lines should look at the gravity direction
D3DXVec3Normalize(&direction, &direction);
D3DXVECTOR3 Up;
// Check for a valid reference axis, can't be the same as +-direction vector.
if( abs( D3DXVec3Dot( &direction, &D3DXVECTOR3( 0, 1, 0 ) ) ) < 0.001f )
{
D3DXVECTOR3 cr;
D3DXVec3Cross(&cr, &direction, &D3DXVECTOR3( 1, 0, 0 ) );
D3DXVec3Cross(&Up, &direction, &cr);
D3DXVec3Normalize( &Up, &Up );
} else {
D3DXVECTOR3 cr;
D3DXVec3Cross(&cr, &direction, &D3DXVECTOR3( 0, 1, 0 ) );
D3DXVec3Cross(&Up, &direction, &cr);
D3DXVec3Normalize( &Up, &Up );
}

D3DXVECTOR3 randVec = GetRandVector(direction, Up);
particle.velocity += randVec * velocity_var;


D3DXVECTOR3 GetRandVector(D3DXVECTOR3 dirVec, D3DXVECTOR3 upVec)
{
D3DXVec3Normalize(&dirVec, &dirVec);

D3DXVECTOR3 vVector;

const float  angleRange = D3DX_PI/2.0f; // 45 degree's.

float angle  = GetRandMinMax( 0.0f, 2.0f * D3DX_PI );  // Anywhere in the full circle.
float range = GetRandMinMax( 0.0f, tan( angleRange ) );

D3DXVECTOR3 offset = upVec * range;

// Hmm.  No D3DX for vector around vector rotation.  Bah..
float s = sin( angle );
float c = cos( angle );

D3DXVECTOR3 temp(
offset.x*(dirVec.x*dirVec.x*(1-c)+c) + offset.y * (dirVec.x*dirVec.y*(1-c)-dirVec.z*s) + offset.z*(dirVec.x*dirVec.z*(1-c)+dirVec.y*s),
offset.x*(dirVec.x*dirVec.y*(1-c)+dirVec.z*s) + offset.y*(dirVec.y*dirVec.y*(1-c)+c) + offset.z*(dirVec.y*dirVec.z*(1-c-dirVec.x*s)),
offset.x*(dirVec.x*dirVec.z*(1-c)-dirVec.y*s) + offset.y*(dirVec.y*dirVec.z*(1-c)+dirVec.x*s)+offset.z*(dirVec.z*dirVec.z*(1-c)+c)
);

temp += dirVec;
D3DXVec3Normalize( &vVector, &temp );

return vVector;
}


##### Share on other sites

I don't see anything obvious which unfortunately means this needs to be debugged.  My primary guesses would be that I screwed something up when translating the rotation about vector code from my libraries or that the cross products are in the wrong orders.  Beyond that, sorry can't help without being able to stick it in a debugger and walk through it.

##### Share on other sites

BTW, I notice that the variable 'EmissionAngle' is defined and never used.