Lighting problem with dome

Looking around the forums, the Dome class seems to be primarily viewed from the inside looking out, as a SkyDome. I need to draw a dome that is going to be looked at only from the outside - and the Dome constructor provides a way to do so (according to the javadoc) by setting "outsideView" to true.



Unfortunately, the winding for dome appears to be backwards, in all cases. When outsideView is false, and CullState(CS_BACK) is set, then the inside of the dome is culled, while the outside is not (which is the opposite of what should happen - when outsideView is false, the inside of the dome should be the "Front" not the "Back"). However, other aspects of dome - such as the lighting - are applied as if the inside but not the outside of the dome were visible. When outside view is true, the exact opposite is the case. This seemed to suggest that the winding was being applied backwards, but the lighting was not.



Going into dome and just switching which winding is used for outsideView/insideView solves the problem, as far as I can tell.







Here is a test case that should display the problem (JME1). Notice how the wrong face of the dome is culled when CS_BACK is used.








import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.input.FirstPersonHandler;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.shape.Capsule;
import com.jme.scene.shape.Dome;
import com.jme.scene.state.CullState;

public class DomeLightingTest extends SimpleGame{
   

    private Quaternion rotQuat = new Quaternion();
    private float angle = 0;
    private Vector3f axis = new Vector3f(1, 1, 0).normalizeLocal();
    private Dome t;
    private Capsule c;

    /**
     * Entry point for the test,
     *
     * @param args
     */
    public static void main(String[] args) {
       DomeLightingTest app = new DomeLightingTest();
        app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
        app.start();
    }

    protected void simpleUpdate() {
        if (timer.getTimePerFrame() < 1) {
            angle = angle + (timer.getTimePerFrame() * 1);
            if (angle > 360) {
                angle = 0;
            }
        }

        rotQuat.fromAngleNormalAxis(angle, axis);
        t.setLocalRotation(rotQuat);
        c.setLocalRotation(rotQuat);
    }

    /**
     * builds the trimesh.
     *
     * @see com.jme.app.SimpleGame#initGame()
     */
    protected void simpleInitGame() {
        display.setTitle("Dome Lighting Test");

        t =new Dome("Dome", new Vector3f(), 30, 30, 0.5f,false);
        t.setModelBound(new BoundingBox());
        t.updateModelBound();
       
        c = new Capsule("Capsule", 40, 32, 16, 0.5f, 1);
        c.setModelBound(new BoundingBox());
        c.updateModelBound();
       
        c.getLocalTranslation().x -= 2;
       
        CullState cs = display.getRenderer().createCullState();
        cs.setCullMode(CullState.CS_BACK);
        rootNode.setRenderState(cs);
       
        input = new FirstPersonHandler(cam, 10f, 1f);
       
        rootNode.attachChild(t);
        rootNode.attachChild(c);
       
        rootNode.updateRenderState();
        c.updateRenderState();
        t.updateRenderState();
       
        lightState.setTwoSidedLighting(false);
    }

}




And here is a patch (JME1)

