This commit is contained in:
Edwin Jakobs
2019-01-26 21:24:58 +01:00
parent a3385abee0
commit 149a7fd183
42 changed files with 2758 additions and 2291 deletions

View File

@@ -1,42 +1,42 @@
# ORX (OPENRNDR EXTRA) # ORX (OPENRNDR EXTRA)
[![](https://jitpack.io/v/openrndr/orx.svg)](https://jitpack.io/#openrndr/orx) [![](https://jitpack.io/v/openrndr/orx.svg)](https://jitpack.io/#openrndr/orx)
A growing library of assorted data structures, algorithms and utilities. A growing library of assorted data structures, algorithms and utilities.
- [`orx-camera`](orx-camera/README.md), 3d camera and controls - [`orx-camera`](orx-camera/README.md), 3d camera and controls
- [`orx-compositor`](orx-compositor/README.md), a simple toolkit to make composite (layered) images - [`orx-compositor`](orx-compositor/README.md), a simple toolkit to make composite (layered) images
- [`orx-filter-extension`](orx-filter-extension/README.md), Program extension method that provides Filter based `extend()` - [`orx-filter-extension`](orx-filter-extension/README.md), Program extension method that provides Filter based `extend()`
- [`orx-integral-image`](orx-integral-image/README.md), a CPU-based implementation for integral images (summed area tables) - [`orx-integral-image`](orx-integral-image/README.md), a CPU-based implementation for integral images (summed area tables)
- `orx-jumpflood`, a filter/shader based implementation of the jump flood algorithm for finding fast approximate (directional) distance fields - `orx-jumpflood`, a filter/shader based implementation of the jump flood algorithm for finding fast approximate (directional) distance fields
- `orx-kdtree`, a kd-tree implementation for fast nearest point searches - `orx-kdtree`, a kd-tree implementation for fast nearest point searches
- [`orx-mesh-generators`](orx-mesh-generators/README.md), triangular mesh generators - [`orx-mesh-generators`](orx-mesh-generators/README.md), triangular mesh generators
- [`orx-noise`](orx-noise/README.md), library for random number generation and noise - [`orx-noise`](orx-noise/README.md), library for random number generation and noise
- [`orx-no-clear`](orx-no-clear/README.md), a simple extension that provides drawing without clearing the background - [`orx-no-clear`](orx-no-clear/README.md), a simple extension that provides drawing without clearing the background
- [`orx-obj-loader`](orx-obj-loader/README.md), simple Wavefront .obj mesh loader - [`orx-obj-loader`](orx-obj-loader/README.md), simple Wavefront .obj mesh loader
## Usage ## Usage
ORX 0.0.19 is built against OPENRNDR 0.3.32, make sure you use this version in your project. Because OPENRNDR's API is pre 1.0 it tends to change from time to time. ORX 0.0.19 is built against OPENRNDR 0.3.32, make sure you use this version in your project. Because OPENRNDR's API is pre 1.0 it tends to change from time to time.
The easiest way to add ORX to your project is through the use of Jitpack. [Jitpack](http://jitpack.io) is a service that pulls Gradle based libraries from Github, builds them and serves the jar files. The easiest way to add ORX to your project is through the use of Jitpack. [Jitpack](http://jitpack.io) is a service that pulls Gradle based libraries from Github, builds them and serves the jar files.
To setup Jitpack support in your project all you have to do is add the Jitpack repository to your `repositories {}`. It is advised to have the jitpack repository as the last entry. To setup Jitpack support in your project all you have to do is add the Jitpack repository to your `repositories {}`. It is advised to have the jitpack repository as the last entry.
``` ```
repositories { repositories {
maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
} }
``` ```
You can then add any of the ORX artefacts to your `dependencies {}`: You can then add any of the ORX artefacts to your `dependencies {}`:
``` ```
dependencies { dependencies {
compile 'com.github.openrndr.orx:<orx-artifact>:v0.0.19' compile 'com.github.openrndr.orx:<orx-artifact>:v0.0.19'
} }
``` ```
For example if you want to use the `orx-no-clear` artifact one would use: For example if you want to use the `orx-no-clear` artifact one would use:
``` ```
dependencies { dependencies {
compile 'com.github.openrndr.orx:orx-no-clear:v0.0.19' compile 'com.github.openrndr.orx:orx-no-clear:v0.0.19'
} }
``` ```

24
ShaderError.txt Normal file
View File

@@ -0,0 +1,24 @@
#version 330 core
uniform sampler2D tex0;
in vec2 v_texCoord0;
out vec4 o_color;
void main() {
vec2 step = 1.0 / textureSize(tex0, 0);
float ref = step(0.5 , texture(tex0, v_texCoord0).r);
vec4 outc = vec4(-1.0, -1.0, 0.0, 1.0);
float contour = 0.0;
for (y = -1; y <= 1; ++y) {
for (x = -1; x <= 1; ++x) {
float smp = step(0.5, texture(tex0, v_texCoord0 + vec2(x,y) * step).r);
if (smp != ref) {
contour = 1.0;
}
}
}
o_color = vec4(contour, contour, contour, 1.0);
}

View File

@@ -1,67 +1,67 @@
plugins { plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.10' id 'org.jetbrains.kotlin.jvm' version '1.3.10'
} }
allprojects { allprojects {
group 'org.openrndr.extra' group 'org.openrndr.extra'
version '0.0.19' version '0.0.20'
} }
repositories { repositories {
mavenLocal() mavenLocal()
mavenCentral() mavenCentral()
} }
ext { ext {
openrndrVersion = "0.3.32-rc1" openrndrVersion = "0.3.32-rc1"
} }
subprojects { subprojects {
apply plugin: 'kotlin' apply plugin: 'kotlin'
apply plugin: 'maven' apply plugin: 'maven'
apply plugin: 'maven-publish' apply plugin: 'maven-publish'
repositories { repositories {
mavenLocal() mavenLocal()
mavenCentral() mavenCentral()
maven { maven {
url = "https://dl.bintray.com/openrndr/openrndr" url = "https://dl.bintray.com/openrndr/openrndr"
} }
} }
dependencies { dependencies {
compile "org.openrndr:openrndr-core:$openrndrVersion" compile "org.openrndr:openrndr-core:$openrndrVersion"
compile "org.openrndr:openrndr-filter:$openrndrVersion" compile "org.openrndr:openrndr-filter:$openrndrVersion"
compile "org.openrndr:openrndr-shape:$openrndrVersion" compile "org.openrndr:openrndr-shape:$openrndrVersion"
compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.0.1' compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.0.1'
} }
publishing { publishing {
publications { publications {
mavenJava(MavenPublication) { mavenJava(MavenPublication) {
from components.java from components.java
artifact sourceJar artifact sourceJar
} }
} }
} }
task sourceJar(type: Jar) { task sourceJar(type: Jar) {
classifier = 'sources' classifier = 'sources'
from sourceSets.main.kotlin from sourceSets.main.kotlin
} }
} }
dependencies { dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8" compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
} }
compileKotlin { compileKotlin {
kotlinOptions.jvmTarget = "1.8" kotlinOptions.jvmTarget = "1.8"
} }
compileTestKotlin { compileTestKotlin {
kotlinOptions.jvmTarget = "1.8" kotlinOptions.jvmTarget = "1.8"
} }

View File

@@ -1,3 +1,3 @@
# orx-camera # orx-camera
3D camera and controls for OPENRNDR. This supersedes the to be deprecated functionality in OPENRNDR. 3D camera and controls for OPENRNDR. This supersedes the to be deprecated functionality in OPENRNDR.

View File

@@ -1,74 +1,74 @@
package org.openrndr.extras.camera package org.openrndr.extras.camera
import org.openrndr.Extension import org.openrndr.Extension
import org.openrndr.Program import org.openrndr.Program
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.draw.* import org.openrndr.draw.*
import org.openrndr.math.Matrix44 import org.openrndr.math.Matrix44
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
@Suppress("unused") @Suppress("unused")
class Debug3D(eye: Vector3 = Vector3(0.0, 0.0, 10.0), lookAt: Vector3 = Vector3.ZERO, private val fov: Double = 90.0) : Extension { class Debug3D(eye: Vector3 = Vector3(0.0, 0.0, 10.0), lookAt: Vector3 = Vector3.ZERO, fov:Double = 90.0) : Extension {
override var enabled: Boolean = true override var enabled: Boolean = true
var showGrid = false var showGrid = false
val orbitalCamera = OrbitalCamera(eye, lookAt) val orbitalCamera = OrbitalCamera(eye, lookAt, 90.0)
private val orbitalControls = OrbitalControls(orbitalCamera) private val orbitalControls = OrbitalControls(orbitalCamera)
private var lastSeconds: Double = -1.0 private var lastSeconds: Double = -1.0
private val grid = vertexBuffer( private val grid = vertexBuffer(
vertexFormat { vertexFormat {
position(3) position(3)
} }
, 4 * 21).apply { , 4 * 21).apply {
put { put {
for (x in -10..10) { for (x in -10..10) {
write(Vector3(x.toDouble(), 0.0, -10.0)) write(Vector3(x.toDouble(), 0.0, -10.0))
write(Vector3(x.toDouble(), 0.0, 10.0)) write(Vector3(x.toDouble(), 0.0, 10.0))
write(Vector3(-10.0, 0.0, x.toDouble())) write(Vector3(-10.0, 0.0, x.toDouble()))
write(Vector3(10.0, 0.0, x.toDouble())) write(Vector3(10.0, 0.0, x.toDouble()))
} }
} }
} }
override fun beforeDraw(drawer: Drawer, program: Program) { override fun beforeDraw(drawer: Drawer, program: Program) {
if (lastSeconds == -1.0) lastSeconds = program.seconds if (lastSeconds == -1.0) lastSeconds = program.seconds
val delta = program.seconds - lastSeconds val delta = program.seconds - lastSeconds
lastSeconds = program.seconds lastSeconds = program.seconds
orbitalCamera.update(delta) orbitalCamera.update(delta)
drawer.background(ColorRGBa.BLACK) drawer.background(ColorRGBa.BLACK)
drawer.perspective(fov, program.window.size.x / program.window.size.y, 0.1, 1000.0) drawer.perspective(orbitalCamera.fov, program.window.size.x / program.window.size.y, 0.1, 1000.0)
drawer.view = orbitalCamera.viewMatrix() drawer.view = orbitalCamera.viewMatrix()
if (showGrid) { if (showGrid) {
drawer.isolated { drawer.isolated {
drawer.fill = ColorRGBa.WHITE drawer.fill = ColorRGBa.WHITE
drawer.stroke = ColorRGBa.WHITE drawer.stroke = ColorRGBa.WHITE
drawer.vertexBuffer(grid, DrawPrimitive.LINES) drawer.vertexBuffer(grid, DrawPrimitive.LINES)
// Axis cross // Axis cross
drawer.fill = ColorRGBa.RED drawer.fill = ColorRGBa.RED
drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_X) drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_X)
drawer.fill = ColorRGBa.GREEN drawer.fill = ColorRGBa.GREEN
drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Y) drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Y)
drawer.fill = ColorRGBa.BLUE drawer.fill = ColorRGBa.BLUE
drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Z) drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Z)
} }
} }
} }
override fun afterDraw(drawer: Drawer, program: Program) { override fun afterDraw(drawer: Drawer, program: Program) {
drawer.isolated { drawer.isolated {
drawer.view = Matrix44.IDENTITY drawer.view = Matrix44.IDENTITY
drawer.ortho() drawer.ortho()
} }
} }
override fun setup(program: Program) { override fun setup(program: Program) {
orbitalControls.setup(program) orbitalControls.setup(program)
} }
} }

View File

@@ -1,120 +1,139 @@
package org.openrndr.extras.camera package org.openrndr.extras.camera
import org.openrndr.* import org.openrndr.*
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.draw.DrawPrimitive import org.openrndr.draw.DrawPrimitive
import org.openrndr.draw.Drawer import org.openrndr.draw.Drawer
import org.openrndr.draw.isolated import org.openrndr.draw.isolated
import org.openrndr.draw.vertexBuffer import org.openrndr.draw.vertexBuffer
import org.openrndr.draw.vertexFormat import org.openrndr.draw.vertexFormat
import org.openrndr.math.Matrix44 import org.openrndr.math.Matrix44
import org.openrndr.math.Spherical import org.openrndr.math.Spherical
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import org.openrndr.math.transforms.lookAt as lookAt_ import org.openrndr.math.transforms.lookAt as lookAt_
class OrbitalCamera(eye: Vector3, lookAt: Vector3) { class OrbitalCamera(eye: Vector3, lookAt: Vector3, var fov:Double) {
// current position in spherical coordinates
var spherical = Spherical.fromVector(eye) // current position in spherical coordinates
private set var spherical = Spherical.fromVector(eye)
var lookAt = lookAt private set
private set var lookAt = lookAt
private set
private var sphericalEnd = Spherical.fromVector(eye)
private var lookAtEnd = lookAt.copy() private var sphericalEnd = Spherical.fromVector(eye)
private var dirty: Boolean = true private var lookAtEnd = lookAt.copy()
private var dirty: Boolean = true
var dampingFactor = 0.05
var zoomSpeed = 1.0 var fovEnd = fov
fun rotate(rotX: Double, rotY: Double) { var dampingFactor = 0.05
sphericalEnd += Spherical(0.0, rotX, rotY) var zoomSpeed = 1.0
sphericalEnd = sphericalEnd.makeSafe()
dirty = true fun setView(lookAt: Vector3, spherical: Spherical, fov:Double) {
} this.lookAt = lookAt
this.lookAtEnd = lookAt
fun rotateTo(rotX: Double, rotY: Double) { this.spherical = spherical
sphericalEnd = sphericalEnd.copy(theta = rotX, phi = rotY) this.sphericalEnd = spherical
sphericalEnd = sphericalEnd.makeSafe() this.fov = fov
dirty = true this.fovEnd= fov
} }
fun rotateTo(eye: Vector3) { fun rotate(rotX: Double, rotY: Double) {
sphericalEnd = Spherical.fromVector(eye) sphericalEnd += Spherical(0.0, rotX, rotY)
sphericalEnd = sphericalEnd.makeSafe() sphericalEnd = sphericalEnd.makeSafe()
dirty = true dirty = true
} }
fun dollyIn() { fun rotateTo(rotX: Double, rotY: Double) {
val zoomScale = Math.pow(0.95, zoomSpeed) sphericalEnd = sphericalEnd.copy(theta = rotX, phi = rotY)
dolly(sphericalEnd.radius * zoomScale - sphericalEnd.radius) sphericalEnd = sphericalEnd.makeSafe()
} dirty = true
}
fun dollyOut() {
val zoomScale = Math.pow(0.95, zoomSpeed) fun rotateTo(eye: Vector3) {
dolly(sphericalEnd.radius / zoomScale - sphericalEnd.radius) sphericalEnd = Spherical.fromVector(eye)
} sphericalEnd = sphericalEnd.makeSafe()
dirty = true
private fun dolly(distance: Double) { }
sphericalEnd += Spherical(distance, 0.0, 0.0)
dirty = true fun dollyIn() {
} val zoomScale = Math.pow(0.95, zoomSpeed)
dolly(sphericalEnd.radius * zoomScale - sphericalEnd.radius)
fun pan(x: Double, y: Double, z: Double) { }
val view = viewMatrix()
val xColumn = Vector3(view.c0r0, view.c1r0, view.c2r0) * x fun dollyOut() {
val yColumn = Vector3(view.c0r1, view.c1r1, view.c2r1) * y val zoomScale = Math.pow(0.95, zoomSpeed)
val zColumn = Vector3(view.c0r2, view.c1r2, view.c2r2) * z dolly(sphericalEnd.radius / zoomScale - sphericalEnd.radius)
lookAtEnd += xColumn + yColumn + zColumn }
dirty = true
} fun dolly(distance: Double) {
sphericalEnd += Spherical(distance, 0.0, 0.0)
fun panTo(target : Vector3) { dirty = true
lookAtEnd = target }
dirty = true
} fun pan(x: Double, y: Double, z: Double) {
val view = viewMatrix()
fun dollyTo(distance: Double) { val xColumn = Vector3(view.c0r0, view.c1r0, view.c2r0) * x
sphericalEnd = sphericalEnd.copy(radius = distance ) val yColumn = Vector3(view.c0r1, view.c1r1, view.c2r1) * y
dirty = true val zColumn = Vector3(view.c0r2, view.c1r2, view.c2r2) * z
} lookAtEnd += xColumn + yColumn + zColumn
dirty = true
fun update(timeDelta: Double) { }
if (!dirty) return
dirty = false fun panTo(target : Vector3) {
lookAtEnd = target
val dampingFactor = dampingFactor * timeDelta / 0.0060 dirty = true
val sphericalDelta = sphericalEnd - spherical }
val lookAtDelta = lookAtEnd - lookAt
fun dollyTo(distance: Double) {
if ( sphericalEnd = sphericalEnd.copy(radius = distance )
Math.abs(sphericalEnd.radius) > EPSILON || dirty = true
Math.abs(sphericalEnd.theta) > EPSILON || }
Math.abs(sphericalEnd.phi) > EPSILON ||
Math.abs(lookAtDelta.x) > EPSILON || fun zoom(degrees: Double) {
Math.abs(lookAtDelta.y) > EPSILON || fovEnd += degrees
Math.abs(lookAtDelta.z) > EPSILON }
) {
fun update(timeDelta: Double) {
spherical += (sphericalDelta * dampingFactor) if (!dirty) return
lookAt += (lookAtDelta * dampingFactor) dirty = false
dirty = true
val dampingFactor = dampingFactor * timeDelta / 0.0060
} else { val sphericalDelta = sphericalEnd - spherical
spherical = sphericalEnd.copy() val lookAtDelta = lookAtEnd - lookAt
lookAt = lookAtEnd.copy() val fovDelta = fovEnd - fov
} if (
spherical = spherical.makeSafe() Math.abs(sphericalEnd.radius) > EPSILON ||
} Math.abs(sphericalEnd.theta) > EPSILON ||
Math.abs(sphericalEnd.phi) > EPSILON ||
fun viewMatrix(): Matrix44 { Math.abs(lookAtDelta.x) > EPSILON ||
return lookAt_(Vector3.fromSpherical(spherical) + lookAt, lookAt, Vector3.UNIT_Y) Math.abs(lookAtDelta.y) > EPSILON ||
} Math.abs(lookAtDelta.z) > EPSILON ||
Math.abs(fovDelta) > EPSILON
companion object { ) {
private const val EPSILON = 0.000001
} fov += (fovDelta * dampingFactor)
} spherical += (sphericalDelta * dampingFactor)
spherical = spherical.makeSafe()
lookAt += (lookAtDelta * dampingFactor)
dirty = true
} else {
spherical = sphericalEnd.copy()
lookAt = lookAtEnd.copy()
}
spherical = spherical.makeSafe()
}
fun viewMatrix(): Matrix44 {
return lookAt_(Vector3.fromSpherical(spherical) + lookAt, lookAt, Vector3.UNIT_Y)
}
companion object {
private const val EPSILON = 0.000001
}
}

