Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c OpenGL VBO球体纹理加载不工作_Objective C_Opengl_Geometry_Vbo - Fatal编程技术网

Objective c OpenGL VBO球体纹理加载不工作

Objective c OpenGL VBO球体纹理加载不工作,objective-c,opengl,geometry,vbo,Objective C,Opengl,Geometry,Vbo,我需要画一个球体并给它纹理。我正在从事的项目将涉及大量的图形,这使我走上了使用VBO的道路 我目前在尝试对球体进行纹理处理时遇到了问题,每次尝试都会导致我看到一个实心着色球体-没有可见纹理。我很可能做了一些愚蠢的事情-但是经过多次尝试,我没有进一步了解问题是因为纹理加载、糟糕的U/V纹理坐标还是使用了错误的着色器 下面是所有源代码的副本 // // // Copyright (c) 2013 Andy Ward. All rights reserved. // #import "Sphere

我需要画一个球体并给它纹理。我正在从事的项目将涉及大量的图形,这使我走上了使用VBO的道路

我目前在尝试对球体进行纹理处理时遇到了问题,每次尝试都会导致我看到一个实心着色球体-没有可见纹理。我很可能做了一些愚蠢的事情-但是经过多次尝试,我没有进一步了解问题是因为纹理加载、糟糕的U/V纹理坐标还是使用了错误的着色器

下面是所有源代码的副本

//
//
//  Copyright (c) 2013 Andy Ward. All rights reserved.
//

#import "SphereRenderer.h"
#import "shaderUtil.h"
#import "fileUtil.h"
#import "debug.h"

//#import <GLKit/GLKit.h>

// Shaders
enum {
    PROGRAM_LIGHTING,
    PROGRAM_PASSTHRU,
    NUM_PROGRAMS
};

enum {
    UNIFORM_MVP,
    UNIFORM_MODELVIEW,
    UNIFORM_MODELVIEWIT,
    UNIFORM_LIGHTDIR,
    UNIFORM_AMBIENT,
    UNIFORM_DIFFUSE,
    UNIFORM_SPECULAR,
    UNIFORM_SHININESS,
    UNIFORM_CONSTANT_COLOR,
    NUM_UNIFORMS
};

enum {
    ATTRIB_VERTEX,
    ATTRIB_COLOR,
    ATTRIB_NORMAL,
    NUM_ATTRIBS
};

typedef struct {
    char *vert, *frag;
GLint uniform[NUM_UNIFORMS];
GLuint id;
} programInfo_t;

programInfo_t program[NUM_PROGRAMS] = {
{ "lighting.vsh",   "color.fsh"     },  // PROGRAM_LIGHTING
    { "color.vsh",      "color.fsh"     },  // PROGRAM_PASSTHRU
};


typedef struct
{
float x;
float y;
float z;
float nx;
float ny;
float nz;
    float u;
    float v;
float r;
float g;
float b;
float a;
    GLbyte padding[16];
} Vertex;


static float lightDir[3]    = { 0.8, 4.0, 1.0 };
static float ambient[4]     = { 0.35, 0.35, 0.35, 0.35 };
static float diffuse[4]     = { 1.0-0.35, 1.0-0.35, 1.0-0.35, 1.0 };
static float specular[4]    = { 0.8, 0.8, 0.8, 1.0 };
static float shininess      = 8;


@implementation SphereRenderer



- (id)init
{
    if (self = [super init])
    {
        angleDelta = -0.05f;
        scaleFactor = 7; //max = 1025
        r =  350; //scaleFactor * 48.0f;

        //maxValue = 1025 * 48.0f;

        xVelocity = 1.5f;
        yVelocity = 0.0f;
        xPos = r*2.0f;
        yPos = r*3.0f;

        // normalize light dir
        lightDirNormalized = GLKVector3Normalize(GLKVector3MakeWithArray(lightDir));

        projectionMatrix = GLKMatrix4Identity;

        [self LoadTexture];

        [self generateSphereData];

        [self setupShaders];


    }
    return self;
}

