Does anyone know the code behind Vector3.Transform?

Started by
5 comments, last by Mike.Popoloski 14 years, 1 month ago
I thought it was simply MxV. But apparently there is more to it than that. Here is my attempt to reproduce it: public static Vector operator *(Matrix left, Vector v) { double w = (left.m41 * v.X) + (left.m42 * v.Y) + (left.m43 * v.Z) + left.m44; Vector v2 = new Vector( ((left.m11 * v.X) + (left.m12 * v.Y) + (left.m13 * v.Z) + left.m14) * w, ((left.m21 * v.X) + (left.m22 * v.Y) + (left.m23 * v.Z) + left.m24) * w, ((left.m31 * v.X) + (left.m32 * v.Y) + (left.m33 * v.Z) + left.m34) * w); return v2; } However, this gives a wierdly skewed results when compared with Transform() using the same Matrix and Vector. Anyone know what I have goofed? Thanks
Advertisement
You have to divide the vector with w, not multiply. Thats how you get rid of homogeneous coordinate.

double w = 1.f / ((left.m41 * v.X) + (left.m42 * v.Y) + (left.m43 * v.Z) + left.m44);

System programmer at 2K Games

Nope, that's not it. Something else is going on. Here is some source code if anyone wants to check my math.

If you step through the call to after T2(), you will notice that works has the correct world coordinates (0,0) for this point after applying the view and projection matrix, however, you will notice broken has other coordinates. If you were to actually plot the coordinates returned by T2, it will be a skewed shape, however the actual skew seems to vary over the y-axis. It's an interesting effect, but unfortunately not the effect I was looking for.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace DirectX_Tutorial
{

public class WinForm : System.Windows.Forms.Form
{
private Device device;
private System.ComponentModel.Container components = null;

public WinForm()
{
InitializeComponent();
this.Setstyle(Controlstyles.AllPaintingInWmPaint | Controlstyles.Opaque, true);
}

public void InitializeDevice()
{
PresentParameters presentParams = new PresentParameters();
presentParams.Windowed = true;
presentParams.SwapEffect = SwapEffect.Discard;
device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
}

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
//device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1f, 50f);
device.Transform.Projection = Matrix.OrthoLH(2, 2, -2f, 2f);
PrintMatrix(device.Transform.Projection);
device.Transform.View = Matrix.LookAtRH(new Vector3(1, 1, 1), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
//device.Transform.View = Matrix.LookAtLH(new Vector3(1.1f, -2.2f, 3.3f), new Vector3(-4.4f, 5.5f, -6.6f), new Vector3(0, 1, 0));
PrintMatrix(device.Transform.View);
device.RenderState.Lighting = false;
device.RenderState.CullMode = Cull.None;
Matrix pxv = device.Transform.View * device.Transform.Projection;

CustomVertex.PositionColored[] vertices = new CustomVertex.PositionColored[6];
vertices[0].Position = new Vector3(.5f, .5f, .5f);
vertices[0].Color = Color.Red.ToArgb();
vertices[1].Position = new Vector3(-.5f, .5f, .5f);
vertices[1].Color = Color.Red.ToArgb();
vertices[2].Position = new Vector3(.5f, -.5f, .5f);
vertices[2].Color = Color.Red.ToArgb();
vertices[3].Position = new Vector3(-.5f, .5f, .5f);
vertices[3].Color = Color.Red.ToArgb();
vertices[4].Position = new Vector3(-.5f, -.5f, .5f);
vertices[4].Color = Color.Red.ToArgb();
vertices[5].Position = new Vector3(.5f, -.5f, .5f);
vertices[5].Color = Color.Red.ToArgb();

Vector4 thisWorks = Vector3.Transform(vertices[0].Position, pxv);
Vector3 broken = T2(pxv, vertices[0].Position);

device.Clear(ClearFlags.Target, Color.DarkSlateBlue, 1.0f, 0);

device.BeginScene();
device.VertexFormat = CustomVertex.PositionColored.Format;
device.DrawUserPrimitives(PrimitiveType.TriangleList, 2, vertices);
device.EndScene();

device.Present();

this.Invalidate();
}

public Vector3 T2(Matrix left, Vector3 v)
{
float w = (left.M41 * v.X) + (left.M42 * v.Y) + (left.M43 * v.Z) + left.M44;
Vector3 v2 = new Vector3(
((left.M11 * v.X) + (left.M12 * v.Y) + (left.M13 * v.Z) + left.M14) * w,
((left.M21 * v.X) + (left.M22 * v.Y) + (left.M23 * v.Z) + left.M24) * w,
((left.M31 * v.X) + (left.M32 * v.Y) + (left.M33 * v.Z) + left.M34) * w);
return v2;
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}

private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.Size = new System.Drawing.Size(500, 500);
this.Text = "DirectX Tutorial";
}

private void PrintMatrix(Matrix m)
{
Console.WriteLine(string.Format("[{0} {1} {2} {3}]", m.M11, m.M12, m.M13, m.M14));
Console.WriteLine(string.Format("[{0} {1} {2} {3}]", m.M21, m.M22, m.M23, m.M24));
Console.WriteLine(string.Format("[{0} {1} {2} {3}]", m.M31, m.M32, m.M33, m.M34));
Console.WriteLine(string.Format("[{0} {1} {2} {3}]", m.M41, m.M42, m.M43, m.M44));
}

static void Main()
{
using (WinForm our_directx_form = new WinForm())
{
our_directx_form.InitializeDevice();
Application.Run(our_directx_form);
}
}
}
}
Try this:

public Vector3 T2(Matrix left, Vector3 v)
{
float w = 1.0 / ((left.M14 * v.X) + (left.M24 * v.Y) + (left.M34 * v.Z) + left.M44);
Vector3 v2 = new Vector3(
((left.M11 * v.X) + (left.M21 * v.Y) + (left.M31 * v.Z) + left.M41) * w,
((left.M12 * v.X) + (left.M22 * v.Y) + (left.M32 * v.Z) + left.M42) * w,
((left.M13 * v.X) + (left.M23 * v.Y) + (left.M33 * v.Z) + left.M43) * w);
return v2;
}

Since its DirectX and not OpenGL, vector & matrix multiplication goes like this:
result_vector = vector * matrix

in your function it goes:
result_vector = matrix * vector

I hope this is it:-)

System programmer at 2K Games

to tranform a vector you multiply each column of matrix with corresponding scallar from transformed vector and then add those 4 vectors.

COL1*vecx+COL2*vecy+COL3*vecz+COL4*vecw=TRVEC

to multiply a vector by a scalar you multiply each coordinate with the number. Result is a vector.
to add vectors you just add each coordinate from vector 1 and vector 2.
Result is a vector.

to transform a vector by 4 dimensianal matrix you write

vector* Transform4Vec(float* matrix,vector tovect){vector* TRVEC=new vector();vector.x=COL1.x*tovect.x+COL2.x*tovect.y+COL3.x*tovect.z+COL4.x*tovect.wvector.y=COL1.y*tovect.x+COL2.y*tovect.y+COL3.y*tovect.z+COL4.y*tovect.wvector.z=COL1.z*tovect.x+COL2.z*tovect.y+COL3.z*tovect.z+COL4.z*tovect.wvector.w=COL1.w*tovect.x+COL2.w*tovect.y+COL3.w*tovect.z+COL4.w*tovect.wreturn TRVEC;}
It is trivial to look at the code for Vector3.Transform if you have Reflector, unless it's an internal call (seems unlikely).
MDX calls into D3DX for all of its math functions, so you aren't going to find any help by reflectoring the internals. You can, however, look at the source for SlimMath, which is checked for correctness against D3DX via a unit test.

For the lazy:
public static void Transform(ref Vector3 vector, ref Matrix transform, out Vector4 result){    result = new Vector4(        (vector.X * transform.M11) + (vector.Y * transform.M21) + (vector.Z * transform.M31) + transform.M41,        (vector.X * transform.M12) + (vector.Y * transform.M22) + (vector.Z * transform.M32) + transform.M42,        (vector.X * transform.M13) + (vector.Y * transform.M23) + (vector.Z * transform.M33) + transform.M43,        (vector.X * transform.M14) + (vector.Y * transform.M24) + (vector.Z * transform.M34) + transform.M44);}
Mike Popoloski | Journal | SlimDX

This topic is closed to new replies.

Advertisement