View File

@@ -1,100 +1,128 @@
package org.openrndr.extras.camera package org.openrndr.extras.camera
import org.openrndr.* import org.openrndr.*
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
class OrbitalControls(val orbitalCamera: OrbitalCamera) { class OrbitalControls(val orbitalCamera: OrbitalCamera) {
enum class STATE { enum class STATE {
NONE, NONE,
ROTATE, ROTATE,
PAN, PAN,
} }
private var state = STATE.NONE private var state = STATE.NONE
var fov = 90.0 var fov = 90.0
private lateinit var program: Program private lateinit var program: Program
private lateinit var lastMousePosition: Vector2 private lateinit var lastMousePosition: Vector2
private fun mouseScrolled(event: MouseEvent) { private fun mouseScrolled(event: MouseEvent) {
if (Math.abs(event.rotation.x) > 0.1) return if (Math.abs(event.rotation.x) > 0.1) return
when { when {
event.rotation.y > 0 -> orbitalCamera.dollyIn() event.rotation.y > 0 -> orbitalCamera.dollyIn()
event.rotation.y < 0 -> orbitalCamera.dollyOut() event.rotation.y < 0 -> orbitalCamera.dollyOut()
} }
} }
private fun mouseMoved(event: MouseEvent) { private fun mouseMoved(event: MouseEvent) {
if (state == STATE.NONE) return if (state == STATE.NONE) return
val delta = lastMousePosition - event.position val delta = lastMousePosition - event.position
lastMousePosition = event.position lastMousePosition = event.position
if (state == STATE.PAN) { if (state == STATE.PAN) {
val offset = Vector3.fromSpherical(orbitalCamera.spherical) - orbitalCamera.lookAt val offset = Vector3.fromSpherical(orbitalCamera.spherical) - orbitalCamera.lookAt
// half of the fov is center to top of screen // half of the fov is center to top of screen
val targetDistance = offset.length * Math.tan((fov / 2) * Math.PI / 180) val targetDistance = offset.length * Math.tan((fov / 2) * Math.PI / 180)
val panX = (2 * delta.x * targetDistance / program.window.size.x) val panX = (2 * delta.x * targetDistance / program.window.size.x)
val panY = (2 * delta.y * targetDistance / program.window.size.y) val panY = (2 * delta.y * targetDistance / program.window.size.y)
orbitalCamera.pan(panX, -panY, 0.0) orbitalCamera.pan(panX, -panY, 0.0)
} else { } else {
val rotX = 2 * Math.PI * delta.x / program.window.size.x val rotX = 2 * Math.PI * delta.x / program.window.size.x
val rotY = 2 * Math.PI * delta.y / program.window.size.y val rotY = 2 * Math.PI * delta.y / program.window.size.y
orbitalCamera.rotate(rotX, rotY) orbitalCamera.rotate(rotX, rotY)
} }
} }
private fun mouseButtonDown(event: MouseEvent) { private fun mouseButtonDown(event: MouseEvent) {
val previousState = state val previousState = state
when (event.button) { when (event.button) {
MouseButton.LEFT -> { MouseButton.LEFT -> {
state = STATE.ROTATE state = STATE.ROTATE
} }
MouseButton.RIGHT -> { MouseButton.RIGHT -> {
state = STATE.PAN state = STATE.PAN
} }
MouseButton.CENTER -> { MouseButton.CENTER -> {
} }
MouseButton.NONE -> { MouseButton.NONE -> {
} }
} }
if (previousState == STATE.NONE) { if (previousState == STATE.NONE) {
lastMousePosition = event.position lastMousePosition = event.position
} }
} }
fun keyPressed(keyEvent: KeyEvent) { fun keyPressed(keyEvent: KeyEvent) {
if (keyEvent.key == KEY_ARROW_RIGHT) { if (keyEvent.key == KEY_ARROW_RIGHT) {
orbitalCamera.pan(1.0, 0.0, 0.0) orbitalCamera.pan(1.0, 0.0, 0.0)
} }
if (keyEvent.key == KEY_ARROW_LEFT) { if (keyEvent.key == KEY_ARROW_LEFT) {
orbitalCamera.pan(-1.0, 0.0, 0.0) orbitalCamera.pan(-1.0, 0.0, 0.0)
} }
if (keyEvent.key == KEY_ARROW_UP) { if (keyEvent.key == KEY_ARROW_UP) {
orbitalCamera.pan(0.0, 1.0, 0.0) orbitalCamera.pan(0.0, 1.0, 0.0)
} }
if (keyEvent.key == KEY_ARROW_DOWN) { if (keyEvent.key == KEY_ARROW_DOWN) {
orbitalCamera.pan(0.0, -1.0, 0.0) orbitalCamera.pan(0.0, -1.0, 0.0)
} }
}
if (keyEvent.name == "q") {
fun setup(program: Program) { orbitalCamera.pan(0.0, -1.0, 0.0)
this.program = program }
program.mouse.moved.listen { mouseMoved(it) } if (keyEvent.name == "e") {
program.mouse.buttonDown.listen { mouseButtonDown(it) } orbitalCamera.pan(0.0, 1.0, 0.0)
program.mouse.buttonUp.listen { state = STATE.NONE } }
program.mouse.scrolled.listen { mouseScrolled(it) } if (keyEvent.name == "w") {
program.keyboard.keyDown.listen { keyPressed(it) } orbitalCamera.pan(0.0, 0.0, -1.0)
program.keyboard.keyRepeat.listen{ keyPressed(it) } }
} if (keyEvent.name == "s") {
} orbitalCamera.pan(0.0, 0.0, 1.0)
}
if (keyEvent.name == "a") {
orbitalCamera.pan(-1.0, 0.0, 0.0)
}
if (keyEvent.name == "d") {
orbitalCamera.pan(1.0, 0.0, 0.0)
}
if (keyEvent.key == KEY_PAGE_UP) {
orbitalCamera.zoom(1.0)
}
if (keyEvent.key == KEY_PAGE_DOWN) {
orbitalCamera.zoom(-1.0)
}
}
fun setup(program: Program) {
this.program = program
program.mouse.moved.listen { mouseMoved(it) }
program.mouse.buttonDown.listen { mouseButtonDown(it) }
program.mouse.buttonUp.listen { state = STATE.NONE }
program.mouse.scrolled.listen { mouseScrolled(it) }
program.keyboard.keyDown.listen { keyPressed(it) }
program.keyboard.keyRepeat.listen{ keyPressed(it) }
}
}

View File

@@ -1,138 +1,138 @@
package org.openrndr.extra.compositor package org.openrndr.extra.compositor
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.draw.* import org.openrndr.draw.*
import org.openrndr.math.Matrix44 import org.openrndr.math.Matrix44
private val postBufferCache = mutableListOf<ColorBuffer>() private val postBufferCache = mutableListOf<ColorBuffer>()
fun RenderTarget.deepDestroy() { fun RenderTarget.deepDestroy() {
val cbcopy = colorBuffers.map { it} val cbcopy = colorBuffers.map { it}
val dbcopy = depthBuffer val dbcopy = depthBuffer
detachDepthBuffer() detachDepthBuffer()
detachColorBuffers() detachColorBuffers()
cbcopy.forEach { cbcopy.forEach {
it.destroy() it.destroy()
} }
dbcopy?.destroy() dbcopy?.destroy()
destroy() destroy()
} }
/** /**
* A single layer representation * A single layer representation
*/ */
class Layer internal constructor() { class Layer internal constructor() {
var drawFunc: () -> Unit = {} var drawFunc: () -> Unit = {}
val children: MutableList<Layer> = mutableListOf() val children: MutableList<Layer> = mutableListOf()
var blendFilter: Pair<Filter, Filter.() -> Unit>? = null var blendFilter: Pair<Filter, Filter.() -> Unit>? = null
val postFilters: MutableList<Pair<Filter, Filter.() -> Unit>> = mutableListOf() val postFilters: MutableList<Pair<Filter, Filter.() -> Unit>> = mutableListOf()
private var layerTarget:RenderTarget? = null private var layerTarget:RenderTarget? = null
/** /**
* draw the layer * draw the layer
*/ */
fun draw(drawer: Drawer) { fun draw(drawer: Drawer) {
val rt = RenderTarget.active val rt = RenderTarget.active
val llt = layerTarget val llt = layerTarget
if (llt == null || (llt.width != rt.width || llt.height != rt.height)) { if (llt == null || (llt.width != rt.width || llt.height != rt.height)) {
layerTarget?.deepDestroy() layerTarget?.deepDestroy()
layerTarget = renderTarget(rt.width, rt.height) { layerTarget = renderTarget(rt.width, rt.height) {
colorBuffer() colorBuffer()
depthBuffer() depthBuffer()
} }
} }
layerTarget?.let { target -> layerTarget?.let { target ->
drawer.isolatedWithTarget(target) { drawer.isolatedWithTarget(target) {
drawer.background(ColorRGBa.TRANSPARENT) drawer.background(ColorRGBa.TRANSPARENT)
drawFunc() drawFunc()
children.forEach { children.forEach {
it.draw(drawer) it.draw(drawer)
} }
} }
if (postFilters.size > 0) { if (postFilters.size > 0) {
val sizeMismatch = if (postBufferCache.isNotEmpty()) { val sizeMismatch = if (postBufferCache.isNotEmpty()) {
postBufferCache[0].width != rt.width || postBufferCache[0].height != rt.height postBufferCache[0].width != rt.width || postBufferCache[0].height != rt.height
} else { } else {
false false
} }
if (sizeMismatch) { if (sizeMismatch) {
postBufferCache.forEach { it.destroy() } postBufferCache.forEach { it.destroy() }
postBufferCache.clear() postBufferCache.clear()
} }
if (postBufferCache.isEmpty()) { if (postBufferCache.isEmpty()) {
postBufferCache += colorBuffer(rt.width, rt.height) postBufferCache += colorBuffer(rt.width, rt.height)
postBufferCache += colorBuffer(rt.width, rt.height) postBufferCache += colorBuffer(rt.width, rt.height)
} }
} }
val layerPost = postFilters.let { filters -> val layerPost = postFilters.let { filters ->
val targets = postBufferCache val targets = postBufferCache
val result = filters.foldIndexed(target.colorBuffer(0)) { i, source, filter -> val result = filters.foldIndexed(target.colorBuffer(0)) { i, source, filter ->
val target = targets[i % targets.size] val target = targets[i % targets.size]
filter.first.apply(filter.second) filter.first.apply(filter.second)
filter.first.apply(source, target) filter.first.apply(source, target)
target target
} }
result result
} }
val lblend = blendFilter val lblend = blendFilter
if (lblend == null) { if (lblend == null) {
drawer.isolatedWithTarget(rt) { drawer.isolatedWithTarget(rt) {
//drawer.ortho(rt) //drawer.ortho(rt)
drawer.ortho() drawer.ortho()
drawer.view = Matrix44.IDENTITY drawer.view = Matrix44.IDENTITY
drawer.model = Matrix44.IDENTITY drawer.model = Matrix44.IDENTITY
drawer.image(layerPost, layerPost.bounds, drawer.bounds) drawer.image(layerPost, layerPost.bounds, drawer.bounds)
} }
} else { } else {
lblend.first.apply(lblend.second) lblend.first.apply(lblend.second)
lblend.first.apply(arrayOf(rt.colorBuffer(0), layerPost), rt.colorBuffer(0)) lblend.first.apply(arrayOf(rt.colorBuffer(0), layerPost), rt.colorBuffer(0))
} }
} }
} }
} }
/** /**
* create a layer within the composition * create a layer within the composition
*/ */
fun Layer.layer(function: Layer.() -> Unit) { fun Layer.layer(function: Layer.() -> Unit) {
children.add(Layer().apply { function() }) children.add(Layer().apply { function() })
} }
/** /**
* set the draw contents of the layer * set the draw contents of the layer
*/ */
fun Layer.draw(function: () -> Unit) { fun Layer.draw(function: () -> Unit) {
drawFunc = function drawFunc = function
} }
/** /**
* add a post-processing filter to the layer * add a post-processing filter to the layer
*/ */
fun <F : Filter> Layer.post(filter: F, configure: F.() -> Unit = {}) { fun <F : Filter> Layer.post(filter: F, configure: F.() -> Unit = {}) {
postFilters.add(Pair(filter as Filter, configure as Filter.() -> Unit)) postFilters.add(Pair(filter as Filter, configure as Filter.() -> Unit))
} }
/** /**
* add a blend filter to the layer * add a blend filter to the layer
*/ */
fun <F : Filter> Layer.blend(filter: F, configure: F.() -> Unit = {}) { fun <F : Filter> Layer.blend(filter: F, configure: F.() -> Unit = {}) {
blendFilter = Pair(filter as Filter, configure as Filter.() -> Unit) blendFilter = Pair(filter as Filter, configure as Filter.() -> Unit)
} }
/** /**
* create a layered composition * create a layered composition
*/ */
fun compose(function: Layer.() -> Unit): Layer { fun compose(function: Layer.() -> Unit): Layer {
val root = Layer() val root = Layer()
root.function() root.function()
return root return root
} }

31
orx-examples/build.gradle Normal file
View File

@@ -0,0 +1,31 @@
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.2.71'
}
group 'org.openrndr.extra'
version '0.0.1'
repositories {
mavenCentral()
maven {
url "https://dl.bintray.com/openrndr/openrndr"
}
}
ext.openrndrVersion = "0.3.26"
ext.orxVersion = "0.0.5"
dependencies {
compile "org.openrndr.extra:orx:0.0.1"
compile "org.openrndr.extra:orx-jumpflood:$orxVersion"
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
compile "org.openrndr:openrndr-core:$openrndrVersion"
runtime "org.openrndr:openrndr-gl3:$openrndrVersion"
runtime "org.openrndr:openrndr-gl3-natives-windows:$openrndrVersion"
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Fri Oct 05 14:22:23 CEST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip

172
orx-examples/gradlew vendored Normal file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
orx-examples/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,2 @@
rootProject.name = 'orx-examples'

View File

@@ -0,0 +1,56 @@
import org.openrndr.Program
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.configuration
import org.openrndr.draw.ColorType
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.jumpfill.EncodePoints
import org.openrndr.extra.jumpfill.JumpFlood
class JumpFill001 : Program() {
var drawFunc = {}
override fun setup() {
val encodePoints = EncodePoints()
val jumpFill = JumpFlood()
val input = colorBuffer(512, 1024)
val coordinates =
listOf(colorBuffer(input.width, input.height, type = ColorType.FLOAT32),
colorBuffer(input.width, input.height, type = ColorType.FLOAT32))
for (i in 0 until 100) {
input.shadow[(Math.random() * input.width).toInt(), (Math.random() * input.height).toInt()] =
ColorRGBa.WHITE
}
input.shadow.upload()
drawFunc = {
encodePoints.apply(input, coordinates[0])
drawer.image(coordinates[0])
jumpFill.maxSteps = 10
for (i in 0 until 10) {
jumpFill.step = i
jumpFill.apply(coordinates[i % 2], coordinates[(i + 1) % 2])
}
drawer.image(coordinates[0])
}
}
override fun draw() {
drawFunc()
}
}
fun main(args: Array<String>) {
application(JumpFill001(), configuration {
width = 1024
height = 1024
})
}

View File

@@ -0,0 +1,45 @@
import org.openrndr.Program
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.configuration
import org.openrndr.draw.colorBuffer
import org.openrndr.extra.jumpfill.contourPoints
import org.openrndr.extra.jumpfill.jumpFlood
import org.openrndr.extra.jumpfill.threshold
class JumpFill002 : Program() {
var drawFunc = {}
override fun setup() {
val input = colorBuffer(512, 1024)
for (i in 0 until 3) {
input.shadow[(Math.random() * input.width).toInt(), (Math.random() * input.height).toInt()] =
ColorRGBa.WHITE
}
input.shadow.upload()
val result = jumpFlood(drawer, input)
// threshold.apply(result, result)
// contourPoints.apply(result, result)
drawFunc = {
drawer.image(result)
}
}
override fun draw() {
drawFunc()
}
}
fun main(args: Array<String>) {
application(JumpFill002(), configuration {
width = 1024
height = 1024
})
}

View File

@@ -1,77 +1,77 @@
package org.openrndr.extra.integralimage package org.openrndr.extra.integralimage
import org.openrndr.draw.* import org.openrndr.draw.*
import org.openrndr.filter.blend.passthrough import org.openrndr.filter.blend.passthrough
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.resourceUrl import org.openrndr.resourceUrl
class FastIntegralImageFilter : Filter(filterShaderFromUrl(resourceUrl( class FastIntegralImageFilter : Filter(filterShaderFromUrl(resourceUrl(
"/shaders/gl3/integral-image.frag" "/shaders/gl3/integral-image.frag"
))) { ))) {
var passIndex: Int by parameters var passIndex: Int by parameters
var passDirection: Vector2 by parameters var passDirection: Vector2 by parameters
var sampleCount: Int by parameters var sampleCount: Int by parameters
var sampleCountBase: Int by parameters var sampleCountBase: Int by parameters
} }
class FastIntegralImage : Filter(filterShaderFromUrl(resourceUrl( class FastIntegralImage : Filter(filterShaderFromUrl(resourceUrl(
"/shaders/gl3/integral-image.frag" "/shaders/gl3/integral-image.frag"
))) { ))) {
var intermediate: ColorBuffer? = null var intermediate: ColorBuffer? = null
val filter = FastIntegralImageFilter() val filter = FastIntegralImageFilter()
private fun sampleCounts(size:Int, sampleCountBase:Int) : List<Int> { private fun sampleCounts(size:Int, sampleCountBase:Int) : List<Int> {
var remainder = size var remainder = size
val sampleCounts = mutableListOf<Int>() val sampleCounts = mutableListOf<Int>()
while (remainder > 0) { while (remainder > 0) {
sampleCounts += if (remainder >= sampleCountBase) { sampleCounts += if (remainder >= sampleCountBase) {
sampleCountBase sampleCountBase
} else { } else {
remainder remainder
} }
remainder /= sampleCountBase remainder /= sampleCountBase
} }
return sampleCounts return sampleCounts
} }
override fun apply(source: Array<ColorBuffer>, target: Array<ColorBuffer>) { override fun apply(source: Array<ColorBuffer>, target: Array<ColorBuffer>) {
val sampleCountBase = 16 val sampleCountBase = 16
val xSampleCounts = sampleCounts(source[0].width, sampleCountBase) val xSampleCounts = sampleCounts(source[0].width, sampleCountBase)
val ySampleCounts = sampleCounts(source[0].height, sampleCountBase) val ySampleCounts = sampleCounts(source[0].height, sampleCountBase)
val li = intermediate val li = intermediate
if (li == null || (li.width != source[0].width || li.height != source[0].height)) { if (li == null || (li.width != source[0].width || li.height != source[0].height)) {
intermediate?.destroy() intermediate?.destroy()
intermediate = colorBuffer(source[0].width, source[0].height, 1.0, ColorFormat.RGBa, ColorType.FLOAT32) intermediate = colorBuffer(source[0].width, source[0].height, 1.0, ColorFormat.RGBa, ColorType.FLOAT32)
} }
val targets = arrayOf(target, arrayOf(intermediate!!)) val targets = arrayOf(target, arrayOf(intermediate!!))
var targetIndex = 0 var targetIndex = 0
filter.sampleCountBase = sampleCountBase filter.sampleCountBase = sampleCountBase
filter.passDirection = Vector2.UNIT_X filter.passDirection = Vector2.UNIT_X
for (pass in 0 until xSampleCounts.size) { for (pass in 0 until xSampleCounts.size) {
filter.sampleCount = xSampleCounts[pass] filter.sampleCount = xSampleCounts[pass]
filter.passIndex = pass filter.passIndex = pass
filter.apply( if (pass == 0) source else targets[targetIndex%2], targets[(targetIndex+1)%2]) filter.apply( if (pass == 0) source else targets[targetIndex%2], targets[(targetIndex+1)%2])
targetIndex++ targetIndex++
} }
filter.passDirection = Vector2.UNIT_Y filter.passDirection = Vector2.UNIT_Y
for (pass in 0 until ySampleCounts.size) { for (pass in 0 until ySampleCounts.size) {
filter.sampleCount = ySampleCounts[pass] filter.sampleCount = ySampleCounts[pass]
filter.passIndex = pass filter.passIndex = pass
filter.apply( targets[targetIndex%2], targets[(targetIndex+1)%2]) filter.apply( targets[targetIndex%2], targets[(targetIndex+1)%2])
targetIndex++ targetIndex++
} }
if (targetIndex%2 == 1) { if (targetIndex%2 == 1) {
passthrough.apply(targets[1], targets[0]) passthrough.apply(targets[1], targets[0])
} }
} }
} }

View File

@@ -1,26 +1,26 @@
#version 330 core #version 330 core
uniform sampler2D tex0; uniform sampler2D tex0;
in vec2 v_texCoord0; in vec2 v_texCoord0;
out vec4 o_color; out vec4 o_color;
uniform int passIndex; uniform int passIndex;
uniform int sampleCount; uniform int sampleCount;
uniform int sampleCountBase; uniform int sampleCountBase;
uniform vec2 passDirection; uniform vec2 passDirection;
void main() { void main() {
vec2 passOffset = vec2(pow(sampleCountBase, passIndex)) * (1.0/textureSize(tex0, 0)) * passDirection; vec2 passOffset = vec2(pow(sampleCountBase, passIndex)) * (1.0/textureSize(tex0, 0)) * passDirection;
vec2 uv0 = v_texCoord0; vec2 uv0 = v_texCoord0;
vec4 result = vec4(0.0); vec4 result = vec4(0.0);
for (int i = 0; i < sampleCount; ++i) { for (int i = 0; i < sampleCount; ++i) {
vec2 readUV = v_texCoord0 - vec2(i *passOffset); vec2 readUV = v_texCoord0 - vec2(i *passOffset);
float factor = step(0.0, readUV.x) * step(0.0, readUV.y); float factor = step(0.0, readUV.x) * step(0.0, readUV.y);
result += factor * texture(tex0, readUV); result += factor * texture(tex0, readUV);
} }
o_color = result; o_color = result;
} }

View File

@@ -1,128 +1,128 @@
package org.openrndr.extra.jumpfill package org.openrndr.extra.jumpfill
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.draw.* import org.openrndr.draw.*
import org.openrndr.math.Matrix44 import org.openrndr.math.Matrix44
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.resourceUrl import org.openrndr.resourceUrl
class EncodePoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/encode-points.frag"))) class EncodePoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/encode-points.frag")))
class JumpFlood : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/jumpflood.frag"))) { class JumpFlood : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/jumpflood.frag"))) {
var maxSteps: Int by parameters var maxSteps: Int by parameters
var step: Int by parameters var step: Int by parameters
} }
class PixelDistance : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/pixel-distance.frag"))) class PixelDistance : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/pixel-distance.frag")))
class ContourPoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/contour-points.frag"))) class ContourPoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/contour-points.frag")))
class Threshold : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/threshold.frag"))) { class Threshold : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/threshold.frag"))) {
var threshold by parameters var threshold by parameters
init { init {
threshold = 0.5 threshold = 0.5
} }
} }
val encodePoints by lazy { EncodePoints() } val encodePoints by lazy { EncodePoints() }
val jumpFlood by lazy { JumpFlood() } val jumpFlood by lazy { JumpFlood() }
val pixelDistance by lazy { PixelDistance() } val pixelDistance by lazy { PixelDistance() }
val contourPoints by lazy { ContourPoints() } val contourPoints by lazy { ContourPoints() }
val threshold by lazy { Threshold() } val threshold by lazy { Threshold() }
class JumpFlooder(val width: Int, val height: Int) { class JumpFlooder(val width: Int, val height: Int) {
private val dimension = Math.max(width, height) private val dimension = Math.max(width, height)
private val exp = Math.ceil(Math.log(dimension.toDouble()) / Math.log(2.0)).toInt() private val exp = Math.ceil(Math.log(dimension.toDouble()) / Math.log(2.0)).toInt()
private val squareDim = Math.pow(2.0, exp.toDouble()).toInt() private val squareDim = Math.pow(2.0, exp.toDouble()).toInt()
private val coordinates = private val coordinates =
listOf(colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32), listOf(colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32),
colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32)) colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32))
private val final = renderTarget(width, height) { private val final = renderTarget(width, height) {
colorBuffer(type = ColorType.FLOAT32) colorBuffer(type = ColorType.FLOAT32)
} }
val result: ColorBuffer get() = final.colorBuffer(0) val result: ColorBuffer get() = final.colorBuffer(0)
private val square = renderTarget(squareDim, squareDim) { private val square = renderTarget(squareDim, squareDim) {
colorBuffer() colorBuffer()
} }
private var contourUsed = false private var contourUsed = false
private val thresholded by lazy { colorBuffer(width, height) } val thresholded by lazy { colorBuffer(width, height) }
private val edges by lazy { colorBuffer(width, height) } val edges by lazy { colorBuffer(width, height) }
fun distanceToContour(drawer: Drawer, input: ColorBuffer, thresholdValue: Double = 0.5): ColorBuffer { fun distanceToContour(drawer: Drawer, input: ColorBuffer, thresholdValue: Double = 0.5): ColorBuffer {
threshold.threshold = thresholdValue threshold.threshold = thresholdValue
threshold.apply(input, thresholded) threshold.apply(input, thresholded)
contourPoints.apply(thresholded, edges) contourPoints.apply(thresholded, edges)
contourUsed = true contourUsed = true
return jumpFlood(drawer, edges) return jumpFlood(drawer, edges)
} }
fun directions(xRange: IntProgression = 0 until width, yRange: IntProgression = 0 until height): Array<List<Vector2>> { fun directions(xRange: IntProgression = 0 until width, yRange: IntProgression = 0 until height): Array<List<Vector2>> {
result.shadow.download() result.shadow.download()
return result.shadow.mapIndexed(xRange, yRange) { _, _, r, g, _, _ -> Vector2(r, g) } return result.shadow.mapIndexed(xRange, yRange) { _, _, r, g, _, _ -> Vector2(r, g) }
} }
fun jumpFlood(drawer: Drawer, input: ColorBuffer): ColorBuffer { fun jumpFlood(drawer: Drawer, input: ColorBuffer): ColorBuffer {
if (input.width != width || input.height != height) { if (input.width != width || input.height != height) {
throw IllegalArgumentException("dimensions mismatch") throw IllegalArgumentException("dimensions mismatch")
} }
drawer.isolatedWithTarget(square) { drawer.isolatedWithTarget(square) {
drawer.background(ColorRGBa.BLACK) drawer.background(ColorRGBa.BLACK)
drawer.ortho(square) drawer.ortho(square)
drawer.view = Matrix44.IDENTITY drawer.view = Matrix44.IDENTITY
drawer.model = Matrix44.IDENTITY drawer.model = Matrix44.IDENTITY
drawer.image(input) drawer.image(input)
} }
encodePoints.apply(square.colorBuffer(0), coordinates[0]) encodePoints.apply(square.colorBuffer(0), coordinates[0])
for (i in 0 until exp) { for (i in 0 until exp) {
jumpFlood.step = i jumpFlood.step = i
jumpFlood.apply(coordinates[i % 2], coordinates[(i + 1) % 2]) jumpFlood.apply(coordinates[i % 2], coordinates[(i + 1) % 2])
} }
pixelDistance.apply( arrayOf(coordinates[exp % 2], thresholded), coordinates[exp % 2]) pixelDistance.apply(arrayOf(coordinates[exp % 2], thresholded), coordinates[exp % 2])
drawer.isolatedWithTarget(final) { drawer.isolatedWithTarget(final) {
drawer.background(ColorRGBa.BLACK) drawer.background(ColorRGBa.BLACK)
drawer.ortho(final) drawer.ortho(final)
drawer.view = Matrix44.IDENTITY drawer.view = Matrix44.IDENTITY
drawer.model = Matrix44.IDENTITY drawer.model = Matrix44.IDENTITY
drawer.image(coordinates[exp % 2]) drawer.image(coordinates[exp % 2])
} }
return result return result
} }
fun destroy(destroyFinal: Boolean = true) { fun destroy(destroyFinal: Boolean = true) {
coordinates.forEach { it.destroy() } coordinates.forEach { it.destroy() }
square.colorBuffer(0).destroy() square.colorBuffer(0).destroy()
square.detachColorBuffers() square.detachColorBuffers()
square.destroy() square.destroy()
if (destroyFinal) { if (destroyFinal) {
final.colorBuffer(0).destroy() final.colorBuffer(0).destroy()
} }
final.detachColorBuffers() final.detachColorBuffers()
final.destroy() final.destroy()
if (contourUsed) { if (contourUsed) {
edges.destroy() edges.destroy()
thresholded.destroy() thresholded.destroy()
} }
} }
} }
fun jumpFlood(drawer: Drawer, points: ColorBuffer): ColorBuffer { fun jumpFlood(drawer: Drawer, points: ColorBuffer): ColorBuffer {
val jumpFlooder = JumpFlooder(points.width, points.height) val jumpFlooder = JumpFlooder(points.width, points.height)
jumpFlooder.jumpFlood(drawer, points) jumpFlooder.jumpFlood(drawer, points)
val result = jumpFlooder.result val result = jumpFlooder.result
jumpFlooder.destroy(false) jumpFlooder.destroy(false)
return result return result
} }

View File

@@ -1,16 +1,16 @@
#version 330 core #version 330 core
uniform sampler2D tex0; uniform sampler2D tex0;
uniform sampler2D tex1; uniform sampler2D tex1;
in vec2 v_texCoord0; in vec2 v_texCoord0;
out vec4 o_color; out vec4 o_color;
void main() { void main() {
vec2 size = textureSize(tex0, 0); vec2 size = textureSize(tex0, 0);
vec2 pixelPosition = v_texCoord0; vec2 pixelPosition = v_texCoord0;
vec2 centroidPixelPosition = texture(tex0, v_texCoord0).xy; vec2 centroidPixelPosition = texture(tex0, v_texCoord0).xy;
vec2 pixelDistance = (centroidPixelPosition - pixelPosition) * size * vec2(1.0, -1.0); vec2 pixelDistance = (centroidPixelPosition - pixelPosition) * size * vec2(1.0, -1.0);
float threshold = texture(tex1, v_texCoord0).r; float threshold = texture(tex1, v_texCoord0).r;
o_color = vec4(pixelDistance, threshold, 1.0); o_color = vec4(pixelDistance, threshold, 1.0);
} }

View File

@@ -1,61 +1,61 @@
package org.openrndr.extras.meshgenerators package org.openrndr.extras.meshgenerators
import org.openrndr.draw.VertexBuffer import org.openrndr.draw.VertexBuffer
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
fun boxMesh(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0, fun boxMesh(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0,
widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1, widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1,
invert: Boolean = false): VertexBuffer { invert: Boolean = false): VertexBuffer {
val vb = meshVertexBuffer(widthSegments * heightSegments * 6 * 2 + val vb = meshVertexBuffer(widthSegments * heightSegments * 6 * 2 +
widthSegments * depthSegments * 6 * 2 + widthSegments * depthSegments * 6 * 2 +
heightSegments * depthSegments * 6 * 2) heightSegments * depthSegments * 6 * 2)
vb.put { vb.put {
generateBox(width, height, depth, generateBox(width, height, depth,
widthSegments, heightSegments, depthSegments, widthSegments, heightSegments, depthSegments,
invert, bufferWriter(this)) invert, bufferWriter(this))
} }
return vb return vb
} }
fun generateBox(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0, fun generateBox(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0,
widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1, widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1,
invert: Boolean = false, invert: Boolean = false,
writer: VertexWriter) { writer: VertexWriter) {
val sign = if (invert) -1.0 else 1.0 val sign = if (invert) -1.0 else 1.0
// +x -- ZY // +x -- ZY
generatePlane(Vector3(width / 2.0 * sign, 0.0, 0.0), generatePlane(Vector3(width / 2.0 * sign, 0.0, 0.0),
Vector3.UNIT_Z, Vector3.UNIT_Y, Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y, Vector3.UNIT_X,
-depth, -height, -depth, -height,
depthSegments, heightSegments, writer) depthSegments, heightSegments, writer)
// -x -- ZY // -x -- ZY
generatePlane(Vector3(-width / 2.0 * sign, 0.0, 0.0), generatePlane(Vector3(-width / 2.0 * sign, 0.0, 0.0),
Vector3.UNIT_Z, Vector3.UNIT_Y, -Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y, -Vector3.UNIT_X,
-depth, height, -depth, height,
depthSegments, heightSegments, writer) depthSegments, heightSegments, writer)
// +y -- XZ // +y -- XZ
generatePlane(Vector3(0.0, height / 2.0 * sign, 0.0), generatePlane(Vector3(0.0, height / 2.0 * sign, 0.0),
Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y, Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y,
width, depth, width, depth,
widthSegments, depthSegments, writer) widthSegments, depthSegments, writer)
// -y -- XZ // -y -- XZ
generatePlane(Vector3(0.0, -height / 2.0 * sign, 0.0), generatePlane(Vector3(0.0, -height / 2.0 * sign, 0.0),
Vector3.UNIT_X, Vector3.UNIT_Z, -Vector3.UNIT_Y, Vector3.UNIT_X, Vector3.UNIT_Z, -Vector3.UNIT_Y,
width, -depth, width, -depth,
widthSegments, depthSegments, writer) widthSegments, depthSegments, writer)
// +z -- XY // +z -- XY
generatePlane(Vector3(0.0, 0.0, depth / 2.0 * sign), generatePlane(Vector3(0.0, 0.0, depth / 2.0 * sign),
Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z, Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z,
-width, height, -width, height,
widthSegments, heightSegments, writer) widthSegments, heightSegments, writer)
// -z -- XY // -z -- XY
generatePlane(Vector3(0.0, 0.0, -depth / 2.0 * sign), generatePlane(Vector3(0.0, 0.0, -depth / 2.0 * sign),
Vector3.UNIT_X, Vector3.UNIT_Y, -Vector3.UNIT_Z, Vector3.UNIT_X, Vector3.UNIT_Y, -Vector3.UNIT_Z,
width, height, width, height,
widthSegments, heightSegments, writer) widthSegments, heightSegments, writer)
} }

View File

@@ -1,101 +1,101 @@
package org.openrndr.extras.meshgenerators package org.openrndr.extras.meshgenerators
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import org.openrndr.math.transforms.rotateY import org.openrndr.math.transforms.rotateY
fun generateCap(sides: Int, radius: Double, enveloppe: List<Vector2> = listOf(Vector2(0.0, 0.0), Vector2(1.0, 0.0)), writer: VertexWriter) { fun generateCap(sides: Int, radius: Double, enveloppe: List<Vector2> = listOf(Vector2(0.0, 0.0), Vector2(1.0, 0.0)), writer: VertexWriter) {
val maxX = enveloppe.maxBy { it.x } ?: Vector2(1.0, 0.0) val maxX = enveloppe.maxBy { it.x } ?: Vector2(1.0, 0.0)
val a = maxX.x val a = maxX.x
val cleanEnveloppe = enveloppe.map { Vector2((it.x / a) * radius, it.y) } val cleanEnveloppe = enveloppe.map { Vector2((it.x / a) * radius, it.y) }
val normals2D = enveloppe.zipWithNext().map { val normals2D = enveloppe.zipWithNext().map {
val d = it.second - it.first val d = it.second - it.first
d.normalized.perpendicular d.normalized.perpendicular
} }
val basePositions = cleanEnveloppe.map { Vector3(it.x, it.y, 0.0) } val basePositions = cleanEnveloppe.map { Vector3(it.x, it.y, 0.0) }
val baseNormals = normals2D.map { Vector3(it.x, it.y, 0.0) } val baseNormals = normals2D.map { Vector3(it.x, it.y, 0.0) }
for (side in 0 until sides) { for (side in 0 until sides) {
val r0 = rotateY(360.0 / sides * side) val r0 = rotateY(360.0 / sides * side)
val r1 = rotateY(360.0 / sides * (side + 1)) val r1 = rotateY(360.0 / sides * (side + 1))
val v0 = basePositions.map { (r0 * it.xyz0).xyz } val v0 = basePositions.map { (r0 * it.xyz0).xyz }
val v1 = basePositions.map { (r1 * it.xyz0).xyz } val v1 = basePositions.map { (r1 * it.xyz0).xyz }
val n0 = baseNormals.map { (r0 * it.xyz0).xyz } val n0 = baseNormals.map { (r0 * it.xyz0).xyz }
val n1 = baseNormals.map { (r1 * it.xyz0).xyz } val n1 = baseNormals.map { (r1 * it.xyz0).xyz }
for (segment in 0 until basePositions.size - 1) { for (segment in 0 until basePositions.size - 1) {
val p00 = v0[segment] val p00 = v0[segment]
val p01 = v0[segment+1] val p01 = v0[segment+1]
val p10 = v1[segment] val p10 = v1[segment]
val p11 = v1[segment+1] val p11 = v1[segment+1]
val nn0 = n0[segment] val nn0 = n0[segment]
val nn1 = n1[segment] val nn1 = n1[segment]
writer(p00, nn0, Vector2.ZERO) writer(p00, nn0, Vector2.ZERO)
writer(p01, nn0, Vector2.ZERO) writer(p01, nn0, Vector2.ZERO)
writer(p11, nn1, Vector2.ZERO) writer(p11, nn1, Vector2.ZERO)
writer(p11, nn1, Vector2.ZERO) writer(p11, nn1, Vector2.ZERO)
writer(p10, nn1, Vector2.ZERO) writer(p10, nn1, Vector2.ZERO)
writer(p00, nn0, Vector2.ZERO) writer(p00, nn0, Vector2.ZERO)
} }
} }
} }
fun generateRevolve(sides: Int, length: Double, enveloppe: List<Vector2> = listOf(Vector2(1.0, 0.0), Vector2(1.0, 1.0)), writer: VertexWriter) { fun generateRevolve(sides: Int, length: Double, enveloppe: List<Vector2> = listOf(Vector2(1.0, 0.0), Vector2(1.0, 1.0)), writer: VertexWriter) {
val maxY = enveloppe.maxBy { it.y } ?: Vector2(0.0, 1.0) val maxY = enveloppe.maxBy { it.y } ?: Vector2(0.0, 1.0)
val a = maxY.y val a = maxY.y
val cleanEnveloppe = enveloppe.map { Vector2((it.x), (it.y/a - 0.5) * length ) } val cleanEnveloppe = enveloppe.map { Vector2((it.x), (it.y/a - 0.5) * length ) }
val normals2D = enveloppe.zipWithNext().map { val normals2D = enveloppe.zipWithNext().map {
val d = it.second - it.first val d = it.second - it.first
d.normalized.perpendicular * Vector2(1.0, -1.0) d.normalized.perpendicular * Vector2(1.0, -1.0)
} }
val extended = listOf(normals2D[0]) + normals2D + normals2D[normals2D.size-1] val extended = listOf(normals2D[0]) + normals2D + normals2D[normals2D.size-1]
// extended.zipW // extended.zipW
println(normals2D.joinToString(", ")) println(normals2D.joinToString(", "))
val basePositions = cleanEnveloppe.map { Vector3(it.x, it.y, 0.0) } val basePositions = cleanEnveloppe.map { Vector3(it.x, it.y, 0.0) }
val baseNormals = normals2D.map { Vector3(it.x, it.y, 0.0) } val baseNormals = normals2D.map { Vector3(it.x, it.y, 0.0) }
for (side in 0 until sides) { for (side in 0 until sides) {
val r0 = rotateY(360.0 / sides * side) val r0 = rotateY(360.0 / sides * side)
val r1 = rotateY(360.0 / sides * (side + 1)) val r1 = rotateY(360.0 / sides * (side + 1))
val v0 = basePositions.map { (r0 * it.xyz0).xyz } val v0 = basePositions.map { (r0 * it.xyz0).xyz }
val v1 = basePositions.map { (r1 * it.xyz0).xyz } val v1 = basePositions.map { (r1 * it.xyz0).xyz }
val n0 = baseNormals.map { (r0 * it.xyz0).xyz } val n0 = baseNormals.map { (r0 * it.xyz0).xyz }
val n1 = baseNormals.map { (r1 * it.xyz0).xyz } val n1 = baseNormals.map { (r1 * it.xyz0).xyz }
for (segment in 0 until basePositions.size - 1) { for (segment in 0 until basePositions.size - 1) {
val p00 = v0[segment] val p00 = v0[segment]
val p01 = v0[segment+1] val p01 = v0[segment+1]
val p10 = v1[segment] val p10 = v1[segment]
val p11 = v1[segment+1] val p11 = v1[segment+1]
val nn0 = n0[segment] val nn0 = n0[segment]
val nn1 = n1[segment] val nn1 = n1[segment]
writer(p00, nn0, Vector2.ZERO) writer(p00, nn0, Vector2.ZERO)
writer(p10, nn1, Vector2.ZERO) writer(p10, nn1, Vector2.ZERO)
writer(p11, nn1, Vector2.ZERO) writer(p11, nn1, Vector2.ZERO)
writer(p11, nn1, Vector2.ZERO) writer(p11, nn1, Vector2.ZERO)
writer(p01, nn0, Vector2.ZERO) writer(p01, nn0, Vector2.ZERO)
writer(p00, nn0, Vector2.ZERO) writer(p00, nn0, Vector2.ZERO)
} }
} }
} }

View File

@@ -1,82 +1,82 @@
package org.openrndr.extras.meshgenerators package org.openrndr.extras.meshgenerators
import org.openrndr.draw.VertexBuffer import org.openrndr.draw.VertexBuffer
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import org.openrndr.math.mix import org.openrndr.math.mix
import org.openrndr.math.transforms.rotateZ import org.openrndr.math.transforms.rotateZ
fun cylinderMesh(sides: Int = 16, segments: Int = 16, radius: Double = 1.0, length: Double, invert: Boolean = false): VertexBuffer { fun cylinderMesh(sides: Int = 16, segments: Int = 16, radius: Double = 1.0, length: Double, invert: Boolean = false): VertexBuffer {
val vertexCount = 6 * sides * segments val vertexCount = 6 * sides * segments
val vb = meshVertexBuffer(vertexCount) val vb = meshVertexBuffer(vertexCount)
vb.put { vb.put {
generateCylinder(sides, segments, radius, length, invert, bufferWriter(this)) generateCylinder(sides, segments, radius, length, invert, bufferWriter(this))
} }
return vb return vb
} }
fun generateCylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false, vertexWriter: VertexWriter) { fun generateCylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false, vertexWriter: VertexWriter) {
return generateTaperedCylinder(sides, segments, radius, radius, length, invert, vertexWriter) return generateTaperedCylinder(sides, segments, radius, radius, length, invert, vertexWriter)
} }
fun generateTaperedCylinder(sides: Int, segments: Int, radiusStart: Double, radiusEnd:Double, length: Double, invert: Boolean = false, vertexWriter: VertexWriter) { fun generateTaperedCylinder(sides: Int, segments: Int, radiusStart: Double, radiusEnd:Double, length: Double, invert: Boolean = false, vertexWriter: VertexWriter) {
val dphi = (Math.PI * 2) / sides val dphi = (Math.PI * 2) / sides
val ddeg = (360.0) / sides val ddeg = (360.0) / sides
val invertFactor = if (invert) -1.0 else 1.0 val invertFactor = if (invert) -1.0 else 1.0
val dr = radiusEnd - radiusStart val dr = radiusEnd - radiusStart
val baseNormal = Vector2(length, dr).normalized.perpendicular.let { Vector3(x=it.y, y=0.0, z=it.x)} val baseNormal = Vector2(length, dr).normalized.perpendicular.let { Vector3(x=it.y, y=0.0, z=it.x)}
//val baseNormal = Vector3(1.0, 0.0, 0.0) //val baseNormal = Vector3(1.0, 0.0, 0.0)
for (segment in 0 until segments) { for (segment in 0 until segments) {
val radius0 = mix(radiusStart, radiusEnd, segment*1.0/segments) val radius0 = mix(radiusStart, radiusEnd, segment*1.0/segments)
val radius1 = mix(radiusStart, radiusEnd, (segment+1)*1.0/segments) val radius1 = mix(radiusStart, radiusEnd, (segment+1)*1.0/segments)
val z0 = (length / segments) * segment - length/2.0 val z0 = (length / segments) * segment - length/2.0
val z1 = (length / segments) * (segment + 1) - length/2.0 val z1 = (length / segments) * (segment + 1) - length/2.0
for (side in 0 until sides) { for (side in 0 until sides) {
val x00 = Math.cos(side * dphi) * radius0 val x00 = Math.cos(side * dphi) * radius0
val x10 = Math.cos(side * dphi + dphi) * radius0 val x10 = Math.cos(side * dphi + dphi) * radius0
val y00 = Math.sin(side * dphi) * radius0 val y00 = Math.sin(side * dphi) * radius0
val y10 = Math.sin(side * dphi + dphi) * radius0 val y10 = Math.sin(side * dphi + dphi) * radius0
val x01 = Math.cos(side * dphi) * radius1 val x01 = Math.cos(side * dphi) * radius1
val x11 = Math.cos(side * dphi + dphi) * radius1 val x11 = Math.cos(side * dphi + dphi) * radius1
val y01 = Math.sin(side * dphi) * radius1 val y01 = Math.sin(side * dphi) * radius1
val y11 = Math.sin(side * dphi + dphi) * radius1 val y11 = Math.sin(side * dphi + dphi) * radius1
val u0 = (segment + 0.0) / segments val u0 = (segment + 0.0) / segments
val u1 = (segment + 1.0) / segments val u1 = (segment + 1.0) / segments
val v0 = (side + 0.0) / sides val v0 = (side + 0.0) / sides
val v1 = (side + 1.0) / sides val v1 = (side + 1.0) / sides
val n0 = (rotateZ(side * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor val n0 = (rotateZ(side * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor
val n1 = (rotateZ((side+1) * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor val n1 = (rotateZ((side+1) * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor
if (!invert) { if (!invert) {
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0))
vertexWriter(Vector3(x10, y10, z0), n1, Vector2(u0, v1)) vertexWriter(Vector3(x10, y10, z0), n1, Vector2(u0, v1))
vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1))
vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1))
vertexWriter(Vector3(x01, y01, z1), n0, Vector2(u1, v0)) vertexWriter(Vector3(x01, y01, z1), n0, Vector2(u1, v0))
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0))
} else { } else {
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0))
vertexWriter(Vector3(x01, y01, z1), n0, Vector2(u1, v0)) vertexWriter(Vector3(x01, y01, z1), n0, Vector2(u1, v0))
vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1))
vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1))
vertexWriter(Vector3(x10, y10, z0), n1, Vector2(u0, v1)) vertexWriter(Vector3(x10, y10, z0), n1, Vector2(u0, v1))
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0))
} }
} }
} }
} }

View File

