Skip to content

[wip] Feature: colored height maps to ordered point clouds + point clouds to wireframes and meshes #343

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5d2b241
new orx-compute-shaders module
morisil Jun 8, 2024
7f7b206
orx-compute-shaders: documentation update and simplified API naming
morisil Jun 11, 2024
46e5ad3
new orx-compute-shaders module
morisil Jun 11, 2024
4eb9908
orx-compute-shaders: documentation update
morisil Jun 11, 2024
7bb629b
orx-point-clouds: initial code + demos + docs
morisil Jun 11, 2024
7cd34c5
gradle: orx-point-clouds added to settings.gradle.kts
morisil Jun 11, 2024
be6c32e
orx-point-clouds: shaders unified with #define = only one GLSL code b…
morisil Jun 11, 2024
5d9fe2f
orx-point-clouds: README structure simplified
morisil Jun 11, 2024
f486999
orx-point-clouds: code formatting fix
morisil Jun 11, 2024
5e23719
orx-wireframes: the initial code + demos + documentation
morisil Jun 11, 2024
659f68e
orx-point-clouds: pointCloudVertexBuffer factories refactored to supp…
morisil Jun 11, 2024
3caba86
more universal shader layouts
morisil Jun 12, 2024
1dee1f7
orx-point-clouds: camera in demos changed to Orbital
morisil Jun 15, 2024
8523edd
orx-wireframes: camera in demos changed to Orbital
morisil Jun 15, 2024
6072122
orx-mesh-generators: add shaders processing to gradle build
morisil Jun 15, 2024
872c2d6
orx-mesh-generators: shader processing added to the build
morisil Jun 15, 2024
44a89d2
orx-wireframes: camera keySpeed reduced in all the demos
morisil Jun 15, 2024
237e49a
orx-point-clouds: camera keySpeed reduced in all the demos
morisil Jun 15, 2024
7fca793
orx-wireframes: the initial code + demos + documentation
morisil Jun 15, 2024
1a62bac
orx-wireframes: use explicit resolution parameter when generating wir…
morisil Jun 17, 2024
cab984a
orx-point-clouds: demos updated with camera near set to small value, …
morisil Jun 17, 2024
9f7f678
orx-compute-shaders: README updated with demo
morisil Jun 17, 2024
ae66a03
orx-point-clouds: README updated with demos
morisil Jun 17, 2024
fbd8c3c
orx-point-clouds: README updated with demos
morisil Jun 17, 2024
1e69055
orx-wireframe: README updated with demos
morisil Jun 17, 2024
d780ea0
main README.md update with new modules
morisil Jun 17, 2024
4c7124b
orx-wireframes: demos updated
morisil Jun 17, 2024
9f1fe47
orx-mesh-generators: PointCloudToMeshes generators + demos + docs
morisil Jun 17, 2024
70f7d7d
Merge branch 'master' into feature/orderedPointCloudToMeshInMeshGener…
morisil Jun 17, 2024
8bc0ed4
gitignore: .lwjgl folder
morisil Jun 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ gradle.properties
/gui-parameters/
/ShaderError.glsl
/.kotlin
/.lwjgl
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ complement [OPENRNDR](https://github.com/openrndr/openrndr).
| [`orx-compositor`](orx-compositor/) | Toolkit to make composite (layered) images using blend modes and filters. |
| [`orx-compute-graph`](orx-compute-graph/) | A graph for computation. |
| [`orx-compute-graph-nodes`](orx-compute-graph-nodes/) | A collection of nodes that can be used with `orx-compute-graph`. |
| [`orx-compute-shaders`](orx-compute-shaders/) | Tools easing the work with compute shaders. |
| [`orx-delegate-magic`](orx-delegate-magic/) | Collection of magical property delegators. For tracking variable change or interpolate towards the value of a variable. |
| [`orx-easing`](orx-easing/) | Easing functions for smooth animation or non-linear interpolation. |
| [`orx-envelopes`](orx-envelopes/) | ADSR (Attack, Decay, Sustain, Release) envelopes and tools. |
Expand All @@ -39,6 +40,7 @@ complement [OPENRNDR](https://github.com/openrndr/openrndr).
| [`orx-obj-loader`](orx-obj-loader/) | Simple loader for Wavefront .obj 3D mesh files. |
| [`orx-palette`](orx-palette/) | Provides hundreds of color palettes. |
| [`orx-parameters`](orx-parameters/) | Provides annotations and tools for turning Kotlin properties into introspectable parameters. Used by [`orx-gui`](../orx-jvm/orx-gui/README.md) to automatically generate user interfaces. |
| [`orx-point-clouds`](orx-point-clouds/) | 3D-point cloud generating functions |
| [`orx-property-watchers`](orx-property-watchers/) | Tools for setting up property watcher based pipelines |
| [`orx-quadtree`](orx-quadtree/) | A [Quadtree](https://en.wikipedia.org/wiki/Quadtree) is a spatial partioning tree structure meant to provide fast spatial queries such as nearest points within a range. |
| [`orx-shade-styles`](orx-shade-styles/) | Shader based fills and strokes, including various types of gradient fills. |
Expand All @@ -52,6 +54,7 @@ complement [OPENRNDR](https://github.com/openrndr/openrndr).
| [`orx-triangulation`](orx-triangulation/) | **Delaunay** triangulation and **Voronoi** diagrams. |
| [`orx-turtle`](orx-turtle/) | Bezier (`ShapeContour`) backed [turtle graphics](https://en.wikipedia.org/wiki/Turtle_graphics). |
| [`orx-view-box`](orx-view-box/) | To create independent views inside one program window. |
| [`orx-wireframes`](orx-wireframes/) | 3D-wireframe generating functions |

## JVM only

Expand Down
Binary file added demo-data/images/nasa-blue-marble-height-map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo-data/images/nasa-blue-marble.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions orx-compute-shaders/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# orx-compute-shaders

Tools easing the work with compute shaders.

## Overview

`orx-compute-shaders` is designed to simplify the execution of compute shaders, especially for 2D data. This can include
images, grids of values, or organized point clouds.

## Executing Compute Shaders for 2D Data

When working with 2-dimensional data, particularly if the dimensions are unknown, certain assumptions must be made about
the dimensions of the computation. Below is an example of how to specify the layout in the shader and execute it.

### Shader Layout
In the shader itself, specify the layout as follows:

```glsl
#version 430
layout (local_size_x = 8, local_size_y = 8) in;

uniform ivec2 resolution;

void main() {
ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
// Prevent computation outside the resolution range
if (coord.x >= resolution.x || coord.y >= resolution.y) {
return;
}

// Desired computation
// ...
}
```

### Execution in Kotlin

Now, you can execute such a shader in Kotlin with the following code:

```kotlin
val shader = ComputeShader.fromCode(shaderCode)
val executeDimensions = computeShaderExecuteDimensions(
resolution,
localSizeX = 8,
localSizeY = 8
)
shader.execute(executeDimensions)
```

Note: Ensure the local size matches between the GLSL and Kotlin code for each respective dimension.

<!-- __demos__ -->
## Demos
### DemoComputeShaderExecute2D
[source code](src/jvmDemo/kotlin/DemoComputeShaderExecute2D.kt)

![DemoComputeShaderExecute2DKt](https://raw.githubusercontent.com/openrndr/orx/media/orx-compute-shaders/images/DemoComputeShaderExecute2DKt.png)
22 changes: 22 additions & 0 deletions orx-compute-shaders/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
plugins {
org.openrndr.extra.convention.`kotlin-multiplatform`
}

kotlin {
sourceSets {
val commonMain by getting {
dependencies {
api(libs.openrndr.application)
api(libs.openrndr.math)
}
}
val commonTest by getting {
dependencies {
api(libs.kotest.assertions)
}
}
val jvmDemo by getting {
dependencies {}
}
}
}
46 changes: 46 additions & 0 deletions orx-compute-shaders/src/commonMain/kotlin/ComputeShaders.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.openrndr.extra.computeshaders

import org.openrndr.draw.ColorBuffer
import org.openrndr.math.IntVector2
import org.openrndr.math.IntVector3
import kotlin.math.ceil

val ColorBuffer.resolution get() = IntVector2(width, height)

/**
* Computes dimensions needed to execute a compute shader when computing 2D data.
*
* @param resolution the resolution of the 2D data to compute.
* @param localSizeX the `local_size_x` specified in the compute shader.
* @param localSizeY the `local_size_y` specified in the compute shader.
*/
fun computeShaderExecuteDimensions(
resolution: IntVector2,
localSizeX: Int,
localSizeY: Int
): IntVector3 = IntVector3(
workGroupDimension(resolution.x, localSizeX),
workGroupDimension(resolution.y, localSizeY),
z = 1
)

/**
* Appends given string after `#version x` statement.
*
* Useful for adding `#define` statements to existing shaders.
*
* @param string the string to append.
*/
fun String.appendAfterVersion(
string: String
) = replace(versionRegex) {
"${it.value}\n$string\n"
}

private fun workGroupDimension(
size: Int,
layout: Int
) = ceil(size.toDouble() / layout.toDouble()).toInt()

private val versionRegex = Regex("#version [0-9]+")

49 changes: 49 additions & 0 deletions orx-compute-shaders/src/commonTest/kotlin/TestComputeShaders.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.openrndr.extra.computeshaders

import io.kotest.matchers.shouldBe
import org.openrndr.math.IntVector2
import org.openrndr.math.IntVector3
import kotlin.test.Test

class TestComputeShaders {

@Test
fun testComputeShaderExecuteDimensions() {

computeShaderExecuteDimensions(
resolution = IntVector2(639, 480),
localSizeX = 8,
localSizeY = 8
) shouldBe IntVector3(80, 60, 1)

computeShaderExecuteDimensions(
resolution = IntVector2(640, 480),
localSizeX = 8,
localSizeY = 8
) shouldBe IntVector3(80, 60, 1)

computeShaderExecuteDimensions(
resolution = IntVector2(641, 480),
localSizeX = 8,
localSizeY = 8
) shouldBe IntVector3(81, 60, 1)

computeShaderExecuteDimensions(
resolution = IntVector2(641, 481),
localSizeX = 8,
localSizeY = 8
) shouldBe IntVector3(81, 61, 1)

}

@Test
fun replaceVersion() {
"foo".appendAfterVersion("bar") shouldBe "foo"
"#version 430".appendAfterVersion("#define FOO") shouldBe """
#version 430
#define FOO

""".trimIndent()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import org.openrndr.application
import org.openrndr.draw.ComputeShader
import org.openrndr.draw.colorBuffer
import org.openrndr.draw.font.BufferAccess
import org.openrndr.draw.imageBinding
import org.openrndr.extra.computeshaders.computeShaderExecuteDimensions
import org.openrndr.extra.computeshaders.resolution

/**
* A compute shader computing an image of an arbitrary size. If dimensions of an image are not a multiplicity
* of a workgroup size dimensions (`local_size_x`, `local_size_y`), then excessive calculations will happen,
* and they should be discarded with the initial if statement in the compute shader.
* The [computeShaderExecuteDimensions] function will calculate proper `executeDimensions` for the `ComputeShader`
* outputting such a 2D image.
*/
fun main() = application {
program {
val image = colorBuffer(
width = width - 1, // we are changing to image size to uneven on purpose
height = height -1
)
val shader = ComputeShader.fromCode(
code = """
|#version 430
|layout (local_size_x = 8, local_size_y = 8) in;
|uniform writeonly image2D image;
|uniform ivec2 resolution;
|uniform float seconds;
|
|void main() {
| ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
| if (coord.x >= resolution.x || coord.y >= resolution.y) {
| return;
| }
| vec4 color = vec4(
| coord.x / float(resolution.x),
| coord.y / float(resolution.y),
| sin(seconds) * .5 + .5,
| 1.0
| );
| imageStore(image, coord, color);
|}
""".trimMargin(),
name = "image-computer"
).apply {
uniform("resolution", image.resolution)
image("image", 0, image.imageBinding(0, BufferAccess.WRITE))
}
val executeDimensions = computeShaderExecuteDimensions(
image.resolution,
localSizeX = 8,
localSizeY = 8
)
extend {
shader.uniform("seconds", seconds)
shader.execute(executeDimensions)
drawer.image(image)
}
}
}
41 changes: 41 additions & 0 deletions orx-mesh-generators/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,37 @@ The [demo folder](src/jvmDemo/kotlin) contains examples using these methods.

Check out the [source code](src/commonMain/kotlin) to learn about function arguments.

## Meshes out of point clouds

```kotlin
val resolution = IntVector2(640, 480)
val mesh = PointCloudToMeshGenerator().generate(pointCloud, resolution)
```

This approach is suitable for one time generation, but the mesh `VertexBuffer` can be also updated continuously.

```kotlin
val resolution = IntVector2(640, 480)
val mesh = meshVertexBuffer(resolution)
val generator = PointCloudToMeshGenerator()
// ...
extend {
generator.populate(mesh, pointCloud, resolution)
}
```

All of this can be also achieved for colored point clouds:

```kotlin
val resolution = IntVector2(640, 480)
val mesh = coloredMeshVertexBuffer(resolution)
val generator = ColoredPointCloudToMeshGenerator()
// ...
extend {
generator.populate(mesh, pointCloud, resolution)
}
```

<!-- __demos__ -->
## Demos
### DemoAll
Expand All @@ -95,6 +126,11 @@ Check out the [source code](src/commonMain/kotlin) to learn about function argum

![DemoBoxKt](https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/DemoBoxKt.png)

### DemoColoredHeightMapToMesh
[source code](src/jvmDemo/kotlin/DemoColoredHeightMapToMesh.kt)

![DemoColoredHeightMapToMeshKt](https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/DemoColoredHeightMapToMeshKt.png)

### DemoComplex01
[source code](src/jvmDemo/kotlin/DemoComplex01.kt)

Expand Down Expand Up @@ -154,3 +190,8 @@ Check out the [source code](src/commonMain/kotlin) to learn about function argum
[source code](src/jvmDemo/kotlin/DemoExtrude06.kt)

![DemoExtrude06Kt](https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/DemoExtrude06Kt.png)

### DemoHeightMapToMesh
[source code](src/jvmDemo/kotlin/DemoHeightMapToMesh.kt)

![DemoHeightMapToMeshKt](https://raw.githubusercontent.com/openrndr/orx/media/orx-mesh-generators/images/DemoHeightMapToMeshKt.png)
14 changes: 11 additions & 3 deletions orx-mesh-generators/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,32 @@ plugins {
org.openrndr.extra.convention.`kotlin-multiplatform`
}

val embedShaders = tasks.register<EmbedShadersTask>("embedShaders") {
inputDir.set(file("$projectDir/src/shaders/glsl"))
outputDir.set(layout.buildDirectory.dir("generated/shaderKotlin"))
defaultPackage.set("org.openrndr.extra.meshgenerators")
defaultVisibility.set("internal")
namePrefix.set("meshgenerators_")
}.get()

kotlin {
kotlin.sourceSets.getByName("commonMain").kotlin.srcDir(embedShaders.outputDir)
sourceSets {
@Suppress("UNUSED_VARIABLE")
val commonMain by getting {
dependencies {
api(libs.openrndr.application)
api(libs.openrndr.math)
implementation(project(":orx-shapes"))
implementation(project(":orx-compute-shaders"))
}
}

@Suppress("UNUSED_VARIABLE")
val jvmDemo by getting {
dependencies {
implementation(project(":orx-shapes"))
implementation(project(":orx-mesh-generators"))
implementation(project(":orx-camera"))
implementation(project(":orx-noise"))
implementation(project(":orx-point-clouds"))
}
}
}
Expand Down
Loading
Loading