OpenGL 2.0 Bug - 设置和着色器工作,不会绘制

时间:2013-08-09 19:39:02

标签: ios xcode opengl-es drawing shader

我有一个加载OpenGL的UIView。设置工作正常(您可以使用不同的颜色测试'erase'调用)并且编译着色器时没有错误。

着色器非常基本:顶点着色器占据位置,片段着色器始终呈现黑色。

然而,它不会画。我已经把这个问题分开几个小时,但是找不到这个bug。

请帮忙。

#pragma mark Imports
#import "ochrDrawingView.h"

#pragma mark - Definitions
#define loquacious YES


typedef struct {
    GLfloat x;
    GLfloat y;
} vertex;

typedef vertex vector;

typedef struct {
    GLfloat r;
    GLfloat g;
    GLfloat b;
    GLfloat a;
} color;


#pragma mark - Inline Functions
static inline GLfloat distanceBetweenVertices (vertex one, vertex two) {
    return sqrtf((two.x - one.x) * (two.x - one.x) + (two.y - one.y) * (two.y - one.y));
}

static inline GLfloat magnitudeOfVector (vector vec) {
    return sqrtf(vec.x * vec.x + vec.y * vec.y);
}

static inline GLfloat dotProductOfVectors(vector one, vector two) {
    return (one.x *two.x + one.y * two.y);
}

static inline GLfloat crossProductOfVectors (vector one, vector two) {
    return (one.x * two.y - one.y * two.x);
}

static inline vector vectorFromVertices (vertex one, vertex two) {
    return (vector) { two.x - one.x, two.y - one.y };
}



#pragma mark - Variables and Implementation
@implementation ochrDrawingView {
    EAGLContext *context;
    CAEAGLLayer *eaglLayer;

    // Buffers
    GLuint renderBuffer;
    GLuint frameBuffer;
    GLuint vertexBufferID;

    // The attributes in for the shader program
    GLuint positionAttribute;
    GLuint colorAttribute;

    GLuint shaderProgram;

    // The pixel dimensions of the backbuffer
    GLint backingWidth;
    GLint backingHeight;

    // Some BOOLs
    BOOL isFirstTouch;

    // The points for drawing
    CGPoint origin;
    CGPoint control;
    CGPoint destination;
}

@synthesize currentColor;

#pragma mark - OpenGL setup

+ (Class) layerClass {
    return [CAEAGLLayer class];
}

- (void) setUpLayer {
    if (loquacious) NSLog(@"setUpLayer called in ochrDrawingView");
    eaglLayer = (CAEAGLLayer *) self.layer;
    [eaglLayer setOpaque:YES];
    [eaglLayer setDrawableProperties:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],     kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]];    
}    

- (void) setUpContext {
    if (loquacious) NSLog(@"setUpContext called in ochrDrawingView");
    context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    [EAGLContext setCurrentContext:context];
    if (!context) {
        NSLog(@"Context failed to set up properly");
    }
}

- (void) setUpRenderBuffer {
    if (loquacious) NSLog(@"setUpRenderBuffer called in ochrDrawingView");
    glGenRenderbuffers(1, &renderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
    [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer];
}

- (void) setUpFrameBuffer {
    if (loquacious) NSLog(@"setUpFrameBuffer called in ochrDrawingView");
    glGenFramebuffers(1, &frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
}

- (void) setUpViewport {
    if (loquacious) NSLog(@"setUpViewport called in ochrDrawingView");
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
    glViewport(0, 0, backingWidth, backingHeight);
 }

- (void) setUpVertexBuffer {
    glGenBuffers(1, &vertexBufferID);
}

#pragma mark - Shaders

- (GLuint)compileShaderOfType:(GLenum)shaderType {

    NSString *shaderString;

    NSString *vertexString =
    @" attribute vec4 Position; "
    @" void main (void) { "
    @"      gl_Position = Position; "
    @"      gl_PointSize = 16.0; "
    @" } ";

    NSString *fragmentString =
    @" void main (void) { "
    @"      gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); "
    @" } " ;

    if (shaderType == GL_VERTEX_SHADER) {
        shaderString = vertexString;
        if (loquacious) NSLog(@"About to compile a vertex shader");
    } else if (shaderType == GL_FRAGMENT_SHADER) {
        shaderString = fragmentString;
        if (loquacious) NSLog(@"About to compile a fragment shader");
    } else {
        NSLog(@"Not a valid shader type");
    }

    GLuint shaderHandle = glCreateShader(shaderType);

    const char *shaderStringUTF8 = [shaderString UTF8String];
    int shaderStringLength = [shaderString length];
    glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);

    glCompileShader(shaderHandle);

    GLint compileSuccess;
    glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
    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;
}

- (void)compileShaders {

    if (loquacious) NSLog(@"compileShaders called in ochrDrawingView");
    GLuint vertexShader = [self compileShaderOfType:GL_VERTEX_SHADER];
    GLuint fragmentShader = [self compileShaderOfType:GL_FRAGMENT_SHADER];

    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    GLint linkSuccess;
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &linkSuccess);
    if (linkSuccess == GL_FALSE) {
        GLchar messages[256];
        glGetProgramInfoLog(shaderProgram, sizeof(messages), 0, &messages[0]);
        NSString *messageString = [NSString stringWithUTF8String:messages];
        NSLog(@"%@", messageString);
        exit(1);
    }

    glUseProgram(shaderProgram);

    positionAttribute = glGetAttribLocation(shaderProgram, "Position");
    glEnableVertexAttribArray(positionAttribute);
}