@@ -1,172 +1,172 @@
package org.openrndr.extras.meshgenerators package org.openrndr.extras.meshgenerators
import org.openrndr.draw.VertexBuffer import org.openrndr.draw.VertexBuffer
import org.openrndr.draw.vertexBuffer import org.openrndr.draw.vertexBuffer
import org.openrndr.draw.vertexFormat import org.openrndr.draw.vertexFormat
import org.openrndr.math.Matrix44 import org.openrndr.math.Matrix44
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import org.openrndr.math.transforms.rotate import org.openrndr.math.transforms.rotate
import org.openrndr.math.transforms.transform import org.openrndr.math.transforms.transform
import org.openrndr.shape.Shape import org.openrndr.shape.Shape
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.ByteOrder import java.nio.ByteOrder
class GeneratorBuffer { class GeneratorBuffer {
class VertexData(val position: Vector3, val normal: Vector3, val texCoord: Vector2) class VertexData(val position: Vector3, val normal: Vector3, val texCoord: Vector2)
var data = mutableListOf<VertexData>() var data = mutableListOf<VertexData>()
fun write(position: Vector3, normal: Vector3, texCoord: Vector2) { fun write(position: Vector3, normal: Vector3, texCoord: Vector2) {
data.add(VertexData(position, normal, texCoord)) data.add(VertexData(position, normal, texCoord))
} }
fun concat(other: GeneratorBuffer) { fun concat(other: GeneratorBuffer) {
data.addAll(other.data) data.addAll(other.data)
} }
fun transform(m: Matrix44) { fun transform(m: Matrix44) {
data = data.map { data = data.map {
VertexData((m * (it.position.xyz1)).xyz, (m * (it.normal.xyz0)).xyz, it.texCoord) VertexData((m * (it.position.xyz1)).xyz, (m * (it.normal.xyz0)).xyz, it.texCoord)
}.toMutableList() }.toMutableList()
} }
fun toByteBuffer(): ByteBuffer { fun toByteBuffer(): ByteBuffer {
val bb = ByteBuffer.allocateDirect(data.size * (3 * 4 + 3 * 4 + 2 * 4)) val bb = ByteBuffer.allocateDirect(data.size * (3 * 4 + 3 * 4 + 2 * 4))
bb.order(ByteOrder.nativeOrder()) bb.order(ByteOrder.nativeOrder())
bb.rewind() bb.rewind()
for (d in data) { for (d in data) {
bb.putFloat(d.position.x.toFloat()) bb.putFloat(d.position.x.toFloat())
bb.putFloat(d.position.y.toFloat()) bb.putFloat(d.position.y.toFloat())
bb.putFloat(d.position.z.toFloat()) bb.putFloat(d.position.z.toFloat())
bb.putFloat(d.normal.x.toFloat()) bb.putFloat(d.normal.x.toFloat())
bb.putFloat(d.normal.y.toFloat()) bb.putFloat(d.normal.y.toFloat())
bb.putFloat(d.normal.z.toFloat()) bb.putFloat(d.normal.z.toFloat())
bb.putFloat(d.texCoord.x.toFloat()) bb.putFloat(d.texCoord.x.toFloat())
bb.putFloat(d.texCoord.y.toFloat()) bb.putFloat(d.texCoord.y.toFloat())
} }
return bb return bb
} }
} }
fun GeneratorBuffer.sphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) { fun GeneratorBuffer.sphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) {
generateSphere(sides, segments, radius, invert, this::write) generateSphere(sides, segments, radius, invert, this::write)
} }
fun GeneratorBuffer.hemisphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) { fun GeneratorBuffer.hemisphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) {
generateHemisphere(sides, segments, radius, invert, this::write) generateHemisphere(sides, segments, radius, invert, this::write)
} }
enum class GridCoordinates { enum class GridCoordinates {
INDEX, INDEX,
UNIPOLAR, UNIPOLAR,
BIPOLAR, BIPOLAR,
} }
fun GeneratorBuffer.grid(width: Int, height: Int, coordinates: GridCoordinates = GridCoordinates.BIPOLAR, builder: GeneratorBuffer.(u: Double, v: Double) -> Unit) { fun GeneratorBuffer.grid(width: Int, height: Int, coordinates: GridCoordinates = GridCoordinates.BIPOLAR, builder: GeneratorBuffer.(u: Double, v: Double) -> Unit) {
for (v in 0 until height) { for (v in 0 until height) {
for (u in 0 until width) { for (u in 0 until width) {
group { group {
when (coordinates) { when (coordinates) {
GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0) GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0)
GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 1.0) - 1, GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 1.0) - 1,
2 * v / (height - 1.0) - 1) 2 * v / (height - 1.0) - 1)
GridCoordinates.UNIPOLAR -> this.builder(u / (width - 1.0), v / (height - 1.0)) GridCoordinates.UNIPOLAR -> this.builder(u / (width - 1.0), v / (height - 1.0))
} }
} }
} }
} }
} }
fun GeneratorBuffer.twist(degreesPerUnit: Double, start: Double, axis: Vector3 = Vector3.UNIT_Y) { fun GeneratorBuffer.twist(degreesPerUnit: Double, start: Double, axis: Vector3 = Vector3.UNIT_Y) {
data = data.map { data = data.map {
val p = it.position.projectedOn(axis) val p = it.position.projectedOn(axis)
val t = if (axis.x != 0.0) p.x / axis.x else if (axis.y != 0.0) p.y / axis.y else if (axis.z != 0.0) p.z / axis.z else val t = if (axis.x != 0.0) p.x / axis.x else if (axis.y != 0.0) p.y / axis.y else if (axis.z != 0.0) p.z / axis.z else
throw IllegalArgumentException("0 axis") throw IllegalArgumentException("0 axis")
val r = rotate(axis, t * degreesPerUnit) val r = rotate(axis, t * degreesPerUnit)
GeneratorBuffer.VertexData((r * it.position.xyz1).xyz, (r * it.normal.xyz0).xyz, it.texCoord) GeneratorBuffer.VertexData((r * it.position.xyz1).xyz, (r * it.normal.xyz0).xyz, it.texCoord)
}.toMutableList() }.toMutableList()
} }
fun GeneratorBuffer.grid(width: Int, height: Int, depth: Int, coordinates: GridCoordinates = GridCoordinates.BIPOLAR, builder: GeneratorBuffer.(u: Double, v: Double, w: Double) -> Unit) { fun GeneratorBuffer.grid(width: Int, height: Int, depth: Int, coordinates: GridCoordinates = GridCoordinates.BIPOLAR, builder: GeneratorBuffer.(u: Double, v: Double, w: Double) -> Unit) {
for (w in 0 until depth) { for (w in 0 until depth) {
for (v in 0 until height) { for (v in 0 until height) {
for (u in 0 until width) { for (u in 0 until width) {
group { group {
when (coordinates) { when (coordinates) {
GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0, w * 1.0) GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0, w * 1.0)
GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 1.0) - 1, GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 1.0) - 1,
2 * v / (height - 1.0) - 1, 2 * w / (depth - 1.0) - 1) 2 * v / (height - 1.0) - 1, 2 * w / (depth - 1.0) - 1)
GridCoordinates.UNIPOLAR -> this.builder(u / (width - 1.0), v / (height - 1.0), w / (depth - 1.0)) GridCoordinates.UNIPOLAR -> this.builder(u / (width - 1.0), v / (height - 1.0), w / (depth - 1.0))
} }
} }
} }
} }
} }
} }
fun GeneratorBuffer.box(width: Double, height: Double, depth: Double, widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1, invert: Boolean = false) { fun GeneratorBuffer.box(width: Double, height: Double, depth: Double, widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1, invert: Boolean = false) {
generateBox(width, height, depth, widthSegments, heightSegments, depthSegments, invert, this::write) generateBox(width, height, depth, widthSegments, heightSegments, depthSegments, invert, this::write)
} }
fun GeneratorBuffer.cylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false) { fun GeneratorBuffer.cylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false) {
generateCylinder(sides, segments, radius, length, invert, this::write) generateCylinder(sides, segments, radius, length, invert, this::write)
} }
fun GeneratorBuffer.taperedCylinder(sides: Int, segments: Int, startRadius: Double, endRadius: Double, length: Double, invert: Boolean = false) { fun GeneratorBuffer.taperedCylinder(sides: Int, segments: Int, startRadius: Double, endRadius: Double, length: Double, invert: Boolean = false) {
generateTaperedCylinder(sides, segments, startRadius, endRadius, length, invert, this::write) generateTaperedCylinder(sides, segments, startRadius, endRadius, length, invert, this::write)
} }
fun GeneratorBuffer.cap(sides: Int, radius: Double, enveloppe: List<Vector2>) { fun GeneratorBuffer.cap(sides: Int, radius: Double, enveloppe: List<Vector2>) {
generateCap(sides, radius, enveloppe, this::write) generateCap(sides, radius, enveloppe, this::write)
} }
fun GeneratorBuffer.revolve(sides:Int, length:Double, enveloppe: List<Vector2>) { fun GeneratorBuffer.revolve(sides:Int, length:Double, enveloppe: List<Vector2>) {
generateRevolve(sides, length, enveloppe, this::write) generateRevolve(sides, length, enveloppe, this::write)
} }
fun GeneratorBuffer.extrudeShape(shape: Shape, length: Double, scale: Double = 1.0, distanceTolerance: Double = 0.5) { fun GeneratorBuffer.extrudeShape(shape: Shape, length: Double, scale: Double = 1.0, distanceTolerance: Double = 0.5) {
extrudeShape(shape, -length / 2.0, length / 2.0, scale, scale, true, true, distanceTolerance, false, this::write) extrudeShape(shape, -length / 2.0, length / 2.0, scale, scale, true, true, distanceTolerance, false, this::write)
} }
fun meshGenerator(builder: GeneratorBuffer.() -> Unit): VertexBuffer { fun meshGenerator(builder: GeneratorBuffer.() -> Unit): VertexBuffer {
val gb = GeneratorBuffer() val gb = GeneratorBuffer()
gb.builder() gb.builder()
val vb = vertexBuffer(vertexFormat { val vb = vertexBuffer(vertexFormat {
position(3) position(3)
normal(3) normal(3)
textureCoordinate(2) textureCoordinate(2)
}, gb.data.size) }, gb.data.size)
val bb = gb.toByteBuffer() val bb = gb.toByteBuffer()
bb.rewind() bb.rewind()
vb.write(bb) vb.write(bb)
return vb return vb
} }
fun generator(builder: GeneratorBuffer.() -> Unit): GeneratorBuffer { fun generator(builder: GeneratorBuffer.() -> Unit): GeneratorBuffer {
val gb = GeneratorBuffer() val gb = GeneratorBuffer()
gb.builder() gb.builder()
return gb return gb
} }
fun GeneratorBuffer.group(builder: GeneratorBuffer.() -> Unit) { fun GeneratorBuffer.group(builder: GeneratorBuffer.() -> Unit) {
val gb = GeneratorBuffer() val gb = GeneratorBuffer()
gb.builder() gb.builder()
this.concat(gb) this.concat(gb)
} }
fun main(args: Array<String>) { fun main(args: Array<String>) {
val gb = generator { val gb = generator {
box(20.0, 20.0, 20.0) box(20.0, 20.0, 20.0)
group { group {
box(40.0, 40.0, 40.0) box(40.0, 40.0, 40.0)
transform(transform { transform(transform {
translate(0.0, 20.0, 0.0) translate(0.0, 20.0, 0.0)
}) })
} }
} }
} }

View File

@@ -1,84 +1,84 @@
package org.openrndr.extras.meshgenerators package org.openrndr.extras.meshgenerators
import org.openrndr.draw.VertexBuffer import org.openrndr.draw.VertexBuffer
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
fun planeMesh(center: Vector3, fun planeMesh(center: Vector3,
right: Vector3, right: Vector3,
forward: Vector3, forward: Vector3,
up: Vector3 = forward.cross(right).normalized, up: Vector3 = forward.cross(right).normalized,
width: Double = 1.0, height: Double = 1.0, width: Double = 1.0, height: Double = 1.0,
widthSegments: Int = 1, heightSegments: Int = 1): VertexBuffer { widthSegments: Int = 1, heightSegments: Int = 1): VertexBuffer {
val vertexCount = (widthSegments * heightSegments) * 6 val vertexCount = (widthSegments * heightSegments) * 6
val vb = meshVertexBuffer(vertexCount) val vb = meshVertexBuffer(vertexCount)
vb.put { vb.put {
generatePlane(center, right, forward, up, generatePlane(center, right, forward, up,
width, height, widthSegments, heightSegments, bufferWriter(this)) width, height, widthSegments, heightSegments, bufferWriter(this))
} }
return vb return vb
} }
/** /**
* generates a finite plane with its center at (0,0,0) and spanning the xz-plane * generates a finite plane with its center at (0,0,0) and spanning the xz-plane
*/ */
fun groundPlaneMesh(width: Double = 1.0, fun groundPlaneMesh(width: Double = 1.0,
height: Double = 1.0, height: Double = 1.0,
widthSegments: Int = 1, widthSegments: Int = 1,
heightSegments: Int = 1): VertexBuffer { heightSegments: Int = 1): VertexBuffer {
return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y, return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y,
width, height, widthSegments, heightSegments) width, height, widthSegments, heightSegments)
} }
/** /**
* generates a finite plane with its center at (0,0,0) and spanning the xy-plane * generates a finite plane with its center at (0,0,0) and spanning the xy-plane
*/ */
fun wallPlaneMesh(width: Double = 1.0, fun wallPlaneMesh(width: Double = 1.0,
height: Double = 1.0, height: Double = 1.0,
widthSegments: Int = 1, widthSegments: Int = 1,
heightSegments: Int = 1): VertexBuffer { heightSegments: Int = 1): VertexBuffer {
return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z, return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z,
width, height, widthSegments, heightSegments) width, height, widthSegments, heightSegments)
} }
fun generatePlane(center: Vector3, fun generatePlane(center: Vector3,
right: Vector3, right: Vector3,
forward: Vector3, forward: Vector3,
up: Vector3 = forward.cross(right).normalized, up: Vector3 = forward.cross(right).normalized,
width: Double = 1.0, height: Double = 1.0, width: Double = 1.0, height: Double = 1.0,
widthSegments: Int = 1, heightSegments: Int = 2, widthSegments: Int = 1, heightSegments: Int = 2,
writer: VertexWriter) { writer: VertexWriter) {
val forwardStep = forward.normalized * (height / heightSegments) val forwardStep = forward.normalized * (height / heightSegments)
val rightStep = right.normalized * (width / widthSegments) val rightStep = right.normalized * (width / widthSegments)
val corner = center - forward.normalized * (height*0.5) - right.normalized * (width * 0.5) val corner = center - forward.normalized * (height*0.5) - right.normalized * (width * 0.5)
val step = Vector2(1.0 / width, 1.0 / height) val step = Vector2(1.0 / width, 1.0 / height)
for (v in 0 until heightSegments) { for (v in 0 until heightSegments) {
for (u in 0 until widthSegments) { for (u in 0 until widthSegments) {
val uv00 = Vector2(u + 0.0, v + 0.0) * step val uv00 = Vector2(u + 0.0, v + 0.0) * step
val uv01 = Vector2(u + 0.0, v + 0.1) * step val uv01 = Vector2(u + 0.0, v + 0.1) * step
val uv10 = Vector2(u + 1.0, v + 0.0) * step val uv10 = Vector2(u + 1.0, v + 0.0) * step
val uv11 = Vector2(u + 1.0, v + 0.1) * step val uv11 = Vector2(u + 1.0, v + 0.1) * step
val c00 = corner + forwardStep * v.toDouble() + rightStep * u.toDouble() val c00 = corner + forwardStep * v.toDouble() + rightStep * u.toDouble()
val c01 = corner + forwardStep * (v + 1).toDouble() + rightStep * u.toDouble() val c01 = corner + forwardStep * (v + 1).toDouble() + rightStep * u.toDouble()
val c10 = corner + forwardStep * v.toDouble() + rightStep * (u + 1).toDouble() val c10 = corner + forwardStep * v.toDouble() + rightStep * (u + 1).toDouble()
val c11 = corner + forwardStep * (v + 1).toDouble() + rightStep * (u + 1).toDouble() val c11 = corner + forwardStep * (v + 1).toDouble() + rightStep * (u + 1).toDouble()
writer(c11, up, uv00) writer(c11, up, uv00)
writer(c10, up, uv10) writer(c10, up, uv10)
writer(c00, up, uv11) writer(c00, up, uv11)
writer(c00, up, uv11) writer(c00, up, uv11)
writer(c01, up, uv01) writer(c01, up, uv01)
writer(c11, up, uv00) writer(c11, up, uv00)
} }
} }
} }

View File

