Hi
Pasted below is as close as possible to my actual setup of displaying a grid of triangles. The program should run as-is and just needs to extend from ExampleBase. Whatever I do I cannot get the scene lighting correct. If you run the code as-is then you will see a dark grey mesh. However, if I comment out the following line in ExampleBase: //_root.setRenderState(_lightState); then you will see the red mesh, as below: The colour buffer is filled correctly. I assign a MaterialState to the grid mesh. So, why does the object not get lit as expected? Thanks. ***** package viewer3d.sample; import java.nio.IntBuffer; import java.util.ArrayList; import java.util.HashMap; import com.ardor3d.bounding.BoundingBox; import com.ardor3d.math.ColorRGBA; import com.ardor3d.math.Vector3; import com.ardor3d.renderer.state.MaterialState; import com.ardor3d.renderer.state.MaterialState.MaterialFace; import com.ardor3d.scenegraph.Mesh; import com.ardor3d.scenegraph.MeshData; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.geom.BufferUtils; import com.ardor3d.example.ExampleBase; public class GridExample extends ExampleBase { /** Keep a reference to the box to be able to rotate it each frame. */ private Mesh grid; public static void main(final String[] args) { start(GridExample.class); } @Override protected void updateExample(final ReadOnlyTimer timer) { } @Override protected void initExample() { _canvas.setTitle("Grid Example"); grid = setupGridMesh(new ColorRGBA(1,0,0,1)); grid.setModelBound(new BoundingBox()); grid.setTranslation(new Vector3(0, 0, -5)); _root.attachChild(grid); // Add a material to the box, to show both vertex color and lighting/shading. final MaterialState materialState = new MaterialState(); materialState.setEnabled(true); materialState.setAmbient(MaterialFace.FrontAndBack, new ColorRGBA(0.1f,0.1f,0.1f,1.0f)); materialState.setDiffuse(MaterialFace.FrontAndBack, new ColorRGBA(0.9f,0.9f,0.9f,1.0f)); grid.setRenderState(materialState); } private Mesh setupGridMesh(ColorRGBA defaultColour) { Vector3 origin = new Vector3(0,0,0); double iSpacing = 1.0; double jSpacing = 1.0; int iSize = 4; int jSize = 3; Grid3D grid = new Grid3D(origin,iSpacing,jSpacing,iSize,jSize); grid.addPoint(0.0,0,0); grid.addPoint(0.0,1,0); grid.addPoint(0.0,2,0); grid.addPoint(0.0,3,0); grid.addPoint(1.0,0,1); grid.addPoint(1.0,1,1); grid.addPoint(1.0,2,1); grid.addPoint(1.0,3,1); grid.addPoint(4.0,0,2); grid.addPoint(4.0,1,2); grid.addPoint(4.0,2,2); grid.addPoint(4.0,3,2); Mesh mesh = buildSolidMesh(grid, defaultColour); return mesh; } private Mesh buildSolidMesh(Grid3D grid, ColorRGBA defaultColour) { Mesh mesh = new Mesh(); MeshData meshData = mesh.getMeshData(); // vertex/colour buffers Vector3[] gridPoints = grid.gridPoints(); int iSize = grid.miSize; int jSize = grid.mjSize; int numberPoints = iSize * jSize; // colours float red = defaultColour.getRed(); float green = defaultColour.getGreen(); float blue = defaultColour.getBlue(); float alpha = defaultColour.getAlpha(); meshData.setVertexBuffer(BufferUtils.createVector3Buffer(numberPoints)); meshData.setColorBuffer(BufferUtils.createColorBuffer(numberPoints)); for (int index=0; index<numberPoints; index++) { // vertex Vector3 p = gridPoints[index]; meshData.getVertexBuffer().put(p.getXf()).put(p.getYf()).put(p.getZf()); meshData.getColorBuffer().put(red).put(green).put(blue).put(alpha); // note *4 indexing into buffer } meshData.getColorBuffer().rewind(); // vertex normals meshData.setNormalBuffer(BufferUtils.createVector3Buffer(numberPoints)); // texture //... not supported at present // triangle indices ArrayList<TripleInteger> triangleIndices = new ArrayList<>(); ArrayList<GridTriangle> triangles = grid.triangles(); int numberTriangles = triangles.size(); for (int i=0; i<numberTriangles; i++) { // indices GridTriangle triangle = triangles.get(i); GridPoint v0gp = triangle.mv0; GridPoint v1gp = triangle.mv1; GridPoint v2gp = triangle.mv2; int v0Index = grid.hashKey(v0gp); int v1Index = grid.hashKey(v1gp); int v2Index = grid.hashKey(v2gp); TripleInteger triple = new TripleInteger(v0Index,v1Index,v2Index); triangleIndices.add(triple); // normals Vector3 v0 = gridPoints[v0Index]; Vector3 v1 = gridPoints[v1Index]; Vector3 v2 = gridPoints[v2Index]; final Vector3 v01 = v1.subtract(v0, null); final Vector3 v02 = v2.subtract(v0, null); final Vector3 cross = v01.cross(v02, null); cross.normalizeLocal(); final float nx = cross.getXf(); final float ny = cross.getYf(); final float nz = cross.getZf(); meshData.getNormalBuffer().put(v0Index+0,nx).put(v0Index+1,ny).put(v0Index+2,nz); meshData.getNormalBuffer().put(v1Index+0,nx).put(v1Index+1,ny).put(v1Index+2,nz); meshData.getNormalBuffer().put(v2Index+0,nx).put(v2Index+1,ny).put(v2Index+2,nz); } int[] indices = new int[3*triangleIndices.size()]; for (int i=0; i<triangleIndices.size(); i++) { TripleInteger triIndices = triangleIndices.get(i); indices[3*i+0] = triIndices.mp; indices[3*i+1] = triIndices.mq; indices[3*i+2] = triIndices.mr; } final IntBuffer ibuf = BufferUtils.createIntBuffer(indices.length); ibuf.put(indices); ibuf.rewind(); meshData.setIndexBuffer(ibuf); return mesh; } } // GridExample class Grid3D { /** Origin. */ protected Vector3 mOrigin; /** Spacing in i-direction. */ protected double miSpacing; /** Spacing in j-direction. */ protected double mjSpacing; /** Number of points in i-direction. */ protected int miSize; /** Number of points in j-direction. */ protected int mjSize; /** Hash-map of z-values. */ protected HashMap<GridPoint, Double> mzValues; public Grid3D(final Vector3 origin, final double iSpacing, final double jSpacing, final int iSize, final int jSize) { mOrigin = origin; miSpacing = iSpacing; mjSpacing = jSpacing; miSize = iSize; mjSize = jSize; mzValues = new HashMap<>(); } public void addPoint(final double zValue, final int i, final int j) { mzValues.put(new GridPoint(i,j), zValue); } public Vector3[] gridPoints() { int numberPoints = miSize*mjSize; Vector3[] points = new Vector3[numberPoints]; for (int i = 0; i < miSize; i++) { for (int j = 0; j < mjSize; j++) { int index = hashKey(new GridPoint(i,j)); double xValue = x(i,j); double yValue = y(i,j); double zValue; zValue = z(i,j); Vector3 point = new Vector3(xValue,yValue,zValue); points[index] = point; } } return points; } public int hashKey(GridPoint gp) { return gp.mGridj + gp.mGridi * mjSize; } public double x(int i, int j) { return i * miSpacing; } public double y(int i, int j) { return j * mjSpacing; } public double z(int i, int j) { return mzValues.get(new GridPoint(i,j)); } public ArrayList<GridTriangle> triangles() { ArrayList<GridTriangle> triangles = new ArrayList<GridTriangle>(); for (int i = 0; i < miSize; i++) { for (int j = 0; j < mjSize; j++) { ArrayList<GridTriangle> tris = triangles(i, j); for (int t = 0; t < tris.size(); t++) { GridTriangle tri = tris.get(t); triangles.add(tri); } } } return triangles; } public ArrayList<GridTriangle> triangles(int loweri, int lowerj) { // neighbouring quadrilateral points [a(loweri,lowerj), b, c, d in // anti-clockwise rotation from a] int ai = loweri, aj = lowerj, bi = loweri + 1, bj = lowerj, ci = loweri + 1, cj = lowerj + 1, di = loweri, dj = lowerj + 1; GridPoint pa = new GridPoint(ai, aj); GridPoint pb = new GridPoint(bi, bj); GridPoint pc = new GridPoint(ci, cj); GridPoint pd = new GridPoint(di, dj); // points and not-a-points boolean aIsPoint = false, bIsPoint = false, cIsPoint = false, dIsPoint = false; if (isGridPoint(ai, aj)) { aIsPoint = true; } if (isGridPoint(bi, bj)) { bIsPoint = true; } if (isGridPoint(ci, cj)) { cIsPoint = true; } if (isGridPoint(di, dj)) { dIsPoint = true; } // triangles ArrayList<GridTriangle> tris = new ArrayList<>(); if (aIsPoint && bIsPoint && cIsPoint && dIsPoint) // full quadrilateral { GridTriangle t1 = new GridTriangle(pa, pb, pc); GridTriangle t2 = new GridTriangle(pa, pc, pd); tris.add(t1); tris.add(t2); return tris; } if (aIsPoint && bIsPoint && cIsPoint) { GridTriangle t = new GridTriangle(pa, pb, pc); tris.add(t); } if (aIsPoint && cIsPoint && dIsPoint) { GridTriangle t = new GridTriangle(pa, pc, pd); tris.add(t); if (tris.size() == 2) // prevent more than 2 triangles being added return tris; } if (aIsPoint && bIsPoint && dIsPoint) { GridTriangle t = new GridTriangle(pa, pb, pd); tris.add(t); if (tris.size() == 2) // prevent more than 2 triangles being added return tris; } if (bIsPoint && cIsPoint && dIsPoint) { GridTriangle t = new GridTriangle(pb, pc, pd); tris.add(t); } return tris; } public boolean isGridPoint(int i, int j) { if (i < 0 || i > miSize - 1 || j < 0 || j > mjSize - 1) { return false; } return true; } } // class Grid3D class GridPoint { /** Grid-point i index. */ protected int mGridi; /** Grid-point j index. */ protected int mGridj; public GridPoint(final int i, final int j) { mGridi = i; mGridj = j; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + mGridi; result = prime * result + mGridj; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; GridPoint other = (GridPoint) obj; if (mGridi != other.mGridi) return false; if (mGridj != other.mGridj) return false; return true; } } // class GridPoint class GridTriangle { /** Vertex 0. */ protected GridPoint mv0; /** Vertex 1. */ protected GridPoint mv1; /** Vertex 2. */ protected GridPoint mv2; public GridTriangle(GridPoint v0,GridPoint v1,GridPoint v2) { mv0 = v0; mv1 = v1; mv2 = v2; } } // class GridTriangle class TripleInteger { /** Triple value p. */ protected int mp; /** Triple value q. */ protected int mq; /** Triple value r. */ protected int mr; public TripleInteger(final int p, final int q, final int r) { mp = p; mq = q; mr = r; } } // class TripleInteger |
Administrator
|
What is the expected lightning? I advise you to read the paragraph entitled "RGB Values for Lights and Materials" here:
http://www.glprogramming.com/red/chapter05.html
Julien Gouesse | Personal blog | Website
|
This post was updated on .
I'd expect to see a red grid just as when I comment out the line in ExampleBase that sets the light render state.
How can a point light with ambient component (0.75,0.75,0.75,0.75) fall on a red object make it appear grey and almost invisible? If you could illuminate the object without having to comment out the line in ExampleBase, then it would be gratefully appreciated. I'll read the recommending reading, but still adhere that there is something I don't get about the assigning of a light render state, a material state to an object and filling a mesh's colour buffer directly. I just can't figure out what! |
I should add that the pasted code started out life as BoxExample, with the object and point light in approx. the same position. Thus, I would expect similar lighting to that of BoxExample.
|
Administrator
|
In reply to this post by hedgehog
ExampleBase is just designed to be used for our examples, it isn't a general purpose class, it's not a reusable class. If you don't need any lightning, just remove the lines about the light state.
Julien Gouesse | Personal blog | Website
|
In thread:
http://forum.jogamp.org/Strange-Red-Lines-and-Vanishing-object-with-Ardor3D-td4031796.html it was noted: "...advise you to provide a SSCCE in the future if you really want to give us a chance to help you..." In this thread I spent some time setting up a SSCCE, and thus curious how someone would solve the lighting for this test case. It's not a solution to simply not use lighting, since I'm still baffled as to how it works outside one of the ardor3d examples. |
In GridExample.initExample() if I replace the lines:
materialState.setAmbient(MaterialFace.FrontAndBack, new ColorRGBA(0.1f,0.1f,0.1f,1.0f)); materialState.setDiffuse(MaterialFace.FrontAndBack, new ColorRGBA(0.9f,0.9f,0.9f,1.0f)); with: materialState.setColorMaterial(ColorMaterial.AmbientAndDiffuse); materialState.setColorMaterialFace(MaterialFace.FrontAndBack); then the red colour returns, just as if I commented out setting the light-state in ExampleBase. Why is that? However, I still don't have any lighting effects. |
Administrator
|
The 2 additional lines tells OpenGL to keep your colors, it calls glEnable(GL_COLOR_MATERIAL). If you don't understand what I mean, read at least the very first part of this tutorial:
http://www.swiftless.com/tutorials/opengl/material_lighting.html Keep in mind that Renanse stopped maintaining Ardor3D and most of the time I was already alone to answer to questions about Ardor3D, it's a bit difficult for me. Moreover, I still think that some knowledge of OpenGL basics is useful to understand how OpenGL-based scenegraphs work.
Julien Gouesse | Personal blog | Website
|
So, the lines without light state set shows the red colour without lighting:
materialState.setAmbient(MaterialFace.FrontAndBack, new ColorRGBA(0.1f,0.1f,0.1f,1.0f)); materialState.setDiffuse(MaterialFace.FrontAndBack, new ColorRGBA(0.9f,0.9f,0.9f,1.0f)); and thus keeps the red colour. The lines: materialState.setColorMaterial(ColorMaterial.AmbientAndDiffuse); materialState.setColorMaterialFace(MaterialFace.FrontAndBack); also keeps the red colour, with the root node light state set, but still no lighting effect like BoxExample. If I also add the lines: materialState.setColorMaterial(ColorMaterial.Emissive); materialState.setColorMaterial(ColorMaterial.Specular); I again lose the red colour and no lighting effect, even though there is no emissive or specular values set by GridExample or the parent ExampleBase. The Mesh colours are entirely set via directly writing to the colour buffer as a flat rgba. From where is it picking up ambient/diffuse/emissive/specular components? I understand the state engine of opengl for turning on/off light/colour states. What I don't understand is how this works in Ardor3D. I call materialState.setColorMaterial(ColorMaterial.AmbientAndDiffuse) and assign it to an object but from where does it get the ambient and diffuse values? In the materialState.setColorMaterial() version they are not assigned. There's something going on when writing directly to the colour buffer that I don't understand. |
Administrator
|
You have to call setColorMaterial just once.
The light components come from your material state when lightning is enabled. setColorMaterial just picks which kind of light parameters are concerned by color materials, you have to call setAmbient, setDiffuse, ... Feel free to look at the source code ardor3d-jogl and ardor3d-core.
Julien Gouesse | Personal blog | Website
|
The pasted code below tweaks ManyLightsExample by setting all light colours to white. It also fills the colour buffers of all object spheres to red.
All object spheres are grey - the same as what I'm seeing in my own code and GridExample. How do we modify ManyLightsExample2 to see red spheres as the lights pass by? import java.util.Random; import com.ardor3d.bounding.BoundingSphere; import com.ardor3d.example.ExampleBase; import com.ardor3d.light.PointLight; import com.ardor3d.math.ColorRGBA; import com.ardor3d.math.MathUtils; import com.ardor3d.math.Vector3; import com.ardor3d.scenegraph.MeshData; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.Spatial; import com.ardor3d.scenegraph.controller.SpatialController; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.shape.Sphere; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.geom.BufferUtils; /** * A demonstration of randomly placed spheres being illuminated by numerious PointLight sources. */ public class ManyLightsExample2 extends ExampleBase { private final Random rand = new Random(); private Node colornode; private final double worldsize = 20; public static void main(final String[] args) { start(ManyLightsExample2.class); } @Override protected void updateExample(final ReadOnlyTimer timer) { _root.sortLights(); } /** * Create a randomly positioned light and lightsphere with a controller * * @param i * Index of the light */ void randomLight(final int i) { // Chose the color for the lights. //final ColorRGBA lightColor = ColorRGBA.randomColor(new ColorRGBA()); final ColorRGBA lightColor = new ColorRGBA(1,1,1,1); // Create a sphere to show where the light is in the demo. final Sphere lightSphere = new Sphere("lightSphere" + i, 9, 9, .1f); lightSphere.setModelBound(new BoundingSphere()); lightSphere.getSceneHints().setLightCombineMode(LightCombineMode.Off); lightSphere.setDefaultColor(lightColor); // Create a new point light and fill out the properties final PointLight pointLight = new PointLight(); pointLight.setAttenuate(true); pointLight.setConstant(.01f); //pointLight.setConstant(.1f); pointLight.setLinear(.001f); pointLight.setQuadratic(.1f); pointLight.setEnabled(true); pointLight.setDiffuse(lightColor); pointLight.setAmbient(new ColorRGBA(.1f, .1f, .1f, .1f)); //pointLight.setAmbient(new ColorRGBA(.9f, .9f, .9f, 1f)); _lightState.attach(pointLight); lightSphere.addController(new SpatialController<Spatial>() { double timeX = rand.nextDouble() * Math.PI * 8; double timeY = rand.nextDouble() * Math.PI * 8; double timeZ = rand.nextDouble() * Math.PI * 8; double speed = MathUtils.nextRandomDouble(); public void update(final double tpf, final Spatial caller) { timeX += tpf * speed; timeY += tpf * speed; timeZ += tpf * speed; final double xPos = Math.sin(timeX * 0.4) * worldsize; final double yPos = Math.cos(timeY * 0.5) * worldsize; final double zPos = Math.sin(timeZ * 0.6) * worldsize; caller.setTranslation(xPos, yPos, zPos); pointLight.setLocation(xPos, yPos, zPos); } }); // Add the light to the world part 2. colornode.attachChild(lightSphere); } /** * Create a random sphere to be affected by the light * * @param i * Index of the sphere */ void randomSphere(final int i) { // Crate a sphere and position it. final Sphere sphere = new Sphere("sphere" + i, 18, 18, MathUtils.nextRandomDouble() * 1.75 + 1.25); sphere.updateModelBound(); sphere.setTranslation(new Vector3(rand.nextDouble() * worldsize * 2 - worldsize, rand.nextDouble() * worldsize * 2 - worldsize, rand.nextDouble() * worldsize * 2 - worldsize)); ColorRGBA sphereColour = new ColorRGBA(1,0,0,1); MeshData meshData = sphere.getMeshData(); int numberVertices = meshData.getVertexCount(); meshData.setColorBuffer(BufferUtils.createColorBuffer(numberVertices)); for (int index=0; index<numberVertices; index++) { float red = sphereColour.getRed(); float green = sphereColour.getGreen(); float blue = sphereColour.getBlue(); float alpha = sphereColour.getAlpha(); meshData.getColorBuffer().put(red).put(green).put(blue).put(alpha); // note *4 indexing into buffer } meshData.getColorBuffer().rewind(); _root.attachChild(sphere); } @Override protected void initExample() { _lightState.detachAll(); _lightState.setTwoSidedLighting(true); _lightState.setLocalViewer(true); rand.setSeed(1337); // Now add all the lights. colornode = new Node("LightNode"); for (int i = 0; i < 40; i++) { randomLight(i); } // Add the spheres. for (int i = 0; i < 30; i++) { randomSphere(i); } _root.attachChild(colornode); } } |
Administrator
|
Modify the parameters of the diffuse point light.
Julien Gouesse | Personal blog | Website
|
To what values?
|
Administrator
|
I don't know exactly as it's additive, it's something not very intuitive for me, like when you paint, it's explained in one of the tutorials I quoted, you can't just use these parameters as RGBA values.
Julien Gouesse | Personal blog | Website
|
I still don't understand how all sphere colour buffers can be filled with red, all point lights are white and yet as the points pass the spheres they show up default grey.
This is a basic application, and I don't think it's related to the tweaking of point light attributes but rather a general setup of object colour via buffer, lighting and assignment of material state. This works well for the stock examples that don't fill the colour buffer, but as soon I do so everything stops working as expected. I still hold that there is something funny going on when a user fills the colour buffer. There must be a set of calls required to set things up just the same as if the colour buffer wasn't filled. If someone knows how to get the modified many-lights example working so that they show as red as the lights pass by, then it would be greatly appreciated. |
Administrator
|
There is nothing magic. If you just want to enable lights but keep exactly the same colors, use GL_COLOR_MATERIAL as you did above. If you want to enable some lights but keep the colors without using GL_COLOR_MATERIAL, just use a single ambient light. If the color buffer wasn't filled, I don't really know which color would be picked to fill your polygons but you have to understand that the resulting color you see is a combination of the color of your object and the influences of all lights. Why not drawing a red triangle in Blender, adding some lights and tweaking their parameters until you get the "expected" behavior?
Julien Gouesse | Personal blog | Website
|
Thanks.
If it's really easy then I'd appreciate you editing the example I added above [ManyLightsExample2] and try and get the spheres so they show up red as the lights pass. If it's easy and straight forward then should only take a couple of minutes. I'd like to see the answer. |
I don't know how Ardor3D does lighting, I can't find any documentation. But one guess is that it maybe uses fixed-function lighting (GL_COLOR_MATERIAL is fixed-function). Then you must supply normals for each vertex, if not then you'd get the effect of material colors not being used, only the light color. So maybe normals are missing/wrong.
|
Administrator
|
You're right, he needs to provide the normals too especially if he doesn't use only an ambient light.
hedgehog, keep in mind that we are volunteers, I answer you on my spare time, I do my best and I don't have a working environment with Ardor3D when I'm at work for example. I already gave you several indications so that you understand that a light is not a color. At first, provide the correct normals. I don't say that the use of lights is easy. Edit.: Please provide normalized normals.
Julien Gouesse | Personal blog | Website
|
This post was updated on .
Thanks for your replies.
If you look closely at the GridExample you will see that the vertex normals were computed. I've re-jigged ManyLightsExample2 by adding the outward normals, and as expected it makes no difference. The spheres are still grey as the white lights pass by. So, it must be something else. Indeed, if you look at com.ardor3d.scenegraph.shape.Sphere you'll see that the normals are computed for the stock Sphere object. However, there is no default assignment/building of the colour buffer. Thus, in theory the sphere normals shouldn't need to be generated a 2nd time. ***Spheres with outward normals*** import java.util.Random; import com.ardor3d.bounding.BoundingSphere; import com.ardor3d.example.ExampleBase; import com.ardor3d.light.PointLight; import com.ardor3d.math.ColorRGBA; import com.ardor3d.math.MathUtils; import com.ardor3d.math.Vector3; import com.ardor3d.scenegraph.MeshData; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.Spatial; import com.ardor3d.scenegraph.controller.SpatialController; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.shape.Sphere; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.geom.BufferUtils; /** * A demonstration of randomly placed spheres being illuminated by numerious PointLight sources. */ public class ManyLightsExample2 extends ExampleBase { private final Random rand = new Random(); private Node colornode; private final double worldsize = 20; public static void main(final String[] args) { start(ManyLightsExample2.class); } @Override protected void updateExample(final ReadOnlyTimer timer) { _root.sortLights(); } /** * Create a randomly positioned light and lightsphere with a controller * * @param i * Index of the light */ void randomLight(final int i) { // Chose the color for the lights. //final ColorRGBA lightColor = ColorRGBA.randomColor(new ColorRGBA()); final ColorRGBA lightColor = new ColorRGBA(1,1,1,1); // Create a sphere to show where the light is in the demo. final Sphere lightSphere = new Sphere("lightSphere" + i, 9, 9, .1f); lightSphere.setModelBound(new BoundingSphere()); lightSphere.getSceneHints().setLightCombineMode(LightCombineMode.Off); lightSphere.setDefaultColor(lightColor); // Create a new point light and fill out the properties final PointLight pointLight = new PointLight(); pointLight.setAttenuate(true); pointLight.setConstant(.01f); //pointLight.setConstant(.1f); pointLight.setLinear(.001f); pointLight.setQuadratic(.1f); pointLight.setEnabled(true); pointLight.setDiffuse(lightColor); pointLight.setAmbient(new ColorRGBA(.1f, .1f, .1f, .1f)); //pointLight.setAmbient(new ColorRGBA(.9f, .9f, .9f, 1f)); _lightState.attach(pointLight); lightSphere.addController(new SpatialController<Spatial>() { double timeX = rand.nextDouble() * Math.PI * 8; double timeY = rand.nextDouble() * Math.PI * 8; double timeZ = rand.nextDouble() * Math.PI * 8; double speed = MathUtils.nextRandomDouble(); public void update(final double tpf, final Spatial caller) { timeX += tpf * speed; timeY += tpf * speed; timeZ += tpf * speed; final double xPos = Math.sin(timeX * 0.4) * worldsize; final double yPos = Math.cos(timeY * 0.5) * worldsize; final double zPos = Math.sin(timeZ * 0.6) * worldsize; caller.setTranslation(xPos, yPos, zPos); pointLight.setLocation(xPos, yPos, zPos); } }); // Add the light to the world part 2. colornode.attachChild(lightSphere); } /** * Create a random sphere to be affected by the light * * @param i * Index of the sphere */ void randomSphere(final int i) { // Crate a sphere and position it. final Sphere sphere = new Sphere("sphere" + i, 18, 18, MathUtils.nextRandomDouble() * 1.75 + 1.25); sphere.updateModelBound(); sphere.setTranslation(new Vector3(rand.nextDouble() * worldsize * 2 - worldsize, rand.nextDouble() * worldsize * 2 - worldsize, rand.nextDouble() * worldsize * 2 - worldsize)); Vector3 sphereCentre = sphere.getCenter(); ColorRGBA sphereColour = new ColorRGBA(1,0,0,1); MeshData meshData = sphere.getMeshData(); int numberVertices = meshData.getVertexCount(); meshData.setColorBuffer(BufferUtils.createColorBuffer(numberVertices)); meshData.setNormalBuffer(BufferUtils.createFloatBuffer(3*numberVertices)); for (int index=0; index<numberVertices; index++) { double vx = meshData.getVertexBuffer().get(3*i+0); double vy = meshData.getVertexBuffer().get(3*i+1); double vz = meshData.getVertexBuffer().get(3*i+2); Vector3 v = new Vector3(vx,vy,vz); Vector3 outwardNormal = v.subtract(sphereCentre, null); outwardNormal = outwardNormal.normalize(null); float red = sphereColour.getRed(); float green = sphereColour.getGreen(); float blue = sphereColour.getBlue(); float alpha = sphereColour.getAlpha(); meshData.getColorBuffer().put(red).put(green).put(blue).put(alpha); // note *4 indexing into buffer meshData.getNormalBuffer().put(outwardNormal.getXf()).put(outwardNormal.getYf()).put(outwardNormal.getZf()); } meshData.getColorBuffer().rewind(); _root.attachChild(sphere); } @Override protected void initExample() { _lightState.detachAll(); _lightState.setTwoSidedLighting(true); _lightState.setLocalViewer(true); rand.setSeed(1337); // Now add all the lights. colornode = new Node("LightNode"); for (int i = 0; i < 40; i++) { randomLight(i); } // Add the spheres. for (int i = 0; i < 30; i++) { randomSphere(i); } _root.attachChild(colornode); } } |
Free forum by Nabble | Edit this page |