Draping an image over a triangulation

HaulInfinity drape screenshot

I recently added a feature to Alastri HaulInfinity to drape an image over a 3d triangulation.The idea is to help engineers design their haul network by allowing them to reference an aerial photo.

Vertically projecting the photo onto the terrain is quite straightforward, and not discussed here.

To perform an affine transformation based on registration points, I used the general approach shown here (homogeneous coordinates).

We’re using the Math.Net Numerics library for this, but you could use basic arithmetic quite easily.

To calculate the transformation matrix (C#):


private void CreateTransformationMatrix()
{
    var r1 = _overlay.RegistrationPoints[0];
    var r2 = _overlay.RegistrationPoints[1];
    var r3 = _overlay.RegistrationPoints[2];

    //model coordinates
    Matrix<float> m = new DenseMatrix(3, 3);
    m.SetRow(0, new float[] { (float)r1.ModelX, (float)r2.ModelX, (float)r3.ModelX });
    m.SetRow(1, new float[] { (float)r1.ModelY, (float)r2.ModelY, (float)r3.ModelY });
    m.SetRow(2, new float[] { 1f, 1f, 1f });

    //image coordinates
    Matrix<float> u = new DenseMatrix(2, 3);
    u.SetRow(0, new float[] { (float)r1.ImageX, (float)r2.ImageX, (float)r3.ImageX });
    u.SetRow(1, new float[] { (float)r1.ImageY, (float)r2.ImageY, (float)r3.ImageY });

    _M = u.Multiply(m.Inverse());
}

To transform individual points (C#):

protected override void TextureMappingFunction(Point3D vertex, out float x, out float y)
{
    Matrix<float> point = new DenseMatrix(3, 1);
    point.SetColumn(0, new float[] { (float)vertex.X, (float)vertex.Y, 1 });
    Matrix<float> outM = _M.Multiply(point);

    x = outM.At(0, 0) / TextureWidth;
    y = 1 - outM.At(1, 0) / TextureHeight; //openGl uses inverted Y coordinates
}

Leave a comment

Create a website or blog at WordPress.com