@@ -1,84 +1,84 @@
package org.openrndr.extras.meshgenerators package org.openrndr.extras.meshgenerators
import org.openrndr.draw.VertexBuffer import org.openrndr.draw.VertexBuffer
import org.openrndr.math.Spherical import org.openrndr.math.Spherical
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
fun sphereMesh(sides: Int = 16, segments: Int = 16, radius: Double = 1.0, invert: Boolean = false): VertexBuffer { fun sphereMesh(sides: Int = 16, segments: Int = 16, radius: Double = 1.0, invert: Boolean = false): VertexBuffer {
val vertexCount = 2 * sides * 3 + Math.max(0, (segments - 2)) * sides * 6 val vertexCount = 2 * sides * 3 + Math.max(0, (segments - 2)) * sides * 6
val vb = meshVertexBuffer(vertexCount) val vb = meshVertexBuffer(vertexCount)
vb.put { vb.put {
generateSphere(sides, segments, radius, invert, bufferWriter(this)) generateSphere(sides, segments, radius, invert, bufferWriter(this))
} }
return vb return vb
} }
fun generateSphere(sides: Int, segments: Int, radius: Double = 1.0, invert: Boolean = false, writer: VertexWriter) { fun generateSphere(sides: Int, segments: Int, radius: Double = 1.0, invert: Boolean = false, writer: VertexWriter) {
val inverter = if (invert) -1.0 else 1.0 val inverter = if (invert) -1.0 else 1.0
for (t in 0 until segments) { for (t in 0 until segments) {
for (s in 0 until sides) { for (s in 0 until sides) {
val st00 = Spherical(radius, s * Math.PI * 2.0 / sides, t * Math.PI / segments) val st00 = Spherical(radius, s * Math.PI * 2.0 / sides, t * Math.PI / segments)
val st01 = Spherical(radius, s * Math.PI * 2.0 / sides, (t + 1) * Math.PI / segments) val st01 = Spherical(radius, s * Math.PI * 2.0 / sides, (t + 1) * Math.PI / segments)
val st10 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, t * Math.PI / segments) val st10 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, t * Math.PI / segments)
val st11 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, (t + 1) * Math.PI / segments) val st11 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, (t + 1) * Math.PI / segments)
val thetaMax = Math.PI val thetaMax = Math.PI
val phiMax = Math.PI * 2.0 val phiMax = Math.PI * 2.0
when (t) { when (t) {
0 -> { 0 -> {
writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax))
writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax))
writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax))
} }
segments - 1 -> { segments - 1 -> {
writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax))
writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax)) writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax))
writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax))
} }
else -> { else -> {
writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax))
writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax))
writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax))
writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax))
writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax)) writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax))
writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax))
} }
} }
} }
} }
} }
fun generateHemisphere(sides: Int, segments: Int, radius: Double = 1.0, invert: Boolean = false, writer: VertexWriter) { fun generateHemisphere(sides: Int, segments: Int, radius: Double = 1.0, invert: Boolean = false, writer: VertexWriter) {
val inverter = if (invert) -1.0 else 1.0 val inverter = if (invert) -1.0 else 1.0
for (t in 0 until segments) { for (t in 0 until segments) {
for (s in 0 until sides) { for (s in 0 until sides) {
val st00 = Spherical(radius, s * Math.PI * 2.0 / sides, t * Math.PI*0.5 / segments) val st00 = Spherical(radius, s * Math.PI * 2.0 / sides, t * Math.PI*0.5 / segments)
val st01 = Spherical(radius, s * Math.PI * 2.0 / sides, (t + 1) * Math.PI*0.5 / segments) val st01 = Spherical(radius, s * Math.PI * 2.0 / sides, (t + 1) * Math.PI*0.5 / segments)
val st10 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, t * Math.PI*0.5 / segments) val st10 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, t * Math.PI*0.5 / segments)
val st11 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, (t + 1) * Math.PI*0.5 / segments) val st11 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, (t + 1) * Math.PI*0.5 / segments)
val thetaMax = Math.PI * 0.5 val thetaMax = Math.PI * 0.5
val phiMax = Math.PI * 2.0 val phiMax = Math.PI * 2.0
when (t) { when (t) {
0 -> { 0 -> {
writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax))
writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax))
writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax))
} }
else -> { else -> {
writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax))
writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax))
writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax))
writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax))
writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax)) writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax))
writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax))
} }
} }
} }
} }
} }

View File

@@ -1,54 +1,54 @@
# orx-no-clear # orx-no-clear
A simple OPENRNDR Extension that provides the classical drawing-without-clearing-the-screen functionality that A simple OPENRNDR Extension that provides the classical drawing-without-clearing-the-screen functionality that
OPENRNDR does not support natively. OPENRNDR does not support natively.
#### Usage #### Usage
```kotlin ```kotlin
fun main() = application { fun main() = application {
configure { configure {
title = "NoClearProgram" title = "NoClearProgram"
} }
program { program {
backgroundColor = ColorRGBa.PINK backgroundColor = ColorRGBa.PINK
extend(NoClear()) extend(NoClear())
extend { extend {
drawer.circle(Math.cos(seconds) * width / 2.0 + width / 2.0, Math.sin(seconds * 0.24) * height / 2.0 + height / 2.0, 20.0) drawer.circle(Math.cos(seconds) * width / 2.0 + width / 2.0, Math.sin(seconds * 0.24) * height / 2.0 + height / 2.0, 20.0)
} }
} }
} }
``` ```
#### Usage with additional configuration #### Usage with additional configuration
Optionally, a static `backdrop` may be setup by providing custom code. Optionally, a static `backdrop` may be setup by providing custom code.
- Example 1. Customising the backdrop with an image - Example 1. Customising the backdrop with an image
```kotlin ```kotlin
extend(NoClear()) { extend(NoClear()) {
val img = loadImage("data\\backdrop.png") val img = loadImage("data\\backdrop.png")
backdrop = { backdrop = {
drawer.image(img, 0.0, 0.0, width * 1.0, height * 1.0) drawer.image(img, 0.0, 0.0, width * 1.0, height * 1.0)
} }
} }
``` ```
- Example 2. Customising the backdrop with a checker-board pattern - Example 2. Customising the backdrop with a checker-board pattern
```kotlin ```kotlin
extend(NoClear()) { extend(NoClear()) {
backdrop = { backdrop = {
val xw = width / 8.0 val xw = width / 8.0
val yh = height / 8.0 val yh = height / 8.0
drawer.fill = ColorRGBa.RED drawer.fill = ColorRGBa.RED
(0..7).forEach { row -> (0..7).forEach { row ->
(0..7).forEach { col -> (0..7).forEach { col ->
if ((row + col) % 2 == 0) { if ((row + col) % 2 == 0) {
drawer.rectangle(row * xw, col * yh, xw, yh) drawer.rectangle(row * xw, col * yh, xw, yh)
} }
} }
} }
} }
} }
``` ```
NB! any submitted _lambda expression_ must be valid within the `renderTarget` context. NB! any submitted _lambda expression_ must be valid within the `renderTarget` context.

View File

@@ -1,57 +1,57 @@
package org.openrndr.extra.noclear package org.openrndr.extra.noclear
import org.openrndr.Extension import org.openrndr.Extension
import org.openrndr.Program import org.openrndr.Program
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.draw.Drawer import org.openrndr.draw.Drawer
import org.openrndr.draw.RenderTarget import org.openrndr.draw.RenderTarget
import org.openrndr.draw.isolated import org.openrndr.draw.isolated
import org.openrndr.draw.renderTarget import org.openrndr.draw.renderTarget
import org.openrndr.math.Matrix44 import org.openrndr.math.Matrix44
class NoClear : Extension { class NoClear : Extension {
override var enabled: Boolean = true override var enabled: Boolean = true
private var renderTarget: RenderTarget? = null private var renderTarget: RenderTarget? = null
/** /**
* code-block to draw an optional custom backdrop * code-block to draw an optional custom backdrop
*/ */
var backdrop: (() -> Unit)? = null var backdrop: (() -> Unit)? = null
override fun beforeDraw(drawer: Drawer, program: Program) { override fun beforeDraw(drawer: Drawer, program: Program) {
if (program.width > 0 && program.height > 0) { // only if the window is not minimised if (program.width > 0 && program.height > 0) { // only if the window is not minimised
if (renderTarget == null || renderTarget?.width != program.width || renderTarget?.height != program.height) { if (renderTarget == null || renderTarget?.width != program.width || renderTarget?.height != program.height) {
renderTarget?.let { renderTarget?.let {
it.colorBuffer(0).destroy() it.colorBuffer(0).destroy()
it.detachColorBuffers() it.detachColorBuffers()
it.destroy() it.destroy()
} }
renderTarget = renderTarget(program.width, program.height) { renderTarget = renderTarget(program.width, program.height) {
colorBuffer() colorBuffer()
depthBuffer() depthBuffer()
} }
renderTarget?.let { renderTarget?.let {
drawer.withTarget(it) { drawer.withTarget(it) {
background(program.backgroundColor ?: ColorRGBa.TRANSPARENT) background(program.backgroundColor ?: ColorRGBa.TRANSPARENT)
backdrop?.invoke() // draw custom backdrop backdrop?.invoke() // draw custom backdrop
} }
} }
} }
} }
renderTarget?.bind() renderTarget?.bind()
} }
override fun afterDraw(drawer: Drawer, program: Program) { override fun afterDraw(drawer: Drawer, program: Program) {
renderTarget?.unbind() renderTarget?.unbind()
renderTarget?.let { renderTarget?.let {
drawer.isolated { drawer.isolated {
drawer.ortho() drawer.ortho()
drawer.view = Matrix44.IDENTITY drawer.view = Matrix44.IDENTITY
drawer.model = Matrix44.IDENTITY drawer.model = Matrix44.IDENTITY
drawer.image(it.colorBuffer(0)) drawer.image(it.colorBuffer(0))
} }
} }
} }
} }

View File

@@ -1,123 +1,123 @@
# orx-noise # orx-noise
A collection of noisy functions A collection of noisy functions
## Uniform random numbers ## Uniform random numbers
```kotlin ```kotlin
val sua = Double.uniform() val sua = Double.uniform()
val sub = Double.uniform(-1.0, 1.0) val sub = Double.uniform(-1.0, 1.0)
val v2ua = Vector2.uniform() val v2ua = Vector2.uniform()
val v2ub = Vector2.uniform(-1.0, 1.0) val v2ub = Vector2.uniform(-1.0, 1.0)
val v2uc = Vector2.uniform(Vector2(0.0, 0.0), Vector2(1.0, 1.0)) val v2uc = Vector2.uniform(Vector2(0.0, 0.0), Vector2(1.0, 1.0))
val v2ur = Vector2.uniformRing(0.5, 1.0) val v2ur = Vector2.uniformRing(0.5, 1.0)
val v3ua = Vector3.uniform() val v3ua = Vector3.uniform()
val v3ub = Vector3.uniform(-1.0, 1.0) val v3ub = Vector3.uniform(-1.0, 1.0)
val v3uc = Vector3.uniform(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0)) val v3uc = Vector3.uniform(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0))
val v3ur = Vector3.uniformRing(0.5, 1.0) val v3ur = Vector3.uniformRing(0.5, 1.0)
val v4ua = Vector4.uniform() val v4ua = Vector4.uniform()
val v4ub = Vector4.uniform(-1.0, 1.0) val v4ub = Vector4.uniform(-1.0, 1.0)
val v4uc = Vector4.uniform(Vector4(0.0, 0.0, 0.0, 0.0), Vector4(1.0, 1.0, 1.0, 1.0)) val v4uc = Vector4.uniform(Vector4(0.0, 0.0, 0.0, 0.0), Vector4(1.0, 1.0, 1.0, 1.0))
val v4ur = Vector4.uniformRing(0.5, 1.0) val v4ur = Vector4.uniformRing(0.5, 1.0)
val ringSamples = List(500) { Vector2.uniformRing() } val ringSamples = List(500) { Vector2.uniformRing() }
``` ```
## Multi-dimensional noise ## Multi-dimensional noise
These are a mostly straight port from FastNoise-Java but have a slightly different interface. These are a mostly straight port from FastNoise-Java but have a slightly different interface.
### Perlin noise ### Perlin noise
``` ```
// -- 2d // -- 2d
val v0 = perlinLinear(seed, x, y) val v0 = perlinLinear(seed, x, y)
val v1 = perlinQuintic(seed, x, y) val v1 = perlinQuintic(seed, x, y)
val v2 = perlinHermite(seed, x, y) val v2 = perlinHermite(seed, x, y)
// -- 3d // -- 3d
val v3 = perlinLinear(seed, x, y, z) val v3 = perlinLinear(seed, x, y, z)
val v4 = perlinQuintic(seed, x, y, z) val v4 = perlinQuintic(seed, x, y, z)
val v5 = perlinHermite(seed, x, y, z) val v5 = perlinHermite(seed, x, y, z)
``` ```
### Value noise ### Value noise
``` ```
// -- 2d // -- 2d
val v0 = valueLinear(seed, x, y) val v0 = valueLinear(seed, x, y)
val v1 = valueQuintic(seed, x, y) val v1 = valueQuintic(seed, x, y)
val v2 = valueHermite(seed, x, y) val v2 = valueHermite(seed, x, y)
// -- 3d // -- 3d
val v3 = valueLinear(seed, x, y, z) val v3 = valueLinear(seed, x, y, z)
val v4 = valueQuintic(seed, x, y, z) val v4 = valueQuintic(seed, x, y, z)
val v5 = valueHermite(seed, x, y ,z) val v5 = valueHermite(seed, x, y ,z)
``` ```
### Simplex noise ### Simplex noise
``` ```
// -- 2d // -- 2d
val v0 = simplexLinear(seed, x, y) val v0 = simplexLinear(seed, x, y)
val v1 = simplexQuintic(seed, x, y) val v1 = simplexQuintic(seed, x, y)
val v2 = simplexHermite(seed, x, y) val v2 = simplexHermite(seed, x, y)
// -- 3d // -- 3d
val v3 = simplexLinear(seed, x, y, z) val v3 = simplexLinear(seed, x, y, z)
val v4 = simplexQuintic(seed, x, y, z) val v4 = simplexQuintic(seed, x, y, z)
val v5 = simplexHermite(seed, x, y ,z) val v5 = simplexHermite(seed, x, y ,z)
``` ```
### Cubic noise ### Cubic noise
``` ```
// -- 2d // -- 2d
val v0 = cubicLinear(seed, x, y) val v0 = cubicLinear(seed, x, y)
val v1 = cubicQuintic(seed, x, y) val v1 = cubicQuintic(seed, x, y)
val v2 = cubicHermite(seed, x, y) val v2 = cubicHermite(seed, x, y)
// -- 3d // -- 3d
val v3 = cubicLinear(seed, x, y, z) val v3 = cubicLinear(seed, x, y, z)
val v4 = cubicQuintic(seed, x, y, z) val v4 = cubicQuintic(seed, x, y, z)
val v5 = cubicHermite(seed, x, y ,z) val v5 = cubicHermite(seed, x, y ,z)
``` ```
### Fractal noise ### Fractal noise
The library provides 3 functions with which fractal noise can be composed. The library provides 3 functions with which fractal noise can be composed.
#### Fractal brownian motion (FBM) #### Fractal brownian motion (FBM)
``` ```
val v0 = fbm(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) val v0 = fbm(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
val v1 = fbm(seed, x, y, ::simplexLinear, octaves, lacunarity, gain) val v1 = fbm(seed, x, y, ::simplexLinear, octaves, lacunarity, gain)
val v2 = fbm(seed, x, y, ::valueLinear, octaves, lacunarity, gain) val v2 = fbm(seed, x, y, ::valueLinear, octaves, lacunarity, gain)
val v3 = fbm(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) val v3 = fbm(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
val v4 = fbm(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain) val v4 = fbm(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain)
val v5 = fbm(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain) val v5 = fbm(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain)
``` ```
#### Rigid #### Rigid
``` ```
val v0 = rigid(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) val v0 = rigid(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
val v1 = rigid(seed, x, y, ::simplexLinear, octaves, lacunarity, gain) val v1 = rigid(seed, x, y, ::simplexLinear, octaves, lacunarity, gain)
val v2 = rigid(seed, x, y, ::valueLinear, octaves, lacunarity, gain) val v2 = rigid(seed, x, y, ::valueLinear, octaves, lacunarity, gain)
val v3 = rigid(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) val v3 = rigid(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
val v4 = rigid(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain) val v4 = rigid(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain)
val v5 = rigid(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain) val v5 = rigid(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain)
``` ```
#### Billow #### Billow
``` ```
val v0 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) val v0 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
val v1 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) val v1 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
val v2 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) val v2 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
val v3 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) val v3 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
val v4 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) val v4 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
val v5 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) val v5 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain)
``` ```

View File

@@ -1,28 +1,28 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
private const val CUBIC_2D_BOUNDING = 1 / (1.5 * 1.5).toFloat() private const val CUBIC_2D_BOUNDING = 1 / (1.5 * 1.5).toFloat()
fun cubic(seed: Int, x: Double, y: Double): Double { fun cubic(seed: Int, x: Double, y: Double): Double {
val x1 = x.fastFloor() val x1 = x.fastFloor()
val y1 = y.fastFloor() val y1 = y.fastFloor()
val x0 = x1 - 1 val x0 = x1 - 1
val y0 = y1 - 1 val y0 = y1 - 1
val x2 = x1 + 1 val x2 = x1 + 1
val y2 = y1 + 1 val y2 = y1 + 1
val x3 = x1 + 2 val x3 = x1 + 2
val y3 = y1 + 2 val y3 = y1 + 2
val xs = x - x1.toDouble() val xs = x - x1.toDouble()
val ys = y - y1.toDouble() val ys = y - y1.toDouble()
return cubic( return cubic(
cubic(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), valCoord2D(seed, x2, y0), valCoord2D(seed, x3, y0), cubic(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), valCoord2D(seed, x2, y0), valCoord2D(seed, x3, y0),
xs), xs),
cubic(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), valCoord2D(seed, x2, y1), valCoord2D(seed, x3, y1), cubic(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), valCoord2D(seed, x2, y1), valCoord2D(seed, x3, y1),
xs), xs),
cubic(valCoord2D(seed, x0, y2), valCoord2D(seed, x1, y2), valCoord2D(seed, x2, y2), valCoord2D(seed, x3, y2), cubic(valCoord2D(seed, x0, y2), valCoord2D(seed, x1, y2), valCoord2D(seed, x2, y2), valCoord2D(seed, x3, y2),
xs), xs),
cubic(valCoord2D(seed, x0, y3), valCoord2D(seed, x1, y3), valCoord2D(seed, x2, y3), valCoord2D(seed, x3, y3), cubic(valCoord2D(seed, x0, y3), valCoord2D(seed, x1, y3), valCoord2D(seed, x2, y3), valCoord2D(seed, x3, y3),
xs), xs),
ys) * CUBIC_2D_BOUNDING ys) * CUBIC_2D_BOUNDING
} }

