我有一个加载 OpenGL 的 UIView。设置工作正常(您可以使用不同的颜色测试“擦除”调用)并且着色器编译没有错误。
着色器非常基本:顶点着色器占据位置,片段着色器始终呈现黑色。
但是,它不会绘制。我已经解决了几个小时的问题,但找不到错误。
请帮忙。
#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