Jump to content

  • Log In with Google      Sign In   
  • Create Account


Álvaro

Member Since 07 Mar 2002
Offline Last Active Yesterday, 09:36 PM

#5173013 Understanding the Z-coordinate.

Posted by Álvaro on 11 August 2014 - 11:10 PM

You draw what's contained in a viewing frustum. The projection to the screen actually doesn't completely forget about the depth of the point that has been projected. Instead, the point gets a value of 0.0 if it is at the near plane, 1.0 if it is at the far plane and somewhere in between if it is inside. This allows you to do basic things like using a z-buffer to make sure nearby things occlude far-away things, and to do advanced things like SSAO.


#5173012 Offsetting 3D Points Based On Rotation + Position Of Camera

Posted by Álvaro on 11 August 2014 - 11:04 PM

I can give you some simple formulas to work with. We'll start with a very simple situation, where we measure everything in pixels and the camera is an eye at a fixed position (0, 0, -1000), looking towards the origin. Our resolution is 1024x768. We can just think of this situation as having the screen contained between (-512, -384, 0) and (+512, +384, 0). So a point (x, y, z) when z = 0 will map to the pixel (512+x,384-y).

If that's clear, we just need to know how to scale things that are farther away from or closer to the eye than the screen. The answer is that point (x,y,z) maps to pixel (512+x*1000/(z+1000), 384-y*1000/(z+1000)). You can convince yourself that this is correct by making a picture of the situation (I suggest from above, to get the formula for the x coordinate) and using triangle similarity.

Now you need to know how to handle other camera positions and angles. Let's handle yaw first. You can rotate the whole world around the origin on the XY plane by using these formulas:

x' = x * cos(angle) - y * sin(angle)
y' = x * sin(angle) + y * cos(angle)

Do that to every point in the scene and your whole world has now rotated around the origin. If you want the rotation to happen around any other point, first subtract the coordinates of the center of rotation, then rotate, then add them back. In particular, you can now perform rotations around the camera, which has the same effect as rotating the camera.

For pitch you can do the same thing in the YZ plane. The order of rotations does matter. You probably want to apply pitch first and then yaw, but if that doesn't do what you want, reverse the order.

Moving the camera around is pretty easy, since all you have to do is -again- move the whole world in the opposite direction, by subtracting some vector from every point.

That's the closest I can get to "simplified math". I hope it helps. But you should really really try to find a gentle introduction to the algebra of matrices and vectors and try to understand the formulas you've found in other places.


#5172291 Triangle vectors on the circle

Posted by Álvaro on 08 August 2014 - 08:59 AM

