如何使用2D纹理将RGB位图渲染到GLKView中?

Mus*_*sis 12 opengl objective-c ios

我有一个内存中的"位图",它只是一个Byte *包含简单RGB格式的像素数据的malloced 数组(所以字节数组的大小是3*像素数).

我的应用程序只是一个带有实例的视图控制器GLKView.我已经像这样实现了它的委托:

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
}
Run Code Online (Sandbox Code Playgroud)

并且正如预期的那样,它设置了GLKView的背景颜色.

我现在要做的是为此实现添加代码,glkView:drawInRect:以便将"bitmap"呈现到此GLKView中.但我似乎无法找到任何简单的方法; 我对OpenGL可以做的所有不同事情感到不知所措,所有这些都比我在这里尝试的要复杂得多.

glReadPixels 似乎有点像我在这里,因为它似乎提供了一个指向缓冲区数据的指针.

编辑:显然这只能通过使用纹理来完成.我试图用这个示例代码实现这一点(请注意,我的"位图"是每个样本4个字节,与格式参数匹配):

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {

    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    // raw data
    int width = 30;
    int height = 30;
    int pixelCount = width * height;
    int byteSize = pixelCount * 4;
    GLubyte *textureData = (GLubyte *)malloc(byteSize);

    for (int i = 0; i < byteSize; i++) {
        textureData[i] = 255; // white
    }

    glEnable(GL_TEXTURE_2D);

    GLuint textureID;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glGenTextures(1, &textureID);
    glBindTexture(GL_TEXTURE_2D, textureID);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, 
        GL_RGBA, GL_UNSIGNED_BYTE, textureData);

    free(textureData);

}
Run Code Online (Sandbox Code Playgroud)

...... 但它不起作用.该glClear()呼叫将按预期,并将整个背景红色; 但如果我正确理解纹理样本,下面的代码应该在角落里绘制一个30x30的白色方块,但我得到的只是纯红色背景.

谁能发现我在这里做错了什么?

Adr*_*upa 4

很抱歉推入 OpenGL :)

我会创建CGImage然后UIImage

void *baseAddress = & textureData;
size_t bytesPerRow = width * 4;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGImageRef cgImage = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIImage *image = [UIImage imageWithCGImage:cgImage];
Run Code Online (Sandbox Code Playgroud)

然后用drawInRect绘制它:

编辑:

这是我写的代码。这不是生产代码:它缺乏对 openGL 错误、一些小泄漏的检查,并且具有全局变量,但它是增强它的好地方。

#import "ViewController.h"
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>

@interface ViewController ()

@end

@implementation ViewController

GLuint tex;
float vertices[] = {
    //  Position    Texcoords
    -1.0f,  1.0f, 0.0f, 0.0f, // Top-left
    1.0f,  1.0f, 1.0f, 0.0f, // Top-right
    1.0f, -1.0f, 1.0f, 1.0f, // Bottom-right
    -1.0, -1.0f, 0.0f, 1.0f  // Bottom-left
};

const char * vertexShader = "attribute vec2 position;\n"
                            "attribute vec2 TexCoordIn;\n"
                            "varying vec2 TexCoordOut;\n"
                            "void main() {\n"
                                "gl_Position = vec4(position, 0.0, 1.0);\n"
                                "TexCoordOut = TexCoordIn;\n"
                            "}\n";

const char * fragmentShader =   "precision mediump float;\n"
                                "varying lowp vec2 TexCoordOut;\n"
                                "uniform sampler2D Texture;\n"
                                "void main() {\n"
                                    "gl_FragColor = texture2D(Texture, TexCoordOut);\n"
                                "}\n";

GLuint shaderProgram;
GLuint vao;
GLuint vbo;

-(void) initOpenGLObjects {
    glGenVertexArraysOES(1, &vao);
    glBindVertexArrayOES(vao);
    
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glGenerateMipmap(GL_TEXTURE_2D);
    
    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, &vertexShader, NULL);
    glCompileShader(vs);
    
    GLint status;
    glGetShaderiv(vs, GL_COMPILE_STATUS, &status);
    
    char buffer[512];
    glGetShaderInfoLog(vs, 512, NULL, buffer);
    
    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, &fragmentShader, NULL);
    glCompileShader(fs);
    
    glGetShaderiv(fs, GL_COMPILE_STATUS, &status);
    
    glGetShaderInfoLog(fs, 512, NULL, buffer);
    
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vs);
    glAttachShader(shaderProgram, fs);
    glLinkProgram(shaderProgram);
    
    GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
    GLint texAttrib = glGetAttribLocation(shaderProgram, "TexCoordIn");
    
    glGenBuffers(1, &vbo); // Generate 1 buffer
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4*sizeof(float), 0);
    glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 4*sizeof(float), (void*)(2*sizeof(float)));
    
    glEnableVertexAttribArray(posAttrib);
    glEnableVertexAttribArray(texAttrib);
}


-(void) viewDidLoad{
    [super viewDidLoad];
    
    self.glkView.context = [[EAGLContext alloc] initWithAPI:
                           kEAGLRenderingAPIOpenGLES2];
    
    [EAGLContext setCurrentContext:self.glkView.context];
    
    CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

    self.glkView.delegate = self;
    [self initOpenGLObjects];
}

- (void)update
{
    [self.glkView setNeedsDisplay];
}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    
    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    int width = 300;
    int height = 300;
    int pixelCount = width * height;
    int byteSize = pixelCount * 4;
    GLubyte *textureData = (GLubyte *)malloc(byteSize);
    static int time = 0;
    time = (time+1)%256;
    
    for (int i = 0; i < byteSize; i+=4) {
        textureData[i] = 255;
        textureData[i+1] = time;
        textureData[i+2] = 255;
        textureData[i+3] = 255;
    }
    
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, textureData);
    
    glUseProgram(shaderProgram);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    
    free(textureData);
}

@end
Run Code Online (Sandbox Code Playgroud)

我不知道你想如何更新数据,也许你不必每次都 malloc/free 它,只需做一些小的更改并用glTexSubImage2D. 大部分时间都花在了填充数据上。

这段代码适用于我的 MacBook(模拟器中装有 Xcode 7)和 iPhone 6(装有 iOS 9.0.2)。