morph208
morph208

Reputation: 110

SCNProgram – How to pass a uniform of type "mat4" to a custom shader?

I'm trying to set a uniform mat4 that I want to use in a custom shader program in SceneKit on iOS (Xcode 6 beta 6). And I'm trying to do that in Swift.

let myMatrix: Array<GLfloat> = [1, 0, 0 , 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1]

var material = SCNMaterial()
var program = SCNProgram()

// setup of vertex/fragment shader goes here
program.vertexShader = //...
program.fragmentShader = //...

material.program = program

// I want to initialize the variable declared as "uniform mat4 u_matrix" in the vertex shader with "myMatrix"

material.handleBindingOfSymbol("u_matrix") {
    programID, location, renderedNode, renderer in            
    let numberOfMatrices = 1
    let needToBeTransposed = false
    glUniformMatrix4fv(GLint(location), GLsizei(numberOfMatrices), GLboolean(needToBeTransposed), myMatrix)
}

Using this code, I have the following compilation error: Cannot invoke 'init' with an argument list of type (GLint, GLsizei, GLboolean, Array<GLfloat>). However, from this documentation here (section "Constant pointers") it is my understanding that we can pass an array to a function that takes an UnsafePointer as argument.

I then tried to directly pass an UnsafePointer by doing the following:

let testPtr: UnsafePointer<GLfloat> = nil
glUniformMatrix4fv(GLint(location), GLsizei(numberOfMatrices), GLboolean(needToBeTransposed), testPtr)

And I got the error Cannot invoke 'init' with an argument list of type '(GLint, GLsizei, GLboolean, UnsafePointer<GLfloat>)'

However, the prototype of glUniformMatrix4fv is exactly that:

func glUniformMatrix4fv(location: GLint, count: GLsizei, transpose: GLboolean, value: UnsafePointer<GLfloat>)

Any idea of what I'm doing wrong? How are we supposed to pass a mat4 as an uniform if we use a custom shader?

Note1: I first attempted to use a SCNMatrix4 for myMatrix but I got the error "SCNMatrix4 is not convertible to UnsafePointer".

Note2: I thought of using GLKMatrix4 but this type is not recognized in Swift.

Upvotes: 3

Views: 1864

Answers (1)

Nate Cook
Nate Cook

Reputation: 93276

I've found the compiler's error messages can provide more misdirection than help when figuring out how to call C APIs. My troubleshooting technique has been to declare each parameter as a local variable and see which one gets the red flag. In this case, it's not the last parameter that's causing problems, it's the GLboolean.

let aTranspose = GLboolean(needToBeTransposed)
// Cannot invoke 'init' with an argument of type 'Bool'

Turns out GLboolean is defined this way:

typealias GLboolean = UInt8

So this is the code we need:

material.handleBindingOfSymbol("u_matrix") {
    programID, location, renderedNode, renderer in

    let numberOfMatrices = 1
    let needToBeTransposed = false

    let aLoc = GLint(location)
    let aCount = GLsizei(numberOfMatrices)
    let aTranspose = GLboolean(needToBeTransposed ? 1 : 0)
    glUniformMatrix4fv(aLoc, aCount, aTranspose, myMatrix)
}

Upvotes: 1

Related Questions