│ ├── Cell.java
│ ├── Matrix.java
│ └── Star.java
+├── diamondsquare_demo/ - Procedural terrain generation demo
+│ ├── DiamondSquareLandscape.java
+│ └── DiamondSquareTerrain.java
├── galaxy_demo/ - Galaxy simulation demo
│ ├── Galaxy.java
│ └── PointCloudDemo.java
import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
import eu.svjatoslav.sixth.e3d.renderer.raster.lighting.LightSource;
-import eu.svjatoslav.sixth.e3d.renderer.raster.lighting.LightingManager;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.LightSourceMarker;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.solid.SolidPolygonCube;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.solid.SolidPolygonCylinder;
* Entry point for the shaded shapes demo.
* @param args command line arguments (ignored)
*/
- public static void main(String[] args) {
- ViewFrame viewFrame = new ViewFrame();
- ViewPanel viewPanel = viewFrame.getViewPanel();
- ShapeCollection shapes = viewPanel.getRootShapeCollection();
+ public static void main(final String[] args) {
+ final ViewFrame viewFrame = new ViewFrame();
+ final ViewPanel viewPanel = viewFrame.getViewPanel();
+ final ShapeCollection shapes = viewPanel.getRootShapeCollection();
- LightingManager lightingManager = new LightingManager();
- lightingManager.setAmbientLight(new Color(25, 25, 25));
+ // Use the global lighting manager from ViewPanel
+ viewPanel.getLightingManager().setAmbientLight(new Color(25, 25, 25));
- Random random = new Random(42);
- List<OrbitingLight> orbitingLights = new ArrayList<>();
+ final Random random = new Random(42);
+ final List<OrbitingLight> orbitingLights = new ArrayList<>();
for (int i = 0; i < LIGHT_COUNT; i++) {
- Color color = new Color(
+ final Color color = new Color(
random.nextInt(256),
random.nextInt(256),
random.nextInt(256)
);
- double orbitRadius = 500 + random.nextInt(200);
- double speed = 0.01 + random.nextDouble() * 0.03;
- double angleOffset = random.nextDouble() * Math.PI * 2;
- double intensity = 2.0 + random.nextDouble() * 3.0;
+ final double orbitRadius = 500 + random.nextInt(200);
+ final double speed = 0.01 + random.nextDouble() * 0.03;
+ final double angleOffset = random.nextDouble() * Math.PI * 2;
+ final double intensity = 2.0 + random.nextDouble() * 3.0;
- int axis = random.nextInt(3);
- double ellipseFactor = 0.7 + random.nextDouble() * 0.3;
+ final int axis = random.nextInt(3);
+ final double ellipseFactor = 0.7 + random.nextDouble() * 0.3;
- LightSource light = new LightSource(new Point3D(0, 0, 0), color, intensity);
- LightSourceMarker marker = new LightSourceMarker(light.getPosition(), color);
+ final LightSource light = new LightSource(new Point3D(0, 0, 0), color, intensity);
+ final LightSourceMarker marker = new LightSourceMarker(light.getPosition(), color);
- lightingManager.addLight(light);
+ viewPanel.getLightingManager().addLight(light);
shapes.addShape(marker);
orbitingLights.add(new OrbitingLight(
}
// Sphere
- SolidPolygonSphere sphere = new SolidPolygonSphere(
+ final SolidPolygonSphere sphere = new SolidPolygonSphere(
new Point3D(-400, 0, 0), 150, 28, new Color(200, 210, 255)
);
- sphere.setLightingManager(lightingManager);
+ sphere.setShadingEnabled(true);
shapes.addShape(sphere);
// Pyramid
- SolidPolygonPyramid pyramid = new SolidPolygonPyramid(
+ final SolidPolygonPyramid pyramid = new SolidPolygonPyramid(
new Point3D(0, 130, 0), 150, 260, new Color(255, 200, 200)
);
- pyramid.setLightingManager(lightingManager);
+ pyramid.setShadingEnabled(true);
shapes.addShape(pyramid);
// Cube
- SolidPolygonCube cube = new SolidPolygonCube(
+ final SolidPolygonCube cube = new SolidPolygonCube(
new Point3D(400, 0, 0), 150, new Color(200, 255, 200)
);
- cube.setLightingManager(lightingManager);
+ cube.setShadingEnabled(true);
shapes.addShape(cube);
// Cylinder
- SolidPolygonCylinder cylinder = new SolidPolygonCylinder(
+ final SolidPolygonCylinder cylinder = new SolidPolygonCylinder(
new Point3D(800, 0, 0), 120, 260, 24, new Color(255, 220, 180)
);
- cylinder.setLightingManager(lightingManager);
+ cylinder.setShadingEnabled(true);
shapes.addShape(cylinder);
// Camera
viewPanel.getCamera().getTransform().setTranslation(new Point3D(200, -250, -900));
- MultiLightAnimator animator = new MultiLightAnimator(orbitingLights);
+ final MultiLightAnimator animator = new MultiLightAnimator(orbitingLights);
viewPanel.addFrameListener(animator);
viewPanel.repaintDuringNextViewUpdate();
private static void setCameraLocation(ViewPanel viewPanel) {
Camera camera = viewPanel.getCamera();
camera.getTransform().setTranslation(new Point3D(500, -300, -800));
- camera.getTransform().getRotation().setQuaternion(Quaternion.fromAngles(0.6, -0.5));
+ camera.getTransform().getRotation().set(Quaternion.fromAngles(0.6, -0.5));
}
}
private static void setCameraLocation(ViewPanel viewPanel) {
Camera camera = viewPanel.getCamera();
camera.getTransform().setTranslation(new Point3D(500, -300, -800));
- camera.getTransform().getRotation().setQuaternion(Quaternion.fromAngles(0.6, -0.5));
+ camera.getTransform().getRotation().set(Quaternion.fromAngles(0.6, -0.5));
}
}
import java.util.List;
import java.util.Random;
+import static eu.svjatoslav.sixth.e3d.math.Transform.*;
+
/**
* Benchmark test for solid opaque cubes with dynamic lighting.
* Renders a grid of fully opaque cubes lit by three orbiting light sources
private final Random random = new Random(RANDOM_SEED);
private final List<SolidPolygonCube> cubes = new ArrayList<>();
private final List<OrbitingLight> orbitingLights = new ArrayList<>();
- private LightingManager lightingManager;
private FrameListener animator;
private ViewPanel viewPanel;
}
@Override
- public void setup(ShapeCollection shapes) {
+ public void setup(final ShapeCollection shapes) {
random.setSeed(RANDOM_SEED);
- lightingManager = new LightingManager();
- lightingManager.setAmbientLight(new Color(15, 15, 20));
-
- Color[] lightColors = {
+ // Note: lights will be added when setViewPanel is called
+ final Color[] lightColors = {
new Color(255, 100, 100),
new Color(100, 255, 100),
new Color(100, 100, 255)
};
for (int i = 0; i < 3; i++) {
- double angleOffset = i * (Math.PI * 2 / 3);
- LightSource light = new LightSource(
+ final double angleOffset = i * (Math.PI * 2 / 3);
+ final LightSource light = new LightSource(
new Point3D(0, 0, 0),
lightColors[i],
2.5
);
- lightingManager.addLight(light);
- LightSourceMarker marker = new LightSourceMarker(light.getPosition(), lightColors[i]);
+ final LightSourceMarker marker = new LightSourceMarker(light.getPosition(), lightColors[i]);
shapes.addShape(marker);
orbitingLights.add(new OrbitingLight(light, marker, 600, 0.002, angleOffset, i));
}
- double offset = -(GRID_SIZE - 1) * SPACING / 2;
+ final double offset = -(GRID_SIZE - 1) * SPACING / 2;
for (int x = 0; x < GRID_SIZE; x++) {
for (int y = 0; y < GRID_SIZE; y++) {
for (int z = 0; z < GRID_SIZE; z++) {
- double px = offset + x * SPACING;
- double py = offset + y * SPACING;
- double pz = offset + z * SPACING;
+ final double px = offset + x * SPACING;
+ final double py = offset + y * SPACING;
+ final double pz = offset + z * SPACING;
- Color color = new Color(
+ final Color color = new Color(
150 + random.nextInt(105),
150 + random.nextInt(105),
150 + random.nextInt(105)
);
- SolidPolygonCube cube = new SolidPolygonCube(
+ final SolidPolygonCube cube = new SolidPolygonCube(
new Point3D(px, py, pz),
CUBE_SIZE,
color
);
- cube.setLightingManager(lightingManager);
+ cube.setShadingEnabled(true);
shapes.addShape(cube);
cubes.add(cube);
}
}
@Override
- public void teardown(ShapeCollection shapes) {
- for (SolidPolygonCube cube : cubes) {
+ public void teardown(final ShapeCollection shapes) {
+ for (final SolidPolygonCube cube : cubes) {
shapes.getShapes().remove(cube);
}
cubes.clear();
- for (OrbitingLight ol : orbitingLights) {
+ for (final OrbitingLight ol : orbitingLights) {
shapes.getShapes().remove(ol.marker);
+ // Remove light from global lighting manager
+ if (viewPanel != null) {
+ viewPanel.getLightingManager().removeLight(ol.light);
+ }
}
orbitingLights.clear();
}
viewPanel = null;
animator = null;
- lightingManager = null;
}
/**
* Sets the view panel for animation callbacks.
* @param viewPanel the view panel
*/
- public void setViewPanel(ViewPanel viewPanel) {
+ public void setViewPanel(final ViewPanel viewPanel) {
this.viewPanel = viewPanel;
if (viewPanel != null) {
+ // Configure global lighting
+ LightingManager lightingManager = viewPanel.getLightingManager();
+ lightingManager.setAmbientLight(new Color(15, 15, 20));
+ for (final OrbitingLight ol : orbitingLights) {
+ lightingManager.addLight(ol.light);
+ }
+
animator = new LightAnimator();
viewPanel.addFrameListener(animator);
}
final int axisIndex;
double angle;
- OrbitingLight(LightSource light, LightSourceMarker marker,
- double orbitRadius, double speed, double angleOffset, int axisIndex) {
+ OrbitingLight(final LightSource light, final LightSourceMarker marker,
+ final double orbitRadius, final double speed, final double angleOffset, final int axisIndex) {
this.light = light;
this.marker = marker;
this.orbitRadius = orbitRadius;
private class LightAnimator implements FrameListener {
@Override
- public boolean onFrame(ViewPanel vp, int millisecondsSinceLastFrame) {
- for (OrbitingLight ol : orbitingLights) {
+ public boolean onFrame(final ViewPanel vp, final int millisecondsSinceLastFrame) {
+ for (final OrbitingLight ol : orbitingLights) {
ol.angle += ol.speed * millisecondsSinceLastFrame;
double x, y, z;
break;
}
- Point3D newPos = new Point3D(x, y, z);
+ final Point3D newPos = new Point3D(x, y, z);
ol.light.setPosition(newPos);
- ol.marker.setTransform(eu.svjatoslav.sixth.e3d.math.Transform.fromAngles(newPos, 0, 0));
+ ol.marker.setTransform(fromAngles(newPos, 0, 0));
}
return true;
}
--- /dev/null
+/*
+ * Sixth 3D engine demos. Author: Svjatoslav Agejenko.
+ * This project is released under Creative Commons Zero (CC0) license.
+ */
+
+package eu.svjatoslav.sixth.e3d.examples.diamondsquare_demo;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
+import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
+import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
+import eu.svjatoslav.sixth.e3d.renderer.raster.lighting.LightSource;
+import eu.svjatoslav.sixth.e3d.renderer.raster.lighting.LightingManager;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.LightSourceMarker;
+
+/**
+ * Demo showing a procedurally generated mountain landscape using the diamond-square algorithm.
+ * Three colored light sources (warm orange, cool cyan, neutral white) illuminate the terrain
+ * from above, demonstrating dynamic flat shading.
+ */
+public class DiamondSquareLandscape {
+
+ /**
+ * Entry point for the diamond-square landscape demo.
+ * @param args command line arguments (ignored)
+ */
+ public static void main(final String[] args) {
+ final ViewFrame viewFrame = new ViewFrame();
+ ViewPanel viewPanel = viewFrame.getViewPanel();
+
+ final ShapeCollection shapes = viewPanel.getRootShapeCollection();
+
+ setLights(viewFrame, shapes);
+
+ shapes.addShape(new DiamondSquareTerrain(129, 0.0, 300.0, 42));
+
+ viewPanel.getCamera().getTransform()
+ .setTranslation(new Point3D(0, -600, -800));
+
+ viewPanel.ensureRenderThreadStarted();
+ }
+
+ // TODO: add javadoc here
+ private static void setLights(ViewFrame viewFrame, ShapeCollection shapes) {
+ LightingManager lightingManager = viewFrame.getViewPanel().getLightingManager();
+ lightingManager.setAmbientLight(new Color(250, 150, 100));
+
+ final LightSource warmLight = new LightSource(
+ new Point3D(-400, -500, 0),
+ new Color(255, 180, 100),
+ 190.0
+ );
+ final LightSource coolLight = new LightSource(
+ new Point3D(400, -500, 0),
+ new Color(100, 200, 255),
+ 220.0
+ );
+ final LightSource neutralLight = new LightSource(
+ new Point3D(0, -600, 300),
+ new Color(255, 255, 255),
+ 250.0
+ );
+
+ lightingManager.addLight(warmLight);
+ lightingManager.addLight(coolLight);
+ lightingManager.addLight(neutralLight);
+
+ shapes.addShape(new LightSourceMarker(warmLight.getPosition(), new Color(255, 180, 100)));
+ shapes.addShape(new LightSourceMarker(coolLight.getPosition(), new Color(100, 200, 255)));
+ shapes.addShape(new LightSourceMarker(neutralLight.getPosition(), new Color(255, 255, 255)));
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Sixth 3D engine demos. Author: Svjatoslav Agejenko.
+ * This project is released under Creative Commons Zero (CC0) license.
+ */
+
+package eu.svjatoslav.sixth.e3d.examples.diamondsquare_demo;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.math.DiamondSquare;
+import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.solidpolygon.SolidPolygon;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape;
+
+/**
+ * A procedurally generated terrain mesh using the diamond-square algorithm.
+ * Creates a grid of triangular polygons with height variation for mountains.
+ */
+public class DiamondSquareTerrain extends AbstractCompositeShape {
+
+ private static final double TERRAIN_SIZE = 800.0;
+
+ /**
+ * Creates a diamond-square terrain with the specified parameters.
+ *
+ * @param gridSize the size of the heightmap grid (must be 2^n + 1)
+ * @param minHeight the minimum terrain height
+ * @param maxHeight the maximum terrain height
+ * @param seed random seed for reproducible terrain
+ */
+ public DiamondSquareTerrain(final int gridSize, final double minHeight, final double maxHeight, final long seed) {
+ super();
+
+ final double[][] heightmap = DiamondSquare.generateMap(gridSize, minHeight, maxHeight, seed);
+ createPolygons(gridSize, heightmap);
+ setBackfaceCulling(true);
+ }
+
+ /**
+ * Creates triangular polygons from the heightmap.
+ */
+ private void createPolygons(final int gridSize, final double[][] heightmap) {
+ final double cellSize = TERRAIN_SIZE / (gridSize - 1);
+ final double offsetX = -TERRAIN_SIZE / 2;
+ final double offsetZ = -TERRAIN_SIZE / 2;
+
+ for (int z = 0; z < gridSize - 1; z++) {
+ for (int x = 0; x < gridSize - 1; x++) {
+ final double x0 = offsetX + x * cellSize;
+ final double x1 = offsetX + (x + 1) * cellSize;
+ final double z0 = offsetZ + z * cellSize;
+ final double z1 = offsetZ + (z + 1) * cellSize;
+
+ final double y00 = heightmap[z][x];
+ final double y10 = heightmap[z][x + 1];
+ final double y01 = heightmap[z + 1][x];
+ final double y11 = heightmap[z + 1][x + 1];
+
+ final Color color = new Color(10, 10, 10);
+
+ final Point3D p00 = new Point3D(x0, y00, z0);
+ final Point3D p10 = new Point3D(x1, y10, z0);
+ final Point3D p01 = new Point3D(x0, y01, z1);
+ final Point3D p11 = new Point3D(x1, y11, z1);
+
+ final SolidPolygon tri1 = new SolidPolygon(p00, p10, p01, color);
+ final SolidPolygon tri2 = new SolidPolygon(p10, p11, p01, color);
+
+ tri1.setShadingEnabled(true);
+ tri2.setShadingEnabled(true);
+
+ addShape(tri1);
+ addShape(tri2);
+ }
+ }
+ }
+}
\ No newline at end of file
package eu.svjatoslav.sixth.e3d.examples.launcher;
+import eu.svjatoslav.sixth.e3d.examples.diamondsquare_demo.DiamondSquareLandscape;
import eu.svjatoslav.sixth.e3d.examples.SineHeightmap;
import eu.svjatoslav.sixth.e3d.examples.graph_demo.MathGraphsDemo;
import eu.svjatoslav.sixth.e3d.examples.MinimalExample;
new DemoEntry("Shaded Shapes",
"Shapes lit by orbiting colored light sources",
new ShowShadedShapes()),
+ new DemoEntry("Diamond-Square Landscape",
+ "Procedural mountains with 3 colored light sources",
+ new ShowDiamondSquareLandscape()),
new DemoEntry("Graphics Benchmark",
"Automated performance measuring FPS across modes",
new ShowGraphicsBenchmark()),
}
}
+ private static class ShowDiamondSquareLandscape extends AbstractAction {
+ ShowDiamondSquareLandscape() {
+ putValue(NAME, "Diamond-Square Landscape");
+ }
+
+ @Override
+ public void actionPerformed(final ActionEvent e) {
+ DiamondSquareLandscape.main(null);
+ }
+ }
+
private static class ShowGraphicsBenchmark extends AbstractAction {
ShowGraphicsBenchmark() {
putValue(NAME, "Graphics Benchmark");
*/
private void setCameraOrientation(final Camera camera) {
camera.getTransform().setTranslation(new Point3D(100, -50, -200));
- camera.getTransform().getRotation().setQuaternion(Quaternion.fromAngles(0.2f, -0.7f));
+ camera.getTransform().getRotation().set(Quaternion.fromAngles(0.2f, -0.7f));
}
}