- (void)makeOrthographicForWidth:(CGFloat)width height:(CGFloat)height
{
     projectionMatrix = GLKMatrix4MakeOrtho(0, width, 0, height, -50000.0f, 2000.0f);     
}



-(void)generateSphereData
{
    #define PI 3.141592654
    #define TWOPI 6.283185308

    int x;
    int index = 0;


    float v1x, v1y, v1z;
    float v2x, v2y, v2z;
    float d;

    int theta, phi;

    float theta0, theta1;
    float phi0, phi1;

    Vertex quad[4];

    Vertex *sphereData = malloc( 128 * 256* 6 * sizeof( Vertex ) );

    float delta = M_PI / 128;

    // 32 vertical segments
    for(theta = 0; theta < 128; theta++)
    {
        theta0 = theta*delta;
        theta1 = (theta+1)*delta;

        // 64 horizontal segments
        for(phi = 0; phi < 256; phi++)
        {
            phi0 = phi*delta;
            phi1 = (phi+1)*delta;

            // Generate 4 points per quad
            quad[0].x = r * sin(theta0) * cos(phi0);
            quad[0].y = r * cos(theta0);
            quad[0].z = r * sin(theta0) * sin(phi0);
                    quad[0].u = (float)theta / (float)128;
                    quad[0].v = (float)phi / (float)256;

            quad[1].x = r * sin(theta0) * cos(phi1);
            quad[1].y = r * cos(theta0);
            quad[1].z = r * sin(theta0) * sin(phi1);
                    quad[1].u = (float)theta / (float)128;
                    quad[1].v = (float)(phi + 1) / (float)256;

            quad[2].x = r * sin(theta1) * cos(phi1);
            quad[2].y = r * cos(theta1);
            quad[2].z = r * sin(theta1) * sin(phi1);
                    quad[2].u = (float)(theta + 1)/ (float)128;
                    quad[2].v = (float)(phi + 1) / (float)256;

            quad[3].x = r * sin(theta1) * cos(phi0);
            quad[3].y = r * cos(theta1);
            quad[3].z = r * sin(theta1) * sin(phi0);
                    quad[3].u = (float)(theta + 1) / (float)128;
                    quad[3].v = (float)phi / (float)256;

            // Generate the normal
            if(theta >= 4)
            {
                v1x = quad[1].x - quad[0].x;
                v1y = quad[1].y - quad[0].y;
                v1z = quad[1].z - quad[0].z;

                v2x = quad[3].x - quad[0].x;
                v2y = quad[3].y - quad[0].y;
                v2z = quad[3].z - quad[0].z;
            }
            else
            {
                v1x = quad[0].x - quad[3].x;
                v1y = quad[0].y - quad[3].y;
                v1z = quad[0].z - quad[3].z;

                v2x = quad[2].x - quad[3].x;
                v2y = quad[2].y - quad[3].y;
                v2z = quad[2].z - quad[3].z;
            }

            quad[0].nx = ( v1y * v2z ) - ( v2y * v1z );
            quad[0].ny = ( v1z * v2x ) - ( v2z * v1x );
            quad[0].nz = ( v1x * v2y ) - ( v2x * v1y );

            d = 1.0f/sqrt(quad[0].nx*quad[0].nx +
                          quad[0].ny*quad[0].ny +
                          quad[0].nz*quad[0].nz);

            quad[0].nx *= d;
            quad[0].ny *= d;
            quad[0].nz *= d;


            // Generate the color - This was for testing until I have the textures loading...
            if((theta ^ phi) & 1)
            {
                quad[0].r = 0.0f;
                quad[0].g = 0.0f;
                quad[0].b = 0.0f;
                quad[0].a = 0.0f;
            }
            else
            {
                quad[0].r = 0.0f;
                quad[0].g = 0.0f;
                quad[0].b = 0.0f;
                quad[0].a = 0.0f;
            }

            // Replicate vertex info.
            for(x = 1; x < 4; x++)
            {
                quad[x].nx = quad[0].nx;
                quad[x].ny = quad[0].ny;
                quad[x].nz = quad[0].nz;
                quad[x].r = quad[0].r;
                quad[x].g = quad[0].g;
                quad[x].b = quad[0].b;
                quad[x].a = quad[0].a;

            }



        // Store the vertices in two triangles. We are drawing everything as triangles.
        sphereData[index++] = quad[0];
        sphereData[index++] = quad[1];
        sphereData[index++] = quad[2];

        sphereData[index++] = quad[0];
        sphereData[index++] = quad[3];
        sphereData[index++] = quad[2];

    }
}

// Create the VAO
glGenVertexArrays(1, &vaoId);
glBindVertexArray(vaoId);

// Create a VBO buffer
glGenBuffers(1, &vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, 128 * 256 * 6 * sizeof(Vertex), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, 128 * 256 * 6 * sizeof(Vertex), sphereData);

// set the colors - left as it's great for debugging
glEnableVertexAttribArray(ATTRIB_COLOR);
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_FLOAT, GL_TRUE, sizeof(Vertex), (GLubyte *)(uintptr_t)offsetof(Vertex,r));

  // set the normals
