light opposite side

Hi, JOGL users.

I write a jogl program which draws 2 spheres, a big and a small one.

Assume that the bigger sphere is the Earth
and the smaller one revolves around the Earth.

The smaller sphere is drawn at the very location
where a local-light-source places.

But I have a problem.

Not only the side which faces the light-source
but also the opposite side which doesn’t face the light source are lit up.

Why the both side lit up? And how not to light the oppsosite side of the sphere?

I feel that my explanation is poor :-X

I hope that the attached picture helps you recognize my problem.

Thanks.

Hi!

I think I know the solution, it has something to do with the configuration of the light depending on the face, you have to use GL_FRONT instead of GL_FRONT_AND_BACK. I’m currently very busy, I will give you a piece of source code tomorrow morning (French time) if possible.

Hi!

Try to use glLightModel but not with GL_LIGHT_MODEL_TWO_SIDE. Let me know what you get.

Thank you for your response :slight_smile:

I tried your suggestion that applying
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

I notice that the SPECULAR and DIFFUSE light doesn’t apply to back face.
Only AMBIENT does.

For example, I tried this for another source code.
I set the same material properties to FRONT_AND_BACK face.

I expected that the both faces turns white.

As expected, the front face turns white.
However the back face turns pure red. ???
Why the back face uses the AMBIENT property only?


	gl.glLightModeli(GL2.GL_LIGHT_MODEL_TWO_SIDE,GL2.GL_TRUE);
	gl.glLightModeli(GL2.GL_LIGHT_MODEL_LOCAL_VIEWER, GL2.GL_TRUE);
	gl.glLightModelfv(GL2.GL_LIGHT_MODEL_AMBIENT, new float[] {0,0,0,0}, 0);
	gl.glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL, GL2.GL_SEPARATE_SPECULAR_COLOR);

	gl.glEnable(GL2.GL_LIGHT1);
	gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, new float[] {0,0,1,0}, 0);
	gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_AMBIENT, new float[] {1.0f,1.0f,1.0f,1.0f}, 0);
	gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_DIFFUSE, new float[] {1.0f,1.0f,1.0f,1}, 0);
	gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_SPECULAR, new float[] {1,1,1,1}, 0);

	gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_EMISSION, new float[] {0,0,0,0}, 0);
	gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT, 
new float[] {1,0,0,0}, 
0);
	gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, new float[] {1,1,1,1}, 0);
	gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_SPECULAR, new float[] {1,1,1,1}, 0);
	gl.glMaterialf(GL2.GL_FRONT_AND_BACK, GL2.GL_SHININESS, 25.0f);

Ambient light doesn’t behave like positional light - you could think of ambient light as to the sun in the sky at 12:00. It (more or less) doesn’t create any shadows, it just lights everything up. A spotlight in a theater is more like other types of light in OpenGL.

http://www.falloutsoftware.com/tutorials/gl/gl8.htm#ambient_light

I’m unsure why ambient light would shade strangely like that (non-uniform). As shown in the link I just sent, ambient light should make a sphere appear 2D. I haven’t looked at your source in depth, but it’s likely there’s something else going on here as well.

Actually I just looked in more detail and things appear to be working right. Follow Julien’s suggestion, and then greatly reduce the strength of your ambient light (it should typically be much weaker than spot sources), and it should work okay.

I think that the problem might come from the method which I use for drawing a sphere.
Because “glutSolidSphere()” works fine with the light but “drawSphere()” does not…

Would you try this code and let me know what the problem is?

The method “drawSphere()” draws a sphere of which radius is 1 and centered at the origin. And you can change the number of subdivision to alter the variable “depth”.

Thank you. :slight_smile:

The code for drawing sphere is as follows.


// the author of this code: Jim X. Chen

    private final float sVdata[][] = { {1.0f, 0.0f, 0.0f}
				       , {0.0f, 1.0f, 0.0f}
				       , {0.0f, 0.0f, 1.0f}
				       , {-1.0f, 0.0f, 0.0f}
				       , {0.0f, -1.0f, 0.0f}
				       , {0.0f, 0.0f, -1.0f}
    };
    private int depth = 4;

    public void drawSphere() {
	subdivideSphere(sVdata[0], sVdata[1], sVdata[2], depth);
	subdivideSphere(sVdata[0], sVdata[2], sVdata[4], depth);
	subdivideSphere(sVdata[0], sVdata[4], sVdata[5], depth);
	subdivideSphere(sVdata[0], sVdata[5], sVdata[1], depth);

	subdivideSphere(sVdata[3], sVdata[1], sVdata[5], depth);
	subdivideSphere(sVdata[3], sVdata[5], sVdata[4], depth);
	subdivideSphere(sVdata[3], sVdata[4], sVdata[2], depth);
	subdivideSphere(sVdata[3], sVdata[2], sVdata[1], depth);
    }


    private void subdivideSphere(float v1[], float v2[], float v3[], long depth) {
	float v12[] = new float[3];
	float v23[] = new float[3];
	float v31[] = new float[3];
	int i;

	if (depth==0) {
	    gl.glColor3f(v1[0]*v1[0], v2[1]*v2[1], v3[2]*v3[2]);
	    drawtriangle(v1, v2, v3);
	    return;
	}
	for (i = 0; i<3; i++) {
	    v12[i] = v1[i]+v2[i];
	    v23[i] = v2[i]+v3[i];
	    v31[i] = v3[i]+v1[i];
	}
	normalize(v12);
	normalize(v23);
	normalize(v31);
	subdivideSphere(v1, v12, v31, depth-1);
	subdivideSphere(v2, v23, v12, depth-1);
	subdivideSphere(v3, v31, v23, depth-1);
	subdivideSphere(v12, v23, v31, depth-1);
    }

    // normalize a 3D vector
    public void normalize(float vector[]) {
	float d = (float) Math.sqrt(vector[0] * vector[0] + vector[1]
				    * vector[1] + vector[2] * vector[2]);

	if (d == 0) {
	    System.out.println("0 length vector: normalize().");
	    return;
	}
	vector[0] /= d;
	vector[1] /= d;
	vector[2] /= d;
    }

    public void drawtriangle(float[] v1, float[] v2, float[] v3) {
	gl.glBegin(GL2.GL_TRIANGLES);
	gl.glVertex3fv(v1, 0);
	gl.glVertex3fv(v2, 0);
	gl.glVertex3fv(v3, 0);
	gl.glEnd();
    }

It doesn’t look like you’re providing normals to OpenGL. To use lighting correctly you need to provide a normal vector per vertex. Right now they’re undefined, which is why it appears to be two-sided. glutSolidSphere provides its own normals.

To add normals, just call glNormal3f before each glVertex3f call. The normal for a sphere is normalize(V - C) where V is the current vertex and C is the center of the sphere. The normal must be set before glVertex3f because OpenGL uses the current set normal when lighting the vertex.

Ah ha

That’s the point causing the problem.

Thank all answerers 8)

D’oh, I should have seen that. :slight_smile: