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