Search code examples
iosopengl-esrenderingtexture-mappingopenframeworks

Openframeworks iOS project: texture on ofSpherePrimitive breaks


I've been working on an iOS project where I am trying to map a texture (world map) onto a ofSpherePrimitive, but there seems to be some rendering issue.

While I can get the texture to be mapped onto the sphere, there seems to be parts of the sphere where the texture in the foreground does not render properly but instead it appears "transparent" and renders the far-side of the sphere, the texture inside out. Below two images to illustrate the point.

First, here with a red light illuminating the front/top and colouring the texture correctly, whereas on the bottom part of the sphere there are those unlit texture parts from inside the sphere's other side. enter image description here

Second, here a minimum test case with no lights, cameras, etc, just a checkered pattern. You can see the smaller checkers from the backside in the bottom half of the sphere. Note, that it is not exclusively in the bottom, but as the sphere rotates, also parts of the top half show the same problem. enter image description here

For the second example, the relevant code is:

void ofApp::setup(){
    r = 0;
    sphere.setRadius(100);
    texture.loadImage("test.png");
}

//--------------------------------------------------------------
void ofApp::update(){
    r += 0.25;
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofPushMatrix();

    ofTranslate(ofGetWidth() / 2, ofGetHeight() / 2);
    ofRotateY(r);

    texture.getTextureReference().bind();
    sphere.draw();

    texture.unbind();

    ofPopMatrix();
}

Noteworthy is that while the sphere is rotating the "transparent" parts rotate with the sphere.

You can also check out the whole code of the second example here: https://github.com/kontur/openframeworks-ios-sphere-texturing-problem

Both texture images are powers of two, the world map image being 1024x1024 and the checker pattern being 512x512 pixels.

I am pretty sure this is some minor problem somehow to do with setting a flag to render the sphere solid, but as a beginner I have not made any progress with this no matter what I have tried so far.

Any ideas?


Solution

  • There is two possible solution to make this work:

    As per this openprocessing forum post making sure the generated main.mm starts using the iOSWindow setup like so:

    int main(){
        ofAppiOSWindow * iOSWindow = new ofAppiOSWindow();
        iOSWindow->enableDepthBuffer();
        ofSetupOpenGL(iOSWindow, 1024, 768, OF_FULLSCREEN);
    
        ofRunApp(new ofApp);
    }
    

    In particular the enableDepthBuffer() seems important.

    The other solution is to explicitly set the backface culling via Open GL commands. For that, the code where the ofSpherePrimitive gets drawn needs to look like so:

    glEnable(GL_CULL_FACE); // Cull back facing polygons
    glCullFace(GL_BACK); // might be GL_FRONT instead
    texture.getTextureReference().bind();
    sphere.draw();
    texture.unbind();
    

    The reason this didn't work out of the box was that the openframeworks Project Generator creates a different kind of window setup in main.mm which does not support the depth buffer per default.

    Hopefully this will be helpful to someone for future reference.