Swiftでシェーダプログラムを読み込む
OpenGLの解説ではなくて、文字列変換に関するメモです。
「実践iPad/iPhoneゲームプログラミング」を読みながら、
Obj-CをSwiftに書き直しています。
まだサポートページも存在するのでサンプルコードも手に入るし、
運が良ければ書店で入手できるかも。
GLKView
が存在するとは言え、貴重な情報源には違いないです。
と言う訳で、さくさく文字列を変換したと思います。
1. シェーダプログラムを追加する
これは、適当なテキストファイルを追加するだけですね。
でもって、XcodeでTypeを変更するとコードヒントが出るようになります。
(Default
からOpenGL Shading Language source
に変更。)
あと、追加したファイルがコンパイル対象ではなく、
リソースとしてコピーされるようにする必要があるみたいだけど、
自分の環境だと何もしなくても良さそうでした。
追加したファイルが、Compile Sources
に存在するなら、
手動で削除したり、追加したりする必要があるんですかね?
2. シェーダプログラムを読み込む
追加したファイルが、
“shader.vsh”と”shader.fsh”ならこんな感じ。(*1)
import UIKit import GLKit class MyGLKViewController: GLKViewController { var program: GLuint = 0 weak var glkView: GLKView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. glkView = self.view as! GLKView glkView.context = EAGLContext( API: .OpenGLES2 ) EAGLContext.setCurrentContext( glkView.context ) loadShaders() // ... } deinit { glDeleteProgram( program ) } func loadShaders() -> Bool { program = glCreateProgram() println( "program = \(program)" ) let vshPath = NSBundle.mainBundle().pathForResource( "shader", ofType: "vsh" ) let fshPath = NSBundle.mainBundle().pathForResource( "shader", ofType: "fsh" ) println( "vshPath = \(vshPath)" ) println( "fshPath = \(fshPath)" ) var vertShader: GLuint = 0 if !compileShader(&vertShader, file: vshPath!, shaderType: GLenum(GL_VERTEX_SHADER)) { return false } glAttachShader( program, vertShader ) if !linkProgram(program) { if vertShader != 0 { glDeleteShader( vertShader ) } return false } // ... if vertShader != 0 { glDeleteShader( vertShader ) } return true } func compileShader(inout shader: GLuint, file: String, shaderType: GLenum) -> Bool { var str = NSString(contentsOfFile: file, encoding: NSUTF8StringEncoding, error: nil ) if str == nil { println( "Failed to load file!" ) println( "file: \(file)" ) return false } var source = str!.UTF8String shader = glCreateShader( shaderType ) glShaderSource( shader, 1, &source, nil ) glCompileShader( shader ) var logLength: GLint = 0 glGetShaderiv( shader, GLenum(GL_INFO_LOG_LENGTH), &logLength ) if 0 < logLength { var log = [GLchar]( count: Int(logLength), repeatedValue: 0 ) glGetShaderInfoLog( shader, logLength, &logLength, &log ) println( String.fromCString(log) ) } var status: GLint = 0 glGetShaderiv( shader, GLenum(GL_COMPILE_STATUS), &status ) if status == 0 { glDeleteShader( shader ) return false } return true } func linkProgram(prog: GLuint) -> Bool { glLinkProgram( prog ) var logLength: GLint = 0 glGetProgramiv( prog, GLenum(GL_INFO_LOG_LENGTH), &logLength ) if 0 < logLength { var log = [GLchar]( count: Int(logLength), repeatedValue: 0 ) glGetProgramInfoLog( prog, logLength, &logLength, &log ) println( String.fromCString(log) ) } var status: GLint = 0 glGetProgramiv( prog, GLenum(GL_LINK_STATUS), &status ) if status == 0 { return false } return true } override func glkView(view: GLKView!, drawInRect rect: CGRect) { glClear( GLbitfield(GL_COLOR_BUFFER_BIT) ) // ... } }
見ての通り、”shader.fsh”は読み込んでないです。
まだ本を読みながら、Swiftに書き直してる段階だけど、
そもそも文字列変換でハマっていたので、何かの参考になれば。
ちなみにこれを実行すると、OpenGLからエラーログが取得できます。
Optional("ERROR: OpenGL ES requires exactly one vertex and one fragment shader to validly link.\n")
おしまい。
(*1) 「実践iPad/iPhoneゲームプログラミング」に載ってるサンプルコードをSwiftで書き直したものです。
Leave a Comment