#pragma mark - Init call

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        if (loquacious) NSLog(@"ochrDrawingView is about to initialize.");
        [self setUpLayer];
        [self setUpContext];
        [self setContentScaleFactor:[[UIScreen mainScreen] scale]];
        [self setUpRenderBuffer];
        [self setUpFrameBuffer];
        [self setUpVertexBuffer];
        [self compileShaders];
        [self erase];
    }
    return self;
}

// Erases the screen
- (void)erase
{
    if (loquacious) NSLog(@"Erase called in ochrDrawingView.");
    [EAGLContext setCurrentContext:context];

    // Clear the buffer
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    // Display the buffer
    glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER];
}


#pragma mark - Touch Response

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    origin = [[touches anyObject] locationInView:self];
    origin.y = self.bounds.size.height - origin.y;
    isFirstTouch = YES;
}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    if (isFirstTouch) {
        isFirstTouch = NO;
        destination = [[touches anyObject] locationInView:self];
        destination.y = self.bounds.size.height - destination.y;
    } else {
        origin = destination;
        destination = [[touches anyObject] locationInView:self];
        destination.y = self.bounds.size.height - destination.y;
    }

    [self renderLineFromPoint:origin toPoint:destination];
}

// Handles the end of a touch event when the touch is a tap.
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if (isFirstTouch) {
        destination = [[touches anyObject] locationInView:self];
        destination.y = self.bounds.size.height - destination.y;
        [self renderLineFromPoint:origin toPoint:destination];
    }
}

- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {

}

#pragma mark - Drawing Algorithm

// Drawings a line onscreen based on where the user touches
- (void)renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end
{
    static GLfloat *vertexBuffer = NULL;
    static NSUInteger vertexMax = 64;
    NSUInteger vertexCount = 0;
    NSUInteger count;
    NSUInteger i;

    [EAGLContext setCurrentContext:context];
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);

    // Convert locations from Points to Pixels
    CGFloat scale = self.contentScaleFactor;
    start.x *= scale;
    start.y *= scale;
    end.x *= scale;
    end.y *= scale;

    // Allocate vertex array buffer
    if (vertexBuffer == NULL) vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat));

    // Add points to the buffer so there are drawing points every X pixels
    count = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / 3), 1);

    for (i = 0; i < count; ++i) {
        if (vertexCount == vertexMax) {
            vertexMax = 2 * vertexMax;
            vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat));
        }

        vertexBuffer[2 * vertexCount + 0] = start.x + (end.x - start.x) * ((GLfloat) i / (GLfloat) count);
        vertexBuffer[2 * vertexCount + 1] = start.y + (end.y - start.y) * ((GLfloat) i / (GLfloat) count);
        vertexCount++;
    }

    // Load data to the Vertex Buffer Object
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
    glBufferData(GL_ARRAY_BUFFER, vertexCount * 2 * sizeof(GLfloat), vertexBuffer, GL_DYNAMIC_DRAW);

    glEnableVertexAttribArray(positionAttribute);
    glVertexAttribPointer(positionAttribute, 2, GL_FLOAT, GL_FALSE, 0, 0);

    // Draw
    glUseProgram(shaderProgram);
    glDrawArrays(GL_POINTS, 0, vertexCount);

    // Display the buffer
    glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER];
}


@end

1 个答案:

答案 0 :(得分:0)

在我看来,你的点是在视口之外绘制的。 对于X和Y,OpenGL使用范围[-1..1]中的标准化设备坐标。

你在屏幕空间中采取不同的触摸位置。例如。对于iPad,它是[0..1024]和[0..768]。为了绘制这些点,您必须将它们从屏幕空间转换为NDC空间:

NDC_x = 2*(touch_x/screen_size_x) - 1;
NDC_y = 2*(touch_y/screen_size_y) - 1;