Search code examples
matrixswift5metalios14compute-shader

iOS Metal how to access elements of a 3x3 matrix using subscripts?


I got a legacy Apple example that I'm rewriting using modern syntax (example was using Metal with Objective C++). It does a lot of abbreviating, and I'm trying to decode what they are doing with their matrices, and it's rather hard. Part of the problem is that I don't know if they are reading the matrix using [row][column] as in x,y or [column],[row].

I'm looking at this Apple document about working with Matrices, and do not see the type of subscripting they are using in their example. The documentation suggests it is [column],[row]. https://developer.apple.com/documentation/accelerate/working_with_matrices

uint2 position = uint2(0,0);
matrix_float3x3 cameraIntrinsicsInversed = ...;
const float depth = 10.0f;

const float xrw = (position.x - cameraIntrinsics[2][0]) * depth / cameraIntrinsics[0][0];
const float yrw = (position.y - cameraIntrinsics[2][1]) * depth / cameraIntrinsics[1][1];

pointCloud[index].position = simd_float3(xrw, yrw, depth);

// later, in the vertex shader:
const auto position = pointCloud[index].position;
float4 projectedPosition = viewProjectionMatrix * float4(position, 1.0);

How to properly access elements of a 3x3 matrix using subscript if I want a specific row and column element?

I tried:

// Cannot initialize a variable of type 'const float' with an lvalue of type 'const vec<float, 3>' (vector of 3 'float' values)
const float tx = cameraIntrinsics[2, 0]; 
const float ty = cameraIntrinsics[2, 1];

//again, I'm not sure if I'm getting a column or row here
const float tx = cameraIntrinsics.columns[2][0]; 
const float ty = cameraIntrinsics.columns[2][1];

enter image description here

var matrix = matrix_identity_float3x3
matrix[2, 0] = tx // this is swift syntax

Solution

  • Matrices in Metal and simd for that matter use column major ordering for matrices. For example, see Working with Matrices:

    A matrix is a 2D array of values arranged in rows and columns. [...] It uses a column major naming convention; for example, a simd_double4x2 is a matrix containing four columns and two rows.

    Also, if you check out Metal Languages Specification, section 2.3.2, it says:

    Matrix components are constructed and consumed in column-major order

    What does column-major order mean?

    Basically, that means that first subscript in square brackets is going to be the index of the column and the second subscript is index of the row. Also, column major means that matrix is layed out column by column in memory. If you mix-and-match different math libraries, you can get a confusion from that cause some use row-major order.

    As for how to write the subscript, it's fairly easy. In the Metal Language Specification, section 2.3.1 there's a code sample

    float4x4 m;
    // This sets the 2nd column to all 2.0. 
    m[1] = float4(2.0f);
    // This sets the 1st element of the 1st column to 1.0. 
    m[0][0] = 1.0f;
    // This sets the 4th element of the 3rd column to 3.0.
    m[2][3] = 3.0f;