View File

@@ -1,51 +1,51 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
private const val CUBIC_3D_BOUNDING = 1 / (1.5 * 1.5 * 1.5).toFloat() private const val CUBIC_3D_BOUNDING = 1 / (1.5 * 1.5 * 1.5).toFloat()
fun cubic(seed: Int, x: Double, y: Double, z: Double): Double { fun cubic(seed: Int, x: Double, y: Double, z: Double): Double {
val x1 = x.fastFloor() val x1 = x.fastFloor()
val y1 = y.fastFloor() val y1 = y.fastFloor()
val z1 = z.fastFloor() val z1 = z.fastFloor()
val x0 = x1 - 1 val x0 = x1 - 1
val y0 = y1 - 1 val y0 = y1 - 1
val z0 = z1 - 1 val z0 = z1 - 1
val x2 = x1 + 1 val x2 = x1 + 1
val y2 = y1 + 1 val y2 = y1 + 1
val z2 = z1 + 1 val z2 = z1 + 1
val x3 = x1 + 2 val x3 = x1 + 2
val y3 = y1 + 2 val y3 = y1 + 2
val z3 = z1 + 2 val z3 = z1 + 2
val xs = x - x1.toFloat() val xs = x - x1.toFloat()
val ys = y - y1.toFloat() val ys = y - y1.toFloat()
val zs = z - z1.toFloat() val zs = z - z1.toFloat()
return cubic( return cubic(
cubic( cubic(
cubic(valCoord3D(seed, x0, y0, z0), valCoord3D(seed, x1, y0, z0), valCoord3D(seed, x2, y0, z0), valCoord3D(seed, x3, y0, z0), xs), cubic(valCoord3D(seed, x0, y0, z0), valCoord3D(seed, x1, y0, z0), valCoord3D(seed, x2, y0, z0), valCoord3D(seed, x3, y0, z0), xs),
cubic(valCoord3D(seed, x0, y1, z0), valCoord3D(seed, x1, y1, z0), valCoord3D(seed, x2, y1, z0), valCoord3D(seed, x3, y1, z0), xs), cubic(valCoord3D(seed, x0, y1, z0), valCoord3D(seed, x1, y1, z0), valCoord3D(seed, x2, y1, z0), valCoord3D(seed, x3, y1, z0), xs),
cubic(valCoord3D(seed, x0, y2, z0), valCoord3D(seed, x1, y2, z0), valCoord3D(seed, x2, y2, z0), valCoord3D(seed, x3, y2, z0), xs), cubic(valCoord3D(seed, x0, y2, z0), valCoord3D(seed, x1, y2, z0), valCoord3D(seed, x2, y2, z0), valCoord3D(seed, x3, y2, z0), xs),
cubic(valCoord3D(seed, x0, y3, z0), valCoord3D(seed, x1, y3, z0), valCoord3D(seed, x2, y3, z0), valCoord3D(seed, x3, y3, z0), xs), cubic(valCoord3D(seed, x0, y3, z0), valCoord3D(seed, x1, y3, z0), valCoord3D(seed, x2, y3, z0), valCoord3D(seed, x3, y3, z0), xs),
ys), ys),
cubic( cubic(
cubic(valCoord3D(seed, x0, y0, z1), valCoord3D(seed, x1, y0, z1), valCoord3D(seed, x2, y0, z1), valCoord3D(seed, x3, y0, z1), xs), cubic(valCoord3D(seed, x0, y0, z1), valCoord3D(seed, x1, y0, z1), valCoord3D(seed, x2, y0, z1), valCoord3D(seed, x3, y0, z1), xs),
cubic(valCoord3D(seed, x0, y1, z1), valCoord3D(seed, x1, y1, z1), valCoord3D(seed, x2, y1, z1), valCoord3D(seed, x3, y1, z1), xs), cubic(valCoord3D(seed, x0, y1, z1), valCoord3D(seed, x1, y1, z1), valCoord3D(seed, x2, y1, z1), valCoord3D(seed, x3, y1, z1), xs),
cubic(valCoord3D(seed, x0, y2, z1), valCoord3D(seed, x1, y2, z1), valCoord3D(seed, x2, y2, z1), valCoord3D(seed, x3, y2, z1), xs), cubic(valCoord3D(seed, x0, y2, z1), valCoord3D(seed, x1, y2, z1), valCoord3D(seed, x2, y2, z1), valCoord3D(seed, x3, y2, z1), xs),
cubic(valCoord3D(seed, x0, y3, z1), valCoord3D(seed, x1, y3, z1), valCoord3D(seed, x2, y3, z1), valCoord3D(seed, x3, y3, z1), xs), cubic(valCoord3D(seed, x0, y3, z1), valCoord3D(seed, x1, y3, z1), valCoord3D(seed, x2, y3, z1), valCoord3D(seed, x3, y3, z1), xs),
ys), ys),
cubic( cubic(
cubic(valCoord3D(seed, x0, y0, z2), valCoord3D(seed, x1, y0, z2), valCoord3D(seed, x2, y0, z2), valCoord3D(seed, x3, y0, z2), xs), cubic(valCoord3D(seed, x0, y0, z2), valCoord3D(seed, x1, y0, z2), valCoord3D(seed, x2, y0, z2), valCoord3D(seed, x3, y0, z2), xs),
cubic(valCoord3D(seed, x0, y1, z2), valCoord3D(seed, x1, y1, z2), valCoord3D(seed, x2, y1, z2), valCoord3D(seed, x3, y1, z2), xs), cubic(valCoord3D(seed, x0, y1, z2), valCoord3D(seed, x1, y1, z2), valCoord3D(seed, x2, y1, z2), valCoord3D(seed, x3, y1, z2), xs),
cubic(valCoord3D(seed, x0, y2, z2), valCoord3D(seed, x1, y2, z2), valCoord3D(seed, x2, y2, z2), valCoord3D(seed, x3, y2, z2), xs), cubic(valCoord3D(seed, x0, y2, z2), valCoord3D(seed, x1, y2, z2), valCoord3D(seed, x2, y2, z2), valCoord3D(seed, x3, y2, z2), xs),
cubic(valCoord3D(seed, x0, y3, z2), valCoord3D(seed, x1, y3, z2), valCoord3D(seed, x2, y3, z2), valCoord3D(seed, x3, y3, z2), xs), cubic(valCoord3D(seed, x0, y3, z2), valCoord3D(seed, x1, y3, z2), valCoord3D(seed, x2, y3, z2), valCoord3D(seed, x3, y3, z2), xs),
ys), ys),
cubic( cubic(
cubic(valCoord3D(seed, x0, y0, z3), valCoord3D(seed, x1, y0, z3), valCoord3D(seed, x2, y0, z3), valCoord3D(seed, x3, y0, z3), xs), cubic(valCoord3D(seed, x0, y0, z3), valCoord3D(seed, x1, y0, z3), valCoord3D(seed, x2, y0, z3), valCoord3D(seed, x3, y0, z3), xs),
cubic(valCoord3D(seed, x0, y1, z3), valCoord3D(seed, x1, y1, z3), valCoord3D(seed, x2, y1, z3), valCoord3D(seed, x3, y1, z3), xs), cubic(valCoord3D(seed, x0, y1, z3), valCoord3D(seed, x1, y1, z3), valCoord3D(seed, x2, y1, z3), valCoord3D(seed, x3, y1, z3), xs),
cubic(valCoord3D(seed, x0, y2, z3), valCoord3D(seed, x1, y2, z3), valCoord3D(seed, x2, y2, z3), valCoord3D(seed, x3, y2, z3), xs), cubic(valCoord3D(seed, x0, y2, z3), valCoord3D(seed, x1, y2, z3), valCoord3D(seed, x2, y2, z3), valCoord3D(seed, x3, y2, z3), xs),
cubic(valCoord3D(seed, x0, y3, z3), valCoord3D(seed, x1, y3, z3), valCoord3D(seed, x2, y3, z3), valCoord3D(seed, x3, y3, z3), xs), cubic(valCoord3D(seed, x0, y3, z3), valCoord3D(seed, x1, y3, z3), valCoord3D(seed, x2, y3, z3), valCoord3D(seed, x3, y3, z3), xs),
ys), ys),
zs) * CUBIC_3D_BOUNDING zs) * CUBIC_3D_BOUNDING
} }

View File

