2012年6月7日 星期四

OpenGL ES 2.0 Tutorial Part 1 - 3

since: 2012/06/07
update: 2012/06/07


reference:
1. OpenGL ES 2.0 for iPhone Tutorial | Ray Wenderlich
2. I touchs: OpenGL ES 2.0 Tutorial Part 1 - 1
3. I touchs: OpenGL ES 2.0 Tutorial Part 1 - 2

Compiling Vertex and Fragment Shaders

A. 說明:
     1. 接下來要做的工作是: 讓應用程式在執行時, 能即時地編譯這些 shaders 以供使用.

     2. 經由這樣的設置方式, shader code 才不會只相依於某些特定的繪圖晶片.

----------------------------------------------------------------------------------


B. 開啟 OpenGLView.h 檔案, 修改如下:
#import <UIKit/UIKit.h>
//@add
#import <QuartzCore/QuartzCore.h>
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>

@interface OpenGLView : UIView
{
    //@add
    CAEAGLLayer *_eaglLayer;
    EAGLContext *_context;
    GLuint _colorRenderBuffer;
   
    //@add
    GLuint _positionSlot;
    GLuint _colorSlot;
}

//@add
- (void)setupLayer; // Set layer to opaque(不透明)
- (void)setupContext; // Create OpenGL context
- (void)setupRenderBuffer; // Create a render buffer
- (void)setupFrameBuffer; // Create a frame buffer
- (void)render; // render something

//@add
- (GLuint)compileShader:(NSString *)shaderName withType:(GLenum)shaderType;
- (void)compileShaders;

@end

----------------------------------------------------------------------------------

C. 開啟 OpenGLView.m 檔案, 修改如下:
....
//@add
- (GLuint)compileShader:(NSString *)shaderName withType:(GLenum)shaderType
{
    // 1. Gets an NSString with the contents of the file.
    NSString *shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:@"glsl"];
   
    NSError *error;
    NSString *shaderString = [NSString stringWithContentsOfFile:shaderPath
                                                       encoding:NSUTF8StringEncoding error:&error];
    if (!shaderString) {
        NSLog(@"Error loading shader: %@", error.localizedDescription);
        exit(1);
    }
   
    // 2. Create a OpenGL object to represent the shader
    GLuint shaderHandle = glCreateShader(shaderType);   
   
    // 3.1
    // Convert the source code from an NSString to a C-string
    const char *shaderStringUTF8 = [shaderString UTF8String];   
    int shaderStringLength = [shaderString length];
    // 3.2
    // Give OpenGL the source code for this shader.
    glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);
   
    // 4. Compile the shader at runtime
    glCompileShader(shaderHandle);
   
    // 5. Error handle
    GLint compileSuccess;
    glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);

    // If fail, output any error messages to the screen & quit app
    if (compileSuccess == GL_FALSE) {
        GLchar messages[256];
        glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
        NSString *messageString = [NSString stringWithUTF8String:messages];
        NSLog(@"%@", messageString);
        exit(1);
    }
   
    return shaderHandle;
}
....
//@add
- (void)compileShaders
{
    // 1. Compile the vertex and fragment shaders.
    GLuint vertexShader = [self compileShader:@"SimpleVertex" withType:GL_VERTEX_SHADER];

    GLuint fragmentShader = [self compileShader:@"SimpleFragment" withType:GL_FRAGMENT_SHADER];
   
    // 2. Link the vertex and fragment shaders into a complete program.
    GLuint programHandle = glCreateProgram();
    glAttachShader(programHandle, vertexShader);
    glAttachShader(programHandle, fragmentShader);
    glLinkProgram(programHandle);
   
    // 3. Check and see if there were any link errors,
    //      and display the output and quit if so.

    GLint linkSuccess;
    glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
    if (linkSuccess == GL_FALSE) {
        GLchar messages[256];
        glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);
        NSString *messageString = [NSString stringWithUTF8String:messages];
        NSLog(@"%@", messageString);
        exit(1);
    }
   
    // 4. Tell OpenGL to actually use this program when given vertex info.
    glUseProgram(programHandle);
   
    // 5-1. Get a pointer to the input values for the vertex shader,
    //         so we can set them in code.

    _positionSlot = glGetAttribLocation(programHandle, "Position");
    _colorSlot = glGetAttribLocation(programHandle, "SourceColor");
    // 備註: 此處可取得 vertex shader "Position" 與 "SourceColor" 變數的指標  

    // 5-2. Enable use of these arrays (they are disabled by default).
    glEnableVertexAttribArray(_positionSlot);
    glEnableVertexAttribArray(_colorSlot);
}
....
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        //@add
        [self setupLayer]; // Set layer to opaque(不透明)      
        [self setupContext]; // Create OpenGL context               
        [self setupRenderBuffer]; // Create a render buffer       
        [self setupFrameBuffer]; // Create a frame buffer   
       
        //@add
        [self compileShaders];
       
        [self render]; // render something  
    }
    return self;
}
....

----------------------------------------------------------------------------------

D. 編譯並執行:
      說明: 如果執行時仍然是顯示綠色的螢幕, 並且沒有因錯誤而離開應用程式,
                 就代表 vertex 與 fragment shaders 在執行時編譯成功.

      結果: 實際上編譯後執行, 出現錯誤訊息如下:
                 ERROR: 0:22: 'premature EOF' : syntax error syntax error
               
      原因: 應該是讀到錯誤的字元, 導致讀檔的動作提前結束.

      解決: 移除 shaders 裡所有的中文字, 包含在註解裡面的.
                 (實際上, 我把所有的註解都移除了, 下次記得 shaders 裡的註解要用英文 )

沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。