3

Summary:

I'm given a series of points in 3D space, and I want to analyze them from any viewing angle. I'm trying to figure out how to reproduce the "Look At" functionality of OpenGL in WPF. I want the mouse move X,Y to manipulate the Phi and Theta Spherical Coordinates (respectively) of the camera so that I as I move my mouse, the camera appears to orbit around the center of mass (generally the origin) of the point cloud, which will represent the target of the Look At

What I've done:

I have made the following code, but so far it isn't doing what I want:

    internal static Matrix3D CalculateLookAt(Vector3D eye, Vector3D at = new Vector3D(), Vector3D up = new Vector3D())
    {
        if (Math.Abs(up.Length - 0.0) < double.Epsilon) up = new Vector3D(0, 1, 0);
        var zaxis = (at - eye);
        zaxis.Normalize();
        var xaxis = Vector3D.CrossProduct(up, zaxis);
        xaxis.Normalize();
        var yaxis = Vector3D.CrossProduct(zaxis, xaxis);

        return new Matrix3D(
            xaxis.X, yaxis.X, zaxis.X, 0,
            xaxis.Y, yaxis.Y, zaxis.Y, 0,
            xaxis.Z, yaxis.Z, zaxis.Z, 0,
            Vector3D.DotProduct(xaxis, -eye), Vector3D.DotProduct(yaxis, -eye), Vector3D.DotProduct(zaxis, -eye), 1
            );
    }

I got the algorithm from this link: http://msdn.microsoft.com/en-us/library/bb205342(VS.85).aspx

I then apply the returned matrix to all of the points using this:

    var vector = new Vector3D(p.X, p.Y, p.Z);

    var projection = Vector3D.Multiply(vector, _camera);    // _camera is the LookAt Matrix

    if (double.IsNaN(projection.X)) projection.X = 0;
    if (double.IsNaN(projection.Y)) projection.Y = 0;
    if (double.IsNaN(projection.Z)) projection.Z = 0;

    return new Point(
        (dispCanvas.ActualWidth * projection.X / 320),
        (dispCanvas.ActualHeight * projection.Y / 240)
        );

I am calculating the center of all the points as the at vector, and I've been setting my initial eye vector at (center.X,center.Y,center.Z + 100) which is plenty far away from all the points

I then take the mouse move and apply the following code to get the Spherical Coordinates and put that into the CalculateLookAt function:

        var center = GetCenter(_points);
        var pos = e.GetPosition(Canvas4);   //e is of type MouseButtonEventArgs
        var delta = _previousPoint - pos;

        double r = 100;
        double theta = delta.Y * Math.PI / 180;
        double phi = delta.X * Math.PI / 180;

        var x = r * Math.Sin(theta) * Math.Cos(phi);
        var y = r * Math.Cos(theta);
        var z = -r * Math.Sin(theta) * Math.Sin(phi);

        _camera = MathHelper.CalculateLookAt(new Vector3D(center.X * x, center.Y * y, center.Z * z), new Vector3D(center.X, center.Y, center.Z));

        UpdateCanvas();   // Redraws the points on the canvas using the new _camera values

Conclusion:

This does not make the camera orbit around the points. So either my understanding of how to use the Look At function is off, or my math is incorrect.

Any help would be very much appreciated.

1
  • Don't involve the mouse yet, just try some values for theta and phi. Does (0, 0) work? How about (0, 0.1)? (0.1, 0)?... Commented Feb 7, 2012 at 23:16

2 Answers 2

4

Vector3D won't transform in affine space. The Vector3D won't translate because it is a vector, which doesn't exist in affine space (i.e. 3D vector space with a translation component), only in vector space. You need a Point3D:

var m = new Matrix3D(
                1, 0, 0, 0, 
                0, 1, 0, 0, 
                0, 0, 1, 0, 
                10, 10, 10, 1);

var v = new Point3D(1, 1, 1);
var r = Point3D.Multiply(v, m); // 11,11,11

Note your presumed answer is also incorrect, as it should be 10 + 1 for each component, since your vector is [1,1,1].

Sign up to request clarification or add additional context in comments.

1 Comment

Ah! Thank you, that is what I was looking for :) I didn't even see Point3D. Yes, I was treating all of my points as Vectors, and not Points. Good to know
-2

Well, it turns out that the Matrix3D libraries have some interesting issues.

I noticed that Vector3D.Multiply(vector, matrix) would not translate the vector.

For example:

var matrixTest = new Matrix3D(
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    10, 10, 10, 1
    );

var vectorTest = new Vector3D(1, 1, 1);

var result = Vector3D.Multiply(vectorTest, matrixTest);
// result = {1,1,1}, should be {11,11,11}

I ended up having to rewrite some of the basic matrix math functions in order for the code to work.

Everything was working except for the logic side, it was the basic math (handled by the Matrix3D library) that was the problem.

Here is the fix. Replace all Vector3D.Multiply method calls with this:

    public static Vector3D Vector3DMultiply(Vector3D vector, Matrix3D matrix)
    {
        return new Vector3D(
            vector.X * matrix.M11 + vector.Y * matrix.M12 + vector.Z * matrix.M13 + matrix.OffsetX,
            vector.X * matrix.M21 + vector.Y * matrix.M22 + vector.Z * matrix.M23 + matrix.OffsetY,
            vector.X * matrix.M31 + vector.Y * matrix.M32 + vector.Z * matrix.M33 + matrix.OffsetZ
            );
    }

And everything works!

1 Comment

That works, but using a Point3D instead of Vector3D is a much better approach.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.