Take the average direction of the two red lines and rotate it 15 degrees to each side to get the directions of the blue lines. [EDIT: Perhaps I didn't understand what you mean by "are angled at 30 degrees". Please tell draw the angles you are talking about.]


#5172241 Debugging memory leak(?) or logic problem

Posted by Álvaro on 08 August 2014 - 04:30 AM

Putting crap in a standard container and never removing it is not technically a leak, but it could very well be what you are experiencing.

See if you can simplify your program a lot and still have the behavior you observe, then try to understand what's going on in the simpler program.


#5172068 Safely using IEEE754 Float types.

Posted by Álvaro on 07 August 2014 - 10:53 AM

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html


I think that's way too much information for the "For Beginners" forum. You might scare people off by drowning them in details.


#5172057 Safely using IEEE754 Float types.

Posted by Álvaro on 07 August 2014 - 09:58 AM

#2 What is the absollutely safe range (maximum and minimum) in floats without losing information(end ressult the number will be represented exactly).


That question doesn't make much sense. There is no entire range of real numbers that can be represented exactly. Here's a description of what can be represented:
From 1 to 2 you can represent anything in increments of 2^-23. So these numbers can be represented exactly:

1.00000000000000000000000
1.00000011920928955078125
1.00000023841857910156250
1.00000035762786865234375
1.00000047683715820312500
1.00000059604644775390625
1.00000071525573730468750
1.00000083446502685546875
1.00000095367431640625000
1.00000107288360595703125
1.00000119209289550781250
1.00000131130218505859375
...
1.99999904632568359375000
1.99999916553497314453125
1.99999928474426269531250
1.99999940395355224609375
1.99999952316284179687500
1.99999964237213134765625
1.99999976158142089843750
1.99999988079071044921875
2.00000000000000000000000

Between 2 and 4 the step is 2^-22, then between 4 and 8 the step is 2^-21 and so on. For numbers smaller than 1, it works similarly: Between 0.5 and 1 the step is 2^-24, between 0.25 and 0.5 the step is 2^-25, and so on.

That is a almost a full description of the situation. Of course there is a maximum number that can be represented and things are different for numbers very close to zero.

If in light of this explanation you still have a question, post it.


#5171946 Turn Based AI Technics

Posted by Álvaro on 06 August 2014 - 03:25 PM

Dave wrote a book that covers precisely that type of thing.

Or you can just take the basic idea (write a function that returns how happy you are with an action (the "expected utility" of the action) and then pick the action with the highest value) and experiment with it. Chances are you'll discover everything that's in the book by yourself. But still, Dave is a nice guy and you should buy his book. smile.png


#5171613 Cohesion and coupling

Posted by Álvaro on 05 August 2014 - 07:09 AM

It looks pretty bad. Perhaps you can post the definition of that function, so we can see what you are doing with each argument.


#5171388 Quaternion angle with itself > 0.001

Posted by Álvaro on 04 August 2014 - 05:47 AM

I just wanted to point a couple things out. I can't be 100% sure, but I believe the original quaternions were already normalized. After a lot of testing and examining, it looks as though the normalization simply traded error on one side for error on the other side, which resulted in a SEEMINGLY better angle result. I noticed this because I can literally renormalize a quaternion over and over again, and get different results each time.


I think the quaternion you posted originally was not properly normalized. Do you care to post a particular quaternion for which the renormalization isn't stable?


Even something as simple as 1+1=2 can turn your game world upside-down if its not interpreted as 1+1=almost definitely 2.


That seems to indicate you don't understand floating-point numbers very much: 1 + 1 is most definitely exactly 2.


#5171262 good random permutation?

Posted by Álvaro on 03 August 2014 - 08:17 AM

Would this be too slow for your program?
  x = (x ^ seed ^ 1234567890) & 2147483647;
  x = ((x << 5) ^ (x >> 26)) & 2147483647;
  x = (x + 675788137) & 2147483647;
  x ^= 751504984u;
  x = (x * 2020831389) & 2147483647;
  x = ((x << 15) ^ (x >> 16)) & 2147483647;
  x = (x + 1804049603) & 2147483647;
  x ^= 1028562816u;
  x = (x * 1430376653) & 2147483647;
  x = ((x << 15) ^ (x >> 16)) & 2147483647;
  x = (x + 1804049603) & 2147483647;
  x ^= 1028562816u;
  x = (x * 1430376653) & 2147483647;
  return x;



#5171260 good random permutation?

Posted by Álvaro on 03 August 2014 - 08:07 AM

You have to be a little bit more careful. The operation g(x) = (x ^ ((x << 6) ^ (x >> 26))) & 2147483647 is not injective:

g(0) = g(1431655765) = 0

So your function ends up not being a permutation. With seed = 0:

f(0) = f(297859934) = f(719478613) = f(1927211019) = 1905156899

EDIT: I didn't check carefully, but `x = (x + ((x << 5) ^ (x >> 12))) & 2147483647;' is probably also problematic.


#5171209 Floats vs Ints.

Posted by Álvaro on 02 August 2014 - 08:34 PM

Float32s cannot perfectly represent all values within their range. They cannot even represent every single possible Int32, which may surprise some people.


How can that possibly surprise anybody? There are 2^32 different Int32 values, and floats are represented using 32 bits. So for every non-integer number that can be represented as a Float32s, there is an integer that cannot be represented as a Float32s.


#5171068 Spring phisic and quaternion

Posted by Álvaro on 02 August 2014 - 05:06 AM

Dampening is next step. It would be more easier. Now it would be good if spring make harmonic vibration from start to target, opposite side and back, without unexpected rotation and flying into deep space.


Is that not what you are getting?

I added a `main' and a couple of extra operators for vectors to show that integrating this torque works. You can set `angular_dampening' to 0.0 if you want to see it oscillate forever. For simplicity, I am assuming the moment of inertia is the identity matrix.

#include <iostream>
#include <cmath>
#include <boost/math/quaternion.hpp>

typedef boost::math::quaternion<double> Quaternion;

struct Vector {
  double x, y, z;
  
  Vector(double x, double y, double z) : x(x), y(y), z(z) {
  }
};

std::ostream &operator<<(std::ostream &os, Vector v) {
  return os << '(' << v.x << ',' << v.y << ',' << v.z << ')';
}

Vector operator*(double s, Vector v) {
  return Vector(s * v.x, s * v.y, s * v.z);
}

Vector operator-(Vector v1, Vector v2) {
  return Vector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}

Vector &operator+=(Vector &v1, Vector v2) {
  v1.x += v2.x;
  v1.y += v2.y;
  v1.z += v2.z;
  
  return v1;
}

Vector cross_product(Vector v1, Vector v2) {
  return Vector(v1.y * v2.z - v1.z * v2.y,
		v1.z * v2.x - v1.x * v2.z,
		v1.x * v2.y - v1.y * v2.x);
}

double dot_product(Vector v1, Vector v2) {
  return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}

double squared_length(Vector v) {
  return dot_product(v, v);
}

double length(Vector v) {
  return std::sqrt(squared_length(v));
}

Quaternion most_natural_rotation(Vector v1, Vector v2) {
  Vector v = cross_product(v1, v2);
  Quaternion q(std::sqrt(squared_length(v1) * squared_length(v2)) + dot_product(v1, v2),
	       v.x, v.y, v.z);
  return q / abs(q);
}

Vector apply_rotation(Quaternion q, Vector v) {
  Quaternion result = q * Quaternion(0.0, v.x, v.y, v.z) * conj(q);
  return Vector(result.R_component_2(), result.R_component_3(), result.R_component_4());
}

Vector log_of_unit_quaternion(Quaternion q) {
  double angle = std::acos(q.real());
  Vector axis(q.R_component_2(), q.R_component_3(), q.R_component_4());
  return (angle / length(axis)) * axis;
}

Vector compute_torque(Quaternion current_attitude,
		      Vector model_needle,
		      Vector target,
		      double spring_force) {
  Vector needle = apply_rotation(current_attitude, model_needle);
  Quaternion rotation = most_natural_rotation(needle, target);
  return spring_force * log_of_unit_quaternion(rotation);
}

int main() {
  Vector model_needle(1.0, 0.0, 0.0);
  Quaternion attitude(1.0, 0.0, 0.0, 0.0);
  Vector angular_velocity(0.0, 0.0, 0.0);
  
  double const angular_dampening = 1.0;
  double const dt = 0.1;
  
  for (int i=0; i<1000; ++i) {
    std::cout << apply_rotation(attitude, model_needle) << ' ' << attitude << ' ' << angular_velocity << '\n';
    Vector torque = compute_torque(attitude, model_needle, Vector(0.0, 1.0, 0.0), 1.0);
    Vector angular_acceleration = torque - angular_dampening * angular_velocity;
    angular_velocity += dt * angular_acceleration;
    attitude *= exp(dt * Quaternion(0.0, angular_velocity.x, angular_velocity.y, angular_velocity.z));
  }
}




#5170872 Spring phisic and quaternion

Posted by Álvaro on 01 August 2014 - 07:04 AM

This should be close to what you need. It is a bit math heavy, so don't feel too bad if you don't understand it all: Just ask me about what parts you don't understand and I'll try to explain them.

#include <iostream>
#include <cmath>
#include <boost/math/quaternion.hpp>
 
typedef boost::math::quaternion<double> Quaternion;
 
struct Vector {
  double x, y, z;
  
  Vector(double x, double y, double z) : x(x), y(y), z(z) {
  }
};
 
std::ostream &operator<<(std::ostream &os, Vector v) {
  return os << '(' << v.x << ',' << v.y << ',' << v.z << ')';
}
 
Vector operator*(double s, Vector v) {
  return Vector(s * v.x, s * v.y, s * v.z);
}
 
Vector cross_product(Vector v1, Vector v2) {
  return Vector(v1.y * v2.z - v1.z * v2.y,
                v1.z * v2.x - v1.x * v2.z,
                v1.x * v2.y - v1.y * v2.x);
}
 
double dot_product(Vector v1, Vector v2) {
  return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
 
double squared_length(Vector v) {
  return dot_product(v, v);
}
 
double length(Vector v) {
  return std::sqrt(squared_length(v));
}
 
Quaternion most_natural_rotation(Vector v1, Vector v2) {
  Vector v = cross_product(v1, v2);
  Quaternion q(std::sqrt(squared_length(v1) * squared_length(v2)) + dot_product(v1, v2),
               v.x, v.y, v.z);
  return q / abs(q);
}
 
Vector apply_rotation(Quaternion q, Vector v) {
  Quaternion result = q * Quaternion(0.0, v.x, v.y, v.z) * conj(q);
  return Vector(result.R_component_2(), result.R_component_3(), result.R_component_4());
}
 
Vector log_of_unit_quaternion(Quaternion q) {
  double angle = std::acos(q.real());
  Vector axis(q.R_component_2(), q.R_component_3(), q.R_component_4());
  return (angle / length(axis)) * axis;
}
 
Vector compute_torque(Quaternion current_attitude,
                      Vector model_needle,
                      Vector target,
                      double spring_force) {
  Vector needle = apply_rotation(current_attitude, model_needle);
  Quaternion rotation = most_natural_rotation(needle, target);
  return spring_force * log_of_unit_quaternion(rotation);
}




#5170674 Why NDC and how to convert?

Posted by Álvaro on 31 July 2014 - 02:05 PM

I chose [-1,1] instead of [0,1] because that's the typical range of NDC. If I remember correctly, OpenGL uses [-1,1] for all three axes, and DirectX uses [-1,1] for x and y and [0,1] for z.


Oh, so by adding 1 you make it positive and later divide by 2 to make up for adding 'that half of the screen' ???


Yes. One way to think about it is that (x + 1) / 2 maps the interval [-1,1] to [0,1], and multiplying by Width maps [0,1] to [0,Width].




PARTNERS