To start the demo application, use command:
: java -jar sixth-3d-demos.jar
-* Navigating in space
+* Essentials
+
+*Resources to help you understand the Sixth 3D library:*
+- Read online [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/][JavaDoc]].
+- See [[https://www3.svjatoslav.eu/projects/sixth-3d/graphs/][Sixth 3D class diagrams]]. (Diagrams were generated by using
+ [[https://www3.svjatoslav.eu/projects/javainspect/][JavaInspect]] utility)
+
+** Minimal example
:PROPERTIES:
-:CUSTOM_ID: navigating-in-space
-:ID: 0aca7419-48df-48ac-b18b-a8bf7b9db0ac
+:CUSTOM_ID: minimal-example
+:ID: 1a2b3c4d-5e6f-7890-abcd-ef1234567890
:END:
-| key | result |
-|---------------------+--------------------------------------|
-| Keyboard arrow keys | Move: left, right, forward, backward |
-| Mouse scroll wheel | Move: up <-> down |
-| Mouse drag | Turn head around in 3D space |
+This is the "Hello World" of *Sixth 3D* - the minimal boilerplate
+needed to render any 3D geometry.
+
+: eu.svjatoslav.sixth.e3d.examples.essentials.MinimalExample
+
+*Brief tutorial:*
+
+Here we guide you through creating your first 3D scene with Sixth 3D
+engine.
+
+Prerequisites:
+- Java 21 or later installed
+- Maven 3.x
+- Basic Java knowledge
-* Example scenes
+*** Add Dependency to Your Project
:PROPERTIES:
-:CUSTOM_ID: example-scenes
-:ID: 5f88b493-6ab3-4659-8280-803f75dbd5e0
+:CUSTOM_ID: add-dependency-to-your-project
+:ID: 3fffc32e-ae66-40b7-ad7d-fab6093c778b
+:END:
+
+Add *Sixth 3D* to your pom.xml:
+
+#+BEGIN_SRC xml
+<dependencies>
+ <dependency>
+ <groupId>eu.svjatoslav</groupId>
+ <artifactId>sixth-3d</artifactId>
+ <version>1.4-SNAPSHOT</version>
+ </dependency>
+</dependencies>
+
+<repositories>
+ <repository>
+ <id>svjatoslav.eu</id>
+ <name>Svjatoslav repository</name>
+ <url>https://www3.svjatoslav.eu/maven/</url>
+ </repository>
+</repositories>
+#+END_SRC
+
+
+*** Create Your First 3D Scene
+:PROPERTIES:
+:CUSTOM_ID: create-your-first-3d-scene
+:ID: 564fa596-9b2b-418a-9df9-baa46f0d0a66
:END:
+
+#+BEGIN_SRC java
+ import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
+ import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
+ import eu.svjatoslav.sixth.e3d.math.Transform;
+ import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+ import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
+ import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.solid.SolidPolygonRectangularBox;
+
+ public class MyFirstScene {
+ public static void main(String[] args) {
+ // Create the application window
+ ViewFrame viewFrame = new ViewFrame("My First Scene");
+
+ // Get the collection where you add 3D shapes
+ ShapeCollection shapes = viewFrame.getViewPanel().getRootShapeCollection();
+
+ // Create a red box centered at origin
+ final Transform boxTransform = new Transform();
+ SolidPolygonRectangularBox box = new SolidPolygonRectangularBox(
+ point(-50, -50, -50),
+ point(50, 50, 50),
+ Color.RED
+ );
+ box.setTransform(boxTransform);
+ shapes.addShape(box);
+
+ // Position your camera
+ viewFrame.getViewPanel().getCamera().getTransform()
+ .setTranslation(point(0, -100, -300));
+
+ // Trigger initial render
+ viewFrame.getViewPanel().repaintDuringNextViewUpdate();
+ }
+ }
+#+END_SRC
+
+Compile and run *MyFirstScene* class. A new window should open that will
+display 3D scene with red box.
+
+
+You should see this:
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Screenshots/Essentials/Minimal example.png]]
+
+
+*Navigating the scene:*
+
+| Input | Action |
+|--------------------+-----------------------------|
+| Arrow Up | Move forward |
+| Arrow Down | Move backward |
+| Arrow Left | Move left (strafe) |
+| Arrow Right | Move right (strafe) |
+| Mouse drag | Look around (rotate camera) |
+| Mouse scroll wheel | Move up / down |
+
+Movement uses physics-based acceleration for smooth, natural
+motion. The faster you're moving, the more acceleration builds up,
+creating an intuitive flying experience.
+
Press *F12* in any demo to open the [[https://www3.svjatoslav.eu/projects/sixth-3d/#outline-container-developer-tools][Developer Tools panel]]. This
debugging interface provides real-time insight into the rendering
pipeline with diagnostic toggles.
+** Coordinate system
+:PROPERTIES:
+:CUSTOM_ID: coordinate-system
+:ID: 2b3c4d5e-6f7a-8901-bcde-f12345678901
+:END:
+
+: eu.svjatoslav.sixth.e3d.examples.essentials.CoordinateSystemDemo
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Screenshots/Essentials/Coordinate system.png]]
+
+Visual reference for the Sixth 3D coordinate system using three colored
+arrows originating from (0,0,0):
+
+| Axis | Color | Direction |
+|------+-------+------------------------------------|
+| X | Red | Points RIGHT (positive X) |
+| Y | Green | Points DOWN (positive Y) |
+| Z | Blue | Points AWAY from viewer (positive Z) |
+
+A wireframe grid on the Y=0 plane provides spatial context and scale. Text
+labels (X, Y, Z) appear at each arrow tip.
+
+This demo is essential for understanding Sixth 3D's coordinate system where:
+- Positive Y goes down (screen coordinates convention)
+- Positive Z goes into the screen (away from camera)
+- Positive X goes to the right
+
+See the [[https://www3.svjatoslav.eu/projects/sixth-3d/#coordinate-system][Coordinate System]] section in the Sixth 3D documentation
+for a detailed explanation of the axis conventions and coordinate math.
+
+** Winding order
+:PROPERTIES:
+:CUSTOM_ID: winding-order
+:ID: 3c4d5e6f-7a8b-9012-cdef-123456789012
+:END:
+
+: eu.svjatoslav.sixth.e3d.examples.essentials.WindingOrderDemo
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Screenshots/Essentials/Winding order.png]]
+
+This demo demonstrates polygon winding order and backface culling - fundamental
+concepts for efficient 3D rendering.
+
+The green triangle uses counter-clockwise (CCW) vertex ordering:
+1. Upper-center vertex
+2. Lower-left vertex
+3. Lower-right vertex
+
+With backface culling enabled:
+- *CCW winding* (negative signed area) = front-facing = visible
+- *CW winding* (positive signed area) = back-facing = culled (not rendered)
+
+This optimization prevents rendering polygons facing away from the camera,
+improving performance by roughly 50% for closed meshes. Navigate around the
+scene and observe that the triangle becomes invisible when viewed from behind,
+demonstrating the culling effect.
+
+See the [[https://www3.svjatoslav.eu/projects/sixth-3d/#winding-order-backface-culling][Winding Order & Backface Culling]] section
+in the Sixth 3D documentation for a detailed explanation with diagrams.
+
+** Shape gallery
+:PROPERTIES:
+:CUSTOM_ID: shape-gallery
+:ID: 4d5e6f7a-8b9c-0123-def0-234567890123
+:END:
+
+: eu.svjatoslav.sixth.e3d.examples.essentials.ShapeGalleryDemo
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Screenshots/Essentials/Shape gallery.png]]
+
+Comprehensive showcase of all primitive 3D shapes available in Sixth 3D,
+organized in a 7×2 grid:
+
+| Column | Shape Type | Description |
+|--------+------------+--------------------------------|
+| 1 | Arrow | 3D arrow with conical tip |
+| 2 | Cone | Circular base cone |
+| 3 | Cube | Regular hexahedron |
+| 4 | Cylinder | Tube with circular caps |
+| 5 | Pyramid | Square base pyramid |
+| 6 | Box | Rectangular parallelepiped |
+| 7 | Sphere | Geodesic sphere approximation |
+
+*Top row:* Wireframe versions - edges only, no surfaces
+*Bottom row:* Solid polygon versions - filled surfaces with lighting
+
+Additional features demonstrated:
+- Dynamic lighting from 10 orbiting colored light sources (visible as small
+ glowing dots)
+- Per-shape color assignment for visual distinction
+- Grid floor showing spatial layout and alignment
+- Text labels identifying each shape type
+- Shading enabled on solid shapes to show lighting effects
+
+See the [[https://www3.svjatoslav.eu/projects/sixth-3d/#mesh][Mesh]] section in the Sixth 3D documentation
+for an explanation of 3D mesh fundamentals and how shapes are constructed.
+
+** CSG demo
+:PROPERTIES:
+:CUSTOM_ID: csg-demo
+:ID: 5e6f7a8b-9c0d-1234-ef01-345678901234
+:END:
+
+: eu.svjatoslav.sixth.e3d.examples.essentials.CSGDemo
+
+#+attr_html: :class responsive-img
+#+attr_latex: :width 1000px
+[[file:Screenshots/Essentials/CSG demo.png]]
+
+Constructive Solid Geometry (CSG) boolean operations on 3D meshes. Three
+operations displayed left to right:
+
+1. *Subtract (Cube - Sphere)* - A red cube with a spherical cavity carved out
+ where a blue sphere intersects it. Shows the cube's interior surfaces.
+
+2. *Union (Cube + Sphere)* - A merged shape combining both volumes. Red
+ surfaces from the cube, blue surfaces from the sphere, seamlessly joined.
+
+3. *Intersect (Cube ∩ Sphere)* - Only the volume shared by both shapes
+ remains. Shows which parts of space were occupied by both the cube and
+ sphere simultaneously.
+
+Color scheme:
+- *Red* = geometry from the first operand (cube)
+- *Blue* = geometry from the second operand (sphere)
+
+Each operation includes a text description panel below the shape. The demo
+uses:
+- SolidPolygonCube (red)
+- SolidPolygonSphere (blue)
+- CSGSolid.subtract(), union(), intersect() methods
+- toMesh() conversion for rendering
+- Backface culling and shading enabled
+
+CSG is powerful for procedural modeling, allowing complex shapes to be built
+from simple primitives through boolean combinations.
+
+* Advanced examples
+:PROPERTIES:
+:CUSTOM_ID: example-scenes
+:ID: 5f88b493-6ab3-4659-8280-803f75dbd5e0
+:END:
+
+
** Conway's Game of Life
:PROPERTIES:
:CUSTOM_ID: conways-game-of-life
:ID: 08914390-742b-4c78-88bf-602ab9640082
:END:
+: eu.svjatoslav.sixth.e3d.examples.life_demo.Main
+
The Game of Life, also known simply as Life, is a cellular automaton
devised by the British mathematician John Horton Conway in 1970.
[[file:Screenshots/Life.png]]
-Current application projects 2D game grid/matrix onto three
-dimensional space. Extra dimension (height) is used to visualize
-history (previous iterations) using glowing dots suspended in space.
+This demo projects the 2D game grid onto three-dimensional space. The extra
+dimension (height) visualizes history (previous iterations) using glowing dots
+suspended in space.
Usage:
| key | result |
:ID: 39250157-db8e-4861-a21b-8568912bd160
:END:
+: eu.svjatoslav.sixth.e3d.examples.TextEditorDemo
+
[[file:Screenshots/Text editors.png]]
-Initial test for creating user interfaces in 3D and:
+Initial test for creating user interfaces in 3D, demonstrating:
+ window focus handling
-+ picking objects using mouse
-+ redirecting keyboard input to focused window
-
++ picking objects using the mouse
++ redirecting keyboard input to the focused window
Window focus acts like a stack.
-When window is clicked with the mouse, previously focused window (if
-any) is pushed to the focus stack and new window receives focus. Red
+When a window is clicked with the mouse, the previously focused window (if
+any) is pushed to the focus stack and the new window receives focus. A red
frame appears around the window to indicate this.
-When ESC key is pressed, window focus is returned to previous window
-(if any).
+When the ESC key is pressed, focus is returned to the previous window (if any).
-When any window is focused, all keyboard input is redirected to that
-window, including cursor keys. To be able to navigate around the world
-again, window must be unfocused first using ESC key.
+When any window is focused, all keyboard input is redirected to that window,
+including cursor keys. To navigate around the world again, the window must be
+unfocused first by pressing the ESC key.
+ TODO:
:ID: a7b8c9d0-e1f2-3456-0123-567890123456
:END:
+: eu.svjatoslav.sixth.e3d.examples.TextEditorDemo2
+
*Quite a lot of text editors can be rendered:*
[[file:Screenshots/Text editors 2.png]]
-See also [[https://hackers-1995.vercel.app/][similar looking web based demo]] ! :)
+See also this [[https://hackers-1995.vercel.app/][similar-looking web-based demo]]!
** Math graphs demo
:PROPERTIES:
:ID: b1c2d3e4-f5a6-7890-bcde-f12345678901
:END:
+: eu.svjatoslav.sixth.e3d.examples.graph_demo.MathGraphsDemo
+
[[file:Screenshots/Mathematical formulas.png]]
+ TODO: instead of projecting 2D visualizations onto 3D space,
:ID: b2c3d4e5-f6a7-8901-bcde-f12345678901
:END:
+: eu.svjatoslav.sixth.e3d.examples.SineHeightmap
+
[[file:Screenshots/Sine heightmap and sphere.png]]
Simple test scene. Easy to implement and looks nice.
:ID: c3d4e5f6-a7b8-9012-cdef-123456789012
:END:
+: eu.svjatoslav.sixth.e3d.examples.OctreeDemo
+
[[file:Screenshots/Raytracing fractal in voxel polygon hybrid scene.png]]
Test scene that is generated simultaneously using:
+ voxels
+ for on-demand raytracing
-Instead of storing voxels in dumb [X * Y * Z] array, dynamically
-partitioned [[https://en.wikipedia.org/wiki/Octree][octree]] is used to compress data. Press "r" key anywhere in
-the scene to raytrace current view through compressed voxel
+Instead of storing voxels in a naive [X × Y × Z] array, a dynamically
+partitioned [[https://en.wikipedia.org/wiki/Octree][octree]] compresses the data. Press the "r" key anywhere in
+the scene to raytrace the current view through the compressed voxel
data structure.
-** Graphics Benchmark
+* Graphics Benchmark
:PROPERTIES:
:CUSTOM_ID: graphics-benchmark
:ID: e5f6a7b8-c9d0-1234-ef01-345678901234
:END:
+: eu.svjatoslav.sixth.e3d.examples.benchmark.GraphicsBenchmark
+
An automated graphics benchmark that measures the engine's rendering
performance across different rendering modes.
[[file:Screenshots/Benchmark.png]]
-The benchmark will cycle through different scenes that utilize different
-rendering primitives (textured polygons, billboards, solid polygons,
-etc.) to measure their relative performance.
+The benchmark cycles through scenes that utilize different rendering
+primitives (textured polygons, billboards, solid polygons, etc.) to measure
+their relative performance.
The camera follows a deterministic orbital path around the scene,
ensuring reproducible results across runs.
-At the end, the benchmark will output a report that is easy to preserve for
-later comparisons.
+Upon completion, the benchmark outputs a report suitable for preservation
+and later comparisons.
Example benchmark report:
#+begin_example
:ID: d4e5f6a7-b8c9-0123-def0-234567890123
:END:
-*This program is free software: released under Creative Commons Zero
-(CC0) license*
+*This program is free software, released under the Creative Commons Zero
+(CC0) license.*
*Program author:*
- Svjatoslav Agejenko
: git clone https://www2.svjatoslav.eu/git/sixth-3d-demos.git
*Understanding the Sixth 3D demos source code:*
-- Read online [[https://www3.svjatoslav.eu/projects/sixth-3d-demos/apidocs/][JavaDoc]].
-- Study underlying [[https://www3.svjatoslav.eu/projects/sixth-3d/][Sixth 3D]] engine.
+- Read the online [[https://www3.svjatoslav.eu/projects/sixth-3d-demos/apidocs/][JavaDoc]].
+- Study the underlying [[https://www3.svjatoslav.eu/projects/sixth-3d/][Sixth 3D]] engine.
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.solid.SolidPolygonCone;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.wireframe.Grid3D;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
+import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.hex;
+
/**
* Demo showcasing the SolidPolygonArrow shape with various colors, sizes,
* orientations, and transparency levels.
final ShapeCollection shapes = viewPanel.getRootShapeCollection();
// Position camera to view the scene
- viewPanel.getCamera().getTransform().setTranslation(new Point3D(0, -200, -600));
+ viewPanel.getCamera().getTransform().setTranslation(point(0, -200, -600));
// Add a 3D grid for spatial reference
- final LineAppearance gridAppearance = new LineAppearance(1, new Color(100, 100, 100, 80));
+ final LineAppearance gridAppearance = new LineAppearance(1, hex("64646450"));
final Grid3D grid = new Grid3D(
- new Point3D(-300, -200, -300),
- new Point3D(300, 200, 300),
+ point(-300, -200, -300),
+ point(300, 200, 300),
100,
gridAppearance
);
// Red arrow pointing up (negative Y direction)
final SolidPolygonArrow redArrow = new SolidPolygonArrow(
- new Point3D(0, 150, 0),
- new Point3D(0, -150, 0),
+ point(0, 150, 0),
+ point(0, -150, 0),
8, Color.RED
);
shapes.addShape(redArrow);
// Green arrow pointing along positive X
final SolidPolygonArrow greenArrow = new SolidPolygonArrow(
- new Point3D(-200, 0, 0),
- new Point3D(0, 0, 0),
+ point(-200, 0, 0),
+ point(0, 0, 0),
6, Color.GREEN
);
shapes.addShape(greenArrow);
// Blue arrow pointing along positive Z
final SolidPolygonArrow blueArrow = new SolidPolygonArrow(
- new Point3D(0, 0, -200),
- new Point3D(0, 0, 0),
+ point(0, 0, -200),
+ point(0, 0, 0),
6, Color.BLUE
);
shapes.addShape(blueArrow);
// Yellow arrow pointing diagonally
final SolidPolygonArrow yellowArrow = new SolidPolygonArrow(
- new Point3D(100, 100, 100),
- new Point3D(300, -100, 300),
+ point(100, 100, 100),
+ point(300, -100, 300),
10, Color.YELLOW
);
shapes.addShape(yellowArrow);
// Semi-transparent cyan arrow (50% opacity)
final SolidPolygonArrow transparentCyanArrow = new SolidPolygonArrow(
- new Point3D(-150, 50, -100),
- new Point3D(-50, -100, 100),
- 8, new Color(0, 255, 255, 128)
+ point(-150, 50, -100),
+ point(-50, -100, 100),
+ 8, hex("00FFFF80")
);
shapes.addShape(transparentCyanArrow);
// Semi-transparent magenta arrow (25% opacity)
final SolidPolygonArrow transparentMagentaArrow = new SolidPolygonArrow(
- new Point3D(50, 200, 50),
- new Point3D(50, 0, 50),
- 12, new Color(255, 0, 255, 64)
+ point(50, 200, 50),
+ point(50, 0, 50),
+ 12, hex("FF00FF40")
);
shapes.addShape(transparentMagentaArrow);
final double endX = (radius + 80) * Math.cos(angle);
final double endZ = (radius + 80) * Math.sin(angle);
-final SolidPolygonArrow circleArrow = new SolidPolygonArrow(
- new Point3D(startX, -80, startZ),
- new Point3D(endX, -80, endZ),
- 4, Color.WHITE
- );
+ final SolidPolygonArrow circleArrow = new SolidPolygonArrow(
+ point(startX, -80, startZ),
+ point(endX, -80, endZ),
+ 4, Color.WHITE
+ );
shapes.addShape(circleArrow);
}
// A standalone cone to demonstrate SolidPolygonCone
final SolidPolygonCone standaloneCone = new SolidPolygonCone(
- new Point3D(-300, 0, 0),
+ point(-300, 0, 0),
40,
80,
16,
- new Color(255, 128, 0)
+ hex("FF8000FF")
);
shapes.addShape(standaloneCone);
import java.awt.event.KeyEvent;
import java.util.Vector;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
+import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.hex;
+
/**
* Demo showing volumetric octree rendering with raytracing capability.
* Creates a 3D scene with various geometric shapes stored in an octree data structure.
* Scale factor for rendering octree voxels in the scene.
*/
private static final double magnification = 5;
- private final LineAppearance gridAppearance = new LineAppearance(40, new Color(255,
- 0, 0, 60));
+ private final LineAppearance gridAppearance = new LineAppearance(40, hex("FF00003C"));
private final Vector<eu.svjatoslav.sixth.e3d.renderer.octree.raytracer.LightSource> lights = new Vector<>();
private OctreeVolume octreeVolume;
private ShapeCollection shapeCollection;
private ViewPanel viewPanel;
+
/**
* Creates a new OctreeDemo instance.
*/
private void addLightToBothSystems(final Point3D location, final Color color,
final float brightness) {
shapeCollection.addShape(new LightSourceMarker(new Point3D(location)
- .scaleUp(magnification), color));
+ .multiply(magnification), color));
lights.add(new eu.svjatoslav.sixth.e3d.renderer.octree.raytracer.LightSource(
location, color, brightness));
viewPanel.getLightingManager().addLight(new LightSource(
- new Point3D(location).scaleUp(magnification), color, brightness * 50));
+ new Point3D(location).multiply(magnification), color, brightness * 50));
}
/**
shapeCollection = viewPanel.getRootShapeCollection();
shapeCollection.addShape(new Grid3D(
- new Point3D(-10000, -10000, -10000), new Point3D(10000, 10000,
+ point(-10000, -10000, -10000), point(10000, 10000,
10000), 4000, gridAppearance));
- addLightToBothSystems(new Point3D(20, -450, 240), new Color(255, 255, 255), 100);
- addLightToBothSystems(new Point3D(-150, -116, 141), new Color(255, 0, 0), 10);
+ addLightToBothSystems(point(20, -450, 240), new Color(255, 255, 255), 100);
+ addLightToBothSystems(point(-150, -116, 141), new Color(255, 0, 0), 10);
dotSpiral();
// arbitrary rectangles
putRect(new IntegerPoint(-10, -10, -10),
new IntegerPoint(10, 10, -20),
- new Color(200, 255, 200, 100));
+ hex("C8FFC864"));
putRect(new IntegerPoint(-3, 0, -30),
new IntegerPoint(12, 3, 300),
- new Color(255, 200, 200, 100));
+ hex("FFC8C864"));
putRect(new IntegerPoint(-20, 20, -20),
new IntegerPoint(20, 80, 20),
- new Color(255, 200, 255, 100));
+ hex("FFC8FF64"));
tiledFloor();
fractal(-50, 20, 100, 32, 1);
- final TextCanvas message = new TextCanvas(new Transform(new Point3D(
+ final TextCanvas message = new TextCanvas(new Transform(point(
-10, 20, -180)), "Press \"r\" to raytrace current view",
Color.WHITE, Color.PURPLE);
shapeCollection.addShape(message);
*/
private void putPixel(final int x, final int y, final int z,
final Color color) {
- shapeCollection.addShape(new GlowingPoint(new Point3D(x, y, z)
- .scaleUp(magnification), 3 * magnification, color));
+ shapeCollection.addShape(new GlowingPoint(point(x, y, z)
+ .multiply(magnification), 3 * magnification, color));
octreeVolume.putCell(x, y, z, color);
}
*/
private void putRect(IntegerPoint p1, IntegerPoint p2, final Color color) {
final SolidPolygonRectangularBox box = new SolidPolygonRectangularBox(
- new Point3D(p1).scaleUp(magnification),
- new Point3D(p2).scaleUp(magnification), color);
+ new Point3D(p1).multiply(magnification),
+ new Point3D(p2).multiply(magnification), color);
box.setShadingEnabled(true);
shapeCollection.addShape(box);
octreeVolume.fillRectangle(p1, p2, color);
private void tiledFloor() {
final int step = 40;
final int size = step - 15;
- Color color = new Color(255, 255, 255, 100);
+ Color color = hex("FFFFFF64");
for (int x = -200; x < 200; x += step)
for (int z = -200; z < 200; z += step)
putRect(
import eu.svjatoslav.sixth.e3d.gui.FrameListener;
import eu.svjatoslav.sixth.e3d.math.Transform;
import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractShape;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.textcanvas.TextCanvas;
Random random = new Random();
for (int i = 0; i < NUMBERS_COUNT; i++) {
- final Point3D location = new Point3D((Math.random() * AREA)
+ final Point3D location = point((Math.random() * AREA)
- AREA_HALF, (Math.random() * AREA) - AREA_HALF,
(Math.random() * AREA) - AREA_HALF);
/*
- * Sixth 3D engine demos. Author: Svjatoslav Agejenko.
+ * Sixth 3D engine demos. Author: Svjatoslav Agejenko.
* This project is released under Creative Commons Zero (CC0) license.
*
*/
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.solidpolygon.SolidPolygon;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.wireframe.WireframeSphere;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.origin;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
+import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.hex;
+
/**
* Demo showing a sine heightmap surface with a central wireframe sphere.
* Two wobbly surfaces are positioned above and below the sphere.
*/
public class SineHeightmap {
+ /**
+ * Frequency of the wave pattern in the wobbly surfaces.
+ */
+ private static final double WAVE_FREQUENCY = 50d;
+ /**
+ * Amplitude of the wave pattern in the wobbly surfaces.
+ */
+ private static final double WAVE_AMPLITUDE = 50d;
+ /**
+ * Color for the square plates in the wobbly surfaces.
+ */
+ private static final Color SQUARE_PLATE_COLOR = hex("88F7");
/**
* Creates a new GraphDemo instance.
*/
public SineHeightmap() {
}
- /** Frequency of the wave pattern in the wobbly surfaces. */
- private static final double WAVE_FREQUENCY = 50d;
- /** Amplitude of the wave pattern in the wobbly surfaces. */
- private static final double WAVE_AMPLITUDE = 50d;
- /** Color for the square plates in the wobbly surfaces. */
- private static final Color SQUARE_PLATE_COLOR = new Color("88F7");
- /** Scale factor for the graph rendering. */
- private static final double GRAPH_SCALE = 50d;
-
/**
* Creates a single square plate at the specified position.
+ *
* @param shapeCollection the collection to add the plate to
- * @param y the Y coordinate (elevation)
- * @param x the X coordinate
- * @param z the Z coordinate
+ * @param y the Y coordinate (elevation)
+ * @param x the X coordinate
+ * @param z the Z coordinate
*/
private static void makeSquarePlate(final ShapeCollection shapeCollection,
final double y, final double x, final double z) {
- final Point3D p1 = new Point3D(x, y, z);
- final Point3D p2 = new Point3D(x + 20, y, z);
- final Point3D p3 = new Point3D(x, y, z + 20);
- final Point3D p4 = new Point3D(x + 20, y, z + 20);
- final SolidPolygon polygon1 = new SolidPolygon(p1, p2, p3, SQUARE_PLATE_COLOR);
- final SolidPolygon polygon2 = new SolidPolygon(p4, p2, p3, SQUARE_PLATE_COLOR);
- shapeCollection.addShape(polygon1);
- shapeCollection.addShape(polygon2);
+ final Point3D p1 = point(x, y, z);
+ final Point3D p2 = point(x + 20, y, z);
+ final Point3D p3 = point(x, y, z + 20);
+ final Point3D p4 = point(x + 20, y, z + 20);
+ final SolidPolygon quad = SolidPolygon.quad(p1, p2, p4, p3, SQUARE_PLATE_COLOR);
+ shapeCollection.addShape(quad);
}
/**
* Creates a wobbly surface composed of square plates arranged in a wave pattern.
- * @param shapeCollection the collection to add plates to
+ *
+ * @param shapeCollection the collection to add plates to
* @param surfaceElevation the base Y elevation of the surface
*/
private static void addWobblySurface(final ShapeCollection shapeCollection,
/**
* Entry point for the graph demo.
+ *
* @param args command line arguments (ignored)
*/
public static void main(final String[] args) {
final ShapeCollection geometryCollection = viewFrame.getViewPanel()
.getRootShapeCollection();
- viewFrame.getViewPanel().getCamera().getTransform().setTranslation(new Point3D(0, 0, -500));
+ viewFrame.getViewPanel().getCamera().getTransform().setTranslation(point(0, 0, -500));
addSphere(geometryCollection);
addWobblySurface(geometryCollection, 200);
addWobblySurface(geometryCollection, -200);
-
+
viewFrame.getViewPanel().repaintDuringNextViewUpdate();
}
/**
* Adds a wireframe sphere at the center of the scene.
+ *
* @param geometryCollection the collection to add the sphere to
*/
private static void addSphere(ShapeCollection geometryCollection) {
- geometryCollection.addShape(new WireframeSphere(new Point3D(0, 0, 0),
+ geometryCollection.addShape(new WireframeSphere(origin(),
100,
new LineAppearance(
4,
- new Color(255,0, 0, 30))
+ hex("FF00001E"))
));
}
/*
- * Sixth 3D engine demos. Author: Svjatoslav Agejenko.
+ * Sixth 3D engine demos. Author: Svjatoslav Agejenko.
* This project is released under Creative Commons Zero (CC0) license.
*
-*/
+ */
package eu.svjatoslav.sixth.e3d.examples;
import eu.svjatoslav.sixth.e3d.geometry.Point2D;
-import eu.svjatoslav.sixth.e3d.geometry.Point3D;
import eu.svjatoslav.sixth.e3d.geometry.Rectangle;
import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
import eu.svjatoslav.sixth.e3d.gui.textEditorComponent.LookAndFeel;
import eu.svjatoslav.sixth.e3d.gui.textEditorComponent.TextEditComponent;
import eu.svjatoslav.sixth.e3d.math.Transform;
-import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.line.LineAppearance;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.wireframe.Grid2D;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
+import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.hex;
+
/**
* Demo showing a grid of 3D text editor components.
* Creates a 5x5 grid of text editors floating in 3D space with a decorative grid
/**
* Entry point for the text editor demo.
+ *
* @param args command line arguments (ignored)
*/
public static void main(final String[] args) {
addGrid(shapeCollection);
addTextEditors(viewPanel, shapeCollection);
-
+
viewFrame.getViewPanel().repaintDuringNextViewUpdate();
}
/**
* Adds a decorative grid below the text editors.
+ *
* @param shapeCollection the collection to add the grid to
*/
private static void addGrid(ShapeCollection shapeCollection) {
final Transform transform = Transform.fromAngles(0, 100, 0, 0, Math.PI / 2, 0);
final Rectangle rectangle = new Rectangle(2000);
- final LineAppearance appearance = new LineAppearance(10, new Color(
- "00b3ad"));
+ final LineAppearance appearance = new LineAppearance(10, hex("00b3ad"));
shapeCollection.addShape(new Grid2D(transform, rectangle, 10, 10, appearance));
}
/**
* Creates a grid of text editor components arranged in 3D space.
- * @param viewPanel the view panel for the text editors
+ *
+ * @param viewPanel the view panel for the text editors
* @param shapeCollection the collection to add editors to
*/
private static void addTextEditors(ViewPanel viewPanel, ShapeCollection shapeCollection) {
for (double x = -500 * m; x <= (500 * m); x += 250 * m) {
final TextEditComponent textEditor = new TextEditComponent(
- new Transform(new Point3D(x, 0, z)), viewPanel,
+ new Transform(point(x, 0, z)), viewPanel,
new Point2D(200, 120), new LookAndFeel());
shapeCollection.addShape(textEditor);
/*
- * Sixth 3D engine demos. Author: Svjatoslav Agejenko.
+ * Sixth 3D engine demos. Author: Svjatoslav Agejenko.
* This project is released under Creative Commons Zero (CC0) license.
*
-*/
+ */
package eu.svjatoslav.sixth.e3d.examples;
import eu.svjatoslav.sixth.e3d.geometry.Point2D;
-import eu.svjatoslav.sixth.e3d.geometry.Point3D;
import eu.svjatoslav.sixth.e3d.geometry.Rectangle;
import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
import eu.svjatoslav.sixth.e3d.gui.textEditorComponent.LookAndFeel;
import eu.svjatoslav.sixth.e3d.gui.textEditorComponent.TextEditComponent;
import eu.svjatoslav.sixth.e3d.math.Transform;
-import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.line.LineAppearance;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.wireframe.Grid2D;
import java.net.URISyntaxException;
import java.util.stream.Collectors;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
import static eu.svjatoslav.sixth.e3d.math.Transform.fromAngles;
+import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.hex;
import static java.lang.Math.PI;
/**
/**
* Entry point for the text editor city demo.
+ *
* @param args command line arguments (ignored)
*/
public static void main(final String[] args) {
}
}
+ /**
+ * Adds a grid to the scene for visual reference.
+ *
+ * @param shapeCollection the collection to add the grid to
+ */
+ private static void addGrid(ShapeCollection shapeCollection) {
+ final Transform transform = fromAngles(0, 100, 0, 0, PI / 2, 0);
+
+ final Rectangle rectangle = new Rectangle(10000);
+ final LineAppearance appearance = new LineAppearance(10, hex("00b3ad"));
+
+ shapeCollection.addShape(new Grid2D(transform, rectangle, 50, 50, appearance));
+ }
+
+ /**
+ * Reads a resource file as a string.
+ *
+ * @param fileName the name of the resource file
+ * @return the file contents as a string, or null if not found
+ * @throws IOException if an I/O error occurs
+ */
+ static String getResourceFileAsString(String fileName) throws IOException {
+ ClassLoader classLoader = ClassLoader.getSystemClassLoader();
+ try (InputStream is = classLoader.getResourceAsStream(fileName)) {
+ if (is == null) return null;
+ try (InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader reader = new BufferedReader(isr)) {
+ return reader.lines().collect(Collectors.joining(System.lineSeparator()));
+ }
+ }
+ }
+
/**
* Builds and displays the 3D city scene with text editors.
+ *
* @throws URISyntaxException if resource URI is malformed
- * @throws IOException if demo text file cannot be read
+ * @throws IOException if demo text file cannot be read
*/
public void build() throws URISyntaxException, IOException {
final ViewFrame viewFrame = new ViewFrame("Text Editors City");
addGrid(shapeCollection);
addCity(viewPanel, shapeCollection);
-
+
viewFrame.getViewPanel().repaintDuringNextViewUpdate();
}
/**
* Creates a grid of buildings in the city.
- * @param viewPanel the view panel for the text editors
+ *
+ * @param viewPanel the view panel for the text editors
* @param shapeCollection the collection to add buildings to
* @throws URISyntaxException if resource URI is malformed
- * @throws IOException if demo text file cannot be read
+ * @throws IOException if demo text file cannot be read
*/
private void addCity(ViewPanel viewPanel, ShapeCollection shapeCollection) throws URISyntaxException, IOException {
int citySize = 4000;
- for (int z = -citySize; z< citySize; z+= 1000 ){
- for (int x = -citySize; x< citySize; x+= 1000 ){
+ for (int z = -citySize; z < citySize; z += 1000) {
+ for (int x = -citySize; x < citySize; x += 1000) {
addBuilding(viewPanel, shapeCollection, x, z);
}
}
}
-
- /**
- * Adds a grid to the scene for visual reference.
- * @param shapeCollection the collection to add the grid to
- */
- private static void addGrid(ShapeCollection shapeCollection) {
- final Transform transform = fromAngles(0, 100, 0, 0, PI / 2, 0);
-
- final Rectangle rectangle = new Rectangle(10000);
- final LineAppearance appearance = new LineAppearance(10, new Color(
- "00b3ad"));
-
- shapeCollection.addShape(new Grid2D(transform, rectangle, 50, 50, appearance));
- }
-
-
/**
* Adds a single building with four text editor panels facing different directions.
- * @param viewPanel the view panel for the text editors
+ *
+ * @param viewPanel the view panel for the text editors
* @param shapeCollection the collection to add the building to
- * @param x the X coordinate of the building center
- * @param z the Z coordinate of the building center
+ * @param x the X coordinate of the building center
+ * @param z the Z coordinate of the building center
* @throws URISyntaxException if resource URI is malformed
- * @throws IOException if demo text file cannot be read
+ * @throws IOException if demo text file cannot be read
*/
private void addBuilding(ViewPanel viewPanel, ShapeCollection shapeCollection, double x, double z) throws URISyntaxException, IOException {
- addTextEditor(viewPanel, shapeCollection, new Transform(new Point3D(x, -390, z-200)));
+ addTextEditor(viewPanel, shapeCollection, new Transform(point(x, -390, z - 200)));
- addTextEditor(viewPanel, shapeCollection, fromAngles(x, -390, z+200, PI, 0, 0));
+ addTextEditor(viewPanel, shapeCollection, fromAngles(x, -390, z + 200, PI, 0, 0));
- addTextEditor(viewPanel, shapeCollection, fromAngles(x-200, -390, z, PI/2, 0, 0));
+ addTextEditor(viewPanel, shapeCollection, fromAngles(x - 200, -390, z, PI / 2, 0, 0));
- addTextEditor(viewPanel, shapeCollection, fromAngles(x+200, -390, z, PI/2*3f, 0, 0));
+ addTextEditor(viewPanel, shapeCollection, fromAngles(x + 200, -390, z, PI / 2 * 3f, 0, 0));
}
/**
* Adds a single text editor component at the specified transform.
- * @param viewPanel the view panel for the text editor
+ *
+ * @param viewPanel the view panel for the text editor
* @param shapeCollection the collection to add the editor to
- * @param transform the position and orientation of the editor
+ * @param transform the position and orientation of the editor
* @throws IOException if demo text file cannot be read
*/
private void addTextEditor(ViewPanel viewPanel, ShapeCollection shapeCollection, Transform transform) throws IOException {
viewPanel,
new Point2D(400, 1000),
lookAndFeel
- );
+ );
String text = getResourceFileAsString("demo.txt");
textEditor.setText(text);
- textEditor.goToLine((int)(Math.random()*200f));
+ textEditor.goToLine((int) (Math.random() * 200f));
shapeCollection.addShape(textEditor);
}
/**
* Creates the look and feel for text editors with a dark theme.
+ *
* @return a LookAndFeel configured with dark blue background and light text
*/
private LookAndFeel getLookAndFeel() {
LookAndFeel lookAndFeel = new LookAndFeel();
- lookAndFeel.background = new Color(20, 20, 50, 150);
+ lookAndFeel.background = hex("141E3296");
lookAndFeel.tabStopBackground = lookAndFeel.background;
- lookAndFeel.foreground = new Color(150, 150, 255,250);
+ lookAndFeel.foreground = hex("9696FFFA");
return lookAndFeel;
}
- /**
- * Reads a resource file as a string.
- * @param fileName the name of the resource file
- * @return the file contents as a string, or null if not found
- * @throws IOException if an I/O error occurs
- */
- static String getResourceFileAsString(String fileName) throws IOException {
- ClassLoader classLoader = ClassLoader.getSystemClassLoader();
- try (InputStream is = classLoader.getResourceAsStream(fileName)) {
- if (is == null) return null;
- try (InputStreamReader isr = new InputStreamReader(is);
- BufferedReader reader = new BufferedReader(isr)) {
- return reader.lines().collect(Collectors.joining(System.lineSeparator()));
- }
- }
- }
-
}
import eu.svjatoslav.sixth.e3d.geometry.Point2D;
import eu.svjatoslav.sixth.e3d.geometry.Point3D;
import eu.svjatoslav.sixth.e3d.math.Vertex;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.texturedpolygon.TexturedPolygon;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.texturedpolygon.TexturedTriangle;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape;
import eu.svjatoslav.sixth.e3d.renderer.raster.texture.Texture;
private void addTexturedFace(Point3D p1, Point3D p2, Point3D p3, Point3D p4,
Point2D t1, Point2D t2, Point2D t3, Point2D t4,
Texture texture) {
- TexturedPolygon tri1 = new TexturedPolygon(
+ TexturedTriangle tri1 = new TexturedTriangle(
new Vertex(p1, t1),
new Vertex(p2, t2),
new Vertex(p3, t3),
);
tri1.setBackfaceCulling(true);
- TexturedPolygon tri2 = new TexturedPolygon(
+ TexturedTriangle tri2 = new TexturedTriangle(
new Vertex(p1, t1),
new Vertex(p3, t3),
new Vertex(p4, t4),
+++ /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.essentials;
-
-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.shapes.basic.line.LineAppearance;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.ForwardOrientedTextBlock;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.solid.SolidPolygonArrow;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.wireframe.Grid3D;
-
-/**
- * Demo displaying coordinate system axes using 3D arrows.
- *
- * <p>This demo illustrates the Sixth 3D coordinate system with three colored
- * arrows originating from the origin (0,0,0), each pointing along a positive
- * axis direction:</p>
- *
- * <ul>
- * <li><b>Red arrow</b> — +X axis (points RIGHT)</li>
- * <li><b>Green arrow</b> — +Y axis (points DOWN visually)</li>
- * <li><b>Blue arrow</b> — +Z axis (points AWAY from viewer)</li>
- * </ul>
- *
- * <p>A reference grid at Y=0 provides spatial context. Text labels identify
- * each axis.</p>
- *
- * @see SolidPolygonArrow
- * @see ForwardOrientedTextBlock
- */
-public class AxisArrowsDemo {
-
- /**
- * Length of each axis arrow.
- */
- private static final double ARROW_LENGTH = 200;
-
- /**
- * Radius of the arrow body (cylindrical shaft).
- */
- private static final double BODY_RADIUS = 6;
-
- /**
- * Distance from arrow tip to text label position.
- */
- private static final double LABEL_OFFSET = 20;
-
- /**
- * Scale factor for text labels.
- */
- private static final double LABEL_SCALE = 20.0;
-
- /**
- * Entry point for the axis arrows demo.
- *
- * @param args command line arguments (ignored)
- */
- public static void main(final String[] args) {
- final ViewFrame viewFrame = new ViewFrame("Axis Arrows Demo");
- final ViewPanel viewPanel = viewFrame.getViewPanel();
- final ShapeCollection shapes = viewPanel.getRootShapeCollection();
-
- // Position camera to view all three axes
- viewPanel.getCamera().getTransform().set(130.66, -65.49, -248.18, -0.06, -0.36, -0.00);
-
- // Create reference grid at Y=0 plane
- createReferenceGrid(shapes);
-
- // Create axis arrows
- createAxisArrows(shapes);
-
- viewPanel.repaintDuringNextViewUpdate();
- }
-
- /**
- * Creates a reference grid on the Y=0 plane.
- *
- * @param shapes the shape collection to add the grid to
- */
- private static void createReferenceGrid(final ShapeCollection shapes) {
- final LineAppearance gridAppearance = new LineAppearance(
- 1, new Color(80, 80, 100));
- final Grid3D grid = new Grid3D(
- new Point3D(-300, 0, -300),
- new Point3D(300, 0, 300),
- 50,
- gridAppearance
- );
- shapes.addShape(grid);
- }
-
- /**
- * Creates the three axis arrows and their labels.
- *
- * @param shapes the shape collection to add the arrows to
- */
- private static void createAxisArrows(final ShapeCollection shapes) {
- // X-axis arrow (RED) - points in positive X direction (RIGHT)
- final SolidPolygonArrow xArrow = new SolidPolygonArrow(
- new Point3D(0, 0, 0),
- new Point3D(ARROW_LENGTH, 0, 0),
- BODY_RADIUS, new Color(255, 0, 0, 180)
- );
- shapes.addShape(xArrow);
- createLabel(shapes, "X", new Point3D(ARROW_LENGTH + LABEL_OFFSET, 0, 0), Color.RED);
-
- // Y-axis arrow (GREEN) - points in positive Y direction (DOWN)
- final SolidPolygonArrow yArrow = new SolidPolygonArrow(
- new Point3D(0, 0, 0),
- new Point3D(0, ARROW_LENGTH, 0),
- BODY_RADIUS, new Color(0, 255, 0, 180)
- );
- shapes.addShape(yArrow);
- createLabel(shapes, "Y", new Point3D(0, ARROW_LENGTH + LABEL_OFFSET, 0), Color.GREEN);
-
- // Z-axis arrow (BLUE) - points in positive Z direction (AWAY)
- final SolidPolygonArrow zArrow = new SolidPolygonArrow(
- new Point3D(0, 0, 0),
- new Point3D(0, 0, ARROW_LENGTH),
- BODY_RADIUS, new Color(0, 0, 255, 180)
- );
- shapes.addShape(zArrow);
- createLabel(shapes, "Z", new Point3D(0, 0, ARROW_LENGTH + LABEL_OFFSET), Color.BLUE);
- }
-
- /**
- * Creates a text label at the specified position.
- *
- * @param shapes the shape collection to add the label to
- * @param text the label text
- * @param position the 3D position of the label
- * @param color the text color
- */
- private static void createLabel(final ShapeCollection shapes,
- final String text,
- final Point3D position,
- final Color color) {
- final ForwardOrientedTextBlock label = new ForwardOrientedTextBlock(
- position, LABEL_SCALE, 2, text, color
- );
- shapes.addShape(label);
- }
-}
\ No newline at end of file
*/
package eu.svjatoslav.sixth.e3d.examples.essentials;
-import eu.svjatoslav.sixth.e3d.csg.CSG;
import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.gui.TextPointer;
import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
+import eu.svjatoslav.sixth.e3d.math.Transform;
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.shapes.composite.ForwardOrientedTextBlock;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.solid.SolidPolygonCube;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.solid.SolidPolygonMesh;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.solid.SolidPolygonSphere;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.textcanvas.TextCanvas;
+
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.origin;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
+import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.hex;
/**
* Demo showcasing Constructive Solid Geometry (CSG) boolean operations.
* <li><b>Intersect:</b> The volume shared by a cube and sphere</li>
* </ul>
*
- * <p>Shapes are rendered with slight transparency (85% opacity) to allow
- * seeing internal structure. The demo demonstrates how existing composite
- * shapes like {@link SolidPolygonCube} and {@link SolidPolygonSphere} can
- * be used with CSG operations.</p>
+ * <p>All operations use a consistent color scheme: red for the first argument
+ * (cube) and blue for the second argument (sphere). This makes it easy to see
+ * which parts of the result came from which input shape.</p>
*
* <p><b>Run this demo:</b></p>
* <pre>{@code
- * java -cp target/sixth-3d-demos.jar eu.svjatoslav.sixth.e3d.examples.CSGDemo
+ * java -cp target/sixth-3d-demos.jar eu.svjatoslav.sixth.e3d.examples.essentials.CSGDemo
* }</pre>
*
- * @see CSG the CSG solid class
- * @see SolidPolygonMesh the renderable mesh
+ * @see eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape#union
+ * @see eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape#subtract
+ * @see eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape#intersect
*/
public class CSGDemo {
/**
- * Distance between shapes on the X axis.
- */
- private static final double SPACING = 500;
-
- /**
- * Size of the cube (half-edge length).
+ * Color for the first argument in boolean operations (cube).
*/
- private static final double CUBE_SIZE = 80;
+ private static final Color COLOR_FIRST = hex("FF6464D9");
/**
- * Radius of the sphere (slightly larger for interesting intersection).
+ * Color for the second argument in boolean operations (sphere).
*/
- private static final double SPHERE_RADIUS = 96;
+ private static final Color COLOR_SECOND = hex("6496FFD9");
/**
- * Number of segments for the sphere (smoothness).
+ * Distance between shapes on the X axis.
*/
- private static final int SPHERE_SEGMENTS = 12;
+ private static final double SPACING = 400;
/**
* Entry point for the CSG demo.
* @param args command line arguments (ignored)
*/
public static void main(final String[] args) {
- final ViewFrame viewFrame = new ViewFrame("CSG Demo - Boolean Operations");
+ final ViewFrame viewFrame = new ViewFrame("CSG demo - Boolean operations");
final ViewPanel viewPanel = viewFrame.getViewPanel();
final ShapeCollection shapes = viewPanel.getRootShapeCollection();
// Position camera to view all three shapes
- viewPanel.getCamera().getTransform().set(0, -150, -600, 0, 0, 0);
+ viewPanel.getCamera().getTransform().set(-244.24, 254.40, -458.83, -0.26, 0.24, -0.00);
// Set up lighting
- viewPanel.getLightingManager().setAmbientLight(new Color(60, 60, 70));
+ viewPanel.getLightingManager().setAmbientLight(hex("3C3C46"));
// Create lights
createLights(viewPanel, shapes);
// Create the three CSG demonstrations
- createSubtractDemo(shapes, -SPACING, 0, 0);
- createUnionDemo(shapes, 0, 0, 0);
- createIntersectDemo(shapes, SPACING, 0, 0);
-
- // Add labels
- createLabels(shapes);
+ createSubtractDemo(shapes, point(-SPACING, 0, 0));
+ createUnionDemo(shapes, origin());
+ createIntersectDemo(shapes, point(SPACING, 0, 0));
viewPanel.repaintDuringNextViewUpdate();
}
* Creates the subtract operation demo: cube - sphere.
* Results in a cube with a spherical cavity.
*
- * @param shapes the shape collection
- * @param x the X position
- * @param y the Y position
- * @param z the Z position
+ * @param shapes the shape collection
+ * @param location the position for the result
*/
- private static void createSubtractDemo(final ShapeCollection shapes,
- final double x, final double y, final double z) {
- final SolidPolygonCube cube = new SolidPolygonCube(
- new Point3D(0, 0, 0), CUBE_SIZE, Color.WHITE);
- final SolidPolygonSphere sphere = new SolidPolygonSphere(
- new Point3D(0, 0, 0), SPHERE_RADIUS, SPHERE_SEGMENTS, Color.WHITE);
-
- final CSG cubeCSG = CSG.fromCompositeShape(cube);
- final CSG sphereCSG = CSG.fromCompositeShape(sphere);
+ private static void createSubtractDemo(final ShapeCollection shapes, final Point3D location) {
- final CSG result = cubeCSG.subtract(sphereCSG);
+ final SolidPolygonCube cube = new SolidPolygonCube(origin(), 80, COLOR_FIRST);
+ cube.subtract(new SolidPolygonSphere(origin(), 96, 12, COLOR_SECOND));
- final SolidPolygonMesh mesh = result.toMesh(new Color(255, 100, 100, 217), new Point3D(x, y, z));
- mesh.setShadingEnabled(true);
- mesh.setBackfaceCulling(true);
+ shapes.addShape(cube
+ .setTransform(new Transform(location))
+ .setShadingEnabled(true)
+ .setBackfaceCulling(true));
- shapes.addShape(mesh);
+ final String description =
+ "Subtract: Cube - Sphere\n" +
+ "\n" +
+ "Red = Cube (kept)\n" +
+ "Blue = Sphere (carved out)";
- System.out.println("Subtract (cube - sphere): " + mesh.getTriangleCount() + " triangles");
+ shapes.addShape(createDescriptionPanel(location, description));
}
/**
* Creates the union operation demo: cube + sphere.
* Results in a combined shape.
*
- * @param shapes the shape collection
- * @param x the X position
- * @param y the Y position
- * @param z the Z position
+ * @param shapes the shape collection
+ * @param location the position for the result
*/
- private static void createUnionDemo(final ShapeCollection shapes,
- final double x, final double y, final double z) {
- final SolidPolygonCube cube = new SolidPolygonCube(
- new Point3D(0, 0, 0), CUBE_SIZE, Color.WHITE);
- final SolidPolygonSphere sphere = new SolidPolygonSphere(
- new Point3D(0, 0, 0), SPHERE_RADIUS, SPHERE_SEGMENTS, Color.WHITE);
+ private static void createUnionDemo(final ShapeCollection shapes, final Point3D location) {
- final CSG cubeCSG = CSG.fromCompositeShape(cube);
- final CSG sphereCSG = CSG.fromCompositeShape(sphere);
+ final SolidPolygonCube cube = new SolidPolygonCube(origin(), 80, COLOR_FIRST);
+ cube.union(new SolidPolygonSphere(origin(), 96, 12, COLOR_SECOND));
- final CSG result = cubeCSG.union(sphereCSG);
+ shapes.addShape(cube
+ .setTransform(new Transform(location))
+ .setShadingEnabled(true)
+ .setBackfaceCulling(true));
- final SolidPolygonMesh mesh = result.toMesh(new Color(100, 255, 100, 217), new Point3D(x, y, z));
- mesh.setShadingEnabled(true);
- mesh.setBackfaceCulling(true);
+ final String description =
+ "Union: Cube + Sphere\n" +
+ "\n" +
+ "Red = Cube\n" +
+ "Blue = Sphere";
- shapes.addShape(mesh);
-
- System.out.println("Union (cube + sphere): " + mesh.getTriangleCount() + " triangles");
+ shapes.addShape(createDescriptionPanel(location, description));
}
/**
* Creates the intersect operation demo: cube ∩ sphere.
* Results in the volume shared by both shapes.
*
- * @param shapes the shape collection
- * @param x the X position
- * @param y the Y position
- * @param z the Z position
+ * @param shapes the shape collection
+ * @param location the position for the result
*/
- private static void createIntersectDemo(final ShapeCollection shapes,
- final double x, final double y, final double z) {
- final SolidPolygonCube cube = new SolidPolygonCube(
- new Point3D(0, 0, 0), CUBE_SIZE, Color.WHITE);
- final SolidPolygonSphere sphere = new SolidPolygonSphere(
- new Point3D(0, 0, 0), SPHERE_RADIUS, SPHERE_SEGMENTS, Color.WHITE);
-
- final CSG cubeCSG = CSG.fromCompositeShape(cube);
- final CSG sphereCSG = CSG.fromCompositeShape(sphere);
+ private static void createIntersectDemo(final ShapeCollection shapes, final Point3D location) {
- final CSG result = cubeCSG.intersect(sphereCSG);
+ final SolidPolygonCube cube = new SolidPolygonCube(origin(), 80, COLOR_FIRST);
+ cube.intersect(new SolidPolygonSphere(origin(), 96, 12, COLOR_SECOND));
- final SolidPolygonMesh mesh = result.toMesh(new Color(100, 150, 255, 217), new Point3D(x, y, z));
- mesh.setShadingEnabled(true);
- mesh.setBackfaceCulling(true);
+ shapes.addShape(cube
+ .setTransform(new Transform(location))
+ .setShadingEnabled(true)
+ .setBackfaceCulling(true));
- shapes.addShape(mesh);
+ final String description =
+ "Intersect: Cube ∩ Sphere\n" +
+ "\n" +
+ "Red = from Cube\n" +
+ "Blue = from Sphere";
- System.out.println("Intersect (cube ∩ sphere): " + mesh.getTriangleCount() + " triangles");
+ shapes.addShape(createDescriptionPanel(location, description));
}
/**
- * Creates labels for each operation.
+ * Creates a description panel positioned below a shape.
*
- * @param shapes the shape collection
+ * @param location the position of the associated shape
+ * @param text the description text to display
+ * @return a TextCanvas positioned below the shape
*/
- private static void createLabels(final ShapeCollection shapes) {
- final double labelY = -150;
- final double labelZ = 0;
-
- // Subtract label
- shapes.addShape(new ForwardOrientedTextBlock(
- new Point3D(-SPACING, labelY, labelZ),
- 8.0, 2, "Subtract", Color.RED
- ));
-
- // Union label
- shapes.addShape(new ForwardOrientedTextBlock(
- new Point3D(0, labelY, labelZ),
- 8.0, 2, "Union", Color.GREEN
- ));
-
- // Intersect label
- shapes.addShape(new ForwardOrientedTextBlock(
- new Point3D(SPACING, labelY, labelZ),
- 8.0, 2, "Intersect", Color.BLUE
- ));
+ private static TextCanvas createDescriptionPanel(final Point3D location, final String text) {
+ final Transform transform = Transform.fromAngles(
+ point(location.x, location.y + 220, location.z),
+ 0, 0);
+
+ final TextCanvas panel = new TextCanvas(
+ transform,
+ new TextPointer(5, 35),
+ Color.WHITE,
+ new Color(0, 0, 40, 180));
+
+ panel.setText(text);
+ return panel;
}
/**
private static void createLights(final ViewPanel viewPanel, final ShapeCollection shapes) {
// Main light from above-front
final LightSource mainLight = new LightSource(
- new Point3D(0, -300, -400),
- new Color(255, 255, 255),
+ point(0, -300, -400),
+ hex("FFFFFF"),
1.5
);
viewPanel.getLightingManager().addLight(mainLight);
// Fill light from the side
final LightSource fillLight = new LightSource(
- new Point3D(500, 100, -200),
- new Color(150, 150, 200),
+ point(500, 100, -200),
+ hex("9696C8"),
0.8
);
viewPanel.getLightingManager().addLight(fillLight);
--- /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.essentials;
+
+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.shapes.basic.line.LineAppearance;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.ForwardOrientedTextBlock;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.solid.SolidPolygonArrow;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.wireframe.Grid3D;
+
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.origin;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
+import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.hex;
+
+/**
+ * Demo displaying coordinate system axes using 3D arrows.
+ *
+ * <p>This demo illustrates the Sixth 3D coordinate system with three colored
+ * arrows originating from the origin (0,0,0), each pointing along a positive
+ * axis direction:</p>
+ *
+ * <ul>
+ * <li><b>Red arrow</b> — +X axis (points RIGHT)</li>
+ * <li><b>Green arrow</b> — +Y axis (points DOWN visually)</li>
+ * <li><b>Blue arrow</b> — +Z axis (points AWAY from viewer)</li>
+ * </ul>
+ *
+ * <p>A reference grid at Y=0 provides spatial context. Text labels identify
+ * each axis.</p>
+ *
+ * @see SolidPolygonArrow
+ * @see ForwardOrientedTextBlock
+ */
+public class CoordinateSystemDemo {
+
+ /**
+ * Length of each axis arrow.
+ */
+ private static final double ARROW_LENGTH = 200;
+
+ /**
+ * Radius of the arrow body (cylindrical shaft).
+ */
+ private static final double BODY_RADIUS = 6;
+
+ /**
+ * Distance from arrow tip to text label position.
+ */
+ private static final double LABEL_OFFSET = 20;
+
+ /**
+ * Scale factor for text labels.
+ */
+ private static final double LABEL_SCALE = 20.0;
+
+ /**
+ * Entry point for the coordinate system demo.
+ *
+ * @param args command line arguments (ignored)
+ */
+ public static void main(final String[] args) {
+ final ViewFrame viewFrame = new ViewFrame("Coordinate System Demo");
+ final ViewPanel viewPanel = viewFrame.getViewPanel();
+ final ShapeCollection shapes = viewPanel.getRootShapeCollection();
+
+ // Position camera to view all three axes
+ viewPanel.getCamera().getTransform().set(130.66, -65.49, -248.18, -0.06, -0.36, -0.00);
+
+ // Create reference grid at Y=0 plane
+ createReferenceGrid(shapes);
+
+ // Create axis arrows
+ createAxisArrows(shapes);
+
+ viewPanel.repaintDuringNextViewUpdate();
+ }
+
+ /**
+ * Creates a reference grid on the Y=0 plane.
+ *
+ * @param shapes the shape collection to add the grid to
+ */
+ private static void createReferenceGrid(final ShapeCollection shapes) {
+ final LineAppearance gridAppearance = new LineAppearance(
+ 1, hex("505064FF"));
+ final Grid3D grid = new Grid3D(
+ point(-300, 0, -300),
+ point(300, 0, 300),
+ 50,
+ gridAppearance
+ );
+ shapes.addShape(grid);
+ }
+
+ /**
+ * Creates the three axis arrows and their labels.
+ *
+ * @param shapes the shape collection to add the arrows to
+ */
+ private static void createAxisArrows(final ShapeCollection shapes) {
+ // X-axis arrow (RED) - points in positive X direction (RIGHT)
+ final SolidPolygonArrow xArrow = new SolidPolygonArrow(
+ origin(),
+ point(ARROW_LENGTH, 0, 0),
+ BODY_RADIUS, hex("FF0000B4")
+ );
+ shapes.addShape(xArrow);
+ createLabel(shapes, "X", point(ARROW_LENGTH + LABEL_OFFSET, 0, 0), Color.RED);
+
+ // Y-axis arrow (GREEN) - points in positive Y direction (DOWN)
+ final SolidPolygonArrow yArrow = new SolidPolygonArrow(
+ origin(),
+ point(0, ARROW_LENGTH, 0),
+ BODY_RADIUS, hex("00FF00B4")
+ );
+ shapes.addShape(yArrow);
+ createLabel(shapes, "Y", point(0, ARROW_LENGTH + LABEL_OFFSET, 0), Color.GREEN);
+
+ // Z-axis arrow (BLUE) - points in positive Z direction (AWAY)
+ final SolidPolygonArrow zArrow = new SolidPolygonArrow(
+ origin(),
+ point(0, 0, ARROW_LENGTH),
+ BODY_RADIUS, hex("0000FFB4")
+ );
+ shapes.addShape(zArrow);
+ createLabel(shapes, "Z", point(0, 0, ARROW_LENGTH + LABEL_OFFSET), Color.BLUE);
+ }
+
+ /**
+ * Creates a text label at the specified position.
+ *
+ * @param shapes the shape collection to add the label to
+ * @param text the label text
+ * @param position the 3D position of the label
+ * @param color the text color
+ */
+ private static void createLabel(final ShapeCollection shapes,
+ final String text,
+ final Point3D position,
+ final Color color) {
+ final ForwardOrientedTextBlock label = new ForwardOrientedTextBlock(
+ position, LABEL_SCALE, 2, text, color
+ );
+ shapes.addShape(label);
+ }
+}
\ No newline at end of file
*/
package eu.svjatoslav.sixth.e3d.examples.essentials;
-import eu.svjatoslav.sixth.e3d.geometry.Point3D;
import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
import eu.svjatoslav.sixth.e3d.math.Transform;
import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.solid.SolidPolygonRectangularBox;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
+
/**
* Minimal example demonstrating how to create a basic 3D scene.
* <p>
ViewFrame viewFrame = new ViewFrame("Minimal example");
ShapeCollection shapes = viewFrame.getViewPanel().getRootShapeCollection();
- viewFrame.getViewPanel().getCamera().getTransform().setTranslation(new Point3D(0, -100, -300));
+ viewFrame.getViewPanel().getCamera().getTransform().setTranslation(point(0, -100, -300));
- Transform boxTransform = Transform.fromAngles(0, 0, 0, 0, 0, 0);
+ final Transform boxTransform = new Transform();
SolidPolygonRectangularBox box = new SolidPolygonRectangularBox(
- new Point3D(-50, -50, -50),
- new Point3D(50, 50, 50),
+ point(-50, -50, -50),
+ point(50, 50, 50),
Color.RED
);
box.setTransform(boxTransform);
import java.util.List;
import java.util.Random;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
import static eu.svjatoslav.sixth.e3d.math.Transform.fromAngles;
+import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.hex;
/**
* Gallery demo showcasing all available 3D shapes in the Sixth 3D engine.
* Color palette - one color per column (shape type).
*/
private static final Color[] SHAPE_COLORS = {
- new Color(255, 100, 100), // Arrow - Red
- new Color(255, 180, 100), // Cone - Orange
- new Color(255, 255, 100), // Cube - Yellow
- new Color(100, 255, 100), // Cylinder - Green
- new Color(100, 255, 255), // Pyramid - Cyan
- new Color(100, 150, 255), // RectangularBox - Blue
- new Color(200, 150, 255), // Sphere - Purple
+ hex("FF6464FF"), // Arrow - Red
+ hex("FFB464FF"), // Cone - Orange
+ hex("FFFF64FF"), // Cube - Yellow
+ hex("64FF64FF"), // Cylinder - Green
+ hex("64FFFFFF"), // Pyramid - Cyan
+ hex("6496FFFF"), // RectangularBox - Blue
+ hex("C896FFFF"), // Sphere - Purple
};
/**
viewPanel.getCamera().getTransform().set(-615.31, -299.50, -378.64, -0.62, -0.66, 0.00);
// Set up lighting
- viewPanel.getLightingManager().setAmbientLight(new Color(40, 40, 50));
+ viewPanel.getLightingManager().setAmbientLight(hex("282832FF"));
// Create floor grid
createFloorGrid(shapes);
* @param shapes the shape collection to add the grid to
*/
private static void createFloorGrid(final ShapeCollection shapes) {
- final LineAppearance gridAppearance = new LineAppearance(1, new Color(80, 80, 100));
+ final LineAppearance gridAppearance = new LineAppearance(1, hex("505064FF"));
// Calculate grid bounds: 7 columns, 2 rows, centered around origin
final double halfWidth = (COLUMN_COUNT * CELL_SIZE) / 2.0;
final double gridDepth = 2 * CELL_SIZE;
- final Point3D cornerA = new Point3D(-halfWidth, 0, -CELL_SIZE / 2);
- final Point3D cornerB = new Point3D(halfWidth, 0, gridDepth - CELL_SIZE / 2);
+ final Point3D cornerA = point(-halfWidth, 0, -CELL_SIZE / 2);
+ final Point3D cornerB = point(halfWidth, 0, gridDepth - CELL_SIZE / 2);
final Grid3D grid = new Grid3D(cornerA, cornerB, CELL_SIZE, gridAppearance);
shapes.addShape(grid);
final String name = SHAPE_NAMES[col];
// Row 0: Solid polygon shapes
- final Point3D solidPos = new Point3D(x, 0, 0);
+ final Point3D solidPos = point(x, 0, 0);
createSolidShape(shapes, col, solidPos, color);
createLabel(shapes, solidPos, name, color);
// Row 1: Wireframe shapes
- final Point3D wireframePos = new Point3D(x, 0, CELL_SIZE);
+ final Point3D wireframePos = point(x, 0, CELL_SIZE);
createWireframeShape(shapes, col, wireframePos, color);
createLabel(shapes, wireframePos, "Wireframe " + name, color);
}
switch (col) {
case 0: // Arrow
final SolidPolygonArrow arrow = new SolidPolygonArrow(
- new Point3D(pos.x, SHAPE_RADIUS, pos.z),
- new Point3D(pos.x, -SHAPE_RADIUS, pos.z),
+ point(pos.x, SHAPE_RADIUS, pos.z),
+ point(pos.x, -SHAPE_RADIUS, pos.z),
8, color);
arrow.setShadingEnabled(true);
shapes.addShape(arrow);
case 1: // Cone (pointing upward)
final SolidPolygonCone cone = new SolidPolygonCone(
- new Point3D(pos.x, -SHAPE_RADIUS, pos.z), // apex above
- new Point3D(pos.x, SHAPE_RADIUS / 2, pos.z), // base below
+ point(pos.x, -SHAPE_RADIUS, pos.z), // apex above
+ point(pos.x, SHAPE_RADIUS / 2, pos.z), // base below
SHAPE_RADIUS * 0.8, SEGMENTS, color);
cone.setShadingEnabled(true);
shapes.addShape(cone);
case 3: // Cylinder
final SolidPolygonCylinder cylinder = new SolidPolygonCylinder(
- new Point3D(pos.x, SHAPE_RADIUS, pos.z),
- new Point3D(pos.x, -SHAPE_RADIUS, pos.z),
+ point(pos.x, SHAPE_RADIUS, pos.z),
+ point(pos.x, -SHAPE_RADIUS, pos.z),
SHAPE_RADIUS * 0.7, SEGMENTS, color);
cylinder.setShadingEnabled(true);
shapes.addShape(cylinder);
case 4: // Pyramid
final SolidPolygonPyramid pyramid = new SolidPolygonPyramid(
- new Point3D(pos.x, -SHAPE_RADIUS, pos.z), // apex above
- new Point3D(pos.x, SHAPE_RADIUS / 2, pos.z), // base below
+ point(pos.x, -SHAPE_RADIUS, pos.z), // apex above
+ point(pos.x, SHAPE_RADIUS / 2, pos.z), // base below
SHAPE_RADIUS * 0.8, color);
pyramid.setShadingEnabled(true);
shapes.addShape(pyramid);
case 5: // RectangularBox
final SolidPolygonRectangularBox box = new SolidPolygonRectangularBox(
- new Point3D(pos.x - SHAPE_RADIUS * 0.35, pos.y - SHAPE_RADIUS, pos.z - SHAPE_RADIUS * 0.35),
- new Point3D(pos.x + SHAPE_RADIUS * 0.35, pos.y + SHAPE_RADIUS, pos.z + SHAPE_RADIUS * 0.35),
+ point(pos.x - SHAPE_RADIUS * 0.35, pos.y - SHAPE_RADIUS, pos.z - SHAPE_RADIUS * 0.35),
+ point(pos.x + SHAPE_RADIUS * 0.35, pos.y + SHAPE_RADIUS, pos.z + SHAPE_RADIUS * 0.35),
color);
box.setShadingEnabled(true);
shapes.addShape(box);
switch (col) {
case 0: // Arrow
final WireframeArrow arrow = new WireframeArrow(
- new Point3D(pos.x, SHAPE_RADIUS, pos.z),
- new Point3D(pos.x, -SHAPE_RADIUS, pos.z),
+ point(pos.x, SHAPE_RADIUS, pos.z),
+ point(pos.x, -SHAPE_RADIUS, pos.z),
8, appearance);
shapes.addShape(arrow);
break;
case 1: // Cone
final WireframeCone cone = new WireframeCone(
- new Point3D(pos.x, -SHAPE_RADIUS, pos.z), // apex above
- new Point3D(pos.x, SHAPE_RADIUS / 2, pos.z), // base below
+ point(pos.x, -SHAPE_RADIUS, pos.z), // apex above
+ point(pos.x, SHAPE_RADIUS / 2, pos.z), // base below
SHAPE_RADIUS * 0.8, SEGMENTS, appearance);
shapes.addShape(cone);
break;
case 3: // Cylinder
final WireframeCylinder cylinder = new WireframeCylinder(
- new Point3D(pos.x, SHAPE_RADIUS, pos.z),
- new Point3D(pos.x, -SHAPE_RADIUS, pos.z),
+ point(pos.x, SHAPE_RADIUS, pos.z),
+ point(pos.x, -SHAPE_RADIUS, pos.z),
SHAPE_RADIUS * 0.7, SEGMENTS, appearance);
shapes.addShape(cylinder);
break;
case 4: // Pyramid
final WireframePyramid pyramid = new WireframePyramid(
- new Point3D(pos.x, -SHAPE_RADIUS, pos.z), // apex above
- new Point3D(pos.x, SHAPE_RADIUS / 2, pos.z), // base below
+ point(pos.x, -SHAPE_RADIUS, pos.z), // apex above
+ point(pos.x, SHAPE_RADIUS / 2, pos.z), // base below
SHAPE_RADIUS * 0.8, appearance);
shapes.addShape(pyramid);
break;
case 5: // Box (WireframeBox)
final WireframeBox box = new WireframeBox(
- new Point3D(pos.x - SHAPE_RADIUS * 0.35, pos.y - SHAPE_RADIUS, pos.z - SHAPE_RADIUS * 0.35),
- new Point3D(pos.x + SHAPE_RADIUS * 0.35, pos.y + SHAPE_RADIUS, pos.z + SHAPE_RADIUS * 0.35),
+ point(pos.x - SHAPE_RADIUS * 0.35, pos.y - SHAPE_RADIUS, pos.z - SHAPE_RADIUS * 0.35),
+ point(pos.x + SHAPE_RADIUS * 0.35, pos.y + SHAPE_RADIUS, pos.z + SHAPE_RADIUS * 0.35),
appearance);
shapes.addShape(box);
break;
*/
private static void createLabel(final ShapeCollection shapes, final Point3D pos,
final String text, final Color color) {
- final Point3D labelPos = new Point3D(pos.x, pos.y + LABEL_Y_OFFSET, pos.z);
+ final Point3D labelPos = point(pos.x, pos.y + LABEL_Y_OFFSET, pos.z);
final ForwardOrientedTextBlock label = new ForwardOrientedTextBlock(
labelPos, 8.0, 2, text, color);
shapes.addShape(label);
final int axis = random.nextInt(3);
final double ellipseFactor = 0.7 + random.nextDouble() * 0.3;
- final LightSource light = new LightSource(new Point3D(0, 0, CELL_SIZE / 2), color, intensity);
+ final LightSource light = new LightSource(point(0, 0, CELL_SIZE / 2), color, intensity);
final LightSourceMarker marker = new LightSourceMarker(light.getPosition(), color);
viewPanel.getLightingManager().addLight(light);
break;
}
- final Point3D newPosition = new Point3D(x, y + centerY, z);
+ final Point3D newPosition = point(x, y + centerY, z);
orbitingLight.light.setPosition(newPosition);
orbitingLight.marker.setTransform(fromAngles(
newPosition.x, newPosition.y, newPosition.z, 0, 0, 0));
import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.solidpolygon.SolidPolygon;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
+
/**
* Demo to test winding order and backface culling documentation.
* <p>
* @param args command line arguments (ignored)
*/
public static void main(String[] args) {
- ViewFrame viewFrame = new ViewFrame("Winding Order Demo");
+ ViewFrame viewFrame = new ViewFrame("Winding order demo");
ViewPanel viewPanel = viewFrame.getViewPanel();
ShapeCollection shapes = viewPanel.getRootShapeCollection();
- viewPanel.getCamera().getTransform().setTranslation(new Point3D(0, 0, -500));
+ viewPanel.getCamera().getTransform().setTranslation(point(0, 0, -500));
double size = 150;
- Point3D upperCenter = new Point3D(0, -size, 0);
- Point3D lowerLeft = new Point3D(-size, +size, 0);
- Point3D lowerRight = new Point3D(+size, +size, 0);
+ Point3D upperCenter = point(0, -size, 0);
+ Point3D lowerLeft = point(-size, +size, 0);
+ Point3D lowerRight = point(+size, +size, 0);
SolidPolygon triangle = new SolidPolygon(upperCenter, lowerLeft, lowerRight, Color.GREEN);
triangle.setBackfaceCulling(true);
import eu.svjatoslav.sixth.e3d.geometry.Point3D;
import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.origin;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.Graph;
*/
private static void addMathFormulas(ShapeCollection geometryCollection) {
int z = 1000;
- Point3D location = new Point3D(-600, -300, z);
+ Point3D location = point(-600, -300, z);
geometryCollection.addShape(getSineGraph(location));
- location = new Point3D(600, -300, z);
+ location = point(600, -300, z);
geometryCollection.addShape(getFormula1Graph(location));
- location = new Point3D(-600, 0, z);
+ location = point(-600, 0, z);
geometryCollection.addShape(getCosineGraph(location));
- location = new Point3D(600, 0, z);
+ location = point(600, 0, z);
geometryCollection.addShape(getFormula2Graph(location));
- location = new Point3D(-600, 300, z);
+ location = point(-600, 300, z);
geometryCollection.addShape(getTangentGraph(location));
- location = new Point3D(600, 300, z);
+ location = point(600, 300, z);
geometryCollection.addShape(getFormula3Graph(location));
}
new Color(150, 150, 150, 180),
Color.WHITE,
scale,
- new Point3D(0, 0, 0)
+ origin()
);
surface.addYIntersectionCurve(4, function, new Color(255, 255, 0, 220), 1.2);
}
private void addQuad(final Point3D p1, final Point3D p2, final Point3D p3, final Point3D p4) {
- final SolidPolygon poly1 = new SolidPolygon(p1, p2, p3, surfaceColor);
- poly1.setBackfaceCulling(false);
- addShape(poly1);
-
- final SolidPolygon poly2 = new SolidPolygon(p2, p4, p3, surfaceColor);
- poly2.setBackfaceCulling(false);
- addShape(poly2);
+ final SolidPolygon quad = SolidPolygon.quad(p1, p2, p4, p3, surfaceColor);
+ quad.setBackfaceCulling(false);
+ addShape(quad);
}
private void addGridLines(final Point3D p1, final Point3D p2, final Point3D p3, final Point3D p4) {
import eu.svjatoslav.sixth.e3d.examples.SineHeightmap;
import eu.svjatoslav.sixth.e3d.examples.TextEditorDemo;
import eu.svjatoslav.sixth.e3d.examples.TextEditorDemo2;
-import eu.svjatoslav.sixth.e3d.examples.essentials.AxisArrowsDemo;
+import eu.svjatoslav.sixth.e3d.examples.essentials.CoordinateSystemDemo;
import eu.svjatoslav.sixth.e3d.examples.essentials.CSGDemo;
import eu.svjatoslav.sixth.e3d.examples.essentials.MinimalExample;
import eu.svjatoslav.sixth.e3d.examples.essentials.ShapeGalleryDemo;
new DemoEntry("Winding order",
"Triangle demo for winding order & backface culling",
new ShowWindingOrder()),
- new DemoEntry("Axis arrows",
+ new DemoEntry("Coordinate system",
"Coordinate system axes: X (red), Y (green), Z (blue)",
- new ShowAxisArrows()),
+ new ShowCoordinateSystem()),
new DemoEntry("Shape gallery",
"All 3D shapes with orbiting colored light sources",
new ShowShadedShapes()),
- new DemoEntry("CSG Demo",
+ new DemoEntry("CSG demo",
"Boolean operations: union, subtract, intersect on 3D shapes",
new ShowCSG()),
};
private static class ShowMinimalExample extends AbstractAction {
ShowMinimalExample() {
- putValue(NAME, "Minimal Example");
+ putValue(NAME, "Minimal example");
}
@Override
private static class ShowWindingOrder extends AbstractAction {
ShowWindingOrder() {
- putValue(NAME, "Winding Order");
+ putValue(NAME, "Winding order");
}
@Override
}
}
- private static class ShowAxisArrows extends AbstractAction {
- ShowAxisArrows() {
- putValue(NAME, "Axis arrows");
+ private static class ShowCoordinateSystem extends AbstractAction {
+ ShowCoordinateSystem() {
+ putValue(NAME, "Coordinate system");
}
@Override
public void actionPerformed(final ActionEvent e) {
- AxisArrowsDemo.main(null);
+ CoordinateSystemDemo.main(null);
}
}
private static class ShowCSG extends AbstractAction {
ShowCSG() {
- putValue(NAME, "CSG Demo");
+ putValue(NAME, "CSG demo");
}
@Override
class Cell extends AbstractCompositeShape implements
MouseInteractionController {
- /** Visual size of each cell in world units. */
+ /**
+ * Visual size of each cell in world units.
+ */
static final int SIZE = 20;
/**
* Color of the active cell (R, G, B, A)
*/
private static final Color ACTIVE_COLOR = new Color("A8FF");
/**
- * Color of the active cell (R, G, B, A) while mouse is over it.
+ * Color of the active cell (R, G, B, A) while the mouse is over it.
*/
private static final Color ACTIVE_COLOR_MOUSE_OVER = new Color("F9FF");
/**
/**
* Constructs a cell at the specified center position.
+ *
* @param center the 3D position of the cell center
*/
public Cell(final Point3D center) {
setMouseInteractionController(this);
}
- /** Creates the visual representation of the cell as two triangles. */
+ /**
+ * Creates the visual representation of the cell as two triangles.
+ */
private void createCellShape() {
final double halfSize = SIZE / 2f;
/**
* Computes the cell color based on active state and mouse hover.
+ *
* @return the appropriate color for the current state
*/
private Color computeCellColor() {
/**
* Returns whether this cell is currently active (alive).
+ *
* @return true if the cell is active
*/
public boolean isActive() {
/**
* Sets the active state of this cell and updates its color.
+ *
* @param active true to make the cell active, false for inactive
*/
public void setActive(final boolean active) {
/**
* Handles mouse click by toggling the cell state.
+ *
* @param button the mouse button that was clicked
* @return true to indicate the event was consumed
*/
/**
* Handles mouse entering the cell area by highlighting it.
+ *
* @return true to indicate the event was consumed
*/
@Override
/**
* Handles mouse exiting the cell area by removing highlight.
+ *
* @return true to indicate the event was consumed
*/
@Override
/**
* Sets the mouse-over state and updates the cell color.
+ *
* @param isMouseOver true if mouse is over the cell
*/
private void setMouseOver(final boolean isMouseOver) {
updateColor();
}
- /** Updates the cell's visual color to match its current state. */
+ /**
+ * Updates the cell's visual color to match its current state.
+ */
private void updateColor() {
setColor(computeCellColor());
}
import eu.svjatoslav.sixth.e3d.gui.humaninput.WorldNavigationUserInputTracker;
import eu.svjatoslav.sixth.e3d.math.Transform;
import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.origin;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
+import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.hex;
import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.line.LineAppearance;
import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.textcanvas.TextCanvas;
* The game of life matrix, centered at the origin.
*/
private static final Matrix MATRIX = new Matrix(
- new Point3D() // position matrix in the center of the scene
+ origin() // position matrix in the center of the scene
);
/**
5, 5,
new LineAppearance(3,
- new Color("FF000050")
+ hex("FF000050")
)
);
}
"Hover - Highlight cell";
final Transform location = Transform.fromAngles(
- new Point3D(500, -80, 0),
+ point(500, -80, 0),
-Math.PI / 2,
0
);
location,
dimensions,
Color.WHITE,
- new Color(0, 0, 80, 200)
+ hex("000050C8")
);
panel.setText(helpText);
import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.origin;
+import static eu.svjatoslav.sixth.e3d.geometry.Point3D.point;
+import static eu.svjatoslav.sixth.e3d.renderer.raster.Color.hex;
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;
// Get terrain height at center and place tree trunk on it
final double terrainHeight = terrain.getHeightAt(0, 0);
- shapes.addShape(new FractalTree(new Point3D(0, terrainHeight, 0), 30, 6));
+ shapes.addShape(new FractalTree(point(0, terrainHeight, 0), 30, 6));
viewPanel.repaintDuringNextViewUpdate();
}
*/
private static void setLights(ViewFrame viewFrame, ShapeCollection shapes) {
LightingManager lightingManager = viewFrame.getViewPanel().getLightingManager();
- lightingManager.setAmbientLight(new Color(250, 150, 100));
+ lightingManager.setAmbientLight(hex("FA9664FF"));
final LightSource warmLight = new LightSource(
- new Point3D(-400, -500, 0),
- new Color(255, 180, 100),
+ point(-400, -500, 0),
+ hex("FFB464FF"),
190.0
);
final LightSource coolLight = new LightSource(
- new Point3D(400, -500, 0),
- new Color(100, 200, 255),
+ point(400, -500, 0),
+ hex("64C8FFFF"),
220.0
);
final LightSource neutralLight = new LightSource(
- new Point3D(0, -600, 300),
- new Color(255, 255, 255),
+ point(0, -600, 300),
+ hex("FFFFFFFF"),
250.0
);
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)));
+ shapes.addShape(new LightSourceMarker(warmLight.getPosition(), hex("FFB464FF")));
+ shapes.addShape(new LightSourceMarker(coolLight.getPosition(), hex("64C8FFFF")));
+ shapes.addShape(new LightSourceMarker(neutralLight.getPosition(), hex("FFFFFFFF")));
}
}
\ No newline at end of file