Open GL: changing appearance after first rendering
Hello,
I'm new to OpenGL and I'm trying to do an X3D viewer for the iPhone. The project is opensource and here is the code you can checkout from google code:
I'm able to parse the XML and draw in the screen all the content (at the moment geometries and various types of lights, soon I'll add transformations).
The only problem is that the app draws the first frame properly and from the second is like the lights are turned off. I set the refreshing rate to 1sec so you see this clearly.
I tried many options, but I can't figure out what's the problem, so some help will be very welcome
Last edited by supertaurus85; 02-12-2010 at 04:11 AM.
OpenGL is state based. You need to re-enable lighting via glEnable to turn it back on. Also the individual lights you use namely GL_LIGHT0
I do glEnable everytime I start a parent of a light node, and a glDisable everytime I end that node.
So the scene was properly lighted the first time, why it's not the second time?
#pragma mark drawView
- (void)drawView {
//NSLog(@"Starting to draw...");
// provare a spostare da qualche altra parte
if (appDelegate == nil)
appDelegate = (iX3DAppDelegate *)[UIApplication sharedApplication].delegate;
// This application only creates a single context which is already set current at this point.
// This call is redundant, but needed if dealing with multiple contexts.
[EAGLContext setCurrentContext:context];
// This application only creates a single default framebuffer which is already bound at this point.
// This call is redundant, but needed if dealing with multiple framebuffers.
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(0, 0, backingWidth, backingHeight);
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW); // passo alla modalità per mettere gli oggetti nella scena
/*
Inizio codice OpenGL per disegnare
*/
glEnable(GL_COLOR_MATERIAL);
//glFrontFace(GL_CCW);
[self drawTree: root]; // inizio a disegnare dalla radice
/*
Fine codice OpenGL per disegnare
*/
// This application only creates a single color renderbuffer which is already bound at this point.
// This call is redundant, but needed if dealing with multiple renderbuffers.
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewFramebuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
[self stopAnimation];
}
-(void)drawTree:(X3DNode*)currentNode {
X3DNode *node;
int firstLightOfTheNode=0;
//NSLog(@"starting: %@", [currentNode description]);
if ( currentNode.lights > 0 ) { // i nodi figli devono essere illuminati
//NSLog(@"i suoi figli hanno luce");
if ( numberOfLights + currentNode.lights < 8 ) {
firstLightOfTheNode = currentLight;
glEnable(GL_LIGHTING);
for (int i=0 ; i<currentNode.lights ; i++) {
NSLog(@"GL_LIGHT0: %d - luca abilitata: %d", GL_LIGHT0, currentLight+numberOfLights+i);
NSLog(@"currentLight: %d - numberOfLights: %d - i: %d", currentLight, numberOfLights, i);
glEnable(currentLight+numberOfLights+i); // abilito tante luci quante ce ne sono nei figli del currentNode
}
}
else {
NSLog(@"troppe luci");
}
numberOfLights+=currentNode.lights; // il numero delle luci viene aumentato
}
/****** vedo che tipo di nodi figli ho e chiamo le varie funzioni che utilizzeranno OpenGL ******/
for ( node in currentNode.sons ) {
if ( [node isMemberOfClass:[Shape class]] ) {
//NSLog(@"one of the sons is a shape");
[self drawTree:node];
}
else if ( [node isMemberOfClass:[IndexedFaceSet class]] ) {
//NSLog(@"one of the sons is a indexedf...");
[self drawIndexedFaceSet:(IndexedFaceSet*)node];
}
else if ( [node isKindOfClass:[Light class]] ) { // appartiene ad una sottoclasse di Light
//NSLog(@"one of the sons is a light...");
[self setLight:(Light*)node];
}
}
if ( currentNode.lights > 0 ) { // finisco il nodo i cui figli devono essere illuminati
if ( numberOfLights < 8 ) {
for (int i=0 ; i<currentNode.lights ; i++) {
NSLog(@"GL_LIGHT0: %d - luca disabilitata: %d", GL_LIGHT0, firstLightOfTheNode+i);
NSLog(@"firstLightOfTheNode: %d - i: %d", firstLightOfTheNode, i);
glDisable(firstLightOfTheNode+i); // vengono disabilitate le luci che dovevano illuminare i figli di questo nodo.
currentLight--;
}
}
numberOfLights-=currentNode.lights;
if ( numberOfLights == 0 ) {
glDisable(GL_LIGHTING);
NSLog(@"numberOfLights == 0");
}
}
//NSLog(@"I'm finishing with the node %@", [currentNode description]);
}
#pragma mark Metodi disegno ausiliari
- (void)drawIndexedFaceSet:(IndexedFaceSet *)indexedFaceSet
{
GLfloat shapeVertices[indexedFaceSet.coordIndexSize*3-1]; // una figura non avrà mai più vetici di così
GLfloat colorVertices[indexedFaceSet.coordIndexSize*4-1];
GLfloat normalVertices[indexedFaceSet.coordIndexSize*3-1];
int faceSize = 0; //Number of vertex in current face
int currentFace = 0; // numero della faccia corrente
for (int index = 0; index < indexedFaceSet.coordIndexSize; index++)
{
if (indexedFaceSet.coordIndex[index] != -1)
{
int position = (indexedFaceSet.coordIndex[index]) * 3;
shapeVertices[faceSize*3] = indexedFaceSet.coord[position];
shapeVertices[faceSize*3+1] = indexedFaceSet.coord[position + 1];
shapeVertices[faceSize*3+2] = indexedFaceSet.coord[position + 2];
if ( indexedFaceSet.normalSize == indexedFaceSet.coordSize ) { // se abbiamo a disposizione le normali
normalVertices[faceSize*3] = indexedFaceSet.normalArray[position];
normalVertices[faceSize*3+1] = indexedFaceSet.normalArray[position + 1];
normalVertices[faceSize*3+2] = indexedFaceSet.normalArray[position + 2];
}
if ( indexedFaceSet.colorPerVertex && indexedFaceSet.colorSize == indexedFaceSet.coordSize ) { // un colore diverso per ogni vertice
colorVertices[faceSize*4] = indexedFaceSet.colorArray[position];
colorVertices[faceSize*4+1] = indexedFaceSet.colorArray[position + 1];
colorVertices[faceSize*4+2] = indexedFaceSet.colorArray[position + 2];
colorVertices[faceSize*4+3] = 0.8f;
}
faceSize++;
}
//End of a face...
else
{
// un colore unico per ogni faccia
if ( !indexedFaceSet.colorPerVertex && currentFace*4+2 < indexedFaceSet.colorSize ) {
glColor4f(indexedFaceSet.colorArray[currentFace*4],
indexedFaceSet.colorArray[currentFace*4+1],
indexedFaceSet.colorArray[currentFace*4+2],
0.8f);
}
else { // un colore diverso per ogni vertice
glColorPointer(4, GL_FLOAT, 0, colorVertices);
glEnableClientState(GL_COLOR_ARRAY); // abilito il disegno con i color array
}
//Draw current face
glVertexPointer(3, GL_FLOAT, 0, shapeVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, normalVertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, faceSize);
//Get ready for next face
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
faceSize = 0;
currentFace++;
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
}
}
}
-(void)setLight:(Light *)light {
GLfloat LightPosition[3];
GLfloat LightAmbient[]= { 0.2f, 0.2f, 0.2f, 1.0f }; // luce ambiente (in x3d non si mette)
GLfloat LightDiffuse[]= { light.color[0], light.color[1], light.color[2], 1.0f }; // Componente diffuse
for ( int i = 0 ; i < 3 ; i++ ) {
LightAmbient[i] *= light.ambientIntensity;
LightDiffuse[i] *= light.intensity;
}
/*** DirectionalLight ***/
if ( [light isMemberOfClass:[DirectionalLight class]] ) {
DirectionalLight *dlight = (DirectionalLight *)light;
for ( int i = 0 ; i < 4 ; i++ )
LightPosition[i] = dlight.direction[i]; // questa è la direzione della luce, l'elemento di indice 3 è messo a 0.0f
}
/*** PointLight ***/
else if ( [light isMemberOfClass:[PointLight class]] ) {
PointLight *plight = (PointLight *)light;
for ( int i = 0 ; i < 4 ; i++ )
LightPosition[i] = plight.location[i]; // questa è la direzione della luce, l'elemento di indice 3 è messo a 1.0f
// cutoff è di 180*2
glLightf(currentLight, GL_SPOT_CUTOFF, 180.0f);
// attenuation
glLightf(currentLight, GL_CONSTANT_ATTENUATION, plight.attenuation[0]);
glLightf(currentLight, GL_LINEAR_ATTENUATION, plight.attenuation[1]);
glLightf(currentLight, GL_QUADRATIC_ATTENUATION, plight.attenuation[2]);
}
/*** SpotLight ***/
else if ( [light isMemberOfClass:[SpotLight class]] ) {
SpotLight *slight = (SpotLight *)light;
GLfloat LightDirection[3];
for ( int i = 0 ; i < 4 ; i++ ) {
LightPosition[i] = slight.location[i]; // questa è la direzione della luce, l'elemento di indice 3 è messo a 1.0f
LightDirection[i] = slight.direction[i];
}
// cutoff
glLightf(currentLight, GL_SPOT_CUTOFF, slight.cutOffAngle/3.1415926536*180);
// direction
glLightfv(currentLight, GL_SPOT_DIRECTION, LightDirection);
// attenuation
glLightf(currentLight, GL_CONSTANT_ATTENUATION, slight.attenuation[0]);
glLightf(currentLight, GL_LINEAR_ATTENUATION, slight.attenuation[1]);
glLightf(currentLight, GL_QUADRATIC_ATTENUATION, slight.attenuation[2]);
// beamwidth
float ft = 0.5/(slight.beamWidth +0.1);
if (ft>128.0) ft=128.0;
if (ft<0.0) ft=0.0;
glLightf(currentLight, GL_SPOT_EXPONENT,ft);
}
glLightfv(currentLight, GL_AMBIENT, LightAmbient);
glLightfv(currentLight, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
glLightfv(currentLight, GL_POSITION, LightPosition); // Position The Light
currentLight++;
}
I can sort of follow this but your code does some very inefficient things we all do when starting out
Namely the
[self stopAnimation]; at the end of each drawing call. If you want asynchronous drawing, then call drawView asynchronously from tap events and don't initialize the timer.
Also, glEnable(GL_LIGHTING) inside a loop is redundant and each state call in opengl on an iphone is very costly, Do this. Remove or comment ALL glEnable/glDisable calls pertaining to lights.
Now, at the very beginning in your drawview call do
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
work? if so, add GL_LIGHT1,2,3... as necessary. If you only use one light, then stick with 0. You can go back to the dynamic stuff when you have the simple case working