简体   繁体   中英

OpenGL ES (on iOS): EXC_BAD_ACCESS on glDrawArrays call for sphere drawing

I'm in need of a procedurally-generated OpenGL ES sphere - I googled around and discovered this OGL code , and decided it looked neat so I'd modify it to be OGLES instead. I eliminated the OGL-only glBegin(), glEnd() and modified the original drawtri and drawsphere to be generatetri and generateSpherePoints. These new functions assign GLfloat values into static arrays for the sphere normals and vertices, meaning I can then call a new function drawSphere() at whim and the points needn't be recalculated. I've also added x,y,z parameters to generateSpherePoints, allowing specification of a non-zero sphere centre.

The problem is that my OGLES version gives an EXC_BAD_ACCESS in XCode at the glDrawArrays line. Through the debugger I've inspected the 'sphereNormals' and 'sphereVertices' arrays and they look well populated as desired. I'd be very grateful if someone can suggest what the issue might be, as I'm clueless right about now!

#define SX .525731112119133606 
#define SZ .850650808352039932

/* Drawing Sphere */
static GLfloat vdata[12][3] = {    
    {-SX, 0.0, SZ}, {SX, 0.0, SZ}, {-SX, 0.0, -SZ}, {SX, 0.0, -SZ},    
    {0.0, SZ, SX}, {0.0, SZ, -SX}, {0.0, -SZ, SX}, {0.0, -SZ, -SX},    
    {SZ, SX, 0.0}, {-SZ, SX, 0.0}, {SZ, -SX, 0.0}, {-SZ, -SX, 0.0} 
};

static GLuint tindices[20][3] = { 
    {0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},    
    {8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},    
    {7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6}, 
    {6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };

void normalize(GLfloat *a) {
    GLfloat d=sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);
    a[0]/=d; a[1]/=d; a[2]/=d;
}

static const int ndiv = 5;
static const int vecSize = 3;
static const int isoVertexCount = 3;
static const int spherePointsSectionCount = 20;
static const int pointSectionSize = 9216;// value MUST be updated to be result of calcPointSectionSize(ndiv)
static const int pointCount = 184320;// value MUST be updated to be spherePointsSectionCount*pointSectionSize;
static const int sphereVertsCount = 61440; // value MUST be updated to be pointCount/vecSize;
static GLfloat spherePoints[184320]; // size MUST be updated to be pointCount value
static GLfloat sphereNormals[184320]; // size MUST be updated to be pointCount value

int calcPointSectionSize(int div) {
    return vecSize*isoVertexCount*powf(4.0f,(float)(div));
}

// OpenGL ES doesn't support glBegin(), glEnd() so must use glDrawArrays() instead
void generatetri(GLfloat *a, GLfloat *b, GLfloat *c, int div, float r, int pos) {
    if (div<=0) {
        int X = 0, Y = 1, Z = 2;
        sphereNormals[pos+X] = a[X];
        sphereNormals[pos+Y] = a[Y];
        sphereNormals[pos+Z] = a[Z];
        spherePoints[pos+X] = a[X]*r;
        spherePoints[pos+Y] = a[Y]*r;
        spherePoints[pos+Z] = a[Z]*r;
        sphereNormals[pos+vecSize+X] = b[X];
        sphereNormals[pos+vecSize+Y] = b[Y];
        sphereNormals[pos+vecSize+Z] = b[Z];
        spherePoints[pos+vecSize+X] = b[X]*r;
        spherePoints[pos+vecSize+Y] = b[Y]*r;
        spherePoints[pos+vecSize+Z] = b[Z]*r;
        sphereNormals[pos+2*vecSize+X] = c[X];
        sphereNormals[pos+2*vecSize+Y] = c[Y];
        sphereNormals[pos+2*vecSize+Z] = c[Z];
        spherePoints[pos+2*vecSize+X] = c[X]*r;
        spherePoints[pos+2*vecSize+Y] = c[Y]*r;
        spherePoints[pos+2*vecSize+Z] = c[Z]*r;
        /*
        glNormal3fv(a); glVertex3f(a[0]*r, a[1]*r, a[2]*r);
        glNormal3fv(b); glVertex3f(b[0]*r, b[1]*r, b[2]*r);
        glNormal3fv(c); glVertex3f(c[0]*r, c[1]*r, c[2]*r);
        */
    } else {
        GLfloat ab[3], ac[3], bc[3];
        for (int i=0;i<3;i++) {
            ab[i]=(a[i]+b[i])/2;
            ac[i]=(a[i]+c[i])/2;
            bc[i]=(b[i]+c[i])/2;
        }
        normalize(ab); normalize(ac); normalize(bc);
        const int pointSectionSize = calcPointSectionSize(div-1);
        generatetri(a, ab, ac, div-1, r, pos+0*pointSectionSize);
        generatetri(b, bc, ab, div-1, r, pos+1*pointSectionSize);
        generatetri(c, ac, bc, div-1, r, pos+2*pointSectionSize);
        generatetri(ab, bc, ac, div-1, r, pos+3*pointSectionSize);
    }  
}

void generateSpherePoints(float x, float y, float z, float radius) {
    for (int i=0;i<20;i++) {
        GLfloat *va = vdata[tindices[i][0]];
        GLfloat *vb = vdata[tindices[i][1]];
        GLfloat *vc = vdata[tindices[i][2]];
        GLfloat a[3] = {va[0]+x,va[1]+y,va[2]+z};
        GLfloat b[3] = {vb[0]+x,vb[1]+y,vb[2]+z};
        GLfloat c[3] = {vc[0]+x,vc[1]+y,vc[2]+z};
        generatetri(a, b, c, ndiv, radius, i*pointSectionSize);
    }
}

void drawSphere() {
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);
    glNormalPointer(GL_FLOAT, 0, sphereNormals);
    glVertexPointer(3, GL_FLOAT, 0, spherePoints);
    glDrawArrays(GL_TRIANGLES, 0, sphereVertsCount);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
}

EXC_BAD_ACCESS means that your code is attempting to access a memory address that it doesn't own. The most common cause of this is an error in memory management code that causes an object to be deallocated while it's still in use. For example, your code may have failed to retain an object it needs, or it may have released an object prematurely.

In this case, I would guess that the view you're drawing to may have been deallocated prematurely. But rather than guessing, you should use the NSZombieEnabled facility to figure out which deallocated object the code is attempting to access. See the iOS Development Guide section on Debugging Applications .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM