Trying To Plot Points Around A Disk From Direction Vector.

Started by
4 comments, last by tonemgub 9 years, 6 months ago

Hi All.

I'm trying to create a particle thruster effect. What I'm thinking of doing is to spawn a ring of particles at the starting location
from a 3d direction vector, Where the ring of points are all perpenicular to the Direction vector. Once I have this ring of points I
will create a vector from the centre and give it length to form a apex where all points on the ring move towards.

here is a image of what I'm doing.

disk1.jpg?psid=1

I found some steps which is as follows,
//1. Choose any point P randomly which doesn't lie on the line through P1 and P2
//2. Calculate the vector R as the cross product between the vectors P - P1 and P2 - P1. This vector R is now perpendicular to P2 - P1. (If R is 0 then 1. wasn't satisfied)
//3. Calculate the vector S as the cross product between the vectors R and P2 - P1. This vector S is now perpendicular to both R and the P2 - P1.
//4. The unit vectors ||R|| and ||S|| are two orthonormal vectors in the plane perpendicular to P2 - P1.

I tryed following the above but when I set a minus Direction like so d3dvector3(0.0, -1.0, 0.0) or (-1,0,0) My particles dont render, I'm wondering
if I have the math wrong here is what Im doing.




float3 plane[3]; 

float3 n,p,r,s,p1p2; 

//the starting point
float3 p1 = gEmitPosW.xyz;

//apex location
float3 p2 = dir * 1900.0;//add some length to the direction



//p.x = rand(); /* Create a random vector */ 
//p.y = rand(); 
//p.z = rand(); 

//now creating a perp vector
randompoint = normalize(Perpendicular(p1p2));
r = randompoint;


s =  normalize(cross(p1p2, r));

  dtheta = 36.0;
  float th =0.0;

  for(theta=0;theta<360;theta+=dtheta) 
  { 
  th = radians(theta);
		 n.x = (r.x) * cos(th) + (s.x) * sin(th); 
		 n.y = (r.y) * cos(th) + (s.y) * sin(th); 
		 n.z = (r.z) * cos(th) + (s.z) * sin(th); 
		 normalize(n); 
		
		 //set the particl up

			////////////////////////////////////////////
			
			Particle p;
			p.initialPosW   = p1 + n* radius;
			p.initialVelW	= gEmitDirW.xyz;
			
			p.pDirW		  =	normalize(p2 - p.initialPosW );//p.initialVelW;
			p.sizeW       = float2(gParticleWidth, gParticleHeight);
			p.age         = 0.0f;//vRandom.x;
			p.type        = PT_FLARE;
			p.arrayid     = 0;
			p.initialVelW.x =  gFlashspeed;

				
			//add new particle
			ptStream.Append(p);
			

	}

Is there some thing wrong in the above code.

If I change the start and end points I can get it to render in the minus directions, but how do I do it when the direction can be unknown at the time.

I tryed doing this but it does nothing

//dir

if(length(p2) - length(p1)< 0)

p1p2 =dir;//p2 - p1;

else

p1p2 =normalize(p1 - p2);

This one has a up direction d3dvector3(0,1,0).

Don't worry about the bit comming out the buttom thats just my flame thrower particle.

Thruster.jpg?psid=1

Advertisement

Pix is telling me some thing but I don't know what it is, googles not saying.

Pix is telling me all my position and direction vars are all equal to 1#QO,??????

Is this divide by zero. because if I set my Direction Vector to d3dvector3(0.001, -1.0, 0.001) it works but if I set it to d3dvector3(0.0,-1.0,0.0) I get 1#QO

What should I do here.

Why are you passing p1p2 (assuming this is the P2-P1 vector from you algorithm ?) and then calculating p1 and p2 separately? Also, isn't the "dir" variable the same as the normalized P2-P1 vector? Why are you passing it separately to your shader (or is it just a constant)? Are you sure all of these variables are according to the algorithm you described? By the looks of it, they aren't. You should only pass P1 and P2 into your shader, then calculate everything else based on those. If you just change of any of these variables (p1, p2, dir, p1p2) - even just the sign of one of their components - it affects what all of the other variables should be. For example, if you just change the sign of dir.y, then P1 and P2's y values should also be swapped with one another (assuming x and z are 0), and the sign of p1p2.y should also be reversed.

Also, are you initializing all of your shader constant buffers properly?

Also, you are declaring the local variable "Particle p" with the same name as the global variable "float3 p" (or are they all local variables? - if so, then your shader really makes no sense at all, because most of them are not initialized anywhere)... things can go wrong here as well.

Is that even a shader or just C++ code? :) Anyway, the problem is clear: a lot of your variables are not initialized anywhere.

Ok I've cleand the code up. But Its not working in the minus x direction or minus y directions.

Works only when directions +. The first image shows the thruster with a right direction vector3(1.0, 0.0, 0.0). I increased the radius to show the ring positions.

The second Image show the thruster with vector3(-1.0, 0.0, 0.0).

Thruster2.jpg?psid=1

Oh and Its strange that the shader compiled with float3 p and a Particle p in the same function no error

