-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Edwin Jakobs <[email protected]>
- Loading branch information
Showing
31 changed files
with
2,637 additions
and
1,162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,95 +1,121 @@ | ||
# orx-mesh-generators | ||
|
||
Generates 3D meshes: sphere, box, cylinder, plane, dodecahedron. | ||
Generates various types of 3D meshes. | ||
|
||
##### usage | ||
## Simple meshes | ||
|
||
```kotlin | ||
// To create simple meshes | ||
val sphere = sphereMesh(32, 32, 4.0) | ||
val unitSphere = sphereMesh() | ||
val cube = boxMesh() | ||
val box = boxMesh(2.0, 4.0, 2.0) | ||
val cylinder = cylinderMesh(radius = 0.5, length = 1.0, center = true) | ||
val dodecahedron = dodecahedronMesh(0.5) | ||
val plane = planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Y) | ||
val disk = capMesh(sides = 15, radius = 0.5) | ||
val tube = revolveMesh(sides = 15, length = 1.0) | ||
|
||
// To draw the generated meshes | ||
drawer.vertexBuffer(dodecahedron, DrawPrimitive.TRIANGLES) | ||
``` | ||
|
||
## Complex triangular mesh generation | ||
|
||
`orx-mesh-generators` comes with `buildTriangleMesh`, which | ||
implements a [DSL](https://en.wikipedia.org/wiki/Domain-specific_language) | ||
to construct 3D shapes. | ||
|
||
... | ||
To create shapes we can call methods like `box()`, `sphere()`, | ||
`cylinder()`, `dodecahedron()`, `plane()`, `revolve()`, | ||
`taperedCylinder()`, `hemisphere()` and `cap()`. | ||
|
||
```kotlin | ||
// Create a rotated box | ||
val mesh = buildTriangleMesh { | ||
rotate(Vector3.UNIT_Z, 45.0) | ||
box() | ||
} | ||
``` | ||
|
||
drawer.vertexBuffer(sphere, DrawPrimitive.TRIANGLES) | ||
drawer.vertexBuffer(unitSphere, DrawPrimitive.TRIANGLES) | ||
drawer.vertexBuffer(cube, DrawPrimitive.TRIANGLES) | ||
drawer.vertexBuffer(box, DrawPrimitive.TRIANGLES) | ||
We can also use methods like `translate()` and `rotate()` to create | ||
more complex compositions. The `color` property sets the color of | ||
the next mesh. | ||
|
||
```kotlin | ||
// Create a ring of boxes of various colors | ||
val mesh = buildTriangleMesh { | ||
repeat(12) { | ||
// Take a small step | ||
translate(2.0, 0.0, 0.0) | ||
// Turn 30 degrees | ||
rotate(Vector3.UNIT_Y, 30.0) | ||
// Set a color | ||
color = rgb(it / 11.0, 1.0, 1.0 - it / 11.0) | ||
// Add a colored box | ||
box(1.0, 1.0, 1.0) | ||
} | ||
} | ||
``` | ||
|
||
## API | ||
`isolated { ... }` can be used to encapsulate transformations and | ||
avoid them accumulating to unpredictable values. | ||
|
||
```kotlin | ||
fun sphereMesh( | ||
sides: Int = 16, | ||
segments: Int = 16, | ||
radius: Double = 1.0, | ||
invert: Boolean = false): VertexBuffer | ||
|
||
fun groundPlaneMesh( | ||
width: Double = 1.0, | ||
height: Double = 1.0, | ||
widthSegments: Int = 1, | ||
heightSegments: Int): VertexBuffer | ||
|
||
fun boxMesh( | ||
width: Double = 1.0, | ||
height: Double = 1.0, | ||
depth: Double = 1.0, | ||
widthSegments: Int = 1, | ||
heightSegments: Int = 1, | ||
depthSegments: Int = 1, | ||
invert: Boolean = false): VertexBuffer | ||
val mesh = buildTriangleMesh { | ||
repeat(10) { x -> | ||
repeat(10) { y -> | ||
isolated { | ||
translate(x * 1.0, y * 1.0, 0.0) | ||
sphere(8, 8, 0.1) | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
<!-- __demos__ > | ||
# Demos | ||
[DemoBoxKt](src/demo/kotlin/DemoBoxKt.kt | ||
![DemoBoxKt](https://github.com/openrndr/orx/blob/media/orx-mesh-generators/images/DemoBoxKt.png | ||
[DemoComplex01Kt](src/demo/kotlin/DemoComplex01Kt.kt | ||
![DemoComplex01Kt](https://github.com/openrndr/orx/blob/media/orx-mesh-generators/images/DemoComplex01Kt.png | ||
[DemoComplex02Kt](src/demo/kotlin/DemoComplex02Kt.kt | ||
![DemoComplex02Kt](https://github.com/openrndr/orx/blob/media/orx-mesh-generators/images/DemoComplex02Kt.png | ||
[DemoComplex03Kt](src/demo/kotlin/DemoComplex03Kt.kt | ||
![DemoComplex03Kt](https://github.com/openrndr/orx/blob/media/orx-mesh-generators/images/DemoComplex03Kt.png | ||
[DemoComplex04Kt](src/demo/kotlin/DemoComplex04Kt.kt | ||
![DemoComplex04Kt](https://github.com/openrndr/orx/blob/media/orx-mesh-generators/images/DemoComplex04Kt.png | ||
[DemoComplex05Kt](src/demo/kotlin/DemoComplex05Kt.kt | ||
![DemoComplex05Kt](https://github.com/openrndr/orx/blob/media/orx-mesh-generators/images/DemoComplex05Kt.png | ||
|
||
Other available methods are: | ||
|
||
- `grid()`: creates a tri-dimensional grid of meshes. | ||
- `extrudeShape()`: gives depth to 2D `Shape`. | ||
- `twist()`: post-processing effect to twist a mesh around an axis. | ||
- `extrudeContourSteps()`: uses Parallel Transport Frames to extrude a contour along a 3D path. | ||
|
||
The [demo folder](src/jvmDemo/kotlin) contains examples using these methods. | ||
|
||
Check out the [source code](src/commonMain/kotlin) to learn about function arguments. | ||
|
||
<!-- __demos__ --> | ||
## Demos | ||
### DemoAll | ||
[source code](src/demo/kotlin/DemoAll.kt) | ||
[source code](src/jvmDemo/kotlin/DemoAll.kt) | ||
|
||
![DemoAllKt](https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/DemoAllKt.png) | ||
|
||
### DemoBox | ||
[source code](src/demo/kotlin/DemoBox.kt) | ||
[source code](src/jvmDemo/kotlin/DemoBox.kt) | ||
|
||
![DemoBoxKt](https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/DemoBoxKt.png) | ||
|
||
### DemoComplex01 | ||
[source code](src/demo/kotlin/DemoComplex01.kt) | ||
[source code](src/jvmDemo/kotlin/DemoComplex01.kt) | ||
|
||
![DemoComplex01Kt](https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/DemoComplex01Kt.png) | ||
|
||
### DemoComplex02 | ||
[source code](src/demo/kotlin/DemoComplex02.kt) | ||
[source code](src/jvmDemo/kotlin/DemoComplex02.kt) | ||
|
||
![DemoComplex02Kt](https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/DemoComplex02Kt.png) | ||
|
||
### DemoComplex03 | ||
[source code](src/demo/kotlin/DemoComplex03.kt) | ||
[source code](src/jvmDemo/kotlin/DemoComplex03.kt) | ||
|
||
![DemoComplex03Kt](https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/DemoComplex03Kt.png) | ||
|
||
### DemoComplex04 | ||
[source code](src/demo/kotlin/DemoComplex04.kt) | ||
[source code](src/jvmDemo/kotlin/DemoComplex04.kt) | ||
|
||
![DemoComplex04Kt](https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/DemoComplex04Kt.png) | ||
|
||
### DemoComplex05 | ||
[source code](src/demo/kotlin/DemoComplex05.kt) | ||
[source code](src/jvmDemo/kotlin/DemoComplex05.kt) | ||
|
||
![DemoComplex05Kt](https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/DemoComplex05Kt.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,24 @@ | ||
plugins { | ||
org.openrndr.extra.convention.`kotlin-jvm` | ||
org.openrndr.extra.convention.`kotlin-multiplatform` | ||
} | ||
|
||
dependencies { | ||
implementation(libs.openrndr.application) | ||
implementation(libs.openrndr.math) | ||
demoImplementation(project(":orx-shapes")) | ||
demoImplementation(project(":orx-mesh-generators")) | ||
demoImplementation(project(":orx-camera")) | ||
} | ||
kotlin { | ||
sourceSets { | ||
@Suppress("UNUSED_VARIABLE") | ||
val commonMain by getting { | ||
dependencies { | ||
api(libs.openrndr.application) | ||
api(libs.openrndr.math) | ||
} | ||
} | ||
|
||
@Suppress("UNUSED_VARIABLE") | ||
val jvmDemo by getting { | ||
dependencies { | ||
implementation(project(":orx-shapes")) | ||
implementation(project(":orx-mesh-generators")) | ||
implementation(project(":orx-camera")) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package org.openrndr.extra.meshgenerators | ||
|
||
import org.openrndr.draw.VertexBuffer | ||
import org.openrndr.math.Vector3 | ||
|
||
/** | ||
* Returns a Box mesh | ||
* | ||
* @param width the width of the box | ||
* @param height the height of the box | ||
* @param depth the depth of the box | ||
* @param widthSegments the number of segments along the x-axis | ||
* @param heightSegments the number of segments along the z-axis | ||
* @param depthSegments the number of segments along the y-axis | ||
* @param flipNormals generates inside-out geometry if true | ||
* @return A vertex buffer containing the triangles to render the 3D shape | ||
*/ | ||
fun boxMesh( | ||
width: Double = 1.0, | ||
height: Double = 1.0, | ||
depth: Double = 1.0, | ||
widthSegments: Int = 1, | ||
heightSegments: Int = 1, | ||
depthSegments: Int = 1, | ||
flipNormals: Boolean = false | ||
): VertexBuffer { | ||
val vb = meshVertexBuffer( | ||
widthSegments * heightSegments * 6 * 2 + | ||
widthSegments * depthSegments * 6 * 2 + | ||
heightSegments * depthSegments * 6 * 2 | ||
) | ||
vb.put { | ||
generateBox( | ||
width, height, depth, | ||
widthSegments, heightSegments, depthSegments, | ||
flipNormals, bufferWriter(this) | ||
) | ||
} | ||
return vb | ||
} | ||
|
||
/** | ||
* Generate a box | ||
* | ||
* @param width the width of the box | ||
* @param height the height of the box | ||
* @param depth the depth of the box | ||
* @param widthSegments the number of segments along the x-axis | ||
* @param heightSegments the number of segments along the z-axis | ||
* @param depthSegments the number of segments along the y-axis | ||
* @param flipNormals generates inside-out geometry if true | ||
* @param writer the vertex writer function | ||
*/ | ||
|
||
fun generateBox( | ||
width: Double = 1.0, | ||
height: Double = 1.0, | ||
depth: Double = 1.0, | ||
widthSegments: Int = 1, | ||
heightSegments: Int = 1, | ||
depthSegments: Int = 1, | ||
flipNormals: Boolean = false, | ||
writer: VertexWriter | ||
) { | ||
|
||
val sign = if (flipNormals) -1.0 else 1.0 | ||
// +x -- ZY | ||
generatePlane( | ||
Vector3(width / 2.0 * sign, 0.0, 0.0), | ||
Vector3.UNIT_Z, Vector3.UNIT_Y, Vector3.UNIT_X, | ||
-depth, -height, | ||
depthSegments, heightSegments, writer | ||
) | ||
|
||
// -x -- ZY | ||
generatePlane( | ||
Vector3(-width / 2.0 * sign, 0.0, 0.0), | ||
Vector3.UNIT_Z, Vector3.UNIT_Y, -Vector3.UNIT_X, | ||
-depth, height, | ||
depthSegments, heightSegments, writer | ||
) | ||
|
||
// +y -- XZ | ||
generatePlane( | ||
Vector3(0.0, height / 2.0 * sign, 0.0), | ||
Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y, | ||
width, depth, | ||
widthSegments, depthSegments, writer | ||
) | ||
|
||
// -y -- XZ | ||
generatePlane( | ||
Vector3(0.0, -height / 2.0 * sign, 0.0), | ||
Vector3.UNIT_X, Vector3.UNIT_Z, -Vector3.UNIT_Y, | ||
width, -depth, | ||
widthSegments, depthSegments, writer | ||
) | ||
|
||
// +z -- XY | ||
generatePlane( | ||
Vector3(0.0, 0.0, depth / 2.0 * sign), | ||
Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z, | ||
-width, height, | ||
widthSegments, heightSegments, writer | ||
) | ||
|
||
// -z -- XY | ||
generatePlane( | ||
Vector3(0.0, 0.0, -depth / 2.0 * sign), | ||
Vector3.UNIT_X, Vector3.UNIT_Y, -Vector3.UNIT_Z, | ||
width, height, | ||
widthSegments, heightSegments, writer | ||
) | ||
} |
Oops, something went wrong.