glEnableVertexAttribArray(ATTRIB_NORMAL);
glVertexAttribPointer(ATTRIB_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLubyte *)(uintptr_t)offsetof(Vertex,nx));


// set the texture
glEnableVertexAttribArray(1);
glError();
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLubyte *)(uintptr_t)offsetof(Vertex,u));
glError();

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);


// set the positions
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLubyte *)(uintptr_t)offsetof(Vertex,x));


//We need to free as we used malloc
free(sphereData);

}




-(void)LoadTexture
{
NSURL                   *url = nil;
CGImageSourceRef        src;
CGImageRef              image;
CGContextRef            context = nil;
CGColorSpaceRef         colorSpace;
    GLubyte *data;
    GLsizei width, height;

   // NSImage* image = [NSImage imageNamed:@"World-satellite-map.png"];
    NSBundle *bundle = [NSBundle bundleWithIdentifier: @"Award.WeatherEye3D"];
    NSString *bundleRoot = [bundle pathForImageResource:@"World-satellite-map.png"];

    url = [NSURL fileURLWithPath: bundleRoot];
src = CGImageSourceCreateWithURL((CFURLRef)url, NULL);

if (!src) {
    NSLog(@"No image");
//      free(data);
    return;
}

image = CGImageSourceCreateImageAtIndex(src, 0, NULL);
CFRelease(src);

width = CGImageGetWidth(image);
height = CGImageGetHeight(image);

    data = (GLubyte*) calloc(width * height * 4, sizeof(GLubyte));

colorSpace = CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate(data, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
CGColorSpaceRelease(colorSpace);

// Core Graphics referential is upside-down compared to OpenGL referential
// Flip the Core Graphics context here
// An alternative is to use flipped OpenGL texture coordinates when drawing textures
CGContextTranslateCTM(context, 0.0, height);
CGContextScaleCTM(context, 1.0, -1.0);

// Set the blend mode to copy before drawing since the previous contents of memory aren't used. This avoids unnecessary blending.
CGContextSetBlendMode(context, kCGBlendModeCopy);

CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);

CGContextRelease(context);
CGImageRelease(image);


    glGenTextures(1, &texture);
glGenBuffers(1, &pboId);

// Bind the texture
glBindTexture(GL_TEXTURE_2D, texture);

// Bind the PBO
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboId);

// Upload the texture data to the PBO
glBufferData(GL_PIXEL_UNPACK_BUFFER, width * height * 4 * sizeof(GLubyte), data, GL_STATIC_DRAW);

// Setup texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);

