Random distribution of particles in a given angle from a direction

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Random distribution of particles in a given angle from a direction

      Hi everyone!

      I have a little problem here and it might be something realy stupid but i do not understand why this is not working as i thought it would...

      I am currently working on particle emitters and i am trying to implement something like a maximum angle in which a particle could be emitted. And i want to randomly choose a direction to distribute a particle. So they would all be in some sort of "emission cone" from the origin of the particle emitter.

      I tried it following this idea: Random Vector (The answer from ktodisco)

      This is my code for it:

      Source Code

      1. randomVector.setX(float((rand() % 2000) / 1000.0) - 1.0);
      2. randomVector.setY(float((rand() % 2000) / 1000.0) - 1.0);
      3. randomVector.setZ(float((rand() % 2000) / 1000.0) - 1.0);
      4. randomVector.normalize();
      5. projectedVector = randomVector - ( emitterDirection * ( emitterDirection * randomVector ) );
      6. randomAngle = float(rand() % int(open * 1000.0)) / 1000.0;
      7. rotation.setOrientationFromAxisAndAngle(randomAngle, projectedVector);
      8. dirVector = emitterDirection;
      9. dirVector = rotation.transform(dirVector);
      10. dirVector.normalize();
      11. emittedParticle->setVelocity(dirVector * 10.0);
      Display All


      the function setOrientationFromAxisAndAngle is like this:

      Source Code

      1. void setOrientationFromAxisAndAngle (const float angle, const cge::Vector3D axis) {
      2. float cosA = cos(angle);
      3. float sinA = sin(angle);
      4. float ux = axis.x();
      5. float uy = axis.y();
      6. float uz = axis.z();
      7. data[0] = cosA + ( ux * ux * ( 1 - cosA ) );
      8. data[1] = (ux * uy * ( 1 - cosA )) - (uz * sinA);
      9. data[2] = (ux * uz * (1 - cosA)) + (uy * sinA);
      10. data[3] = (uy * ux * ( 1 - cosA )) + (uz * sinA);
      11. data[4] = cosA + ( uy * uy * ( 1 - cosA ) );
      12. data[5] = (uy * uz * ( 1 - cosA )) - (ux * sinA);
      13. data[6] = (uz * ux * ( 1 - cosA )) - (uy * sinA);
      14. data[7] = (uz * uy * ( 1 - cosA )) + (ux * sinA);
      15. data[8] = cosA + ( uz * uz * ( 1 - cosA ) );
      16. }
      Display All


      The function follows the definition for the rotation matrix from an axis and an angle in the wikipedia .here

      And it does not work. For small values for the angle the distribution seems to be more focused and for realy small values of 1.0 and lower its very focused. But it seems to be distributed everywhere from 5.0 and up. Nothing i could work with as it is not determined what happens when. And i can not figure out what i am doing wrong. So if someone could take a look at that code and maybe point out why i am stupid i would be happy :)

      Thank you!
    • You're not implementing his formula:

      Source Code

      1. projectedVector = randomVector - (coneDirection * (dot(coneDirection,randomVector));


      Yours is:

      Source Code

      1. projectedVector = randomVector - ( emitterDirection * ( emitterDirection * randomVector ) );


      You're multiplying emitterDirection and randomVector and then multiplying that again by emitterDirection. He's taking the dot product of those two vectors and multiplying it by emitter direction.

      -Rez
    • Oh, i should have explained that part. If i multiply two vectors the * means dot product and returns a float. If i multiply a vector and a float it is a normal multiplication (I did not write the Vector3 class, so i have to work with what is in there...). So the line first evaluates

      Source Code

      1. emitterDirection * randomDirection

      as the dot product and returns a float.
      then

      Source Code

      1. emitterDirection * (result of the dot product)

      multiplies the float with a vector.

      I manually checked this part a few times (running the program, setting break points and checking the values of the vectors then calculating what the result should be by hand on paper) and the results were correct.
    • Ok, i now have it sorted out:

      Source Code

      1. randomVector.setX(float((rand() % 2000) / 1000.0) - float(1.0));
      2. randomVector.setY(float((rand() % 2000) / 1000.0) - float(1.0));
      3. randomVector.setZ(float((rand() % 2000) / 1000.0) - float(1.0));
      4. randomVector.normalize();
      5. projectedVector = randomVector - ( emitterDirection * ( emitterDirection * randomVector ) );
      6. randomAngle = float(rand() % int(1000.0 * open)) / float(1000.0);
      7. randomAngle *= float(PI);
      8. projectedVector.normalize();
      9. rotation.matrixFromAxisAngle(randomAngle, projectedVector);
      10. dirVector = rotation * emitterDirection;
      11. dirVector.normalize();
      Display All


      does the heavy lifting and

      Source Code

      1. void matrixFromAxisAngle(const float angle, const cge::Vector3D axis) {
      2. real c = cos(angle);
      3. real s = sin(angle);
      4. real t = real(1.0) - c;
      5. data[0] = c + axis.x()*axis.x()*t;
      6. data[4] = c + axis.y()*axis.y()*t;
      7. data[8] = c + axis.z()*axis.z()*t;
      8. real tmp1 = axis.x()*axis.y()*t;
      9. real tmp2 = axis.z()*s;
      10. data[3] = tmp1 + tmp2;
      11. data[1] = tmp1 - tmp2;
      12. tmp1 = axis.x()*axis.z()*t;
      13. tmp2 = axis.y()*s;
      14. data[6] = tmp1 - tmp2;
      15. data[2] = tmp1 + tmp2; tmp1 = axis.y()*axis.z()*t;
      16. tmp2 = axis.x()*s;
      17. data[7] = tmp1 + tmp2;
      18. data[5] = tmp1 - tmp2;
      19. }
      Display All

      gets me the rotation matrix from the axis and angle. It does the same as the other code in my original posting but it is a little bit faster and more efficient.

      Most parts are the same with one simple change.

      Source Code

      1. randomAngle = float(rand() % int(1000.0 * open)) / float(1000.0);
      2. randomAngle *= float(PI);


      The opening angle now is given as a value between 0 and 1.0 and is multiplied by pi. I am not completely sure about why it takes the values from 0 to pi as an argument but with this 0 means no spread and pi means 180° spread.
    • Originally posted by sebastianp
      Oh, i should have explained that part. If i multiply two vectors the * means dot product and returns a float. If i multiply a vector and a float it is a normal multiplication (I did not write the Vector3 class, so i have to work with what is in there...).


      Really?? What crazy math library is this that overloads the multiplication operator like that? That doesn't read at all and serves as a great example of horrible operator overloading and poor interface design. I mean, how do you multiply two vectors together? This is a much more common operation than a dot product. Please tell me there's not a Mult() function or something.... Or do you just have to do it manually?

      You should excise that vector class from your code like the unholy demon it is. I will give you a 3D vector class from my own engine if you promise me you will never use that class again.

      On an entirely less sarcastic note, I'm glad you got it to work. :) Dealing with annoying math issues can be frustrating because it's not immediately obvious what the issue is.

      After a bit of hunting, I found this, which seems to be closer to what I'd expect for this type of system and is probably the approach I'd take. If it's working for you, it's probably not worth changing over to another method though.
      math.stackexchange.com/questio…m-direction-within-a-cone

      -Rez
    • Originally posted by rezination

      Really?? What crazy math library is this that overloads the multiplication operator like that? That doesn't read at all and serves as a great example of horrible operator overloading and poor interface design. I mean, how do you multiply two vectors together? This is a much more common operation than a dot product. Please tell me there's not a Mult() function or something.... Or do you just have to do it manually?

      You should excise that vector class from your code like the unholy demon it is. I will give you a 3D vector class from my own engine if you promise me you will never use that class again.


      Yeah i know what you must be thinking and trust me, i am thinking exactly the same. I did not write the Vector3 class, and i would do a lot of things different. The existing class was written by a fresh computer science student and has some realy annoying things in it... For example, the only way to set value in a vector (besides the constructor) is with functions like setX (). And to get a value you call the function x() or y() or z(). This makes some really messy code... And its on top of my "things i would like to change"-list since day one. But i didnt have the time yet... I promise i will schedule this after my current task. ;)

      On an entirely less sarcastic note, I'm glad you got it to work. :) Dealing with annoying math issues can be frustrating because it's not immediately obvious what the issue is.

      After a bit of hunting, I found this, which seems to be closer to what I'd expect for this type of system and is probably the approach I'd take. If it's working for you, it's probably not worth changing over to another method though.
      math.stackexchange.com/questio…m-direction-within-a-cone

      -Rez


      Yeah, thats one of the things i stumbled across, too. But somehow i thought of the solution i posted above to be easier to implement... I will read up on the other one and see if i fully understand it ;)

      The post was edited 1 time, last by sebastianp ().

    • I really wish schools were better about teaching interface design. It's one of those things that I find lacking in a lot of code I see, including my own code from a decade ago. Hmm, that might make a good tutorial...

      -Rez
    • Yeah, it something you dont learn at school or university... At school we were just doing dumb mini-programs and in the university i programmed a lot but we never had lectures specific to interface design (but i know a lot about message-busses for cars, bezier-curve computation by hand, a* solutions done on paper and so on ;) )... So i probably lack a lot of competence in that field, too ;) This means: Yes, make a tutorial :)
    • I use a fairly simple library from here
      VMath

      Check it out it has served me fairly well so far :)
      PC - Custom Built
      CPU: 3rd Gen. Intel i7 3770 3.4Ghz
      GPU: ATI Radeon HD 7959 3GB
      RAM: 16GB

      Laptop - Alienware M17x
      CPU: 3rd Gen. Intel i7 - Ivy Bridge
      GPU: NVIDIA GeForce GTX 660M - 2GB GDDR5
      RAM: 8GB Dual Channel DDR3 @ 1600mhz