-
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.
[orx-noise] Add Rseq and Hammersley sequences
- Loading branch information
Showing
9 changed files
with
397 additions
and
0 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
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,75 @@ | ||
package org.openrndr.extra.noise.hammersley | ||
|
||
import org.openrndr.math.Vector2 | ||
import org.openrndr.math.Vector3 | ||
import org.openrndr.math.Vector4 | ||
|
||
/** | ||
* Computes a 2D Hammersley point based on the given index and total number of samples. | ||
* | ||
* @param i The index of the sample, typically in the range [0, n). | ||
* @param n The total number of samples. | ||
* @return A 2D point as a `Vector2` within the unit square [0, 1] x [0, 1]. | ||
*/ | ||
fun hammersley2D(i: Int, n: Int): Vector2 { | ||
return Vector2(i.toDouble() / n, radicalInverseBase2(i.toUInt())) | ||
} | ||
|
||
/** | ||
* Computes a 3D point in the Hammersley sequence based on the given index and total number of samples. | ||
* | ||
* @param i The index of the sample, typically in the range [0, n). | ||
* @param n The total number of samples. | ||
* @return A 3D point as a `Vector3` within the unit cube [0, 1] x [0, 1] x [0, 1]. | ||
*/ | ||
fun hammersley3D(i: Int, n: Int): Vector3 { | ||
return Vector3(i.toDouble() / n, radicalInverseBase2(i.toUInt()), radicalInverse(3, i)) | ||
} | ||
|
||
/** | ||
* Computes a 4D Hammersley point based on the given index and total number of samples. | ||
* | ||
* @param i The index of the sample, typically in the range [0, n). | ||
* @param n The total number of samples. | ||
* @return A 4D point as a `Vector4` where each component lies within the range [0, 1]. | ||
*/ | ||
fun hammersley4D(i: Int, n: Int): Vector4 { | ||
return Vector4(i.toDouble() / n, radicalInverseBase2(i.toUInt()), radicalInverse(3, i), radicalInverse(5, i)) | ||
} | ||
|
||
/** | ||
* Computes the radical inverse of a given unsigned integer `i` in base 2. | ||
* | ||
* @param i The input unsigned integer for which the radical inverse in base 2 is computed. | ||
* @return The radical inverse value of the input as a `Double`, mapped to the range [0, 1). | ||
*/ | ||
fun radicalInverseBase2(i: UInt): Double { | ||
var bits = i | ||
bits = ((bits shl 16) or (bits shr 16)) | ||
bits = ((bits and 0x55555555u) shl 1) or ((bits and 0xAAAAAAAAu) shr 1) | ||
bits = ((bits and 0x33333333u) shl 2) or ((bits and 0xCCCCCCCCu) shr 2) | ||
bits = ((bits and 0x0F0F0F0Fu) shl 4) or ((bits and 0xF0F0F0F0u) shr 4) | ||
bits = ((bits and 0x00FF00FFu) shl 8) or ((bits and 0xFF00FF00u) shr 8) | ||
return bits.toDouble() * 2.3283064365386963e-10 | ||
} | ||
|
||
/** | ||
* Computes the radical inverse of an integer `i` in a given base. | ||
* This method is often used in quasi-random sequence generation for sampling. | ||
* | ||
* @param base The base in which to compute the radical inverse. Must be greater than 1. | ||
* @param i The integer for which the radical inverse is calculated. Must be non-negative. | ||
* @return The radical inverse value as a `Double`, within the range [0, 1). | ||
*/ | ||
fun radicalInverse(base: Int, i: Int): Double { | ||
var v = 0.0 | ||
var denom = 1.0 | ||
var n = i | ||
while (n > 0) { | ||
denom *= base | ||
val remainder = n.mod(base) | ||
n /= base | ||
v += remainder / denom | ||
} | ||
return v | ||
} |
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,67 @@ | ||
package org.openrndr.extra.noise.rsequence | ||
|
||
import org.openrndr.math.Vector2 | ||
import org.openrndr.math.Vector3 | ||
import org.openrndr.math.Vector4 | ||
|
||
private const val g1 = 1.618033988749895 | ||
private const val a11 = 1.0 / g1 | ||
|
||
private const val g2 = 1.324717957244746 | ||
private const val a21 = 1.0 / g2 | ||
private const val a22 = 1.0 / (g2 * g2) | ||
|
||
private const val g3 = 1.2207440846057596 | ||
private const val a31 = 1.0 / g3 | ||
private const val a32 = 1.0 / (g3 * g3) | ||
private const val a33 = 1.0 / (g3 * g3 * g3) | ||
|
||
private const val g4 = 1.1673039782614187 | ||
private const val a41 = 1.0 / g4 | ||
private const val a42 = 1.0 / (g4 * g4) | ||
private const val a43 = 1.0 / (g4 * g4 * g4) | ||
private const val a44 = 1.0 / (g4 * g4 * g4 * g4) | ||
|
||
/** | ||
* Computes the R1 low-discrepancy quasirandom sequence value for a given index as described by Martin Roberts. | ||
* | ||
* @param n The index for which the R1 sequence value is to be calculated. | ||
* @return The R1 sequence value as a Double, providing a low-discrepancy quasirandom number. | ||
*/ | ||
fun rSeq1D(n: Int): Double = (0.5 + a11 * n).mod(1.0) | ||
|
||
/** | ||
* Computes the R2 low-discrepancy quasirandom sequence value for a given index as described by Martin Roberts. | ||
* | ||
* @param n The index for which the R2 sequence value is to be calculated. | ||
* @return The R2 sequence value as a [Vector2], providing a low-discrepancy quasirandom number. | ||
*/ | ||
fun rSeq2D(n: Int): Vector2 = Vector2( | ||
(0.5 + a21 * n).mod(1.0), | ||
(0.5 + a22 * n).mod(1.0) | ||
) | ||
|
||
/** | ||
* Computes the R3 low-discrepancy quasirandom sequence value for a given index as described by Martin Roberts. | ||
* | ||
* @param n The index for which the R3 sequence value is to be calculated. | ||
* @return The R3 sequence value as a [Vector3], providing a low-discrepancy quasirandom number. | ||
*/ | ||
fun rSeq3D(n: Int): Vector3 = Vector3( | ||
(0.5 + a31 * n).mod(1.0), | ||
(0.5 + a32 * n).mod(1.0), | ||
(0.5 + a33 * n).mod(1.0) | ||
) | ||
|
||
/** | ||
* Computes the R4 low-discrepancy quasirandom sequence value for a given index as described by Martin Roberts. | ||
* | ||
* @param n The index for which the R4 sequence value is to be calculated. | ||
* @return The R4 sequence value as a [Vector4], providing a low-discrepancy quasirandom number. | ||
*/ | ||
fun rSeq4D(n: Int): Vector4 = Vector4( | ||
(0.5 + a41 * n).mod(1.0), | ||
(0.5 + a42 * n).mod(1.0), | ||
(0.5 + a43 * n).mod(1.0), | ||
(0.5 + a44 * n).mod(1.0) | ||
) |
29 changes: 29 additions & 0 deletions
29
orx-noise/src/jvmDemo/kotlin/hammersley/DemoHammersley2D01.kt
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,29 @@ | ||
package hammersley | ||
|
||
import org.openrndr.application | ||
import org.openrndr.extra.noise.hammersley.hammersley2D | ||
|
||
/** | ||
* Demo that visualizes a 2D Hammersley point set. | ||
* | ||
* The application is configured to run at 720x720 resolution. The program computes | ||
* 400 2D Hammersley points mapped within the bounds of the application's resolution. | ||
* These points are visualized by rendering circles at their respective positions. | ||
*/ | ||
fun main() { | ||
application { | ||
configure { | ||
width = 720 | ||
height = 720 | ||
} | ||
|
||
program { | ||
extend { | ||
val points = (0 until 400).map { | ||
hammersley2D(it, 400) * 720.0 | ||
} | ||
drawer.circles(points, 5.0) | ||
} | ||
} | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
orx-noise/src/jvmDemo/kotlin/hammersley/DemoHammersley3D01.kt
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,46 @@ | ||
package hammersley | ||
|
||
import org.openrndr.application | ||
import org.openrndr.draw.DrawPrimitive | ||
import org.openrndr.draw.isolated | ||
import org.openrndr.extra.camera.Orbital | ||
import org.openrndr.extra.meshgenerators.sphereMesh | ||
import org.openrndr.extra.noise.hammersley.hammersley3D | ||
import org.openrndr.math.Vector3 | ||
|
||
/** | ||
* Demo program rendering a 3D visualization of points distributed using the Hammersley sequence in 3D space. | ||
* | ||
* The application is set up at a resolution of 720x720 pixels. Within the visual | ||
* program, a sphere mesh is created and a set of 1400 points is generated using | ||
* the Hammersley sequence. Each point is translated and rendered as a small sphere | ||
* in 3D space. This is achieved by mapping the generated points into a scaled domain. | ||
* | ||
* The rendering utilizes the Orbital extension, enabling an interactive 3D camera | ||
* to navigate the scene. The visualization relies on the draw loop for continuous | ||
* rendering of the points. | ||
*/ | ||
fun main() { | ||
application { | ||
configure { | ||
width = 720 | ||
height = 720 | ||
} | ||
|
||
program { | ||
val sphere = sphereMesh(radius = 0.1) | ||
extend(Orbital()) | ||
extend { | ||
val points = (0 until 1400).map { | ||
(hammersley3D(it, 1400) - Vector3(0.5)) * 10.0 | ||
} | ||
for (point in points) { | ||
drawer.isolated { | ||
drawer.translate(point) | ||
drawer.vertexBuffer(sphere, DrawPrimitive.TRIANGLES) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
orx-noise/src/jvmDemo/kotlin/hammersley/DemoHammersley4D01.kt
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,52 @@ | ||
package hammersley | ||
|
||
import org.openrndr.application | ||
import org.openrndr.color.ColorRGBa | ||
import org.openrndr.draw.DrawPrimitive | ||
import org.openrndr.draw.isolated | ||
import org.openrndr.extra.camera.Orbital | ||
import org.openrndr.extra.meshgenerators.sphereMesh | ||
import org.openrndr.extra.noise.hammersley.hammersley4D | ||
import org.openrndr.extra.noise.rsequence.rSeq4D | ||
import org.openrndr.math.Vector4 | ||
import kotlin.math.abs | ||
import kotlin.math.min | ||
|
||
/** | ||
* Demo that visualizes a 4D Hammersley point set in a 3D space, with colors determined by the 4th dimension. | ||
* | ||
* The application is configured at a resolution of 720x720 pixels. A sphere mesh is created | ||
* using the `sphereMesh` utility, and a total of 10,000 4D points are generated with the | ||
* `hammersley4D` sequence. These points are scaled, translated, and rendered as small spheres. | ||
* The color of each sphere is modified based on the 4th dimension of its corresponding point by | ||
* shifting the hue in HSV color space. | ||
* | ||
* This program employs the `Orbital` extension, enabling camera interaction for 3D navigation | ||
* of the scene. Rendering occurs within the draw loop, providing continuous visualization | ||
* of the point distribution. | ||
*/ | ||
fun main() { | ||
application { | ||
configure { | ||
width = 720 | ||
height = 720 | ||
} | ||
|
||
program { | ||
val sphere = sphereMesh(radius = 0.1) | ||
extend(Orbital()) | ||
extend { | ||
val points = (0 until 10000).map { | ||
(hammersley4D(it, 10000) - Vector4(0.5, 0.5, 0.5, 0.0)) * Vector4(10.0, 10.0, 10.0, 1.0) | ||
} | ||
for (point in points) { | ||
drawer.isolated { | ||
drawer.translate(point.xyz) | ||
drawer.fill = ColorRGBa.RED.toHSVa().shiftHue(point.w * 360.0).toRGBa() | ||
drawer.vertexBuffer(sphere, DrawPrimitive.TRIANGLES) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
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,27 @@ | ||
package rseq | ||
|
||
import org.openrndr.application | ||
import org.openrndr.extra.noise.rsequence.rSeq2D | ||
|
||
/** | ||
* This demo sets up a window with dimensions 720x720 and renders frames | ||
* demonstrating 2D quasirandomly distributed points. The points are generated | ||
* using the R2 sequence and drawn as circles with a radius of 5.0. | ||
*/ | ||
fun main() { | ||
application { | ||
configure { | ||
width = 720 | ||
height = 720 | ||
} | ||
|
||
program { | ||
extend { | ||
val points = (0 until 4000).map { | ||
rSeq2D(it) * 720.0 | ||
} | ||
drawer.circles(points, 5.0) | ||
} | ||
} | ||
} | ||
} |
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,45 @@ | ||
package rseq | ||
|
||
import org.openrndr.application | ||
import org.openrndr.draw.DrawPrimitive | ||
import org.openrndr.draw.isolated | ||
import org.openrndr.extra.camera.Orbital | ||
import org.openrndr.extra.meshgenerators.sphereMesh | ||
import org.openrndr.extra.noise.rsequence.rSeq3D | ||
import org.openrndr.math.Vector3 | ||
|
||
/** | ||
* This demo renders a 3D visualizationof points distributed using the R3 quasirandom sequence. Each point is | ||
* represented as a sphere and positioned in 3D space based on the quasirandom sequence values. | ||
* | ||
* The visualization setup includes: | ||
* - Configuration of application window size to 720x720. | ||
* - Usage of an orbital camera for interactive 3D navigation. | ||
* - Creation of a reusable sphere mesh with a specified radius. | ||
* - Generation of quasirandom points in 3D space using the `rSeq3D` function. | ||
* - Transformation and rendering of each point as a sphere using vertex buffers. | ||
*/ | ||
fun main() { | ||
application { | ||
configure { | ||
width = 720 | ||
height = 720 | ||
} | ||
|
||
program { | ||
val sphere = sphereMesh(radius = 0.1) | ||
extend(Orbital()) | ||
extend { | ||
val points = (0 until 1400).map { | ||
(rSeq3D(it) - Vector3(0.5)) * 10.0 | ||
} | ||
for (point in points) { | ||
drawer.isolated { | ||
drawer.translate(point) | ||
drawer.vertexBuffer(sphere, DrawPrimitive.TRIANGLES) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.