// OpenGL likes the GL_BGRA + GL_UNSIGNED_INT_8_8_8_8_REV combination
// Use offset instead of pointer to indictate that we want to use data copied from a PBO
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
             GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);

// We can delete the application copy of the texture data now
free(data);

glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);


}





- (void)setupShaders
{

//This code has been lifted from an example.
for (int i = 0; i < NUM_PROGRAMS; i++)
{
    char *vsrc = readFile(pathForResource(program[i].vert));
    char *fsrc = readFile(pathForResource(program[i].frag));
    GLsizei attribCt = 0;
    GLchar *attribUsed[NUM_ATTRIBS];
    GLint attrib[NUM_ATTRIBS];
    GLchar *attribName[NUM_ATTRIBS] = {
        "inVertex", "inColor", "inNormal",
    };
    const GLchar *uniformName[NUM_UNIFORMS] = {
        "MVP", "ModelView", "ModelViewIT", "lightDir", "ambient", "diffuse", "specular", "shininess", "constantColor",
    };

    // auto-assign known attribs
    for (int j = 0; j < NUM_ATTRIBS; j++)
    {
        if (strstr(vsrc, attribName[j]))
        {
            attrib[attribCt] = j;
            attribUsed[attribCt++] = attribName[j];
        }
    }

    glueCreateProgram(vsrc, fsrc,
                      attribCt, (const GLchar **)&attribUsed[0], attrib,
                      NUM_UNIFORMS, &uniformName[0], program[i].uniform,
                      &program[i].id);
    free(vsrc);
    free(fsrc);

    // set constant uniforms
    glUseProgram(program[i].id);

    if (i == PROGRAM_LIGHTING)
    {
        // Set up lighting stuff used by the shaders
        glUniform3fv(program[i].uniform[UNIFORM_LIGHTDIR], 1, lightDirNormalized.v);
        glUniform4fv(program[i].uniform[UNIFORM_AMBIENT], 1, ambient);
        glUniform4fv(program[i].uniform[UNIFORM_DIFFUSE], 1, diffuse);
        glUniform4fv(program[i].uniform[UNIFORM_SPECULAR], 1, specular);
        glUniform1f(program[i].uniform[UNIFORM_SHININESS], shininess);
    }
    else if (i == PROGRAM_PASSTHRU)
    {
        glUniform4f(program[i].uniform[UNIFORM_CONSTANT_COLOR], 0.0f,0.0f,0.0f,0.4f);
    }
}

glError();
}


- (void)update
{


yPos = 400;
xPos = 375;

}

- (void)render
{
GLKMatrix4 modelViewMatrix, MVPMatrix, modelViewMatrixIT;
GLKMatrix3 normalMatrix;

glBindVertexArray(vaoId);
// glBindTexture(GL_TEXTURE, texture);

// Draw "shadow"
/* glUseProgram(program[PROGRAM_PASSTHRU].id);

glEnable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE_MINUS_SRC_ALPHA);
*/
/*// Make the "shadow" move around a bit. This is not a real shadow projection.
GLKVector3 pos = GLKVector3Normalize(GLKVector3Make(xPos, yPos, -100.0f));
modelViewMatrix = GLKMatrix4MakeTranslation(xPos + (pos.v[0]-lightDirNormalized.v[0])*20.0,
                                            yPos + (pos.v[1]-lightDirNormalized.v[1])*10.0,
                                            -800.0f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, -16.0f, 0.0f, 0.0f, 1.0f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, angle, 0.0f, 1.0f, 0.0f);
modelViewMatrix = GLKMatrix4Scale(modelViewMatrix, 1.05f, 1.05f, 1.05f);

MVPMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
glUniformMatrix4fv(program[PROGRAM_PASSTHRU].uniform[UNIFORM_MVP], 1, GL_FALSE, MVPMatrix.m);

//Draw the shadow arrays
glDrawArrays(GL_TRIANGLES, 0, 32*64*6);
*/


// Draw Sphere
glUseProgram(program[PROGRAM_LIGHTING].id);

glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LESS);
glDisable(GL_BLEND);

glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);

// ModelView
modelViewMatrix = GLKMatrix4MakeTranslation(xPos, yPos, -200.0f);                         // was -100
//modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, -0.01f, 0.0f, 0.0f, 0.01f);
// modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, angle, 0.0f, 1.0f, 0.0f);
glUniformMatrix4fv(program[PROGRAM_LIGHTING].uniform[UNIFORM_MODELVIEW], 1, GL_FALSE, modelViewMatrix.m);

// MVP
MVPMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
glUniformMatrix4fv(program[PROGRAM_LIGHTING].uniform[UNIFORM_MVP], 1, GL_FALSE, MVPMatrix.m);

// ModelViewIT (normal matrix)
bool success;
modelViewMatrixIT = GLKMatrix4InvertAndTranspose(modelViewMatrix, &success);
if (success) {
    normalMatrix = GLKMatrix4GetMatrix3(modelViewMatrixIT);
    glUniformMatrix3fv(program[PROGRAM_LIGHTING].uniform[UNIFORM_MODELVIEWIT], 1, GL_FALSE, normalMatrix.m);
}



glDrawArrays(GL_TRIANGLE_STRIP, 0, 128*256*6 ); // Value needs changing for number of triangles...

glUseProgram(0);

glError();
}

- (void)dealloc
{
if (vboId) {
    glDeleteBuffers(1, &vboId);
    vboId = 0;
}
if (vaoId) {
    glDeleteVertexArrays(1, &vaoId);
    vaoId = 0;
}
if (vertexShader) {
    glDeleteShader(vertexShader);
    vertexShader = 0;
}
if (fragmentShader) {
    glDeleteShader(fragmentShader);
    fragmentShader = 0;
}
if (shaderProgram) {
    glDeleteProgram(shaderProgram);
    shaderProgram = 0;
}

[super dealloc];
}

@end
color.vsh:- #版本150

in vec4 inVertex;
out vec4 color;

uniform mat4 MVP;
uniform vec4 constantColor;

void main()
{
gl_Position = MVP * inVertex;
    color = constantColor;
}
Color.fsh:-

#version 150

in vec4 color;
out vec4 fragColor;

void main()
{
    fragColor = color;
}

对于纹理加载,我总是仔细检查我使用的模式。 对于您的着色器,我会检查顶点和片段着色器的#版本,并确保它与您安装的任何OpenGL版本或您的视频卡支持的任何版本都能很好地配合使用。我过去经常使用JOGL,每当我使用330版而不是400版时,那是因为我的视频卡当时不是最新的型号,并且不支持330以外的任何着色器。实际上,版本150和400之间存在很大的差异,因此如果您在GL代码中执行比着色器支持的更高级的操作,则不会加载纹理。(也就是说,OpenGL在这方面发生了重大变化,不再是固定的功能管道,而是所有可编程的管道,因此,您可以以做更多工作为代价进行更多的控制……比如编写自己的VBO,呵呵) GLSL中的某些函数在不同版本中也有所不同,当您追溯到150时,许多较新的函数将无法识别

这里是着色器语言以及它们与哪些版本的OpenGL兼容的良好参考。我知道这只是wiki,但是上面所有的版本映射看起来都是正确的

而且,我总是要检查法线的方向。如果它们是颠倒的或相反的方向(比如指向内部而不是外部),那么你的照明和纹理也不会工作

以下是我在开始使用较新的着色器版本之前编写的着色器示例:

v、 glsl

#version 130
in vec4 vPosition;
in vec4 vColor;
in vec3 vNormal;
in vec2 vTexCoord;
out vec4 color;
out vec3 E,L,N;
out vec2 texCoord;

uniform vec4 LightPosition;
uniform vec4 Projection, Model, View;