But uninitialized vars return errors so I had none of them.

Heres the HLSL code.


float radius = 50.0;

float3 n,r,s; 

float3 p1 = gEmitPosW.xyz;//passed from the app

//the app only has a direction
float3 p1p2 = gEmitDirW.xyz;//passed from the app

float3 randompoint = Perpendicular(p1p2);//this is our random point

//apex location defined by user length member
//we dont have a point2 we create it in the direction we have
float3 p2 = p1 + p1p2 * 1900.0;//add some length to the direction



float theta = 0.0;
float dtheta = 36.0;//segment size


r = normalize(cross(p1p2, randompoint));

s =  normalize(cross(r,p1p2 ));

 
  float th = 0.0;
  for(theta = 0; theta < 360; theta += dtheta) 
  { 
		 th = radians(theta);
		 n.x =  (s.x) * cos(th) +   (r.x) * sin(th); 
		 n.y =  (s.y) * cos(th) +   (r.y) * sin(th); 
		 n.z =  (s.z) * cos(th) +   (r.z) * sin(th); 
		 normalize(n); 
		
		//set the particl up
		////////////////////////////////////////////
			
			Particle p;
			p.initialPosW   = p1 + n * radius;//places this particle on the ring
			p.initialVelW	= gEmitDirW.xyz;//not used in this particle shader
			
			p.pDirW		  =	 normalize(p2 - p.initialPosW );//alows us to move from the outer ring to the apex like a cone
			p.sizeW       = float2(gParticleWidth, gParticleHeight);
			p.age         = 0.0f;
			p.type        = PT_FLARE;
			p.arrayid     = 0;//todo set array index to textures
			p.initialVelW.x =  gFlashspeed;//used to end the particles life

				
			//add new particle
			ptStream.Append(p);
			

	}
	
	// reset the time to emit
	gIn[0].age = 0.0f;

Hey Again.

I think I know what the problem is. It's in my perpendicular functions not returning a perpendicular.

So I changed this bit of the code


 // measure the projection of "direction" onto each of the axes
    float id =	(dot(i, direction));//i.dot (direction);
    float jd =	(dot(j, direction));//j.dot (direction);
    float kd =	(dot(k, direction));//k.dot (direction);

To this .


 // measure the projection of "direction" onto each of the axes
    float id =	abs(dot(i, direction));//i.dot (direction);
    float jd =	abs(dot(j, direction));//j.dot (direction);
    float kd =	abs(dot(k, direction));//k.dot (direction);

Can Someone verify that thats the right way to get a perpendicula vector.

I'm going to see if I can break it now.

Heres the whole Function


//---------------------------------------------------------------
//returns the mid point between 2 points
//---------------------------------------------------------------
float3 Perpendicular(float3 direction)
{

 // to be filled in
    float3 quasiPerp;// a direction which is "almost perpendicular"
    float3 result;// the computed perpendicular to be returned

    // three mutually perpendicular basis vectors
    float3 i = float3(1, 0, 0);
    float3 j = float3(0, 1, 0);
    float3 k = float3(0, 0, 1);

    // measure the projection of "direction" onto each of the axes
    float id = abs(dot(i, direction));//i.dot (direction);
    float jd =abs( dot(j, direction));//j.dot (direction);
    float kd = abs(dot(k, direction));//k.dot (direction);

    // set quasiPerp to the basis which is least parallel to "direction"
    if ((id <= jd) && (id <= kd))
    {
        quasiPerp = i;               // projection onto i was the smallest
    }
    else
    {
        if ((jd <= id) && (jd <= kd))
            quasiPerp = j;           // projection onto j was the smallest
        else
            quasiPerp = k;           // projection onto k was the smallest
    }

    // return the cross product (direction x quasiPerp)
    // which is guaranteed to be perpendicular to both of them
   // result.cross (direction, quasiPerp);
	result = cross(direction, quasiPerp);
	return result;

}//end Perpendicular
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////


Can Someone verify that thats the right way to get a perpendicula vector.

The vector perpendicular to two other vectors in 3D is the vector given by by the cross-product of the two other vectors. The direction of the resulting perpendicular vector follows the "right- hand" rule.

I'm not sure what your "Perpendicular" function is trying to do. All this does is return the (absolute of) x, y, and z values from "direction" into id, jd and kd:

// three mutually perpendicular basis vectors
float3 i = float3(1, 0, 0);
float3 j = float3(0, 1, 0);
float3 k = float3(0, 0, 1);

// measure the projection of "direction" onto each of the axes
float id = abs(dot(i, direction));//i.dot (direction);
float jd =abs( dot(j, direction));//j.dot (direction);
float kd = abs(dot(k, direction));//k.dot (direction);

And the final return value from your Perpendicular function will be the cross product between the input "direction" (your p1p2 vector) and one of the i, j, k vectors (the one "least parallel" to "direction"/p1p2)...

Anyway, it seems all other position vectors are in world space, so maybe you need to rotate the i, j and k basis vectors with the rotation part of your world matrix as well...

This topic is closed to new replies.

Advertisement