I've set up a test project for learning Metal on iOS to do some rendering, but I'm a bit stumped on how to get a prism rotating correctly about its y axis.

Here is the prism rendered without depth testing so all sides can be seen, so it looks like this part is at least correct:

enter image description here

These are the vertices:

static const float vertexData[] = {
     0.f,  1.f,  0.5f,
     1.f, -1.f,  0.f,
    -1.f, -1.f,  0.f,

     0.f,  1.f,  0.5f,
     1.f, -1.f,  1.f,
     1.f, -1.f,  0.f,

     0.f,  1.f,  0.5f,
    -1.f, -1.f,  1.f,
     1.f, -1.f,  1.f,

     0.f,  1.f,  0.5f,
    -1.f, -1.f,  0.f,
    -1.f, -1.f,  1.f

However, when I turn on rotation, this is what happens: https://www.dropbox.com/s/esg41j3ibncofox/prism_rotate.mov?dl=0

(The video has depth testing turned on). Why is the prism clipping like that (and/or what is it clipping through)? And it's not rotating about it's centre.

Here are how the MVP matrices are being calculated:

static simd::float3 viewEye = {0.f, 0.f, -2.f};
static simd::float3 viewCenter = {0.f, 0.f, 1.f};
static simd::float3 viewUp = {0.f, 1.f, 0.f};
static float fov = 45.f;

CGSize size = self.view.bounds.size;
Uniforms *uniforms = (Uniforms *)[uniformBuffer contents];
uniforms->view = AAPL::lookAt(viewEye, viewCenter, viewUp);
uniforms->projection = AAPL::perspective_fov(fov, size.width, size.height, 0.1f, 100.f);

uniforms->model = AAPL::translate(0.f, 0.f, 12.f) * AAPL::rotate(tAngle, 0.f, 1.f, 0.f);
tAngle += 0.5f;

The transform, lookAt, rotate, and perspective_fov functions are lifted straight from Apple sample code I used as reference.

Here is the shader:

typedef struct {
    float4 pos [[ position ]];
    half4 color;
    float mod;
} VertexOut;

vertex VertexOut basic_vertex(const device packed_float3* vertex_array [[ buffer(0) ]],
                              const device packed_float3* colors [[ buffer(1) ]],
                              constant Uniforms& uniform [[ buffer(2) ]],
                              uint vid [[ vertex_id ]],
                              uint iid [[ instance_id ]])
    float4 v = float4(vertex_array[vid], 1.f);
    float4x4 mvp_matrix = uniform.projection * uniform.view * uniform.model;

    VertexOut out;
    out.pos = v * mvp_matrix;
    uint colorIndex = vid / 3;
    out.color = half4(half3(colors[colorIndex]), 1.f);
    return out;

fragment half4 basic_fragment(VertexOut f [[ stage_in ]]) {
    return f.color;

Any help/tips would be appreciated!


The problem was in the shader, and I had the order of multiplication wrong with the MVP matrix.

So this:

out.pos = v * mvp_matrix;

should be:

out.pos = mvp_matrix * v;

For whatever reason, I'm used to dealing with row vectors and had myself convinced the problem was due to the matrices themselves and the clip region..


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.