void main() {
   vec3 pos = (Model * vPosition).xyz;
   E = normalize((View * vec4(0,0,0,1)).xyz-pos);
   //camera eye
   L = normalize(LightPosition.xyz - pos);
   N = normalize(Model * vec4(vNormal, 0.0)).xyz; //set normal vector
   gl_Position = Projection * View * Model * vPosition; //view mode: Projection
   texCoord = vTextCoord; //output vector of texture coordinates
   color = vColor; //output vector that tells you the color of each vertex
}
f、 glsl

#version 130
in vec4 color;
in vec2 texCoord;
in vec3 N,L,E;

out vec4 fColor;
uniform sampler2D texture;
uniform vec4 GlobalAmbient, AmbientProduct, DiffuseProduct, SpecularProduct;
uniform vec3 LightDirection;

uniform float Shininess, CutoffAngle, LightIntensity;

void main() {
   vec3 D, H;
   //process the spotlight
   D = normalize(LightDirection);
   H = normalize(L+E); //normalize the sum of the Light and Camera (Eye) vectors

   vec4 ambient = vec4(0,0,0,0);
   vec4 diffuse = vec4(0,0,0,1);
   vec4 specular = vec4(0,0,0,1);
   vec4 color = vec4(0,0,0,0);

   //spot coefficient
   float Kc = LightIntensity * max(dot(D,-L)-CutoffAngle,0.0);
   //ambient coefficient
   ambient = (Kc*AmbientProduct) + ambient + GlobalAmbient;
   //diffuse coefficient
   float Kd = max(dot(L,N), 0.0);
   //diffuse component
   diffuse = Kc * Kd * DiffuseProduct + diffuse;
   //specular coefficient
   float Ks = pow(max(dot(E,H), 0.0), Shininess);
   //specular component
   if(dot(L,N) >= 0.0) {
      specular = Kc * Ks * SpecularProduct + specular;
   }

   fColor = (color + ambient + diffuse + specular) * texture2D(texture, texCoord);
   fColor.a = 1.0; //fully opaque
}
我回家后会再看看这个,因为我喜欢图形。现在,这个着色器代码与Java代码对话(使用JOGL libs),因此在Objective C中的实现方式有所不同,但思路都是一样的

还要检查gl函数调用的顺序,这在许多情况下都会产生影响

在ObjC中,我想象你会像这样交出你的像素数据:

- (GLuint)setupTexture:(NSString *)fileName {    

   CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
   if (!spriteImage) {
       NSLog(@"Failed to load image %@", fileName);
       exit(1);
   }


   size_t width = CGImageGetWidth(spriteImage);
   size_t height = CGImageGetHeight(spriteImage);

   GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));

   CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, 
    CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);    

   CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);

   CGContextRelease(spriteContext);

   GLuint texName;
   glGenTextures(1, &texName);
   glBindTexture(GL_TEXTURE_2D, texName);

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 

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

   free(spriteData);        
   return texName; 
}

我应该补充一点-我使用的是一款15英寸的Macbook Pro,内置了Nvidia GT 650M图形。笔记本电脑使用的是Mavericks。谢谢你Brittany-这非常有用。我刚刚使用OpenGL Extension Viewer进行了检查-我显然支持OpenGL着色器版本4.1。查看法线-如果(θ>=4)线,我猜当我将θ的范围从8增加到128时,我应该将if语句中的值增加到64?例如:-if(θ>=64)
- (GLuint)setupTexture:(NSString *)fileName {    

   CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
   if (!spriteImage) {
       NSLog(@"Failed to load image %@", fileName);
       exit(1);
   }


   size_t width = CGImageGetWidth(spriteImage);
   size_t height = CGImageGetHeight(spriteImage);

   GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));

   CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, 
    CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);    

   CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);

   CGContextRelease(spriteContext);

   GLuint texName;
   glGenTextures(1, &texName);
   glBindTexture(GL_TEXTURE_2D, texName);

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 

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

   free(spriteData);        
   return texName; 
}