@@ -1,105 +1,105 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
inline fun fbm(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, inline fun fbm(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = noise(seed, x, y, z) var sum = noise(seed, x, y, z)
var amp = 1.0 var amp = 1.0
var x = x var x = x
var y = y var y = y
var z = z var z = z
for (i in 1 until octaves) { for (i in 1 until octaves) {
x *= lacunarity x *= lacunarity
y *= lacunarity y *= lacunarity
z *= lacunarity z *= lacunarity
amp *= gain amp *= gain
sum += noise(seed + i, x, y, z) * amp sum += noise(seed + i, x, y, z) * amp
} }
return sum return sum
} }
inline fun fbm(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double, inline fun fbm(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = noise(seed, x, y) var sum = noise(seed, x, y)
var amp = 1.0 var amp = 1.0
var x = x var x = x
var y = y var y = y
for (i in 1 until octaves) { for (i in 1 until octaves) {
x *= lacunarity x *= lacunarity
y *= lacunarity y *= lacunarity
amp *= gain amp *= gain
sum += noise(seed + i, x, y) * amp sum += noise(seed + i, x, y) * amp
} }
return sum return sum
} }
inline fun billow(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, inline fun billow(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) : Double { octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) : Double {
var sum = Math.abs(noise(seed, x, y, z) * 2.0 - 1.0) var sum = Math.abs(noise(seed, x, y, z) * 2.0 - 1.0)
var amp = 1.0 var amp = 1.0
var x = x var x = x
var y = y var y = y
var z = z var z = z
for (i in 1 until octaves) { for (i in 1 until octaves) {
x *= lacunarity x *= lacunarity
y *= lacunarity y *= lacunarity
z *= lacunarity z *= lacunarity
amp *= gain amp *= gain
sum += Math.abs(noise(seed + i, x, y, z) * 2.0 - 1.0) * amp sum += Math.abs(noise(seed + i, x, y, z) * 2.0 - 1.0) * amp
} }
return sum return sum
} }
inline fun billow(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double, inline fun billow(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) : Double { octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) : Double {
var sum = Math.abs(noise(seed, x, y) * 2.0 - 1.0) var sum = Math.abs(noise(seed, x, y) * 2.0 - 1.0)
var amp = 1.0 var amp = 1.0
var x = x var x = x
var y = y var y = y
for (i in 1 until octaves) { for (i in 1 until octaves) {
x *= lacunarity x *= lacunarity
y *= lacunarity y *= lacunarity
amp *= gain amp *= gain
sum += Math.abs(noise(seed + i, x, y) * 2.0 - 1.0) * amp sum += Math.abs(noise(seed + i, x, y) * 2.0 - 1.0) * amp
} }
return sum return sum
} }
inline fun rigid(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double, inline fun rigid(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = 1.0 - Math.abs(noise(seed, x, y)) var sum = 1.0 - Math.abs(noise(seed, x, y))
var amp = 1.0 var amp = 1.0
var x = x var x = x
var y = y var y = y
for (i in 1 until octaves) { for (i in 1 until octaves) {
x *= lacunarity x *= lacunarity
y *= lacunarity y *= lacunarity
amp *= gain amp *= gain
sum -= (1.0 - Math.abs(noise(seed + i, x, y))) * amp sum -= (1.0 - Math.abs(noise(seed + i, x, y))) * amp
} }
return sum return sum
} }
inline fun rigid(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, inline fun rigid(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double,
octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double {
var sum = 1.0 - Math.abs(noise(seed, x, y, z)) var sum = 1.0 - Math.abs(noise(seed, x, y, z))
var amp = 1.0 var amp = 1.0
var x = x var x = x
var y = y var y = y
var z = z var z = z
for (i in 1 until octaves) { for (i in 1 until octaves) {
x *= lacunarity x *= lacunarity
y *= lacunarity y *= lacunarity
z *= lacunarity z *= lacunarity
amp *= gain amp *= gain
sum -= (1.0 - Math.abs(noise(seed + i, x, y, z))) * amp sum -= (1.0 - Math.abs(noise(seed + i, x, y, z))) * amp
} }
return sum return sum
} }

File diff suppressed because one or more lines are too long

View File

@@ -1,24 +1,24 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
fun hermite(t: Double): Double { fun hermite(t: Double): Double {
return t * t * (3 - 2 * t) return t * t * (3 - 2 * t)
} }
fun quintic(t: Double): Double { fun quintic(t: Double): Double {
return t * t * t * (t * (t * 6 - 15) + 10) return t * t * t * (t * (t * 6 - 15) + 10)
} }
fun cubic(a: Double, b: Double, c: Double, d: Double, t: Double) : Double { fun cubic(a: Double, b: Double, c: Double, d: Double, t: Double) : Double {
val p = d - c - (a - b) val p = d - c - (a - b)
return t * t * t * p + t * t * (a - b - p) + t * (c - a) + b return t * t * t * p + t * t * (a - b - p) + t * (c - a) + b
} }
fun linear(x: Double) : Double { fun linear(x: Double) : Double {
return x return x
} }
fun lerp(left: Double, right: Double, x: Double): Double { fun lerp(left: Double, right: Double, x: Double): Double {
return left * (1.0 - x) + right * x return left * (1.0 - x) + right * x
} }

View File

@@ -1,6 +1,6 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
fun Double.fastFloor(): Int { fun Double.fastFloor(): Int {
return if (this >= 0) this.toInt() else this.toInt() - 1 return if (this >= 0) this.toInt() else this.toInt() - 1
} }

View File

@@ -1,26 +1,26 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
fun perlinLinear(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::linear) fun perlinLinear(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::linear)
fun perlinQuintic(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::quintic) fun perlinQuintic(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::quintic)
fun perlinHermite(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::hermite) fun perlinHermite(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::hermite)
private fun perlin(seed: Int, x: Double, y: Double, interpolator: (Double) -> Double): Double { private fun perlin(seed: Int, x: Double, y: Double, interpolator: (Double) -> Double): Double {
val x0 = x.fastFloor() val x0 = x.fastFloor()
val y0 = y.fastFloor() val y0 = y.fastFloor()
val x1 = x0 + 1 val x1 = x0 + 1
val y1 = y0 + 1 val y1 = y0 + 1
val xs = interpolator(x - x0) val xs = interpolator(x - x0)
val ys = interpolator(y - y0) val ys = interpolator(y - y0)
val xd0 = x - x0 val xd0 = x - x0
val yd0 = y - y0 val yd0 = y - y0
val xd1 = xd0 - 1 val xd1 = xd0 - 1
val yd1 = yd0 - 1 val yd1 = yd0 - 1
val xf0 = lerp(gradCoord2D(seed, x0, y0, xd0, yd0), gradCoord2D(seed, x1, y0, xd1, yd0), xs) val xf0 = lerp(gradCoord2D(seed, x0, y0, xd0, yd0), gradCoord2D(seed, x1, y0, xd1, yd0), xs)
val xf1 = lerp(gradCoord2D(seed, x0, y1, xd0, yd1), gradCoord2D(seed, x1, y1, xd1, yd1), xs) val xf1 = lerp(gradCoord2D(seed, x0, y1, xd0, yd1), gradCoord2D(seed, x1, y1, xd1, yd1), xs)
return lerp(xf0, xf1, ys) return lerp(xf0, xf1, ys)
} }

View File

@@ -1,35 +1,35 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
fun perlinLinear(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::linear) fun perlinLinear(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::linear)
fun perlinQuintic(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::quintic) fun perlinQuintic(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::quintic)
fun perlinHermite(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::hermite) fun perlinHermite(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::hermite)
inline fun perlin(seed: Int, x: Double, y: Double, z: Double, crossinline interpolator: (Double) -> Double = ::linear): Double { inline fun perlin(seed: Int, x: Double, y: Double, z: Double, crossinline interpolator: (Double) -> Double = ::linear): Double {
val x0 = x.fastFloor() val x0 = x.fastFloor()
val y0 = y.fastFloor() val y0 = y.fastFloor()
val z0 = z.fastFloor() val z0 = z.fastFloor()
val x1 = x0 + 1 val x1 = x0 + 1
val y1 = y0 + 1 val y1 = y0 + 1
val z1 = z0 + 1 val z1 = z0 + 1
val xs: Double = interpolator(x - x0) val xs: Double = interpolator(x - x0)
val ys: Double = interpolator(y - y0) val ys: Double = interpolator(y - y0)
val zs: Double = interpolator(z - z0) val zs: Double = interpolator(z - z0)
val xd0 = x - x0 val xd0 = x - x0
val yd0 = y - y0 val yd0 = y - y0
val zd0 = z - z0 val zd0 = z - z0
val xd1 = xd0 - 1 val xd1 = xd0 - 1
val yd1 = yd0 - 1 val yd1 = yd0 - 1
val zd1 = zd0 - 1 val zd1 = zd0 - 1
val xf00 = lerp(gradCoord3D(seed, x0, y0, z0, xd0, yd0, zd0), gradCoord3D(seed, x1, y0, z0, xd1, yd0, zd0), xs) val xf00 = lerp(gradCoord3D(seed, x0, y0, z0, xd0, yd0, zd0), gradCoord3D(seed, x1, y0, z0, xd1, yd0, zd0), xs)
val xf10 = lerp(gradCoord3D(seed, x0, y1, z0, xd0, yd1, zd0), gradCoord3D(seed, x1, y1, z0, xd1, yd1, zd0), xs) val xf10 = lerp(gradCoord3D(seed, x0, y1, z0, xd0, yd1, zd0), gradCoord3D(seed, x1, y1, z0, xd1, yd1, zd0), xs)
val xf01 = lerp(gradCoord3D(seed, x0, y0, z1, xd0, yd0, zd1), gradCoord3D(seed, x1, y0, z1, xd1, yd0, zd1), xs) val xf01 = lerp(gradCoord3D(seed, x0, y0, z1, xd0, yd0, zd1), gradCoord3D(seed, x1, y0, z1, xd1, yd0, zd1), xs)
val xf11 = lerp(gradCoord3D(seed, x0, y1, z1, xd0, yd1, zd1), gradCoord3D(seed, x1, y1, z1, xd1, yd1, zd1), xs) val xf11 = lerp(gradCoord3D(seed, x0, y1, z1, xd0, yd1, zd1), gradCoord3D(seed, x1, y1, z1, xd1, yd1, zd1), xs)
val yf0 = lerp(xf00, xf10, ys) val yf0 = lerp(xf00, xf10, ys)
val yf1 = lerp(xf01, xf11, ys) val yf1 = lerp(xf01, xf11, ys)
return lerp(yf0, yf1, zs) return lerp(yf0, yf1, zs)
} }

View File

@@ -1,63 +1,63 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
private val G2 = 1.0 / 4.0 private val G2 = 1.0 / 4.0
private val F2 = 1.0 / 2.0 private val F2 = 1.0 / 2.0
fun simplex(seed: Int, x: Double, y: Double): Double { fun simplex(seed: Int, x: Double, y: Double): Double {
var t = (x + y) * F2 var t = (x + y) * F2
val i = (x + t).fastFloor() val i = (x + t).fastFloor()
val j = (y + t).fastFloor() val j = (y + t).fastFloor()
t = ((i + j) * G2) t = ((i + j) * G2)
val X0 = i - t val X0 = i - t
val Y0 = j - t val Y0 = j - t
val x0 = x - X0 val x0 = x - X0
val y0 = y - Y0 val y0 = y - Y0
val i1: Int val i1: Int
val j1: Int val j1: Int
if (x0 > y0) { if (x0 > y0) {
i1 = 1 i1 = 1
j1 = 0 j1 = 0
} else { } else {
i1 = 0 i1 = 0
j1 = 1 j1 = 1
} }
val x1 = x0 - i1 + G2 val x1 = x0 - i1 + G2
val y1 = y0 - j1 + G2 val y1 = y0 - j1 + G2
val x2 = x0 - 1 + F2 val x2 = x0 - 1 + F2
val y2 = y0 - 1 + F2 val y2 = y0 - 1 + F2
val n0: Double val n0: Double
val n1: Double val n1: Double
val n2: Double val n2: Double
t = 0.5 - x0 * x0 - y0 * y0 t = 0.5 - x0 * x0 - y0 * y0
if (t < 0) if (t < 0)
n0 = 0.0 n0 = 0.0
else { else {
t *= t t *= t
n0 = t * t * gradCoord2D(seed, i, j, x0, y0) n0 = t * t * gradCoord2D(seed, i, j, x0, y0)
} }
t = 0.5 - x1 * x1 - y1 * y1 t = 0.5 - x1 * x1 - y1 * y1
if (t < 0) if (t < 0)
n1 = 0.0 n1 = 0.0
else { else {
t *= t t *= t
n1 = t * t * gradCoord2D(seed, i + i1, j + j1, x1, y1) n1 = t * t * gradCoord2D(seed, i + i1, j + j1, x1, y1)
} }
t = 0.5 - x2 * x2 - y2 * y2 t = 0.5 - x2 * x2 - y2 * y2
if (t < 0) if (t < 0)
n2 = 0.0 n2 = 0.0
else { else {
t *= t t *= t
n2 = t * t * gradCoord2D(seed, i + 1, j + 1, x2, y2) n2 = t * t * gradCoord2D(seed, i + 1, j + 1, x2, y2)
} }
return 50.0 * (n0 + n1 + n2) return 50.0 * (n0 + n1 + n2)
} }

View File

@@ -1,94 +1,94 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
fun simplex(seed: Int, x: Double, y: Double, z: Double): Double { fun simplex(seed: Int, x: Double, y: Double, z: Double): Double {
var t = (x + y + z) / 3.0 var t = (x + y + z) / 3.0
val i = (x + t).fastFloor() val i = (x + t).fastFloor()
val j = (y + t).fastFloor() val j = (y + t).fastFloor()
val k = (z + t).fastFloor() val k = (z + t).fastFloor()
val t2 = (i + j + k) / 6.0 val t2 = (i + j + k) / 6.0
val x0 = x - (i - t2) val x0 = x - (i - t2)
val y0 = y - (j - t2) val y0 = y - (j - t2)
val z0 = z - (k - t2) val z0 = z - (k - t2)
val i1: Int val i1: Int
val j1: Int val j1: Int
val k1: Int val k1: Int
val i2: Int val i2: Int
val j2: Int val j2: Int
val k2: Int val k2: Int
if (x0 >= y0) { if (x0 >= y0) {
when { when {
y0 >= z0 -> { y0 >= z0 -> {
i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; }
x0 >= z0 -> { x0 >= z0 -> {
i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; }
else -> { else -> {
i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; }
} }
} else { } else {
when { when {
y0 < z0 -> { y0 < z0 -> {
i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; } i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; }
x0 < z0 -> { x0 < z0 -> {
i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; } i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; }
else -> { else -> {
i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; }
} }
} }
val x1 = x0 - i1 + 1.0 / 6.0 val x1 = x0 - i1 + 1.0 / 6.0
val y1 = y0 - j1 + 1.0 / 6.0 val y1 = y0 - j1 + 1.0 / 6.0
val z1 = z0 - k1 + 1.0 / 6.0 val z1 = z0 - k1 + 1.0 / 6.0
val x2 = x0 - i2 + 1.0 / 3.0 val x2 = x0 - i2 + 1.0 / 3.0
val y2 = y0 - j2 + 1.0 / 3.0 val y2 = y0 - j2 + 1.0 / 3.0
val z2 = z0 - k2 + 1.0 / 3.0 val z2 = z0 - k2 + 1.0 / 3.0
val x3 = x0 + ((1.0 / 6.0) * 3.0 - 1.0) val x3 = x0 + ((1.0 / 6.0) * 3.0 - 1.0)
val y3 = y0 + ((1.0 / 6.0) * 3.0 - 1.0) val y3 = y0 + ((1.0 / 6.0) * 3.0 - 1.0)
val z3 = z0 + ((1.0 / 6.0) * 3.0 - 1.0) val z3 = z0 + ((1.0 / 6.0) * 3.0 - 1.0)
val n0: Double val n0: Double
run { run {
var t = 0.6 * x0 * x0 - y0 * y0 - z0 * z0 var t = 0.6 * x0 * x0 - y0 * y0 - z0 * z0
if (t < 0) { if (t < 0) {
n0 = 0.0 n0 = 0.0
} else { } else {
t *= t t *= t
n0 = t * t * gradCoord3D(seed, i, j, k, x0, y0, z0) n0 = t * t * gradCoord3D(seed, i, j, k, x0, y0, z0)
} }
} }
val n1: Double val n1: Double
run { run {
var t = 0.6 * x1 * x1 - y1 * y1 - z1 * z1 var t = 0.6 * x1 * x1 - y1 * y1 - z1 * z1
if (t < 0) { if (t < 0) {
n1 = 0.0 n1 = 0.0
} else { } else {
t *= t t *= t
n1 = t * t * gradCoord3D(seed, i + i1, j + j1, k + k1, x1, y1, z1) n1 = t * t * gradCoord3D(seed, i + i1, j + j1, k + k1, x1, y1, z1)
} }
} }
val n2: Double val n2: Double
run { run {
var t = 0.6 * x2 * x2 - y2 * y2 - z2 * z2 var t = 0.6 * x2 * x2 - y2 * y2 - z2 * z2
if (t < 0) { if (t < 0) {
n2 = 0.0 n2 = 0.0
} else { } else {
t *= t t *= t
n2 = t * t * gradCoord3D(seed, i + i2, j + j2, k + k2, x2, y2, z2) n2 = t * t * gradCoord3D(seed, i + i2, j + j2, k + k2, x2, y2, z2)
} }
} }
val n3: Double val n3: Double
run { run {
var t = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 var t = 0.6 - x3 * x3 - y3 * y3 - z3 * z3
if (t < 0) if (t < 0)
n3 = 0.0 n3 = 0.0
else { else {
t *= t t *= t
n3 = t * t * gradCoord3D(seed, i + 1, j + 1, k + 1, x3, y3, z3) n3 = t * t * gradCoord3D(seed, i + 1, j + 1, k + 1, x3, y3, z3)
} }
} }
return 32 * (n0 + n1 + n2 + n3) return 32 * (n0 + n1 + n2 + n3)
} }

View File

@@ -1,71 +1,71 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import org.openrndr.math.Vector4 import org.openrndr.math.Vector4
fun Double.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Double { fun Double.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Double {
return (Math.random() * (max - min)) + min return (Math.random() * (max - min)) + min
} }
fun Vector2.Companion.uniform(min: Vector2 = -ONE, max: Vector2 = ONE): Vector2 { fun Vector2.Companion.uniform(min: Vector2 = -ONE, max: Vector2 = ONE): Vector2 {
return Vector2(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y)) return Vector2(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y))
} }
fun Vector2.Companion.uniform(min: Double = -1.0, max: Double = 1.0) = fun Vector2.Companion.uniform(min: Double = -1.0, max: Double = 1.0) =
Vector2.uniform(Vector2(min, min), Vector2(max, max)) Vector2.uniform(Vector2(min, min), Vector2(max, max))
fun Vector2.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector2 { fun Vector2.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector2 {
while (true) { while (true) {
uniform(-outerRadius, outerRadius).let { uniform(-outerRadius, outerRadius).let {
val squaredLength = it.squaredLength val squaredLength = it.squaredLength
if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) { if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) {
return it return it
} }
} }
} }
} }
fun Vector3.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Vector3 = fun Vector3.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Vector3 =
Vector3.uniform(Vector3(min, min, min), Vector3(max, max, max)) Vector3.uniform(Vector3(min, min, min), Vector3(max, max, max))
fun Vector3.Companion.uniform(min: Vector3 = -ONE, max: Vector3 = ONE): Vector3 { fun Vector3.Companion.uniform(min: Vector3 = -ONE, max: Vector3 = ONE): Vector3 {
return Vector3(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y), Double.uniform(min.z, max.z)) return Vector3(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y), Double.uniform(min.z, max.z))
} }
// squared length 'polyfill' for OPENRNDR 0.3.30 // squared length 'polyfill' for OPENRNDR 0.3.30
private val Vector3.squaredLength__: Double get() = x * x + y * y + z * z private val Vector3.squaredLength__: Double get() = x * x + y * y + z * z
fun Vector3.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector3 { fun Vector3.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector3 {
while (true) { while (true) {
uniform(-outerRadius, outerRadius).let { uniform(-outerRadius, outerRadius).let {
val squaredLength = it.squaredLength__ val squaredLength = it.squaredLength__
if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) { if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) {
return it return it
} }
} }
} }
} }
// squared length 'polyfill' for OPENRNDR 0.3.30 // squared length 'polyfill' for OPENRNDR 0.3.30
private val Vector4.squaredLength__: Double get() = x * x + y * y + z * z + w * w private val Vector4.squaredLength__: Double get() = x * x + y * y + z * z + w * w
fun Vector4.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Vector4 = fun Vector4.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Vector4 =
Vector4.uniform(Vector4(min, min, min, min), Vector4(max, max,max, max)) Vector4.uniform(Vector4(min, min, min, min), Vector4(max, max,max, max))
fun Vector4.Companion.uniform(min: Vector4 = -ONE, max: Vector4 = ONE): Vector4 { fun Vector4.Companion.uniform(min: Vector4 = -ONE, max: Vector4 = ONE): Vector4 {
return Vector4(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y), Double.uniform(min.z, max.z), Double.uniform(min.w, max.w)) return Vector4(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y), Double.uniform(min.z, max.z), Double.uniform(min.w, max.w))
} }
fun Vector4.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector4 { fun Vector4.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector4 {
while (true) { while (true) {
uniform(-outerRadius, outerRadius).let { uniform(-outerRadius, outerRadius).let {
val squaredLength = it.squaredLength__ val squaredLength = it.squaredLength__
if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) { if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) {
return it return it
} }
} }
} }
} }

View File

@@ -1,21 +1,21 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
fun valueLinear(seed: Int, x:Double, y:Double) = value(seed, x, y, ::linear) fun valueLinear(seed: Int, x:Double, y:Double) = value(seed, x, y, ::linear)
fun valueQuintic(seed: Int, x:Double, y:Double) = value(seed, x, y, ::quintic) fun valueQuintic(seed: Int, x:Double, y:Double) = value(seed, x, y, ::quintic)
fun valueHermite(seed: Int, x:Double, y:Double) = value(seed, x, y, ::hermite) fun valueHermite(seed: Int, x:Double, y:Double) = value(seed, x, y, ::hermite)
inline fun value(seed: Int, x: Double, y: Double, crossinline interpolation: (Double) -> Double = ::linear): Double { inline fun value(seed: Int, x: Double, y: Double, crossinline interpolation: (Double) -> Double = ::linear): Double {
val x0 = x.fastFloor() val x0 = x.fastFloor()
val y0 = y.fastFloor() val y0 = y.fastFloor()
val x1 = x0 + 1 val x1 = x0 + 1
val y1 = y0 + 1 val y1 = y0 + 1
val xs = interpolation(x - x0) val xs = interpolation(x - x0)
val ys = interpolation(y - y0) val ys = interpolation(y - y0)
val xf0 = lerp(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), xs) val xf0 = lerp(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), xs)
val xf1 = lerp(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), xs) val xf1 = lerp(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), xs)
return lerp(xf0, xf1, ys) return lerp(xf0, xf1, ys)
} }

View File

@@ -1,29 +1,29 @@
package org.openrndr.extra.noise package org.openrndr.extra.noise
fun valueLinear(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::linear) fun valueLinear(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::linear)
fun valueQuintic(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::quintic) fun valueQuintic(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::quintic)
fun valueHermite(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::hermite) fun valueHermite(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::hermite)
inline fun value(seed:Int, x: Double, y: Double, z: Double, crossinline interpolation:(Double)->Double = ::linear) : Double { inline fun value(seed:Int, x: Double, y: Double, z: Double, crossinline interpolation:(Double)->Double = ::linear) : Double {
val x0 = x.fastFloor() val x0 = x.fastFloor()
val y0 = y.fastFloor() val y0 = y.fastFloor()
val z0 = z.fastFloor() val z0 = z.fastFloor()
val x1 = x0 + 1 val x1 = x0 + 1
val y1 = y0 + 1 val y1 = y0 + 1
val z1 = z0 + 1 val z1 = z0 + 1
val xs = interpolation(x - x0) val xs = interpolation(x - x0)
val ys = interpolation(y - y0) val ys = interpolation(y - y0)
val zs = interpolation(z - z0) val zs = interpolation(z - z0)
val xf00 = lerp(valCoord3D(seed, x0, y0, z0), valCoord3D(seed, x1, y0, z0), xs) val xf00 = lerp(valCoord3D(seed, x0, y0, z0), valCoord3D(seed, x1, y0, z0), xs)
val xf10 = lerp(valCoord3D(seed, x0, y1, z0), valCoord3D(seed, x1, y1, z0), xs) val xf10 = lerp(valCoord3D(seed, x0, y1, z0), valCoord3D(seed, x1, y1, z0), xs)
val xf01 = lerp(valCoord3D(seed, x0, y0, z1), valCoord3D(seed, x1, y0, z1), xs) val xf01 = lerp(valCoord3D(seed, x0, y0, z1), valCoord3D(seed, x1, y0, z1), xs)
val xf11 = lerp(valCoord3D(seed, x0, y1, z1), valCoord3D(seed, x1, y1, z1), xs) val xf11 = lerp(valCoord3D(seed, x0, y1, z1), valCoord3D(seed, x1, y1, z1), xs)
val yf0 = lerp(xf00, xf10, ys) val yf0 = lerp(xf00, xf10, ys)
val yf1 = lerp(xf01, xf11, ys) val yf1 = lerp(xf01, xf11, ys)
return lerp(yf0, yf1, zs) return lerp(yf0, yf1, zs)
} }