Index: Dome.java
===================================================================
RCS file: /cvs/jme/src/com/jme/scene/shape/Dome.java,v
retrieving revision 1.11
diff -u -r1.11 Dome.java
--- Dome.java   21 Sep 2007 15:45:27 -0000   1.11
+++ Dome.java   11 Jul 2008 01:20:29 -0000
@@ -284,7 +284,7 @@
             int bottomPlaneStart = (plane - 1) * (radialSamples + 1);
             int topPlaneStart = plane * (radialSamples + 1);
             for (int sample = 0; sample < radialSamples; sample++, index += 6) {
-                if (outsideView) {
+                if (!outsideView) {
                    batch.getIndexBuffer().put(bottomPlaneStart + sample);
                    batch.getIndexBuffer().put(bottomPlaneStart + sample + 1);
                    batch.getIndexBuffer().put(topPlaneStart + sample);
@@ -306,7 +306,7 @@
         // pole triangles
         int bottomPlaneStart = (planes - 2) * (radialSamples + 1);
         for (int samples = 0; samples < radialSamples; samples++, index += 3) {
-            if (outsideView) {
+            if (!outsideView) {
                batch.getIndexBuffer().put(bottomPlaneStart + samples);
                batch.getIndexBuffer().put(bottomPlaneStart + samples + 1);
                batch.getIndexBuffer().put(batch.getVertexCount() - 1);





Great, fixed.

i dont like this fix… it totally ruins skydome!



the sphere and dome are not lit up differently. and i think the dome is lit up wrong when viewing from inside. the opposite side of the dome is lit up. if u have a moving light source, when the light is say at the left of the dome, the right side of the dome is lit up. and when the light is at the right side of the dome, the left side of the dome gets lit.

Yah - I took a brief look at the sky dome code a while ago (I dont use skydome).



I think SkyDome was written in such a way to compensate for this bug, and the compensation is now causing problems.

sbayless said:

Yah - I took a brief look at the sky dome code a while ago (I dont use skydome).

I think SkyDome was written in such a way to compensate for this bug, and the compensation is now causing problems.


i agree that there was a bug before, but the fix for that bug essentially caused another bug. if u compare the lighting between dome and sphere, u'll c that dome is lit up wrong. the various skydome implementations was built on the correct lighting model. and now the lighting model is wrong.

i agree that there was a bug before, but the fix for that bug essentially caused another bug. if u compare the lighting between dome and sphere, u'll c that dome is lit up wrong. the various skydome implementations was built on the correct lighting model. and now the lighting model is wrong.



Thats entirely possible - My fix was pretty superficial, and I didn't put enough time into it to discover the root problem.

Calm down neakor.  The fix was for culling. I'll look into it now.



edit: looking into it

Okay… so the answer is that sbayless's patch was correct and the Dome shape now currently has correct normals.  Inside view has normals facing in and outside has normals facing out as you would expect.  If you are viewing a Sphere, you are viewing it from the outside and the normals also face out.



The user submitted SkyDome on the wiki (not part of jME) may have been written to compensate for bad normals, but that is no reason to leave them bad.

renanse said:

Okay... so the answer is that sbayless's patch was correct and the Dome shape now currently has correct normals.  Inside view has normals facing in and outside has normals facing out as you would expect.  If you are viewing a Sphere, you are viewing it from the outside and the normals also face out.

The user submitted SkyDome on the wiki (not part of jME) may have been written to compensate for bad normals, but that is no reason to leave them bad.


im not using the SkyDome on the wiki. but what ive found is that the lighting for dome is not affected by the boolean value.

here i wrote a simple test to show this problem. there r two domes in the test, one is set to view from inside the other is set to view from outside. however, as u will c, both domes r lit up exactly the same way even their normals r completely opposite of each other.



import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.light.DirectionalLight;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.shape.Dome;

public class TestLighting extends SimpleGame {
   
   public static void main(String[] args) {
      TestLighting test = new TestLighting();
      test.setConfigShowMode(ConfigShowMode.AlwaysShow);
      test.start();
   }

   @Override
   protected void simpleInitGame() {
      this.buildInsideDome();
      this.buildOutsideDome();
      this.buildLight();
      this.rootNode.updateRenderState();
   }
   
   private void buildInsideDome() {
      Dome dome = new Dome("InsideDome", new Vector3f(), 32, 32, 20, false);
      dome.setModelBound(new BoundingBox());
      dome.updateModelBound();
      this.rootNode.attachChild(dome);
   }
   
   private void buildOutsideDome() {
      Dome dome = new Dome("OutsideDome", new Vector3f(50, 0, 0), 32, 32, 20, true);
      dome.setModelBound(new BoundingBox());
      dome.updateModelBound();
      this.rootNode.attachChild(dome);
   }
   
   private void buildLight() {
      this.lightState.detachAll();
      DirectionalLight light = new DirectionalLight();
      light.setDiffuse(ColorRGBA.white);
      light.setDirection(Vector3f.UNIT_Y.negate());
      light.setEnabled(true);
      this.lightState.attach(light);
   }
}

Thanks for your persistence on this neakor.  Apologies that it took a bit to sink in.



So, yeah, the normals are pointing the "expected" way in Dome and the winding works for culling, but put them together and you are right, the lighting ends up the same.



I'm going to change Dome to provide only one set of windings.  Use jME2.0's polygon wind param in cullstate to set clockwise or counterclockwise, depending on inside or outside facing.  I've changed the test you provided to illustrate that and added it as jmetest.shape.TestInsideOutsideDomes.

great! thx~  :smiley: