changes
This commit is contained in:
84
README.md
84
README.md
@@ -1,42 +1,42 @@
|
||||
# ORX (OPENRNDR EXTRA)
|
||||
|
||||
[](https://jitpack.io/#openrndr/orx)
|
||||
|
||||
A growing library of assorted data structures, algorithms and utilities.
|
||||
|
||||
- [`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-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-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-mesh-generators`](orx-mesh-generators/README.md), triangular mesh generators
|
||||
- [`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-obj-loader`](orx-obj-loader/README.md), simple Wavefront .obj mesh loader
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
```
|
||||
repositories {
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
```
|
||||
|
||||
You can then add any of the ORX artefacts to your `dependencies {}`:
|
||||
```
|
||||
dependencies {
|
||||
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:
|
||||
```
|
||||
dependencies {
|
||||
compile 'com.github.openrndr.orx:orx-no-clear:v0.0.19'
|
||||
}
|
||||
```
|
||||
# ORX (OPENRNDR EXTRA)
|
||||
|
||||
[](https://jitpack.io/#openrndr/orx)
|
||||
|
||||
A growing library of assorted data structures, algorithms and utilities.
|
||||
|
||||
- [`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-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-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-mesh-generators`](orx-mesh-generators/README.md), triangular mesh generators
|
||||
- [`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-obj-loader`](orx-obj-loader/README.md), simple Wavefront .obj mesh loader
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
```
|
||||
repositories {
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
```
|
||||
|
||||
You can then add any of the ORX artefacts to your `dependencies {}`:
|
||||
```
|
||||
dependencies {
|
||||
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:
|
||||
```
|
||||
dependencies {
|
||||
compile 'com.github.openrndr.orx:orx-no-clear:v0.0.19'
|
||||
}
|
||||
```
|
||||
|
||||
24
ShaderError.txt
Normal file
24
ShaderError.txt
Normal 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);
|
||||
}
|
||||
132
build.gradle
132
build.gradle
@@ -1,67 +1,67 @@
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.3.10'
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group 'org.openrndr.extra'
|
||||
version '0.0.19'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
ext {
|
||||
openrndrVersion = "0.3.32-rc1"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'maven-publish'
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url = "https://dl.bintray.com/openrndr/openrndr"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.openrndr:openrndr-core:$openrndrVersion"
|
||||
compile "org.openrndr:openrndr-filter:$openrndrVersion"
|
||||
compile "org.openrndr:openrndr-shape:$openrndrVersion"
|
||||
compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.0.1'
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
from components.java
|
||||
|
||||
artifact sourceJar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task sourceJar(type: Jar) {
|
||||
classifier = 'sources'
|
||||
from sourceSets.main.kotlin
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.3.10'
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group 'org.openrndr.extra'
|
||||
version '0.0.20'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
ext {
|
||||
openrndrVersion = "0.3.32-rc1"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'maven-publish'
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url = "https://dl.bintray.com/openrndr/openrndr"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.openrndr:openrndr-core:$openrndrVersion"
|
||||
compile "org.openrndr:openrndr-filter:$openrndrVersion"
|
||||
compile "org.openrndr:openrndr-shape:$openrndrVersion"
|
||||
compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.0.1'
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
from components.java
|
||||
|
||||
artifact sourceJar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task sourceJar(type: Jar) {
|
||||
classifier = 'sources'
|
||||
from sourceSets.main.kotlin
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
# orx-camera
|
||||
|
||||
# orx-camera
|
||||
|
||||
3D camera and controls for OPENRNDR. This supersedes the to be deprecated functionality in OPENRNDR.
|
||||
@@ -1,74 +1,74 @@
|
||||
package org.openrndr.extras.camera
|
||||
|
||||
import org.openrndr.Extension
|
||||
import org.openrndr.Program
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.*
|
||||
import org.openrndr.math.Matrix44
|
||||
import org.openrndr.math.Vector3
|
||||
|
||||
@Suppress("unused")
|
||||
class Debug3D(eye: Vector3 = Vector3(0.0, 0.0, 10.0), lookAt: Vector3 = Vector3.ZERO, private val fov: Double = 90.0) : Extension {
|
||||
|
||||
override var enabled: Boolean = true
|
||||
var showGrid = false
|
||||
val orbitalCamera = OrbitalCamera(eye, lookAt)
|
||||
private val orbitalControls = OrbitalControls(orbitalCamera)
|
||||
private var lastSeconds: Double = -1.0
|
||||
|
||||
private val grid = vertexBuffer(
|
||||
vertexFormat {
|
||||
position(3)
|
||||
}
|
||||
, 4 * 21).apply {
|
||||
put {
|
||||
for (x in -10..10) {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeDraw(drawer: Drawer, program: Program) {
|
||||
if (lastSeconds == -1.0) lastSeconds = program.seconds
|
||||
|
||||
val delta = program.seconds - lastSeconds
|
||||
lastSeconds = program.seconds
|
||||
orbitalCamera.update(delta)
|
||||
|
||||
drawer.background(ColorRGBa.BLACK)
|
||||
drawer.perspective(fov, program.window.size.x / program.window.size.y, 0.1, 1000.0)
|
||||
drawer.view = orbitalCamera.viewMatrix()
|
||||
|
||||
if (showGrid) {
|
||||
drawer.isolated {
|
||||
drawer.fill = ColorRGBa.WHITE
|
||||
drawer.stroke = ColorRGBa.WHITE
|
||||
drawer.vertexBuffer(grid, DrawPrimitive.LINES)
|
||||
|
||||
// Axis cross
|
||||
drawer.fill = ColorRGBa.RED
|
||||
drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_X)
|
||||
|
||||
drawer.fill = ColorRGBa.GREEN
|
||||
drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Y)
|
||||
|
||||
drawer.fill = ColorRGBa.BLUE
|
||||
drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Z)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterDraw(drawer: Drawer, program: Program) {
|
||||
drawer.isolated {
|
||||
drawer.view = Matrix44.IDENTITY
|
||||
drawer.ortho()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setup(program: Program) {
|
||||
orbitalControls.setup(program)
|
||||
}
|
||||
package org.openrndr.extras.camera
|
||||
|
||||
import org.openrndr.Extension
|
||||
import org.openrndr.Program
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.*
|
||||
import org.openrndr.math.Matrix44
|
||||
import org.openrndr.math.Vector3
|
||||
|
||||
@Suppress("unused")
|
||||
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
|
||||
var showGrid = false
|
||||
val orbitalCamera = OrbitalCamera(eye, lookAt, 90.0)
|
||||
private val orbitalControls = OrbitalControls(orbitalCamera)
|
||||
private var lastSeconds: Double = -1.0
|
||||
|
||||
private val grid = vertexBuffer(
|
||||
vertexFormat {
|
||||
position(3)
|
||||
}
|
||||
, 4 * 21).apply {
|
||||
put {
|
||||
for (x in -10..10) {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeDraw(drawer: Drawer, program: Program) {
|
||||
if (lastSeconds == -1.0) lastSeconds = program.seconds
|
||||
|
||||
val delta = program.seconds - lastSeconds
|
||||
lastSeconds = program.seconds
|
||||
orbitalCamera.update(delta)
|
||||
|
||||
drawer.background(ColorRGBa.BLACK)
|
||||
drawer.perspective(orbitalCamera.fov, program.window.size.x / program.window.size.y, 0.1, 1000.0)
|
||||
drawer.view = orbitalCamera.viewMatrix()
|
||||
|
||||
if (showGrid) {
|
||||
drawer.isolated {
|
||||
drawer.fill = ColorRGBa.WHITE
|
||||
drawer.stroke = ColorRGBa.WHITE
|
||||
drawer.vertexBuffer(grid, DrawPrimitive.LINES)
|
||||
|
||||
// Axis cross
|
||||
drawer.fill = ColorRGBa.RED
|
||||
drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_X)
|
||||
|
||||
drawer.fill = ColorRGBa.GREEN
|
||||
drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Y)
|
||||
|
||||
drawer.fill = ColorRGBa.BLUE
|
||||
drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Z)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterDraw(drawer: Drawer, program: Program) {
|
||||
drawer.isolated {
|
||||
drawer.view = Matrix44.IDENTITY
|
||||
drawer.ortho()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setup(program: Program) {
|
||||
orbitalControls.setup(program)
|
||||
}
|
||||
}
|
||||
@@ -1,120 +1,139 @@
|
||||
package org.openrndr.extras.camera
|
||||
|
||||
import org.openrndr.*
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.DrawPrimitive
|
||||
import org.openrndr.draw.Drawer
|
||||
import org.openrndr.draw.isolated
|
||||
import org.openrndr.draw.vertexBuffer
|
||||
import org.openrndr.draw.vertexFormat
|
||||
import org.openrndr.math.Matrix44
|
||||
import org.openrndr.math.Spherical
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.transforms.lookAt as lookAt_
|
||||
|
||||
class OrbitalCamera(eye: Vector3, lookAt: Vector3) {
|
||||
|
||||
// current position in spherical coordinates
|
||||
var spherical = Spherical.fromVector(eye)
|
||||
private set
|
||||
var lookAt = lookAt
|
||||
private set
|
||||
|
||||
private var sphericalEnd = Spherical.fromVector(eye)
|
||||
private var lookAtEnd = lookAt.copy()
|
||||
private var dirty: Boolean = true
|
||||
|
||||
var dampingFactor = 0.05
|
||||
var zoomSpeed = 1.0
|
||||
|
||||
fun rotate(rotX: Double, rotY: Double) {
|
||||
sphericalEnd += Spherical(0.0, rotX, rotY)
|
||||
sphericalEnd = sphericalEnd.makeSafe()
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun rotateTo(rotX: Double, rotY: Double) {
|
||||
sphericalEnd = sphericalEnd.copy(theta = rotX, phi = rotY)
|
||||
sphericalEnd = sphericalEnd.makeSafe()
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun rotateTo(eye: Vector3) {
|
||||
sphericalEnd = Spherical.fromVector(eye)
|
||||
sphericalEnd = sphericalEnd.makeSafe()
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun dollyIn() {
|
||||
val zoomScale = Math.pow(0.95, zoomSpeed)
|
||||
dolly(sphericalEnd.radius * zoomScale - sphericalEnd.radius)
|
||||
}
|
||||
|
||||
fun dollyOut() {
|
||||
val zoomScale = Math.pow(0.95, zoomSpeed)
|
||||
dolly(sphericalEnd.radius / zoomScale - sphericalEnd.radius)
|
||||
}
|
||||
|
||||
private fun dolly(distance: Double) {
|
||||
sphericalEnd += Spherical(distance, 0.0, 0.0)
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun pan(x: Double, y: Double, z: Double) {
|
||||
val view = viewMatrix()
|
||||
val xColumn = Vector3(view.c0r0, view.c1r0, view.c2r0) * x
|
||||
val yColumn = Vector3(view.c0r1, view.c1r1, view.c2r1) * y
|
||||
val zColumn = Vector3(view.c0r2, view.c1r2, view.c2r2) * z
|
||||
lookAtEnd += xColumn + yColumn + zColumn
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun panTo(target : Vector3) {
|
||||
lookAtEnd = target
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun dollyTo(distance: Double) {
|
||||
sphericalEnd = sphericalEnd.copy(radius = distance )
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun update(timeDelta: Double) {
|
||||
if (!dirty) return
|
||||
dirty = false
|
||||
|
||||
val dampingFactor = dampingFactor * timeDelta / 0.0060
|
||||
val sphericalDelta = sphericalEnd - spherical
|
||||
val lookAtDelta = lookAtEnd - lookAt
|
||||
|
||||
if (
|
||||
Math.abs(sphericalEnd.radius) > EPSILON ||
|
||||
Math.abs(sphericalEnd.theta) > EPSILON ||
|
||||
Math.abs(sphericalEnd.phi) > EPSILON ||
|
||||
Math.abs(lookAtDelta.x) > EPSILON ||
|
||||
Math.abs(lookAtDelta.y) > EPSILON ||
|
||||
Math.abs(lookAtDelta.z) > EPSILON
|
||||
) {
|
||||
|
||||
spherical += (sphericalDelta * dampingFactor)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
package org.openrndr.extras.camera
|
||||
|
||||
import org.openrndr.*
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.DrawPrimitive
|
||||
import org.openrndr.draw.Drawer
|
||||
import org.openrndr.draw.isolated
|
||||
import org.openrndr.draw.vertexBuffer
|
||||
import org.openrndr.draw.vertexFormat
|
||||
import org.openrndr.math.Matrix44
|
||||
import org.openrndr.math.Spherical
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.transforms.lookAt as lookAt_
|
||||
|
||||
class OrbitalCamera(eye: Vector3, lookAt: Vector3, var fov:Double) {
|
||||
|
||||
|
||||
// current position in spherical coordinates
|
||||
var spherical = Spherical.fromVector(eye)
|
||||
private set
|
||||
var lookAt = lookAt
|
||||
private set
|
||||
|
||||
private var sphericalEnd = Spherical.fromVector(eye)
|
||||
private var lookAtEnd = lookAt.copy()
|
||||
private var dirty: Boolean = true
|
||||
|
||||
var fovEnd = fov
|
||||
|
||||
var dampingFactor = 0.05
|
||||
var zoomSpeed = 1.0
|
||||
|
||||
fun setView(lookAt: Vector3, spherical: Spherical, fov:Double) {
|
||||
this.lookAt = lookAt
|
||||
this.lookAtEnd = lookAt
|
||||
this.spherical = spherical
|
||||
this.sphericalEnd = spherical
|
||||
this.fov = fov
|
||||
this.fovEnd= fov
|
||||
}
|
||||
|
||||
fun rotate(rotX: Double, rotY: Double) {
|
||||
sphericalEnd += Spherical(0.0, rotX, rotY)
|
||||
sphericalEnd = sphericalEnd.makeSafe()
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun rotateTo(rotX: Double, rotY: Double) {
|
||||
sphericalEnd = sphericalEnd.copy(theta = rotX, phi = rotY)
|
||||
sphericalEnd = sphericalEnd.makeSafe()
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun rotateTo(eye: Vector3) {
|
||||
sphericalEnd = Spherical.fromVector(eye)
|
||||
sphericalEnd = sphericalEnd.makeSafe()
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun dollyIn() {
|
||||
val zoomScale = Math.pow(0.95, zoomSpeed)
|
||||
dolly(sphericalEnd.radius * zoomScale - sphericalEnd.radius)
|
||||
}
|
||||
|
||||
fun dollyOut() {
|
||||
val zoomScale = Math.pow(0.95, zoomSpeed)
|
||||
dolly(sphericalEnd.radius / zoomScale - sphericalEnd.radius)
|
||||
}
|
||||
|
||||
fun dolly(distance: Double) {
|
||||
sphericalEnd += Spherical(distance, 0.0, 0.0)
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun pan(x: Double, y: Double, z: Double) {
|
||||
val view = viewMatrix()
|
||||
val xColumn = Vector3(view.c0r0, view.c1r0, view.c2r0) * x
|
||||
val yColumn = Vector3(view.c0r1, view.c1r1, view.c2r1) * y
|
||||
val zColumn = Vector3(view.c0r2, view.c1r2, view.c2r2) * z
|
||||
lookAtEnd += xColumn + yColumn + zColumn
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun panTo(target : Vector3) {
|
||||
lookAtEnd = target
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun dollyTo(distance: Double) {
|
||||
sphericalEnd = sphericalEnd.copy(radius = distance )
|
||||
dirty = true
|
||||
}
|
||||
|
||||
fun zoom(degrees: Double) {
|
||||
fovEnd += degrees
|
||||
}
|
||||
|
||||
fun update(timeDelta: Double) {
|
||||
if (!dirty) return
|
||||
dirty = false
|
||||
|
||||
val dampingFactor = dampingFactor * timeDelta / 0.0060
|
||||
val sphericalDelta = sphericalEnd - spherical
|
||||
val lookAtDelta = lookAtEnd - lookAt
|
||||
val fovDelta = fovEnd - fov
|
||||
if (
|
||||
Math.abs(sphericalEnd.radius) > EPSILON ||
|
||||
Math.abs(sphericalEnd.theta) > EPSILON ||
|
||||
Math.abs(sphericalEnd.phi) > EPSILON ||
|
||||
Math.abs(lookAtDelta.x) > EPSILON ||
|
||||
Math.abs(lookAtDelta.y) > EPSILON ||
|
||||
Math.abs(lookAtDelta.z) > EPSILON ||
|
||||
Math.abs(fovDelta) > EPSILON
|
||||
) {
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,100 +1,128 @@
|
||||
package org.openrndr.extras.camera
|
||||
|
||||
import org.openrndr.*
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
|
||||
class OrbitalControls(val orbitalCamera: OrbitalCamera) {
|
||||
enum class STATE {
|
||||
NONE,
|
||||
ROTATE,
|
||||
PAN,
|
||||
}
|
||||
|
||||
private var state = STATE.NONE
|
||||
var fov = 90.0
|
||||
|
||||
private lateinit var program: Program
|
||||
private lateinit var lastMousePosition: Vector2
|
||||
|
||||
private fun mouseScrolled(event: MouseEvent) {
|
||||
|
||||
if (Math.abs(event.rotation.x) > 0.1) return
|
||||
|
||||
when {
|
||||
event.rotation.y > 0 -> orbitalCamera.dollyIn()
|
||||
event.rotation.y < 0 -> orbitalCamera.dollyOut()
|
||||
}
|
||||
}
|
||||
|
||||
private fun mouseMoved(event: MouseEvent) {
|
||||
|
||||
if (state == STATE.NONE) return
|
||||
val delta = lastMousePosition - event.position
|
||||
lastMousePosition = event.position
|
||||
|
||||
if (state == STATE.PAN) {
|
||||
|
||||
val offset = Vector3.fromSpherical(orbitalCamera.spherical) - orbitalCamera.lookAt
|
||||
|
||||
// half of the fov is center to top of screen
|
||||
val targetDistance = offset.length * Math.tan((fov / 2) * Math.PI / 180)
|
||||
val panX = (2 * delta.x * targetDistance / program.window.size.x)
|
||||
val panY = (2 * delta.y * targetDistance / program.window.size.y)
|
||||
|
||||
orbitalCamera.pan(panX, -panY, 0.0)
|
||||
|
||||
} else {
|
||||
val rotX = 2 * Math.PI * delta.x / program.window.size.x
|
||||
val rotY = 2 * Math.PI * delta.y / program.window.size.y
|
||||
orbitalCamera.rotate(rotX, rotY)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun mouseButtonDown(event: MouseEvent) {
|
||||
val previousState = state
|
||||
|
||||
when (event.button) {
|
||||
MouseButton.LEFT -> {
|
||||
state = STATE.ROTATE
|
||||
}
|
||||
MouseButton.RIGHT -> {
|
||||
state = STATE.PAN
|
||||
}
|
||||
MouseButton.CENTER -> {
|
||||
}
|
||||
MouseButton.NONE -> {
|
||||
}
|
||||
}
|
||||
|
||||
if (previousState == STATE.NONE) {
|
||||
lastMousePosition = event.position
|
||||
}
|
||||
}
|
||||
|
||||
fun keyPressed(keyEvent: KeyEvent) {
|
||||
if (keyEvent.key == KEY_ARROW_RIGHT) {
|
||||
orbitalCamera.pan(1.0, 0.0, 0.0)
|
||||
}
|
||||
if (keyEvent.key == KEY_ARROW_LEFT) {
|
||||
orbitalCamera.pan(-1.0, 0.0, 0.0)
|
||||
}
|
||||
if (keyEvent.key == KEY_ARROW_UP) {
|
||||
orbitalCamera.pan(0.0, 1.0, 0.0)
|
||||
}
|
||||
if (keyEvent.key == KEY_ARROW_DOWN) {
|
||||
orbitalCamera.pan(0.0, -1.0, 0.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) }
|
||||
}
|
||||
}
|
||||
package org.openrndr.extras.camera
|
||||
|
||||
import org.openrndr.*
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
|
||||
class OrbitalControls(val orbitalCamera: OrbitalCamera) {
|
||||
enum class STATE {
|
||||
NONE,
|
||||
ROTATE,
|
||||
PAN,
|
||||
}
|
||||
|
||||
private var state = STATE.NONE
|
||||
var fov = 90.0
|
||||
|
||||
private lateinit var program: Program
|
||||
private lateinit var lastMousePosition: Vector2
|
||||
|
||||
private fun mouseScrolled(event: MouseEvent) {
|
||||
|
||||
if (Math.abs(event.rotation.x) > 0.1) return
|
||||
|
||||
when {
|
||||
event.rotation.y > 0 -> orbitalCamera.dollyIn()
|
||||
event.rotation.y < 0 -> orbitalCamera.dollyOut()
|
||||
}
|
||||
}
|
||||
|
||||
private fun mouseMoved(event: MouseEvent) {
|
||||
|
||||
if (state == STATE.NONE) return
|
||||
val delta = lastMousePosition - event.position
|
||||
lastMousePosition = event.position
|
||||
|
||||
if (state == STATE.PAN) {
|
||||
|
||||
val offset = Vector3.fromSpherical(orbitalCamera.spherical) - orbitalCamera.lookAt
|
||||
|
||||
// half of the fov is center to top of screen
|
||||
val targetDistance = offset.length * Math.tan((fov / 2) * Math.PI / 180)
|
||||
val panX = (2 * delta.x * targetDistance / program.window.size.x)
|
||||
val panY = (2 * delta.y * targetDistance / program.window.size.y)
|
||||
|
||||
orbitalCamera.pan(panX, -panY, 0.0)
|
||||
|
||||
} else {
|
||||
val rotX = 2 * Math.PI * delta.x / program.window.size.x
|
||||
val rotY = 2 * Math.PI * delta.y / program.window.size.y
|
||||
orbitalCamera.rotate(rotX, rotY)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun mouseButtonDown(event: MouseEvent) {
|
||||
val previousState = state
|
||||
|
||||
when (event.button) {
|
||||
MouseButton.LEFT -> {
|
||||
state = STATE.ROTATE
|
||||
}
|
||||
MouseButton.RIGHT -> {
|
||||
state = STATE.PAN
|
||||
}
|
||||
MouseButton.CENTER -> {
|
||||
}
|
||||
MouseButton.NONE -> {
|
||||
}
|
||||
}
|
||||
|
||||
if (previousState == STATE.NONE) {
|
||||
lastMousePosition = event.position
|
||||
}
|
||||
}
|
||||
|
||||
fun keyPressed(keyEvent: KeyEvent) {
|
||||
if (keyEvent.key == KEY_ARROW_RIGHT) {
|
||||
orbitalCamera.pan(1.0, 0.0, 0.0)
|
||||
}
|
||||
if (keyEvent.key == KEY_ARROW_LEFT) {
|
||||
orbitalCamera.pan(-1.0, 0.0, 0.0)
|
||||
}
|
||||
if (keyEvent.key == KEY_ARROW_UP) {
|
||||
orbitalCamera.pan(0.0, 1.0, 0.0)
|
||||
}
|
||||
if (keyEvent.key == KEY_ARROW_DOWN) {
|
||||
orbitalCamera.pan(0.0, -1.0, 0.0)
|
||||
}
|
||||
|
||||
if (keyEvent.name == "q") {
|
||||
orbitalCamera.pan(0.0, -1.0, 0.0)
|
||||
}
|
||||
if (keyEvent.name == "e") {
|
||||
orbitalCamera.pan(0.0, 1.0, 0.0)
|
||||
}
|
||||
if (keyEvent.name == "w") {
|
||||
orbitalCamera.pan(0.0, 0.0, -1.0)
|
||||
}
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,138 +1,138 @@
|
||||
package org.openrndr.extra.compositor
|
||||
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.*
|
||||
import org.openrndr.math.Matrix44
|
||||
|
||||
|
||||
private val postBufferCache = mutableListOf<ColorBuffer>()
|
||||
|
||||
fun RenderTarget.deepDestroy() {
|
||||
val cbcopy = colorBuffers.map { it}
|
||||
val dbcopy = depthBuffer
|
||||
detachDepthBuffer()
|
||||
detachColorBuffers()
|
||||
cbcopy.forEach {
|
||||
it.destroy()
|
||||
}
|
||||
dbcopy?.destroy()
|
||||
destroy()
|
||||
}
|
||||
|
||||
/**
|
||||
* A single layer representation
|
||||
*/
|
||||
class Layer internal constructor() {
|
||||
var drawFunc: () -> Unit = {}
|
||||
val children: MutableList<Layer> = mutableListOf()
|
||||
var blendFilter: Pair<Filter, Filter.() -> Unit>? = null
|
||||
val postFilters: MutableList<Pair<Filter, Filter.() -> Unit>> = mutableListOf()
|
||||
|
||||
private var layerTarget:RenderTarget? = null
|
||||
|
||||
/**
|
||||
* draw the layer
|
||||
*/
|
||||
fun draw(drawer: Drawer) {
|
||||
val rt = RenderTarget.active
|
||||
|
||||
val llt = layerTarget
|
||||
if (llt == null || (llt.width != rt.width || llt.height != rt.height)) {
|
||||
layerTarget?.deepDestroy()
|
||||
layerTarget = renderTarget(rt.width, rt.height) {
|
||||
colorBuffer()
|
||||
depthBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
layerTarget?.let { target ->
|
||||
drawer.isolatedWithTarget(target) {
|
||||
drawer.background(ColorRGBa.TRANSPARENT)
|
||||
drawFunc()
|
||||
children.forEach {
|
||||
it.draw(drawer)
|
||||
}
|
||||
}
|
||||
|
||||
if (postFilters.size > 0) {
|
||||
val sizeMismatch = if (postBufferCache.isNotEmpty()) {
|
||||
postBufferCache[0].width != rt.width || postBufferCache[0].height != rt.height
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
if (sizeMismatch) {
|
||||
postBufferCache.forEach { it.destroy() }
|
||||
postBufferCache.clear()
|
||||
}
|
||||
|
||||
if (postBufferCache.isEmpty()) {
|
||||
postBufferCache += colorBuffer(rt.width, rt.height)
|
||||
postBufferCache += colorBuffer(rt.width, rt.height)
|
||||
}
|
||||
}
|
||||
|
||||
val layerPost = postFilters.let { filters ->
|
||||
val targets = postBufferCache
|
||||
val result = filters.foldIndexed(target.colorBuffer(0)) { i, source, filter ->
|
||||
val target = targets[i % targets.size]
|
||||
filter.first.apply(filter.second)
|
||||
filter.first.apply(source, target)
|
||||
target
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
val lblend = blendFilter
|
||||
if (lblend == null) {
|
||||
drawer.isolatedWithTarget(rt) {
|
||||
//drawer.ortho(rt)
|
||||
drawer.ortho()
|
||||
drawer.view = Matrix44.IDENTITY
|
||||
drawer.model = Matrix44.IDENTITY
|
||||
drawer.image(layerPost, layerPost.bounds, drawer.bounds)
|
||||
}
|
||||
} else {
|
||||
lblend.first.apply(lblend.second)
|
||||
lblend.first.apply(arrayOf(rt.colorBuffer(0), layerPost), rt.colorBuffer(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create a layer within the composition
|
||||
*/
|
||||
fun Layer.layer(function: Layer.() -> Unit) {
|
||||
children.add(Layer().apply { function() })
|
||||
}
|
||||
|
||||
/**
|
||||
* set the draw contents of the layer
|
||||
*/
|
||||
fun Layer.draw(function: () -> Unit) {
|
||||
drawFunc = function
|
||||
}
|
||||
|
||||
/**
|
||||
* add a post-processing filter to the layer
|
||||
*/
|
||||
fun <F : Filter> Layer.post(filter: F, configure: F.() -> Unit = {}) {
|
||||
postFilters.add(Pair(filter as Filter, configure as Filter.() -> Unit))
|
||||
}
|
||||
|
||||
/**
|
||||
* add a blend filter to the layer
|
||||
*/
|
||||
fun <F : Filter> Layer.blend(filter: F, configure: F.() -> Unit = {}) {
|
||||
blendFilter = Pair(filter as Filter, configure as Filter.() -> Unit)
|
||||
}
|
||||
|
||||
/**
|
||||
* create a layered composition
|
||||
*/
|
||||
fun compose(function: Layer.() -> Unit): Layer {
|
||||
val root = Layer()
|
||||
root.function()
|
||||
return root
|
||||
package org.openrndr.extra.compositor
|
||||
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.*
|
||||
import org.openrndr.math.Matrix44
|
||||
|
||||
|
||||
private val postBufferCache = mutableListOf<ColorBuffer>()
|
||||
|
||||
fun RenderTarget.deepDestroy() {
|
||||
val cbcopy = colorBuffers.map { it}
|
||||
val dbcopy = depthBuffer
|
||||
detachDepthBuffer()
|
||||
detachColorBuffers()
|
||||
cbcopy.forEach {
|
||||
it.destroy()
|
||||
}
|
||||
dbcopy?.destroy()
|
||||
destroy()
|
||||
}
|
||||
|
||||
/**
|
||||
* A single layer representation
|
||||
*/
|
||||
class Layer internal constructor() {
|
||||
var drawFunc: () -> Unit = {}
|
||||
val children: MutableList<Layer> = mutableListOf()
|
||||
var blendFilter: Pair<Filter, Filter.() -> Unit>? = null
|
||||
val postFilters: MutableList<Pair<Filter, Filter.() -> Unit>> = mutableListOf()
|
||||
|
||||
private var layerTarget:RenderTarget? = null
|
||||
|
||||
/**
|
||||
* draw the layer
|
||||
*/
|
||||
fun draw(drawer: Drawer) {
|
||||
val rt = RenderTarget.active
|
||||
|
||||
val llt = layerTarget
|
||||
if (llt == null || (llt.width != rt.width || llt.height != rt.height)) {
|
||||
layerTarget?.deepDestroy()
|
||||
layerTarget = renderTarget(rt.width, rt.height) {
|
||||
colorBuffer()
|
||||
depthBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
layerTarget?.let { target ->
|
||||
drawer.isolatedWithTarget(target) {
|
||||
drawer.background(ColorRGBa.TRANSPARENT)
|
||||
drawFunc()
|
||||
children.forEach {
|
||||
it.draw(drawer)
|
||||
}
|
||||
}
|
||||
|
||||
if (postFilters.size > 0) {
|
||||
val sizeMismatch = if (postBufferCache.isNotEmpty()) {
|
||||
postBufferCache[0].width != rt.width || postBufferCache[0].height != rt.height
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
if (sizeMismatch) {
|
||||
postBufferCache.forEach { it.destroy() }
|
||||
postBufferCache.clear()
|
||||
}
|
||||
|
||||
if (postBufferCache.isEmpty()) {
|
||||
postBufferCache += colorBuffer(rt.width, rt.height)
|
||||
postBufferCache += colorBuffer(rt.width, rt.height)
|
||||
}
|
||||
}
|
||||
|
||||
val layerPost = postFilters.let { filters ->
|
||||
val targets = postBufferCache
|
||||
val result = filters.foldIndexed(target.colorBuffer(0)) { i, source, filter ->
|
||||
val target = targets[i % targets.size]
|
||||
filter.first.apply(filter.second)
|
||||
filter.first.apply(source, target)
|
||||
target
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
val lblend = blendFilter
|
||||
if (lblend == null) {
|
||||
drawer.isolatedWithTarget(rt) {
|
||||
//drawer.ortho(rt)
|
||||
drawer.ortho()
|
||||
drawer.view = Matrix44.IDENTITY
|
||||
drawer.model = Matrix44.IDENTITY
|
||||
drawer.image(layerPost, layerPost.bounds, drawer.bounds)
|
||||
}
|
||||
} else {
|
||||
lblend.first.apply(lblend.second)
|
||||
lblend.first.apply(arrayOf(rt.colorBuffer(0), layerPost), rt.colorBuffer(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create a layer within the composition
|
||||
*/
|
||||
fun Layer.layer(function: Layer.() -> Unit) {
|
||||
children.add(Layer().apply { function() })
|
||||
}
|
||||
|
||||
/**
|
||||
* set the draw contents of the layer
|
||||
*/
|
||||
fun Layer.draw(function: () -> Unit) {
|
||||
drawFunc = function
|
||||
}
|
||||
|
||||
/**
|
||||
* add a post-processing filter to the layer
|
||||
*/
|
||||
fun <F : Filter> Layer.post(filter: F, configure: F.() -> Unit = {}) {
|
||||
postFilters.add(Pair(filter as Filter, configure as Filter.() -> Unit))
|
||||
}
|
||||
|
||||
/**
|
||||
* add a blend filter to the layer
|
||||
*/
|
||||
fun <F : Filter> Layer.blend(filter: F, configure: F.() -> Unit = {}) {
|
||||
blendFilter = Pair(filter as Filter, configure as Filter.() -> Unit)
|
||||
}
|
||||
|
||||
/**
|
||||
* create a layered composition
|
||||
*/
|
||||
fun compose(function: Layer.() -> Unit): Layer {
|
||||
val root = Layer()
|
||||
root.function()
|
||||
return root
|
||||
}
|
||||
31
orx-examples/build.gradle
Normal file
31
orx-examples/build.gradle
Normal 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"
|
||||
}
|
||||
BIN
orx-examples/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
orx-examples/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
orx-examples/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
orx-examples/gradle/wrapper/gradle-wrapper.properties
vendored
Normal 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
172
orx-examples/gradlew
vendored
Normal 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
84
orx-examples/gradlew.bat
vendored
Normal 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
|
||||
2
orx-examples/settings.gradle
Normal file
2
orx-examples/settings.gradle
Normal file
@@ -0,0 +1,2 @@
|
||||
rootProject.name = 'orx-examples'
|
||||
|
||||
56
orx-examples/src/main/kotlin/jumpfil-001.kt
Normal file
56
orx-examples/src/main/kotlin/jumpfil-001.kt
Normal 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
|
||||
|
||||
})
|
||||
}
|
||||
45
orx-examples/src/main/kotlin/jumpfil-002.kt
Normal file
45
orx-examples/src/main/kotlin/jumpfil-002.kt
Normal 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
|
||||
|
||||
})
|
||||
}
|
||||
@@ -1,77 +1,77 @@
|
||||
package org.openrndr.extra.integralimage
|
||||
|
||||
import org.openrndr.draw.*
|
||||
import org.openrndr.filter.blend.passthrough
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.resourceUrl
|
||||
|
||||
|
||||
class FastIntegralImageFilter : Filter(filterShaderFromUrl(resourceUrl(
|
||||
"/shaders/gl3/integral-image.frag"
|
||||
))) {
|
||||
var passIndex: Int by parameters
|
||||
var passDirection: Vector2 by parameters
|
||||
var sampleCount: Int by parameters
|
||||
var sampleCountBase: Int by parameters
|
||||
}
|
||||
|
||||
class FastIntegralImage : Filter(filterShaderFromUrl(resourceUrl(
|
||||
"/shaders/gl3/integral-image.frag"
|
||||
))) {
|
||||
|
||||
var intermediate: ColorBuffer? = null
|
||||
val filter = FastIntegralImageFilter()
|
||||
|
||||
private fun sampleCounts(size:Int, sampleCountBase:Int) : List<Int> {
|
||||
var remainder = size
|
||||
val sampleCounts = mutableListOf<Int>()
|
||||
while (remainder > 0) {
|
||||
sampleCounts += if (remainder >= sampleCountBase) {
|
||||
sampleCountBase
|
||||
} else {
|
||||
remainder
|
||||
}
|
||||
remainder /= sampleCountBase
|
||||
}
|
||||
return sampleCounts
|
||||
}
|
||||
|
||||
override fun apply(source: Array<ColorBuffer>, target: Array<ColorBuffer>) {
|
||||
|
||||
val sampleCountBase = 16
|
||||
val xSampleCounts = sampleCounts(source[0].width, sampleCountBase)
|
||||
val ySampleCounts = sampleCounts(source[0].height, sampleCountBase)
|
||||
|
||||
val li = intermediate
|
||||
if (li == null || (li.width != source[0].width || li.height != source[0].height)) {
|
||||
intermediate?.destroy()
|
||||
intermediate = colorBuffer(source[0].width, source[0].height, 1.0, ColorFormat.RGBa, ColorType.FLOAT32)
|
||||
}
|
||||
|
||||
val targets = arrayOf(target, arrayOf(intermediate!!))
|
||||
|
||||
var targetIndex = 0
|
||||
|
||||
filter.sampleCountBase = sampleCountBase
|
||||
|
||||
filter.passDirection = Vector2.UNIT_X
|
||||
for (pass in 0 until xSampleCounts.size) {
|
||||
filter.sampleCount = xSampleCounts[pass]
|
||||
filter.passIndex = pass
|
||||
filter.apply( if (pass == 0) source else targets[targetIndex%2], targets[(targetIndex+1)%2])
|
||||
targetIndex++
|
||||
}
|
||||
|
||||
filter.passDirection = Vector2.UNIT_Y
|
||||
for (pass in 0 until ySampleCounts.size) {
|
||||
filter.sampleCount = ySampleCounts[pass]
|
||||
filter.passIndex = pass
|
||||
filter.apply( targets[targetIndex%2], targets[(targetIndex+1)%2])
|
||||
targetIndex++
|
||||
}
|
||||
|
||||
if (targetIndex%2 == 1) {
|
||||
passthrough.apply(targets[1], targets[0])
|
||||
}
|
||||
}
|
||||
package org.openrndr.extra.integralimage
|
||||
|
||||
import org.openrndr.draw.*
|
||||
import org.openrndr.filter.blend.passthrough
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.resourceUrl
|
||||
|
||||
|
||||
class FastIntegralImageFilter : Filter(filterShaderFromUrl(resourceUrl(
|
||||
"/shaders/gl3/integral-image.frag"
|
||||
))) {
|
||||
var passIndex: Int by parameters
|
||||
var passDirection: Vector2 by parameters
|
||||
var sampleCount: Int by parameters
|
||||
var sampleCountBase: Int by parameters
|
||||
}
|
||||
|
||||
class FastIntegralImage : Filter(filterShaderFromUrl(resourceUrl(
|
||||
"/shaders/gl3/integral-image.frag"
|
||||
))) {
|
||||
|
||||
var intermediate: ColorBuffer? = null
|
||||
val filter = FastIntegralImageFilter()
|
||||
|
||||
private fun sampleCounts(size:Int, sampleCountBase:Int) : List<Int> {
|
||||
var remainder = size
|
||||
val sampleCounts = mutableListOf<Int>()
|
||||
while (remainder > 0) {
|
||||
sampleCounts += if (remainder >= sampleCountBase) {
|
||||
sampleCountBase
|
||||
} else {
|
||||
remainder
|
||||
}
|
||||
remainder /= sampleCountBase
|
||||
}
|
||||
return sampleCounts
|
||||
}
|
||||
|
||||
override fun apply(source: Array<ColorBuffer>, target: Array<ColorBuffer>) {
|
||||
|
||||
val sampleCountBase = 16
|
||||
val xSampleCounts = sampleCounts(source[0].width, sampleCountBase)
|
||||
val ySampleCounts = sampleCounts(source[0].height, sampleCountBase)
|
||||
|
||||
val li = intermediate
|
||||
if (li == null || (li.width != source[0].width || li.height != source[0].height)) {
|
||||
intermediate?.destroy()
|
||||
intermediate = colorBuffer(source[0].width, source[0].height, 1.0, ColorFormat.RGBa, ColorType.FLOAT32)
|
||||
}
|
||||
|
||||
val targets = arrayOf(target, arrayOf(intermediate!!))
|
||||
|
||||
var targetIndex = 0
|
||||
|
||||
filter.sampleCountBase = sampleCountBase
|
||||
|
||||
filter.passDirection = Vector2.UNIT_X
|
||||
for (pass in 0 until xSampleCounts.size) {
|
||||
filter.sampleCount = xSampleCounts[pass]
|
||||
filter.passIndex = pass
|
||||
filter.apply( if (pass == 0) source else targets[targetIndex%2], targets[(targetIndex+1)%2])
|
||||
targetIndex++
|
||||
}
|
||||
|
||||
filter.passDirection = Vector2.UNIT_Y
|
||||
for (pass in 0 until ySampleCounts.size) {
|
||||
filter.sampleCount = ySampleCounts[pass]
|
||||
filter.passIndex = pass
|
||||
filter.apply( targets[targetIndex%2], targets[(targetIndex+1)%2])
|
||||
targetIndex++
|
||||
}
|
||||
|
||||
if (targetIndex%2 == 1) {
|
||||
passthrough.apply(targets[1], targets[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,26 @@
|
||||
#version 330 core
|
||||
|
||||
uniform sampler2D tex0;
|
||||
in vec2 v_texCoord0;
|
||||
out vec4 o_color;
|
||||
|
||||
uniform int passIndex;
|
||||
uniform int sampleCount;
|
||||
uniform int sampleCountBase;
|
||||
uniform vec2 passDirection;
|
||||
|
||||
|
||||
void main() {
|
||||
vec2 passOffset = vec2(pow(sampleCountBase, passIndex)) * (1.0/textureSize(tex0, 0)) * passDirection;
|
||||
|
||||
vec2 uv0 = v_texCoord0;
|
||||
vec4 result = vec4(0.0);
|
||||
for (int i = 0; i < sampleCount; ++i) {
|
||||
vec2 readUV = v_texCoord0 - vec2(i *passOffset);
|
||||
float factor = step(0.0, readUV.x) * step(0.0, readUV.y);
|
||||
result += factor * texture(tex0, readUV);
|
||||
}
|
||||
|
||||
o_color = result;
|
||||
|
||||
#version 330 core
|
||||
|
||||
uniform sampler2D tex0;
|
||||
in vec2 v_texCoord0;
|
||||
out vec4 o_color;
|
||||
|
||||
uniform int passIndex;
|
||||
uniform int sampleCount;
|
||||
uniform int sampleCountBase;
|
||||
uniform vec2 passDirection;
|
||||
|
||||
|
||||
void main() {
|
||||
vec2 passOffset = vec2(pow(sampleCountBase, passIndex)) * (1.0/textureSize(tex0, 0)) * passDirection;
|
||||
|
||||
vec2 uv0 = v_texCoord0;
|
||||
vec4 result = vec4(0.0);
|
||||
for (int i = 0; i < sampleCount; ++i) {
|
||||
vec2 readUV = v_texCoord0 - vec2(i *passOffset);
|
||||
float factor = step(0.0, readUV.x) * step(0.0, readUV.y);
|
||||
result += factor * texture(tex0, readUV);
|
||||
}
|
||||
|
||||
o_color = result;
|
||||
|
||||
}
|
||||
@@ -1,128 +1,128 @@
|
||||
package org.openrndr.extra.jumpfill
|
||||
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.*
|
||||
import org.openrndr.math.Matrix44
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.resourceUrl
|
||||
|
||||
class EncodePoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/encode-points.frag")))
|
||||
class JumpFlood : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/jumpflood.frag"))) {
|
||||
var maxSteps: Int by parameters
|
||||
var step: Int by parameters
|
||||
}
|
||||
|
||||
class PixelDistance : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/pixel-distance.frag")))
|
||||
class ContourPoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/contour-points.frag")))
|
||||
class Threshold : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/threshold.frag"))) {
|
||||
var threshold by parameters
|
||||
|
||||
init {
|
||||
threshold = 0.5
|
||||
}
|
||||
}
|
||||
|
||||
val encodePoints by lazy { EncodePoints() }
|
||||
val jumpFlood by lazy { JumpFlood() }
|
||||
val pixelDistance by lazy { PixelDistance() }
|
||||
val contourPoints by lazy { ContourPoints() }
|
||||
val threshold by lazy { Threshold() }
|
||||
|
||||
|
||||
class JumpFlooder(val width: Int, val height: Int) {
|
||||
private val dimension = Math.max(width, height)
|
||||
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 coordinates =
|
||||
listOf(colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32),
|
||||
colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32))
|
||||
|
||||
private val final = renderTarget(width, height) {
|
||||
colorBuffer(type = ColorType.FLOAT32)
|
||||
}
|
||||
|
||||
val result: ColorBuffer get() = final.colorBuffer(0)
|
||||
|
||||
private val square = renderTarget(squareDim, squareDim) {
|
||||
colorBuffer()
|
||||
}
|
||||
|
||||
private var contourUsed = false
|
||||
private val thresholded by lazy { colorBuffer(width, height) }
|
||||
private val edges by lazy { colorBuffer(width, height) }
|
||||
|
||||
fun distanceToContour(drawer: Drawer, input: ColorBuffer, thresholdValue: Double = 0.5): ColorBuffer {
|
||||
threshold.threshold = thresholdValue
|
||||
threshold.apply(input, thresholded)
|
||||
contourPoints.apply(thresholded, edges)
|
||||
contourUsed = true
|
||||
return jumpFlood(drawer, edges)
|
||||
}
|
||||
|
||||
fun directions(xRange: IntProgression = 0 until width, yRange: IntProgression = 0 until height): Array<List<Vector2>> {
|
||||
result.shadow.download()
|
||||
return result.shadow.mapIndexed(xRange, yRange) { _, _, r, g, _, _ -> Vector2(r, g) }
|
||||
}
|
||||
|
||||
|
||||
fun jumpFlood(drawer: Drawer, input: ColorBuffer): ColorBuffer {
|
||||
if (input.width != width || input.height != height) {
|
||||
throw IllegalArgumentException("dimensions mismatch")
|
||||
}
|
||||
|
||||
drawer.isolatedWithTarget(square) {
|
||||
drawer.background(ColorRGBa.BLACK)
|
||||
drawer.ortho(square)
|
||||
drawer.view = Matrix44.IDENTITY
|
||||
drawer.model = Matrix44.IDENTITY
|
||||
drawer.image(input)
|
||||
}
|
||||
encodePoints.apply(square.colorBuffer(0), coordinates[0])
|
||||
|
||||
for (i in 0 until exp) {
|
||||
jumpFlood.step = i
|
||||
jumpFlood.apply(coordinates[i % 2], coordinates[(i + 1) % 2])
|
||||
}
|
||||
|
||||
pixelDistance.apply( arrayOf(coordinates[exp % 2], thresholded), coordinates[exp % 2])
|
||||
drawer.isolatedWithTarget(final) {
|
||||
drawer.background(ColorRGBa.BLACK)
|
||||
drawer.ortho(final)
|
||||
drawer.view = Matrix44.IDENTITY
|
||||
drawer.model = Matrix44.IDENTITY
|
||||
drawer.image(coordinates[exp % 2])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun destroy(destroyFinal: Boolean = true) {
|
||||
coordinates.forEach { it.destroy() }
|
||||
|
||||
square.colorBuffer(0).destroy()
|
||||
square.detachColorBuffers()
|
||||
square.destroy()
|
||||
|
||||
if (destroyFinal) {
|
||||
final.colorBuffer(0).destroy()
|
||||
}
|
||||
final.detachColorBuffers()
|
||||
|
||||
final.destroy()
|
||||
|
||||
if (contourUsed) {
|
||||
edges.destroy()
|
||||
thresholded.destroy()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun jumpFlood(drawer: Drawer, points: ColorBuffer): ColorBuffer {
|
||||
val jumpFlooder = JumpFlooder(points.width, points.height)
|
||||
jumpFlooder.jumpFlood(drawer, points)
|
||||
val result = jumpFlooder.result
|
||||
jumpFlooder.destroy(false)
|
||||
return result
|
||||
package org.openrndr.extra.jumpfill
|
||||
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.*
|
||||
import org.openrndr.math.Matrix44
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.resourceUrl
|
||||
|
||||
class EncodePoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/encode-points.frag")))
|
||||
class JumpFlood : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/jumpflood.frag"))) {
|
||||
var maxSteps: Int by parameters
|
||||
var step: Int by parameters
|
||||
}
|
||||
|
||||
class PixelDistance : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/pixel-distance.frag")))
|
||||
class ContourPoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/contour-points.frag")))
|
||||
class Threshold : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/threshold.frag"))) {
|
||||
var threshold by parameters
|
||||
|
||||
init {
|
||||
threshold = 0.5
|
||||
}
|
||||
}
|
||||
|
||||
val encodePoints by lazy { EncodePoints() }
|
||||
val jumpFlood by lazy { JumpFlood() }
|
||||
val pixelDistance by lazy { PixelDistance() }
|
||||
val contourPoints by lazy { ContourPoints() }
|
||||
val threshold by lazy { Threshold() }
|
||||
|
||||
|
||||
class JumpFlooder(val width: Int, val height: Int) {
|
||||
private val dimension = Math.max(width, height)
|
||||
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 coordinates =
|
||||
listOf(colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32),
|
||||
colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32))
|
||||
|
||||
private val final = renderTarget(width, height) {
|
||||
colorBuffer(type = ColorType.FLOAT32)
|
||||
}
|
||||
|
||||
val result: ColorBuffer get() = final.colorBuffer(0)
|
||||
|
||||
private val square = renderTarget(squareDim, squareDim) {
|
||||
colorBuffer()
|
||||
}
|
||||
|
||||
private var contourUsed = false
|
||||
val thresholded by lazy { colorBuffer(width, height) }
|
||||
val edges by lazy { colorBuffer(width, height) }
|
||||
|
||||
fun distanceToContour(drawer: Drawer, input: ColorBuffer, thresholdValue: Double = 0.5): ColorBuffer {
|
||||
threshold.threshold = thresholdValue
|
||||
threshold.apply(input, thresholded)
|
||||
contourPoints.apply(thresholded, edges)
|
||||
contourUsed = true
|
||||
return jumpFlood(drawer, edges)
|
||||
}
|
||||
|
||||
fun directions(xRange: IntProgression = 0 until width, yRange: IntProgression = 0 until height): Array<List<Vector2>> {
|
||||
result.shadow.download()
|
||||
return result.shadow.mapIndexed(xRange, yRange) { _, _, r, g, _, _ -> Vector2(r, g) }
|
||||
}
|
||||
|
||||
|
||||
fun jumpFlood(drawer: Drawer, input: ColorBuffer): ColorBuffer {
|
||||
if (input.width != width || input.height != height) {
|
||||
throw IllegalArgumentException("dimensions mismatch")
|
||||
}
|
||||
|
||||
drawer.isolatedWithTarget(square) {
|
||||
drawer.background(ColorRGBa.BLACK)
|
||||
drawer.ortho(square)
|
||||
drawer.view = Matrix44.IDENTITY
|
||||
drawer.model = Matrix44.IDENTITY
|
||||
drawer.image(input)
|
||||
}
|
||||
encodePoints.apply(square.colorBuffer(0), coordinates[0])
|
||||
|
||||
for (i in 0 until exp) {
|
||||
jumpFlood.step = i
|
||||
jumpFlood.apply(coordinates[i % 2], coordinates[(i + 1) % 2])
|
||||
}
|
||||
|
||||
pixelDistance.apply(arrayOf(coordinates[exp % 2], thresholded), coordinates[exp % 2])
|
||||
drawer.isolatedWithTarget(final) {
|
||||
drawer.background(ColorRGBa.BLACK)
|
||||
drawer.ortho(final)
|
||||
drawer.view = Matrix44.IDENTITY
|
||||
drawer.model = Matrix44.IDENTITY
|
||||
drawer.image(coordinates[exp % 2])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun destroy(destroyFinal: Boolean = true) {
|
||||
coordinates.forEach { it.destroy() }
|
||||
|
||||
square.colorBuffer(0).destroy()
|
||||
square.detachColorBuffers()
|
||||
square.destroy()
|
||||
|
||||
if (destroyFinal) {
|
||||
final.colorBuffer(0).destroy()
|
||||
}
|
||||
final.detachColorBuffers()
|
||||
|
||||
final.destroy()
|
||||
|
||||
if (contourUsed) {
|
||||
edges.destroy()
|
||||
thresholded.destroy()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun jumpFlood(drawer: Drawer, points: ColorBuffer): ColorBuffer {
|
||||
val jumpFlooder = JumpFlooder(points.width, points.height)
|
||||
jumpFlooder.jumpFlood(drawer, points)
|
||||
val result = jumpFlooder.result
|
||||
jumpFlooder.destroy(false)
|
||||
return result
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
#version 330 core
|
||||
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
in vec2 v_texCoord0;
|
||||
|
||||
out vec4 o_color;
|
||||
|
||||
void main() {
|
||||
vec2 size = textureSize(tex0, 0);
|
||||
vec2 pixelPosition = v_texCoord0;
|
||||
vec2 centroidPixelPosition = texture(tex0, v_texCoord0).xy;
|
||||
vec2 pixelDistance = (centroidPixelPosition - pixelPosition) * size * vec2(1.0, -1.0);
|
||||
float threshold = texture(tex1, v_texCoord0).r;
|
||||
o_color = vec4(pixelDistance, threshold, 1.0);
|
||||
#version 330 core
|
||||
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
in vec2 v_texCoord0;
|
||||
|
||||
out vec4 o_color;
|
||||
|
||||
void main() {
|
||||
vec2 size = textureSize(tex0, 0);
|
||||
vec2 pixelPosition = v_texCoord0;
|
||||
vec2 centroidPixelPosition = texture(tex0, v_texCoord0).xy;
|
||||
vec2 pixelDistance = (centroidPixelPosition - pixelPosition) * size * vec2(1.0, -1.0);
|
||||
float threshold = texture(tex1, v_texCoord0).r;
|
||||
o_color = vec4(pixelDistance, threshold, 1.0);
|
||||
}
|
||||
@@ -1,61 +1,61 @@
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.math.Vector3
|
||||
|
||||
fun boxMesh(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0,
|
||||
widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1,
|
||||
invert: Boolean = false): VertexBuffer {
|
||||
val vb = meshVertexBuffer(widthSegments * heightSegments * 6 * 2 +
|
||||
widthSegments * depthSegments * 6 * 2 +
|
||||
heightSegments * depthSegments * 6 * 2)
|
||||
vb.put {
|
||||
generateBox(width, height, depth,
|
||||
widthSegments, heightSegments, depthSegments,
|
||||
invert, bufferWriter(this))
|
||||
}
|
||||
return vb
|
||||
}
|
||||
|
||||
fun generateBox(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0,
|
||||
widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1,
|
||||
invert: Boolean = false,
|
||||
writer: VertexWriter) {
|
||||
|
||||
val sign = if (invert) -1.0 else 1.0
|
||||
// +x -- ZY
|
||||
generatePlane(Vector3(width / 2.0 * sign, 0.0, 0.0),
|
||||
Vector3.UNIT_Z, Vector3.UNIT_Y, Vector3.UNIT_X,
|
||||
-depth, -height,
|
||||
depthSegments, heightSegments, writer)
|
||||
|
||||
// -x -- ZY
|
||||
generatePlane(Vector3(-width / 2.0 * sign, 0.0, 0.0),
|
||||
Vector3.UNIT_Z, Vector3.UNIT_Y, -Vector3.UNIT_X,
|
||||
-depth, height,
|
||||
depthSegments, heightSegments, writer)
|
||||
|
||||
// +y -- XZ
|
||||
generatePlane(Vector3(0.0, height / 2.0 * sign, 0.0),
|
||||
Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y,
|
||||
width, depth,
|
||||
widthSegments, depthSegments, writer)
|
||||
|
||||
// -y -- XZ
|
||||
generatePlane(Vector3(0.0, -height / 2.0 * sign, 0.0),
|
||||
Vector3.UNIT_X, Vector3.UNIT_Z, -Vector3.UNIT_Y,
|
||||
width, -depth,
|
||||
widthSegments, depthSegments, writer)
|
||||
|
||||
// +z -- XY
|
||||
generatePlane(Vector3(0.0, 0.0, depth / 2.0 * sign),
|
||||
Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z,
|
||||
-width, height,
|
||||
widthSegments, heightSegments, writer)
|
||||
|
||||
// -z -- XY
|
||||
generatePlane(Vector3(0.0, 0.0, -depth / 2.0 * sign),
|
||||
Vector3.UNIT_X, Vector3.UNIT_Y, -Vector3.UNIT_Z,
|
||||
width, height,
|
||||
widthSegments, heightSegments, writer)
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.math.Vector3
|
||||
|
||||
fun boxMesh(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0,
|
||||
widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1,
|
||||
invert: Boolean = false): VertexBuffer {
|
||||
val vb = meshVertexBuffer(widthSegments * heightSegments * 6 * 2 +
|
||||
widthSegments * depthSegments * 6 * 2 +
|
||||
heightSegments * depthSegments * 6 * 2)
|
||||
vb.put {
|
||||
generateBox(width, height, depth,
|
||||
widthSegments, heightSegments, depthSegments,
|
||||
invert, bufferWriter(this))
|
||||
}
|
||||
return vb
|
||||
}
|
||||
|
||||
fun generateBox(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0,
|
||||
widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1,
|
||||
invert: Boolean = false,
|
||||
writer: VertexWriter) {
|
||||
|
||||
val sign = if (invert) -1.0 else 1.0
|
||||
// +x -- ZY
|
||||
generatePlane(Vector3(width / 2.0 * sign, 0.0, 0.0),
|
||||
Vector3.UNIT_Z, Vector3.UNIT_Y, Vector3.UNIT_X,
|
||||
-depth, -height,
|
||||
depthSegments, heightSegments, writer)
|
||||
|
||||
// -x -- ZY
|
||||
generatePlane(Vector3(-width / 2.0 * sign, 0.0, 0.0),
|
||||
Vector3.UNIT_Z, Vector3.UNIT_Y, -Vector3.UNIT_X,
|
||||
-depth, height,
|
||||
depthSegments, heightSegments, writer)
|
||||
|
||||
// +y -- XZ
|
||||
generatePlane(Vector3(0.0, height / 2.0 * sign, 0.0),
|
||||
Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y,
|
||||
width, depth,
|
||||
widthSegments, depthSegments, writer)
|
||||
|
||||
// -y -- XZ
|
||||
generatePlane(Vector3(0.0, -height / 2.0 * sign, 0.0),
|
||||
Vector3.UNIT_X, Vector3.UNIT_Z, -Vector3.UNIT_Y,
|
||||
width, -depth,
|
||||
widthSegments, depthSegments, writer)
|
||||
|
||||
// +z -- XY
|
||||
generatePlane(Vector3(0.0, 0.0, depth / 2.0 * sign),
|
||||
Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z,
|
||||
-width, height,
|
||||
widthSegments, heightSegments, writer)
|
||||
|
||||
// -z -- XY
|
||||
generatePlane(Vector3(0.0, 0.0, -depth / 2.0 * sign),
|
||||
Vector3.UNIT_X, Vector3.UNIT_Y, -Vector3.UNIT_Z,
|
||||
width, height,
|
||||
widthSegments, heightSegments, writer)
|
||||
}
|
||||
@@ -1,101 +1,101 @@
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
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) {
|
||||
val maxX = enveloppe.maxBy { it.x } ?: Vector2(1.0, 0.0)
|
||||
val a = maxX.x
|
||||
|
||||
val cleanEnveloppe = enveloppe.map { Vector2((it.x / a) * radius, it.y) }
|
||||
|
||||
val normals2D = enveloppe.zipWithNext().map {
|
||||
val d = it.second - it.first
|
||||
d.normalized.perpendicular
|
||||
}
|
||||
|
||||
val basePositions = cleanEnveloppe.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) {
|
||||
val r0 = rotateY(360.0 / sides * side)
|
||||
val r1 = rotateY(360.0 / sides * (side + 1))
|
||||
|
||||
val v0 = basePositions.map { (r0 * it.xyz0).xyz }
|
||||
val v1 = basePositions.map { (r1 * it.xyz0).xyz }
|
||||
val n0 = baseNormals.map { (r0 * it.xyz0).xyz }
|
||||
val n1 = baseNormals.map { (r1 * it.xyz0).xyz }
|
||||
|
||||
for (segment in 0 until basePositions.size - 1) {
|
||||
|
||||
val p00 = v0[segment]
|
||||
val p01 = v0[segment+1]
|
||||
val p10 = v1[segment]
|
||||
val p11 = v1[segment+1]
|
||||
|
||||
val nn0 = n0[segment]
|
||||
val nn1 = n1[segment]
|
||||
|
||||
writer(p00, nn0, Vector2.ZERO)
|
||||
writer(p01, nn0, Vector2.ZERO)
|
||||
writer(p11, nn1, Vector2.ZERO)
|
||||
|
||||
writer(p11, nn1, Vector2.ZERO)
|
||||
writer(p10, nn1, 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) {
|
||||
val maxY = enveloppe.maxBy { it.y } ?: Vector2(0.0, 1.0)
|
||||
val a = maxY.y
|
||||
|
||||
val cleanEnveloppe = enveloppe.map { Vector2((it.x), (it.y/a - 0.5) * length ) }
|
||||
|
||||
val normals2D = enveloppe.zipWithNext().map {
|
||||
val d = it.second - it.first
|
||||
d.normalized.perpendicular * Vector2(1.0, -1.0)
|
||||
|
||||
}
|
||||
|
||||
val extended = listOf(normals2D[0]) + normals2D + normals2D[normals2D.size-1]
|
||||
|
||||
// extended.zipW
|
||||
|
||||
println(normals2D.joinToString(", "))
|
||||
|
||||
val basePositions = cleanEnveloppe.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) {
|
||||
val r0 = rotateY(360.0 / sides * side)
|
||||
val r1 = rotateY(360.0 / sides * (side + 1))
|
||||
|
||||
val v0 = basePositions.map { (r0 * it.xyz0).xyz }
|
||||
val v1 = basePositions.map { (r1 * it.xyz0).xyz }
|
||||
val n0 = baseNormals.map { (r0 * it.xyz0).xyz }
|
||||
val n1 = baseNormals.map { (r1 * it.xyz0).xyz }
|
||||
|
||||
for (segment in 0 until basePositions.size - 1) {
|
||||
|
||||
val p00 = v0[segment]
|
||||
val p01 = v0[segment+1]
|
||||
val p10 = v1[segment]
|
||||
val p11 = v1[segment+1]
|
||||
|
||||
val nn0 = n0[segment]
|
||||
val nn1 = n1[segment]
|
||||
|
||||
writer(p00, nn0, Vector2.ZERO)
|
||||
writer(p10, nn1, Vector2.ZERO)
|
||||
writer(p11, nn1, Vector2.ZERO)
|
||||
|
||||
writer(p11, nn1, Vector2.ZERO)
|
||||
writer(p01, nn0, Vector2.ZERO)
|
||||
|
||||
writer(p00, nn0, Vector2.ZERO)
|
||||
}
|
||||
}
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
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) {
|
||||
val maxX = enveloppe.maxBy { it.x } ?: Vector2(1.0, 0.0)
|
||||
val a = maxX.x
|
||||
|
||||
val cleanEnveloppe = enveloppe.map { Vector2((it.x / a) * radius, it.y) }
|
||||
|
||||
val normals2D = enveloppe.zipWithNext().map {
|
||||
val d = it.second - it.first
|
||||
d.normalized.perpendicular
|
||||
}
|
||||
|
||||
val basePositions = cleanEnveloppe.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) {
|
||||
val r0 = rotateY(360.0 / sides * side)
|
||||
val r1 = rotateY(360.0 / sides * (side + 1))
|
||||
|
||||
val v0 = basePositions.map { (r0 * it.xyz0).xyz }
|
||||
val v1 = basePositions.map { (r1 * it.xyz0).xyz }
|
||||
val n0 = baseNormals.map { (r0 * it.xyz0).xyz }
|
||||
val n1 = baseNormals.map { (r1 * it.xyz0).xyz }
|
||||
|
||||
for (segment in 0 until basePositions.size - 1) {
|
||||
|
||||
val p00 = v0[segment]
|
||||
val p01 = v0[segment+1]
|
||||
val p10 = v1[segment]
|
||||
val p11 = v1[segment+1]
|
||||
|
||||
val nn0 = n0[segment]
|
||||
val nn1 = n1[segment]
|
||||
|
||||
writer(p00, nn0, Vector2.ZERO)
|
||||
writer(p01, nn0, Vector2.ZERO)
|
||||
writer(p11, nn1, Vector2.ZERO)
|
||||
|
||||
writer(p11, nn1, Vector2.ZERO)
|
||||
writer(p10, nn1, 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) {
|
||||
val maxY = enveloppe.maxBy { it.y } ?: Vector2(0.0, 1.0)
|
||||
val a = maxY.y
|
||||
|
||||
val cleanEnveloppe = enveloppe.map { Vector2((it.x), (it.y/a - 0.5) * length ) }
|
||||
|
||||
val normals2D = enveloppe.zipWithNext().map {
|
||||
val d = it.second - it.first
|
||||
d.normalized.perpendicular * Vector2(1.0, -1.0)
|
||||
|
||||
}
|
||||
|
||||
val extended = listOf(normals2D[0]) + normals2D + normals2D[normals2D.size-1]
|
||||
|
||||
// extended.zipW
|
||||
|
||||
println(normals2D.joinToString(", "))
|
||||
|
||||
val basePositions = cleanEnveloppe.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) {
|
||||
val r0 = rotateY(360.0 / sides * side)
|
||||
val r1 = rotateY(360.0 / sides * (side + 1))
|
||||
|
||||
val v0 = basePositions.map { (r0 * it.xyz0).xyz }
|
||||
val v1 = basePositions.map { (r1 * it.xyz0).xyz }
|
||||
val n0 = baseNormals.map { (r0 * it.xyz0).xyz }
|
||||
val n1 = baseNormals.map { (r1 * it.xyz0).xyz }
|
||||
|
||||
for (segment in 0 until basePositions.size - 1) {
|
||||
|
||||
val p00 = v0[segment]
|
||||
val p01 = v0[segment+1]
|
||||
val p10 = v1[segment]
|
||||
val p11 = v1[segment+1]
|
||||
|
||||
val nn0 = n0[segment]
|
||||
val nn1 = n1[segment]
|
||||
|
||||
writer(p00, nn0, Vector2.ZERO)
|
||||
writer(p10, nn1, Vector2.ZERO)
|
||||
writer(p11, nn1, Vector2.ZERO)
|
||||
|
||||
writer(p11, nn1, Vector2.ZERO)
|
||||
writer(p01, nn0, Vector2.ZERO)
|
||||
|
||||
writer(p00, nn0, Vector2.ZERO)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +1,82 @@
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.mix
|
||||
import org.openrndr.math.transforms.rotateZ
|
||||
|
||||
fun cylinderMesh(sides: Int = 16, segments: Int = 16, radius: Double = 1.0, length: Double, invert: Boolean = false): VertexBuffer {
|
||||
val vertexCount = 6 * sides * segments
|
||||
val vb = meshVertexBuffer(vertexCount)
|
||||
vb.put {
|
||||
generateCylinder(sides, segments, radius, length, invert, bufferWriter(this))
|
||||
}
|
||||
return vb
|
||||
}
|
||||
|
||||
fun generateCylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false, vertexWriter: 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) {
|
||||
val dphi = (Math.PI * 2) / sides
|
||||
val ddeg = (360.0) / sides
|
||||
|
||||
val invertFactor = if (invert) -1.0 else 1.0
|
||||
|
||||
val dr = radiusEnd - radiusStart
|
||||
|
||||
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)
|
||||
|
||||
for (segment in 0 until segments) {
|
||||
|
||||
val radius0 = mix(radiusStart, radiusEnd, segment*1.0/segments)
|
||||
val radius1 = mix(radiusStart, radiusEnd, (segment+1)*1.0/segments)
|
||||
val z0 = (length / segments) * segment - length/2.0
|
||||
val z1 = (length / segments) * (segment + 1) - length/2.0
|
||||
|
||||
|
||||
for (side in 0 until sides) {
|
||||
val x00 = Math.cos(side * dphi) * radius0
|
||||
val x10 = Math.cos(side * dphi + dphi) * radius0
|
||||
val y00 = Math.sin(side * dphi) * radius0
|
||||
val y10 = Math.sin(side * dphi + dphi) * radius0
|
||||
|
||||
val x01 = Math.cos(side * dphi) * radius1
|
||||
val x11 = Math.cos(side * dphi + dphi) * radius1
|
||||
val y01 = Math.sin(side * dphi) * radius1
|
||||
val y11 = Math.sin(side * dphi + dphi) * radius1
|
||||
|
||||
|
||||
val u0 = (segment + 0.0) / segments
|
||||
val u1 = (segment + 1.0) / segments
|
||||
val v0 = (side + 0.0) / sides
|
||||
val v1 = (side + 1.0) / sides
|
||||
|
||||
|
||||
val n0 = (rotateZ(side * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor
|
||||
val n1 = (rotateZ((side+1) * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor
|
||||
|
||||
|
||||
if (!invert) {
|
||||
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0))
|
||||
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(x01, y01, z1), n0, Vector2(u1, v0))
|
||||
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0))
|
||||
} else {
|
||||
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, 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(x10, y10, z0), n1, Vector2(u0, v1))
|
||||
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0))
|
||||
}
|
||||
}
|
||||
}
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.mix
|
||||
import org.openrndr.math.transforms.rotateZ
|
||||
|
||||
fun cylinderMesh(sides: Int = 16, segments: Int = 16, radius: Double = 1.0, length: Double, invert: Boolean = false): VertexBuffer {
|
||||
val vertexCount = 6 * sides * segments
|
||||
val vb = meshVertexBuffer(vertexCount)
|
||||
vb.put {
|
||||
generateCylinder(sides, segments, radius, length, invert, bufferWriter(this))
|
||||
}
|
||||
return vb
|
||||
}
|
||||
|
||||
fun generateCylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false, vertexWriter: 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) {
|
||||
val dphi = (Math.PI * 2) / sides
|
||||
val ddeg = (360.0) / sides
|
||||
|
||||
val invertFactor = if (invert) -1.0 else 1.0
|
||||
|
||||
val dr = radiusEnd - radiusStart
|
||||
|
||||
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)
|
||||
|
||||
for (segment in 0 until segments) {
|
||||
|
||||
val radius0 = mix(radiusStart, radiusEnd, segment*1.0/segments)
|
||||
val radius1 = mix(radiusStart, radiusEnd, (segment+1)*1.0/segments)
|
||||
val z0 = (length / segments) * segment - length/2.0
|
||||
val z1 = (length / segments) * (segment + 1) - length/2.0
|
||||
|
||||
|
||||
for (side in 0 until sides) {
|
||||
val x00 = Math.cos(side * dphi) * radius0
|
||||
val x10 = Math.cos(side * dphi + dphi) * radius0
|
||||
val y00 = Math.sin(side * dphi) * radius0
|
||||
val y10 = Math.sin(side * dphi + dphi) * radius0
|
||||
|
||||
val x01 = Math.cos(side * dphi) * radius1
|
||||
val x11 = Math.cos(side * dphi + dphi) * radius1
|
||||
val y01 = Math.sin(side * dphi) * radius1
|
||||
val y11 = Math.sin(side * dphi + dphi) * radius1
|
||||
|
||||
|
||||
val u0 = (segment + 0.0) / segments
|
||||
val u1 = (segment + 1.0) / segments
|
||||
val v0 = (side + 0.0) / sides
|
||||
val v1 = (side + 1.0) / sides
|
||||
|
||||
|
||||
val n0 = (rotateZ(side * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor
|
||||
val n1 = (rotateZ((side+1) * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor
|
||||
|
||||
|
||||
if (!invert) {
|
||||
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0))
|
||||
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(x01, y01, z1), n0, Vector2(u1, v0))
|
||||
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0))
|
||||
} else {
|
||||
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, 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(x10, y10, z0), n1, Vector2(u0, v1))
|
||||
vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,172 +1,172 @@
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.draw.vertexBuffer
|
||||
import org.openrndr.draw.vertexFormat
|
||||
import org.openrndr.math.Matrix44
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.transforms.rotate
|
||||
import org.openrndr.math.transforms.transform
|
||||
import org.openrndr.shape.Shape
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
|
||||
class GeneratorBuffer {
|
||||
class VertexData(val position: Vector3, val normal: Vector3, val texCoord: Vector2)
|
||||
|
||||
var data = mutableListOf<VertexData>()
|
||||
|
||||
fun write(position: Vector3, normal: Vector3, texCoord: Vector2) {
|
||||
data.add(VertexData(position, normal, texCoord))
|
||||
}
|
||||
|
||||
fun concat(other: GeneratorBuffer) {
|
||||
data.addAll(other.data)
|
||||
}
|
||||
|
||||
fun transform(m: Matrix44) {
|
||||
data = data.map {
|
||||
VertexData((m * (it.position.xyz1)).xyz, (m * (it.normal.xyz0)).xyz, it.texCoord)
|
||||
}.toMutableList()
|
||||
}
|
||||
|
||||
fun toByteBuffer(): ByteBuffer {
|
||||
val bb = ByteBuffer.allocateDirect(data.size * (3 * 4 + 3 * 4 + 2 * 4))
|
||||
bb.order(ByteOrder.nativeOrder())
|
||||
bb.rewind()
|
||||
for (d in data) {
|
||||
bb.putFloat(d.position.x.toFloat())
|
||||
bb.putFloat(d.position.y.toFloat())
|
||||
bb.putFloat(d.position.z.toFloat())
|
||||
|
||||
bb.putFloat(d.normal.x.toFloat())
|
||||
bb.putFloat(d.normal.y.toFloat())
|
||||
bb.putFloat(d.normal.z.toFloat())
|
||||
|
||||
bb.putFloat(d.texCoord.x.toFloat())
|
||||
bb.putFloat(d.texCoord.y.toFloat())
|
||||
}
|
||||
return bb
|
||||
}
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.sphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) {
|
||||
generateSphere(sides, segments, radius, invert, this::write)
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.hemisphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) {
|
||||
generateHemisphere(sides, segments, radius, invert, this::write)
|
||||
}
|
||||
|
||||
enum class GridCoordinates {
|
||||
INDEX,
|
||||
UNIPOLAR,
|
||||
BIPOLAR,
|
||||
}
|
||||
|
||||
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 (u in 0 until width) {
|
||||
group {
|
||||
when (coordinates) {
|
||||
GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0)
|
||||
GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 1.0) - 1,
|
||||
2 * v / (height - 1.0) - 1)
|
||||
GridCoordinates.UNIPOLAR -> this.builder(u / (width - 1.0), v / (height - 1.0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.twist(degreesPerUnit: Double, start: Double, axis: Vector3 = Vector3.UNIT_Y) {
|
||||
data = data.map {
|
||||
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
|
||||
throw IllegalArgumentException("0 axis")
|
||||
val r = rotate(axis, t * degreesPerUnit)
|
||||
GeneratorBuffer.VertexData((r * it.position.xyz1).xyz, (r * it.normal.xyz0).xyz, it.texCoord)
|
||||
}.toMutableList()
|
||||
}
|
||||
|
||||
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 (v in 0 until height) {
|
||||
for (u in 0 until width) {
|
||||
group {
|
||||
when (coordinates) {
|
||||
GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0, w * 1.0)
|
||||
GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.cylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false) {
|
||||
generateCylinder(sides, segments, radius, length, invert, this::write)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.cap(sides: Int, radius: Double, enveloppe: List<Vector2>) {
|
||||
generateCap(sides, radius, enveloppe, this::write)
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.revolve(sides:Int, length:Double, enveloppe: List<Vector2>) {
|
||||
generateRevolve(sides, length, enveloppe, this::write)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun meshGenerator(builder: GeneratorBuffer.() -> Unit): VertexBuffer {
|
||||
val gb = GeneratorBuffer()
|
||||
gb.builder()
|
||||
|
||||
val vb = vertexBuffer(vertexFormat {
|
||||
position(3)
|
||||
normal(3)
|
||||
textureCoordinate(2)
|
||||
}, gb.data.size)
|
||||
|
||||
val bb = gb.toByteBuffer()
|
||||
bb.rewind()
|
||||
vb.write(bb)
|
||||
return vb
|
||||
}
|
||||
|
||||
fun generator(builder: GeneratorBuffer.() -> Unit): GeneratorBuffer {
|
||||
val gb = GeneratorBuffer()
|
||||
gb.builder()
|
||||
return gb
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.group(builder: GeneratorBuffer.() -> Unit) {
|
||||
val gb = GeneratorBuffer()
|
||||
gb.builder()
|
||||
this.concat(gb)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val gb = generator {
|
||||
box(20.0, 20.0, 20.0)
|
||||
group {
|
||||
box(40.0, 40.0, 40.0)
|
||||
transform(transform {
|
||||
translate(0.0, 20.0, 0.0)
|
||||
})
|
||||
}
|
||||
}
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.draw.vertexBuffer
|
||||
import org.openrndr.draw.vertexFormat
|
||||
import org.openrndr.math.Matrix44
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.transforms.rotate
|
||||
import org.openrndr.math.transforms.transform
|
||||
import org.openrndr.shape.Shape
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
|
||||
class GeneratorBuffer {
|
||||
class VertexData(val position: Vector3, val normal: Vector3, val texCoord: Vector2)
|
||||
|
||||
var data = mutableListOf<VertexData>()
|
||||
|
||||
fun write(position: Vector3, normal: Vector3, texCoord: Vector2) {
|
||||
data.add(VertexData(position, normal, texCoord))
|
||||
}
|
||||
|
||||
fun concat(other: GeneratorBuffer) {
|
||||
data.addAll(other.data)
|
||||
}
|
||||
|
||||
fun transform(m: Matrix44) {
|
||||
data = data.map {
|
||||
VertexData((m * (it.position.xyz1)).xyz, (m * (it.normal.xyz0)).xyz, it.texCoord)
|
||||
}.toMutableList()
|
||||
}
|
||||
|
||||
fun toByteBuffer(): ByteBuffer {
|
||||
val bb = ByteBuffer.allocateDirect(data.size * (3 * 4 + 3 * 4 + 2 * 4))
|
||||
bb.order(ByteOrder.nativeOrder())
|
||||
bb.rewind()
|
||||
for (d in data) {
|
||||
bb.putFloat(d.position.x.toFloat())
|
||||
bb.putFloat(d.position.y.toFloat())
|
||||
bb.putFloat(d.position.z.toFloat())
|
||||
|
||||
bb.putFloat(d.normal.x.toFloat())
|
||||
bb.putFloat(d.normal.y.toFloat())
|
||||
bb.putFloat(d.normal.z.toFloat())
|
||||
|
||||
bb.putFloat(d.texCoord.x.toFloat())
|
||||
bb.putFloat(d.texCoord.y.toFloat())
|
||||
}
|
||||
return bb
|
||||
}
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.sphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) {
|
||||
generateSphere(sides, segments, radius, invert, this::write)
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.hemisphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) {
|
||||
generateHemisphere(sides, segments, radius, invert, this::write)
|
||||
}
|
||||
|
||||
enum class GridCoordinates {
|
||||
INDEX,
|
||||
UNIPOLAR,
|
||||
BIPOLAR,
|
||||
}
|
||||
|
||||
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 (u in 0 until width) {
|
||||
group {
|
||||
when (coordinates) {
|
||||
GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0)
|
||||
GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 1.0) - 1,
|
||||
2 * v / (height - 1.0) - 1)
|
||||
GridCoordinates.UNIPOLAR -> this.builder(u / (width - 1.0), v / (height - 1.0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.twist(degreesPerUnit: Double, start: Double, axis: Vector3 = Vector3.UNIT_Y) {
|
||||
data = data.map {
|
||||
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
|
||||
throw IllegalArgumentException("0 axis")
|
||||
val r = rotate(axis, t * degreesPerUnit)
|
||||
GeneratorBuffer.VertexData((r * it.position.xyz1).xyz, (r * it.normal.xyz0).xyz, it.texCoord)
|
||||
}.toMutableList()
|
||||
}
|
||||
|
||||
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 (v in 0 until height) {
|
||||
for (u in 0 until width) {
|
||||
group {
|
||||
when (coordinates) {
|
||||
GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0, w * 1.0)
|
||||
GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.cylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false) {
|
||||
generateCylinder(sides, segments, radius, length, invert, this::write)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.cap(sides: Int, radius: Double, enveloppe: List<Vector2>) {
|
||||
generateCap(sides, radius, enveloppe, this::write)
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.revolve(sides:Int, length:Double, enveloppe: List<Vector2>) {
|
||||
generateRevolve(sides, length, enveloppe, this::write)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun meshGenerator(builder: GeneratorBuffer.() -> Unit): VertexBuffer {
|
||||
val gb = GeneratorBuffer()
|
||||
gb.builder()
|
||||
|
||||
val vb = vertexBuffer(vertexFormat {
|
||||
position(3)
|
||||
normal(3)
|
||||
textureCoordinate(2)
|
||||
}, gb.data.size)
|
||||
|
||||
val bb = gb.toByteBuffer()
|
||||
bb.rewind()
|
||||
vb.write(bb)
|
||||
return vb
|
||||
}
|
||||
|
||||
fun generator(builder: GeneratorBuffer.() -> Unit): GeneratorBuffer {
|
||||
val gb = GeneratorBuffer()
|
||||
gb.builder()
|
||||
return gb
|
||||
}
|
||||
|
||||
fun GeneratorBuffer.group(builder: GeneratorBuffer.() -> Unit) {
|
||||
val gb = GeneratorBuffer()
|
||||
gb.builder()
|
||||
this.concat(gb)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val gb = generator {
|
||||
box(20.0, 20.0, 20.0)
|
||||
group {
|
||||
box(40.0, 40.0, 40.0)
|
||||
transform(transform {
|
||||
translate(0.0, 20.0, 0.0)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +1,84 @@
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
|
||||
fun planeMesh(center: Vector3,
|
||||
right: Vector3,
|
||||
forward: Vector3,
|
||||
up: Vector3 = forward.cross(right).normalized,
|
||||
width: Double = 1.0, height: Double = 1.0,
|
||||
widthSegments: Int = 1, heightSegments: Int = 1): VertexBuffer {
|
||||
|
||||
val vertexCount = (widthSegments * heightSegments) * 6
|
||||
val vb = meshVertexBuffer(vertexCount)
|
||||
vb.put {
|
||||
generatePlane(center, right, forward, up,
|
||||
width, height, widthSegments, heightSegments, bufferWriter(this))
|
||||
}
|
||||
return vb
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a finite plane with its center at (0,0,0) and spanning the xz-plane
|
||||
*/
|
||||
fun groundPlaneMesh(width: Double = 1.0,
|
||||
height: Double = 1.0,
|
||||
widthSegments: Int = 1,
|
||||
heightSegments: Int = 1): VertexBuffer {
|
||||
return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y,
|
||||
width, height, widthSegments, heightSegments)
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a finite plane with its center at (0,0,0) and spanning the xy-plane
|
||||
*/
|
||||
fun wallPlaneMesh(width: Double = 1.0,
|
||||
height: Double = 1.0,
|
||||
widthSegments: Int = 1,
|
||||
heightSegments: Int = 1): VertexBuffer {
|
||||
return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z,
|
||||
width, height, widthSegments, heightSegments)
|
||||
}
|
||||
|
||||
|
||||
fun generatePlane(center: Vector3,
|
||||
right: Vector3,
|
||||
forward: Vector3,
|
||||
up: Vector3 = forward.cross(right).normalized,
|
||||
|
||||
width: Double = 1.0, height: Double = 1.0,
|
||||
widthSegments: Int = 1, heightSegments: Int = 2,
|
||||
writer: VertexWriter) {
|
||||
|
||||
val forwardStep = forward.normalized * (height / heightSegments)
|
||||
val rightStep = right.normalized * (width / widthSegments)
|
||||
|
||||
val corner = center - forward.normalized * (height*0.5) - right.normalized * (width * 0.5)
|
||||
|
||||
val step = Vector2(1.0 / width, 1.0 / height)
|
||||
|
||||
for (v in 0 until heightSegments) {
|
||||
for (u in 0 until widthSegments) {
|
||||
|
||||
val uv00 = Vector2(u + 0.0, v + 0.0) * step
|
||||
val uv01 = Vector2(u + 0.0, v + 0.1) * step
|
||||
val uv10 = Vector2(u + 1.0, v + 0.0) * step
|
||||
val uv11 = Vector2(u + 1.0, v + 0.1) * step
|
||||
|
||||
val c00 = corner + forwardStep * v.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 c11 = corner + forwardStep * (v + 1).toDouble() + rightStep * (u + 1).toDouble()
|
||||
|
||||
writer(c11, up, uv00)
|
||||
writer(c10, up, uv10)
|
||||
writer(c00, up, uv11)
|
||||
|
||||
writer(c00, up, uv11)
|
||||
writer(c01, up, uv01)
|
||||
writer(c11, up, uv00)
|
||||
}
|
||||
}
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
|
||||
fun planeMesh(center: Vector3,
|
||||
right: Vector3,
|
||||
forward: Vector3,
|
||||
up: Vector3 = forward.cross(right).normalized,
|
||||
width: Double = 1.0, height: Double = 1.0,
|
||||
widthSegments: Int = 1, heightSegments: Int = 1): VertexBuffer {
|
||||
|
||||
val vertexCount = (widthSegments * heightSegments) * 6
|
||||
val vb = meshVertexBuffer(vertexCount)
|
||||
vb.put {
|
||||
generatePlane(center, right, forward, up,
|
||||
width, height, widthSegments, heightSegments, bufferWriter(this))
|
||||
}
|
||||
return vb
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a finite plane with its center at (0,0,0) and spanning the xz-plane
|
||||
*/
|
||||
fun groundPlaneMesh(width: Double = 1.0,
|
||||
height: Double = 1.0,
|
||||
widthSegments: Int = 1,
|
||||
heightSegments: Int = 1): VertexBuffer {
|
||||
return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y,
|
||||
width, height, widthSegments, heightSegments)
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a finite plane with its center at (0,0,0) and spanning the xy-plane
|
||||
*/
|
||||
fun wallPlaneMesh(width: Double = 1.0,
|
||||
height: Double = 1.0,
|
||||
widthSegments: Int = 1,
|
||||
heightSegments: Int = 1): VertexBuffer {
|
||||
return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z,
|
||||
width, height, widthSegments, heightSegments)
|
||||
}
|
||||
|
||||
|
||||
fun generatePlane(center: Vector3,
|
||||
right: Vector3,
|
||||
forward: Vector3,
|
||||
up: Vector3 = forward.cross(right).normalized,
|
||||
|
||||
width: Double = 1.0, height: Double = 1.0,
|
||||
widthSegments: Int = 1, heightSegments: Int = 2,
|
||||
writer: VertexWriter) {
|
||||
|
||||
val forwardStep = forward.normalized * (height / heightSegments)
|
||||
val rightStep = right.normalized * (width / widthSegments)
|
||||
|
||||
val corner = center - forward.normalized * (height*0.5) - right.normalized * (width * 0.5)
|
||||
|
||||
val step = Vector2(1.0 / width, 1.0 / height)
|
||||
|
||||
for (v in 0 until heightSegments) {
|
||||
for (u in 0 until widthSegments) {
|
||||
|
||||
val uv00 = Vector2(u + 0.0, v + 0.0) * step
|
||||
val uv01 = Vector2(u + 0.0, v + 0.1) * step
|
||||
val uv10 = Vector2(u + 1.0, v + 0.0) * step
|
||||
val uv11 = Vector2(u + 1.0, v + 0.1) * step
|
||||
|
||||
val c00 = corner + forwardStep * v.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 c11 = corner + forwardStep * (v + 1).toDouble() + rightStep * (u + 1).toDouble()
|
||||
|
||||
writer(c11, up, uv00)
|
||||
writer(c10, up, uv10)
|
||||
writer(c00, up, uv11)
|
||||
|
||||
writer(c00, up, uv11)
|
||||
writer(c01, up, uv01)
|
||||
writer(c11, up, uv00)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +1,84 @@
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.math.Spherical
|
||||
import org.openrndr.math.Vector2
|
||||
|
||||
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 vb = meshVertexBuffer(vertexCount)
|
||||
vb.put {
|
||||
generateSphere(sides, segments, radius, invert, bufferWriter(this))
|
||||
}
|
||||
return vb
|
||||
}
|
||||
|
||||
|
||||
fun generateSphere(sides: Int, segments: Int, radius: Double = 1.0, invert: Boolean = false, writer: VertexWriter) {
|
||||
val inverter = if (invert) -1.0 else 1.0
|
||||
for (t in 0 until segments) {
|
||||
for (s in 0 until sides) {
|
||||
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 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 thetaMax = Math.PI
|
||||
val phiMax = Math.PI * 2.0
|
||||
|
||||
when (t) {
|
||||
0 -> {
|
||||
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(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax))
|
||||
}
|
||||
segments - 1 -> {
|
||||
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(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax))
|
||||
}
|
||||
else -> {
|
||||
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(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(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) {
|
||||
val inverter = if (invert) -1.0 else 1.0
|
||||
for (t in 0 until segments) {
|
||||
for (s in 0 until sides) {
|
||||
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 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 thetaMax = Math.PI * 0.5
|
||||
val phiMax = Math.PI * 2.0
|
||||
|
||||
when (t) {
|
||||
0 -> {
|
||||
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(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax))
|
||||
}
|
||||
else -> {
|
||||
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(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(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
package org.openrndr.extras.meshgenerators
|
||||
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.math.Spherical
|
||||
import org.openrndr.math.Vector2
|
||||
|
||||
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 vb = meshVertexBuffer(vertexCount)
|
||||
vb.put {
|
||||
generateSphere(sides, segments, radius, invert, bufferWriter(this))
|
||||
}
|
||||
return vb
|
||||
}
|
||||
|
||||
|
||||
fun generateSphere(sides: Int, segments: Int, radius: Double = 1.0, invert: Boolean = false, writer: VertexWriter) {
|
||||
val inverter = if (invert) -1.0 else 1.0
|
||||
for (t in 0 until segments) {
|
||||
for (s in 0 until sides) {
|
||||
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 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 thetaMax = Math.PI
|
||||
val phiMax = Math.PI * 2.0
|
||||
|
||||
when (t) {
|
||||
0 -> {
|
||||
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(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax))
|
||||
}
|
||||
segments - 1 -> {
|
||||
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(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax))
|
||||
}
|
||||
else -> {
|
||||
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(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(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) {
|
||||
val inverter = if (invert) -1.0 else 1.0
|
||||
for (t in 0 until segments) {
|
||||
for (s in 0 until sides) {
|
||||
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 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 thetaMax = Math.PI * 0.5
|
||||
val phiMax = Math.PI * 2.0
|
||||
|
||||
when (t) {
|
||||
0 -> {
|
||||
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(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax))
|
||||
}
|
||||
else -> {
|
||||
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(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(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +1,54 @@
|
||||
# orx-no-clear
|
||||
|
||||
A simple OPENRNDR Extension that provides the classical drawing-without-clearing-the-screen functionality that
|
||||
OPENRNDR does not support natively.
|
||||
|
||||
#### Usage
|
||||
|
||||
```kotlin
|
||||
fun main() = application {
|
||||
configure {
|
||||
title = "NoClearProgram"
|
||||
}
|
||||
program {
|
||||
backgroundColor = ColorRGBa.PINK
|
||||
extend(NoClear())
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Usage with additional configuration
|
||||
Optionally, a static `backdrop` may be setup by providing custom code.
|
||||
|
||||
- Example 1. Customising the backdrop with an image
|
||||
```kotlin
|
||||
extend(NoClear()) {
|
||||
val img = loadImage("data\\backdrop.png")
|
||||
backdrop = {
|
||||
drawer.image(img, 0.0, 0.0, width * 1.0, height * 1.0)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Example 2. Customising the backdrop with a checker-board pattern
|
||||
```kotlin
|
||||
extend(NoClear()) {
|
||||
backdrop = {
|
||||
val xw = width / 8.0
|
||||
val yh = height / 8.0
|
||||
drawer.fill = ColorRGBa.RED
|
||||
(0..7).forEach { row ->
|
||||
(0..7).forEach { col ->
|
||||
if ((row + col) % 2 == 0) {
|
||||
drawer.rectangle(row * xw, col * yh, xw, yh)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# orx-no-clear
|
||||
|
||||
A simple OPENRNDR Extension that provides the classical drawing-without-clearing-the-screen functionality that
|
||||
OPENRNDR does not support natively.
|
||||
|
||||
#### Usage
|
||||
|
||||
```kotlin
|
||||
fun main() = application {
|
||||
configure {
|
||||
title = "NoClearProgram"
|
||||
}
|
||||
program {
|
||||
backgroundColor = ColorRGBa.PINK
|
||||
extend(NoClear())
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Usage with additional configuration
|
||||
Optionally, a static `backdrop` may be setup by providing custom code.
|
||||
|
||||
- Example 1. Customising the backdrop with an image
|
||||
```kotlin
|
||||
extend(NoClear()) {
|
||||
val img = loadImage("data\\backdrop.png")
|
||||
backdrop = {
|
||||
drawer.image(img, 0.0, 0.0, width * 1.0, height * 1.0)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Example 2. Customising the backdrop with a checker-board pattern
|
||||
```kotlin
|
||||
extend(NoClear()) {
|
||||
backdrop = {
|
||||
val xw = width / 8.0
|
||||
val yh = height / 8.0
|
||||
drawer.fill = ColorRGBa.RED
|
||||
(0..7).forEach { row ->
|
||||
(0..7).forEach { col ->
|
||||
if ((row + col) % 2 == 0) {
|
||||
drawer.rectangle(row * xw, col * yh, xw, yh)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
NB! any submitted _lambda expression_ must be valid within the `renderTarget` context.
|
||||
@@ -1,57 +1,57 @@
|
||||
package org.openrndr.extra.noclear
|
||||
|
||||
import org.openrndr.Extension
|
||||
import org.openrndr.Program
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.Drawer
|
||||
import org.openrndr.draw.RenderTarget
|
||||
import org.openrndr.draw.isolated
|
||||
import org.openrndr.draw.renderTarget
|
||||
import org.openrndr.math.Matrix44
|
||||
|
||||
class NoClear : Extension {
|
||||
override var enabled: Boolean = true
|
||||
private var renderTarget: RenderTarget? = null
|
||||
|
||||
/**
|
||||
* code-block to draw an optional custom backdrop
|
||||
*/
|
||||
var backdrop: (() -> Unit)? = null
|
||||
|
||||
override fun beforeDraw(drawer: Drawer, program: Program) {
|
||||
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) {
|
||||
renderTarget?.let {
|
||||
it.colorBuffer(0).destroy()
|
||||
it.detachColorBuffers()
|
||||
it.destroy()
|
||||
}
|
||||
renderTarget = renderTarget(program.width, program.height) {
|
||||
colorBuffer()
|
||||
depthBuffer()
|
||||
}
|
||||
|
||||
renderTarget?.let {
|
||||
drawer.withTarget(it) {
|
||||
background(program.backgroundColor ?: ColorRGBa.TRANSPARENT)
|
||||
backdrop?.invoke() // draw custom backdrop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
renderTarget?.bind()
|
||||
}
|
||||
|
||||
override fun afterDraw(drawer: Drawer, program: Program) {
|
||||
renderTarget?.unbind()
|
||||
|
||||
renderTarget?.let {
|
||||
drawer.isolated {
|
||||
drawer.ortho()
|
||||
drawer.view = Matrix44.IDENTITY
|
||||
drawer.model = Matrix44.IDENTITY
|
||||
drawer.image(it.colorBuffer(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
package org.openrndr.extra.noclear
|
||||
|
||||
import org.openrndr.Extension
|
||||
import org.openrndr.Program
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.Drawer
|
||||
import org.openrndr.draw.RenderTarget
|
||||
import org.openrndr.draw.isolated
|
||||
import org.openrndr.draw.renderTarget
|
||||
import org.openrndr.math.Matrix44
|
||||
|
||||
class NoClear : Extension {
|
||||
override var enabled: Boolean = true
|
||||
private var renderTarget: RenderTarget? = null
|
||||
|
||||
/**
|
||||
* code-block to draw an optional custom backdrop
|
||||
*/
|
||||
var backdrop: (() -> Unit)? = null
|
||||
|
||||
override fun beforeDraw(drawer: Drawer, program: Program) {
|
||||
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) {
|
||||
renderTarget?.let {
|
||||
it.colorBuffer(0).destroy()
|
||||
it.detachColorBuffers()
|
||||
it.destroy()
|
||||
}
|
||||
renderTarget = renderTarget(program.width, program.height) {
|
||||
colorBuffer()
|
||||
depthBuffer()
|
||||
}
|
||||
|
||||
renderTarget?.let {
|
||||
drawer.withTarget(it) {
|
||||
background(program.backgroundColor ?: ColorRGBa.TRANSPARENT)
|
||||
backdrop?.invoke() // draw custom backdrop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
renderTarget?.bind()
|
||||
}
|
||||
|
||||
override fun afterDraw(drawer: Drawer, program: Program) {
|
||||
renderTarget?.unbind()
|
||||
|
||||
renderTarget?.let {
|
||||
drawer.isolated {
|
||||
drawer.ortho()
|
||||
drawer.view = Matrix44.IDENTITY
|
||||
drawer.model = Matrix44.IDENTITY
|
||||
drawer.image(it.colorBuffer(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,123 +1,123 @@
|
||||
# orx-noise
|
||||
|
||||
A collection of noisy functions
|
||||
|
||||
## Uniform random numbers
|
||||
|
||||
```kotlin
|
||||
val sua = Double.uniform()
|
||||
val sub = Double.uniform(-1.0, 1.0)
|
||||
|
||||
val v2ua = Vector2.uniform()
|
||||
val v2ub = Vector2.uniform(-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 v3ua = Vector3.uniform()
|
||||
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 v3ur = Vector3.uniformRing(0.5, 1.0)
|
||||
|
||||
val v4ua = Vector4.uniform()
|
||||
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 v4ur = Vector4.uniformRing(0.5, 1.0)
|
||||
|
||||
val ringSamples = List(500) { Vector2.uniformRing() }
|
||||
```
|
||||
|
||||
## Multi-dimensional noise
|
||||
|
||||
These are a mostly straight port from FastNoise-Java but have a slightly different interface.
|
||||
|
||||
### Perlin noise
|
||||
```
|
||||
// -- 2d
|
||||
val v0 = perlinLinear(seed, x, y)
|
||||
val v1 = perlinQuintic(seed, x, y)
|
||||
val v2 = perlinHermite(seed, x, y)
|
||||
|
||||
// -- 3d
|
||||
val v3 = perlinLinear(seed, x, y, z)
|
||||
val v4 = perlinQuintic(seed, x, y, z)
|
||||
val v5 = perlinHermite(seed, x, y, z)
|
||||
```
|
||||
|
||||
### Value noise
|
||||
```
|
||||
// -- 2d
|
||||
val v0 = valueLinear(seed, x, y)
|
||||
val v1 = valueQuintic(seed, x, y)
|
||||
val v2 = valueHermite(seed, x, y)
|
||||
|
||||
// -- 3d
|
||||
val v3 = valueLinear(seed, x, y, z)
|
||||
val v4 = valueQuintic(seed, x, y, z)
|
||||
val v5 = valueHermite(seed, x, y ,z)
|
||||
```
|
||||
|
||||
### Simplex noise
|
||||
```
|
||||
// -- 2d
|
||||
val v0 = simplexLinear(seed, x, y)
|
||||
val v1 = simplexQuintic(seed, x, y)
|
||||
val v2 = simplexHermite(seed, x, y)
|
||||
|
||||
// -- 3d
|
||||
val v3 = simplexLinear(seed, x, y, z)
|
||||
val v4 = simplexQuintic(seed, x, y, z)
|
||||
val v5 = simplexHermite(seed, x, y ,z)
|
||||
```
|
||||
|
||||
### Cubic noise
|
||||
```
|
||||
// -- 2d
|
||||
val v0 = cubicLinear(seed, x, y)
|
||||
val v1 = cubicQuintic(seed, x, y)
|
||||
val v2 = cubicHermite(seed, x, y)
|
||||
|
||||
// -- 3d
|
||||
val v3 = cubicLinear(seed, x, y, z)
|
||||
val v4 = cubicQuintic(seed, x, y, z)
|
||||
val v5 = cubicHermite(seed, x, y ,z)
|
||||
```
|
||||
|
||||
### Fractal noise
|
||||
|
||||
The library provides 3 functions with which fractal noise can be composed.
|
||||
|
||||
#### Fractal brownian motion (FBM)
|
||||
|
||||
```
|
||||
val v0 = fbm(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
|
||||
val v1 = fbm(seed, x, y, ::simplexLinear, 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 v4 = fbm(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain)
|
||||
val v5 = fbm(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain)
|
||||
```
|
||||
|
||||
#### Rigid
|
||||
|
||||
```
|
||||
val v0 = rigid(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
|
||||
val v1 = rigid(seed, x, y, ::simplexLinear, 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 v4 = rigid(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain)
|
||||
val v5 = rigid(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain)
|
||||
```
|
||||
|
||||
#### Billow
|
||||
|
||||
```
|
||||
val v0 = 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 v3 = 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)
|
||||
# orx-noise
|
||||
|
||||
A collection of noisy functions
|
||||
|
||||
## Uniform random numbers
|
||||
|
||||
```kotlin
|
||||
val sua = Double.uniform()
|
||||
val sub = Double.uniform(-1.0, 1.0)
|
||||
|
||||
val v2ua = Vector2.uniform()
|
||||
val v2ub = Vector2.uniform(-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 v3ua = Vector3.uniform()
|
||||
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 v3ur = Vector3.uniformRing(0.5, 1.0)
|
||||
|
||||
val v4ua = Vector4.uniform()
|
||||
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 v4ur = Vector4.uniformRing(0.5, 1.0)
|
||||
|
||||
val ringSamples = List(500) { Vector2.uniformRing() }
|
||||
```
|
||||
|
||||
## Multi-dimensional noise
|
||||
|
||||
These are a mostly straight port from FastNoise-Java but have a slightly different interface.
|
||||
|
||||
### Perlin noise
|
||||
```
|
||||
// -- 2d
|
||||
val v0 = perlinLinear(seed, x, y)
|
||||
val v1 = perlinQuintic(seed, x, y)
|
||||
val v2 = perlinHermite(seed, x, y)
|
||||
|
||||
// -- 3d
|
||||
val v3 = perlinLinear(seed, x, y, z)
|
||||
val v4 = perlinQuintic(seed, x, y, z)
|
||||
val v5 = perlinHermite(seed, x, y, z)
|
||||
```
|
||||
|
||||
### Value noise
|
||||
```
|
||||
// -- 2d
|
||||
val v0 = valueLinear(seed, x, y)
|
||||
val v1 = valueQuintic(seed, x, y)
|
||||
val v2 = valueHermite(seed, x, y)
|
||||
|
||||
// -- 3d
|
||||
val v3 = valueLinear(seed, x, y, z)
|
||||
val v4 = valueQuintic(seed, x, y, z)
|
||||
val v5 = valueHermite(seed, x, y ,z)
|
||||
```
|
||||
|
||||
### Simplex noise
|
||||
```
|
||||
// -- 2d
|
||||
val v0 = simplexLinear(seed, x, y)
|
||||
val v1 = simplexQuintic(seed, x, y)
|
||||
val v2 = simplexHermite(seed, x, y)
|
||||
|
||||
// -- 3d
|
||||
val v3 = simplexLinear(seed, x, y, z)
|
||||
val v4 = simplexQuintic(seed, x, y, z)
|
||||
val v5 = simplexHermite(seed, x, y ,z)
|
||||
```
|
||||
|
||||
### Cubic noise
|
||||
```
|
||||
// -- 2d
|
||||
val v0 = cubicLinear(seed, x, y)
|
||||
val v1 = cubicQuintic(seed, x, y)
|
||||
val v2 = cubicHermite(seed, x, y)
|
||||
|
||||
// -- 3d
|
||||
val v3 = cubicLinear(seed, x, y, z)
|
||||
val v4 = cubicQuintic(seed, x, y, z)
|
||||
val v5 = cubicHermite(seed, x, y ,z)
|
||||
```
|
||||
|
||||
### Fractal noise
|
||||
|
||||
The library provides 3 functions with which fractal noise can be composed.
|
||||
|
||||
#### Fractal brownian motion (FBM)
|
||||
|
||||
```
|
||||
val v0 = fbm(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
|
||||
val v1 = fbm(seed, x, y, ::simplexLinear, 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 v4 = fbm(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain)
|
||||
val v5 = fbm(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain)
|
||||
```
|
||||
|
||||
#### Rigid
|
||||
|
||||
```
|
||||
val v0 = rigid(seed, x, y, ::perlinLinear, octaves, lacunarity, gain)
|
||||
val v1 = rigid(seed, x, y, ::simplexLinear, 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 v4 = rigid(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain)
|
||||
val v5 = rigid(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain)
|
||||
```
|
||||
|
||||
#### Billow
|
||||
|
||||
```
|
||||
val v0 = 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 v3 = 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)
|
||||
```
|
||||
@@ -1,28 +1,28 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
private const val CUBIC_2D_BOUNDING = 1 / (1.5 * 1.5).toFloat()
|
||||
fun cubic(seed: Int, x: Double, y: Double): Double {
|
||||
val x1 = x.fastFloor()
|
||||
val y1 = y.fastFloor()
|
||||
|
||||
val x0 = x1 - 1
|
||||
val y0 = y1 - 1
|
||||
val x2 = x1 + 1
|
||||
val y2 = y1 + 1
|
||||
val x3 = x1 + 2
|
||||
val y3 = y1 + 2
|
||||
|
||||
val xs = x - x1.toDouble()
|
||||
val ys = y - y1.toDouble()
|
||||
|
||||
return cubic(
|
||||
cubic(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), valCoord2D(seed, x2, y0), valCoord2D(seed, x3, y0),
|
||||
xs),
|
||||
cubic(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), valCoord2D(seed, x2, y1), valCoord2D(seed, x3, y1),
|
||||
xs),
|
||||
cubic(valCoord2D(seed, x0, y2), valCoord2D(seed, x1, y2), valCoord2D(seed, x2, y2), valCoord2D(seed, x3, y2),
|
||||
xs),
|
||||
cubic(valCoord2D(seed, x0, y3), valCoord2D(seed, x1, y3), valCoord2D(seed, x2, y3), valCoord2D(seed, x3, y3),
|
||||
xs),
|
||||
ys) * CUBIC_2D_BOUNDING
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
private const val CUBIC_2D_BOUNDING = 1 / (1.5 * 1.5).toFloat()
|
||||
fun cubic(seed: Int, x: Double, y: Double): Double {
|
||||
val x1 = x.fastFloor()
|
||||
val y1 = y.fastFloor()
|
||||
|
||||
val x0 = x1 - 1
|
||||
val y0 = y1 - 1
|
||||
val x2 = x1 + 1
|
||||
val y2 = y1 + 1
|
||||
val x3 = x1 + 2
|
||||
val y3 = y1 + 2
|
||||
|
||||
val xs = x - x1.toDouble()
|
||||
val ys = y - y1.toDouble()
|
||||
|
||||
return cubic(
|
||||
cubic(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), valCoord2D(seed, x2, y0), valCoord2D(seed, x3, y0),
|
||||
xs),
|
||||
cubic(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), valCoord2D(seed, x2, y1), valCoord2D(seed, x3, y1),
|
||||
xs),
|
||||
cubic(valCoord2D(seed, x0, y2), valCoord2D(seed, x1, y2), valCoord2D(seed, x2, y2), valCoord2D(seed, x3, y2),
|
||||
xs),
|
||||
cubic(valCoord2D(seed, x0, y3), valCoord2D(seed, x1, y3), valCoord2D(seed, x2, y3), valCoord2D(seed, x3, y3),
|
||||
xs),
|
||||
ys) * CUBIC_2D_BOUNDING
|
||||
}
|
||||
@@ -1,51 +1,51 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
|
||||
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 {
|
||||
val x1 = x.fastFloor()
|
||||
val y1 = y.fastFloor()
|
||||
val z1 = z.fastFloor()
|
||||
|
||||
val x0 = x1 - 1
|
||||
val y0 = y1 - 1
|
||||
val z0 = z1 - 1
|
||||
val x2 = x1 + 1
|
||||
val y2 = y1 + 1
|
||||
val z2 = z1 + 1
|
||||
val x3 = x1 + 2
|
||||
val y3 = y1 + 2
|
||||
val z3 = z1 + 2
|
||||
|
||||
val xs = x - x1.toFloat()
|
||||
val ys = y - y1.toFloat()
|
||||
val zs = z - z1.toFloat()
|
||||
|
||||
return 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, 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, y3, z0), valCoord3D(seed, x1, y3, z0), valCoord3D(seed, x2, y3, z0), valCoord3D(seed, x3, y3, z0), xs),
|
||||
ys),
|
||||
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, 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, y3, z1), valCoord3D(seed, x1, y3, z1), valCoord3D(seed, x2, y3, z1), valCoord3D(seed, x3, y3, z1), xs),
|
||||
ys),
|
||||
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, 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, y3, z2), valCoord3D(seed, x1, y3, z2), valCoord3D(seed, x2, y3, z2), valCoord3D(seed, x3, y3, z2), xs),
|
||||
ys),
|
||||
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, 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, y3, z3), valCoord3D(seed, x1, y3, z3), valCoord3D(seed, x2, y3, z3), valCoord3D(seed, x3, y3, z3), xs),
|
||||
ys),
|
||||
zs) * CUBIC_3D_BOUNDING
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
|
||||
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 {
|
||||
val x1 = x.fastFloor()
|
||||
val y1 = y.fastFloor()
|
||||
val z1 = z.fastFloor()
|
||||
|
||||
val x0 = x1 - 1
|
||||
val y0 = y1 - 1
|
||||
val z0 = z1 - 1
|
||||
val x2 = x1 + 1
|
||||
val y2 = y1 + 1
|
||||
val z2 = z1 + 1
|
||||
val x3 = x1 + 2
|
||||
val y3 = y1 + 2
|
||||
val z3 = z1 + 2
|
||||
|
||||
val xs = x - x1.toFloat()
|
||||
val ys = y - y1.toFloat()
|
||||
val zs = z - z1.toFloat()
|
||||
|
||||
return 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, 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, y3, z0), valCoord3D(seed, x1, y3, z0), valCoord3D(seed, x2, y3, z0), valCoord3D(seed, x3, y3, z0), xs),
|
||||
ys),
|
||||
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, 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, y3, z1), valCoord3D(seed, x1, y3, z1), valCoord3D(seed, x2, y3, z1), valCoord3D(seed, x3, y3, z1), xs),
|
||||
ys),
|
||||
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, 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, y3, z2), valCoord3D(seed, x1, y3, z2), valCoord3D(seed, x2, y3, z2), valCoord3D(seed, x3, y3, z2), xs),
|
||||
ys),
|
||||
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, 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, y3, z3), valCoord3D(seed, x1, y3, z3), valCoord3D(seed, x2, y3, z3), valCoord3D(seed, x3, y3, z3), xs),
|
||||
ys),
|
||||
zs) * CUBIC_3D_BOUNDING
|
||||
}
|
||||
@@ -1,105 +1,105 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
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 {
|
||||
var sum = noise(seed, x, y, z)
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
var z = z
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
z *= lacunarity
|
||||
amp *= gain
|
||||
sum += noise(seed + i, x, y, z) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
var sum = noise(seed, x, y)
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
amp *= gain
|
||||
sum += noise(seed + i, x, y) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
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 {
|
||||
var sum = Math.abs(noise(seed, x, y, z) * 2.0 - 1.0)
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
var z = z
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
z *= lacunarity
|
||||
amp *= gain
|
||||
sum += Math.abs(noise(seed + i, x, y, z) * 2.0 - 1.0) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
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 {
|
||||
var sum = Math.abs(noise(seed, x, y) * 2.0 - 1.0)
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
amp *= gain
|
||||
sum += Math.abs(noise(seed + i, x, y) * 2.0 - 1.0) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
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 {
|
||||
var sum = 1.0 - Math.abs(noise(seed, x, y))
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
amp *= gain
|
||||
sum -= (1.0 - Math.abs(noise(seed + i, x, y))) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
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 {
|
||||
var sum = 1.0 - Math.abs(noise(seed, x, y, z))
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
var z = z
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
z *= lacunarity
|
||||
amp *= gain
|
||||
sum -= (1.0 - Math.abs(noise(seed + i, x, y, z))) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
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 {
|
||||
var sum = noise(seed, x, y, z)
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
var z = z
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
z *= lacunarity
|
||||
amp *= gain
|
||||
sum += noise(seed + i, x, y, z) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
var sum = noise(seed, x, y)
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
amp *= gain
|
||||
sum += noise(seed + i, x, y) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
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 {
|
||||
var sum = Math.abs(noise(seed, x, y, z) * 2.0 - 1.0)
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
var z = z
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
z *= lacunarity
|
||||
amp *= gain
|
||||
sum += Math.abs(noise(seed + i, x, y, z) * 2.0 - 1.0) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
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 {
|
||||
var sum = Math.abs(noise(seed, x, y) * 2.0 - 1.0)
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
amp *= gain
|
||||
sum += Math.abs(noise(seed + i, x, y) * 2.0 - 1.0) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
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 {
|
||||
var sum = 1.0 - Math.abs(noise(seed, x, y))
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
amp *= gain
|
||||
sum -= (1.0 - Math.abs(noise(seed + i, x, y))) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
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 {
|
||||
var sum = 1.0 - Math.abs(noise(seed, x, y, z))
|
||||
var amp = 1.0
|
||||
|
||||
var x = x
|
||||
var y = y
|
||||
var z = z
|
||||
for (i in 1 until octaves) {
|
||||
x *= lacunarity
|
||||
y *= lacunarity
|
||||
z *= lacunarity
|
||||
amp *= gain
|
||||
sum -= (1.0 - Math.abs(noise(seed + i, x, y, z))) * amp
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,24 +1,24 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
|
||||
|
||||
fun hermite(t: Double): Double {
|
||||
return t * t * (3 - 2 * t)
|
||||
}
|
||||
|
||||
fun quintic(t: Double): Double {
|
||||
return t * t * t * (t * (t * 6 - 15) + 10)
|
||||
}
|
||||
|
||||
fun cubic(a: Double, b: Double, c: Double, d: Double, t: Double) : Double {
|
||||
val p = d - c - (a - b)
|
||||
return t * t * t * p + t * t * (a - b - p) + t * (c - a) + b
|
||||
}
|
||||
|
||||
fun linear(x: Double) : Double {
|
||||
return x
|
||||
}
|
||||
|
||||
fun lerp(left: Double, right: Double, x: Double): Double {
|
||||
return left * (1.0 - x) + right * x
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
|
||||
|
||||
fun hermite(t: Double): Double {
|
||||
return t * t * (3 - 2 * t)
|
||||
}
|
||||
|
||||
fun quintic(t: Double): Double {
|
||||
return t * t * t * (t * (t * 6 - 15) + 10)
|
||||
}
|
||||
|
||||
fun cubic(a: Double, b: Double, c: Double, d: Double, t: Double) : Double {
|
||||
val p = d - c - (a - b)
|
||||
return t * t * t * p + t * t * (a - b - p) + t * (c - a) + b
|
||||
}
|
||||
|
||||
fun linear(x: Double) : Double {
|
||||
return x
|
||||
}
|
||||
|
||||
fun lerp(left: Double, right: Double, x: Double): Double {
|
||||
return left * (1.0 - x) + right * x
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
|
||||
fun Double.fastFloor(): Int {
|
||||
return if (this >= 0) this.toInt() else this.toInt() - 1
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
|
||||
fun Double.fastFloor(): Int {
|
||||
return if (this >= 0) this.toInt() else this.toInt() - 1
|
||||
}
|
||||
@@ -1,26 +1,26 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
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 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 {
|
||||
val x0 = x.fastFloor()
|
||||
val y0 = y.fastFloor()
|
||||
val x1 = x0 + 1
|
||||
val y1 = y0 + 1
|
||||
|
||||
val xs = interpolator(x - x0)
|
||||
val ys = interpolator(y - y0)
|
||||
|
||||
|
||||
val xd0 = x - x0
|
||||
val yd0 = y - y0
|
||||
val xd1 = xd0 - 1
|
||||
val yd1 = yd0 - 1
|
||||
|
||||
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)
|
||||
|
||||
return lerp(xf0, xf1, ys)
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
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 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 {
|
||||
val x0 = x.fastFloor()
|
||||
val y0 = y.fastFloor()
|
||||
val x1 = x0 + 1
|
||||
val y1 = y0 + 1
|
||||
|
||||
val xs = interpolator(x - x0)
|
||||
val ys = interpolator(y - y0)
|
||||
|
||||
|
||||
val xd0 = x - x0
|
||||
val yd0 = y - y0
|
||||
val xd1 = xd0 - 1
|
||||
val yd1 = yd0 - 1
|
||||
|
||||
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)
|
||||
|
||||
return lerp(xf0, xf1, ys)
|
||||
}
|
||||
@@ -1,35 +1,35 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
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 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 {
|
||||
val x0 = x.fastFloor()
|
||||
val y0 = y.fastFloor()
|
||||
val z0 = z.fastFloor()
|
||||
val x1 = x0 + 1
|
||||
val y1 = y0 + 1
|
||||
val z1 = z0 + 1
|
||||
|
||||
val xs: Double = interpolator(x - x0)
|
||||
val ys: Double = interpolator(y - y0)
|
||||
val zs: Double = interpolator(z - z0)
|
||||
|
||||
val xd0 = x - x0
|
||||
val yd0 = y - y0
|
||||
val zd0 = z - z0
|
||||
val xd1 = xd0 - 1
|
||||
val yd1 = yd0 - 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 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 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 yf1 = lerp(xf01, xf11, ys)
|
||||
|
||||
return lerp(yf0, yf1, zs)
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
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 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 {
|
||||
val x0 = x.fastFloor()
|
||||
val y0 = y.fastFloor()
|
||||
val z0 = z.fastFloor()
|
||||
val x1 = x0 + 1
|
||||
val y1 = y0 + 1
|
||||
val z1 = z0 + 1
|
||||
|
||||
val xs: Double = interpolator(x - x0)
|
||||
val ys: Double = interpolator(y - y0)
|
||||
val zs: Double = interpolator(z - z0)
|
||||
|
||||
val xd0 = x - x0
|
||||
val yd0 = y - y0
|
||||
val zd0 = z - z0
|
||||
val xd1 = xd0 - 1
|
||||
val yd1 = yd0 - 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 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 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 yf1 = lerp(xf01, xf11, ys)
|
||||
|
||||
return lerp(yf0, yf1, zs)
|
||||
}
|
||||
@@ -1,63 +1,63 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
|
||||
private val G2 = 1.0 / 4.0
|
||||
private val F2 = 1.0 / 2.0
|
||||
|
||||
fun simplex(seed: Int, x: Double, y: Double): Double {
|
||||
var t = (x + y) * F2
|
||||
val i = (x + t).fastFloor()
|
||||
val j = (y + t).fastFloor()
|
||||
|
||||
t = ((i + j) * G2)
|
||||
val X0 = i - t
|
||||
val Y0 = j - t
|
||||
|
||||
val x0 = x - X0
|
||||
val y0 = y - Y0
|
||||
|
||||
val i1: Int
|
||||
val j1: Int
|
||||
if (x0 > y0) {
|
||||
i1 = 1
|
||||
j1 = 0
|
||||
} else {
|
||||
i1 = 0
|
||||
j1 = 1
|
||||
}
|
||||
|
||||
val x1 = x0 - i1 + G2
|
||||
val y1 = y0 - j1 + G2
|
||||
val x2 = x0 - 1 + F2
|
||||
val y2 = y0 - 1 + F2
|
||||
|
||||
val n0: Double
|
||||
val n1: Double
|
||||
val n2: Double
|
||||
|
||||
t = 0.5 - x0 * x0 - y0 * y0
|
||||
if (t < 0)
|
||||
n0 = 0.0
|
||||
else {
|
||||
t *= t
|
||||
n0 = t * t * gradCoord2D(seed, i, j, x0, y0)
|
||||
}
|
||||
|
||||
t = 0.5 - x1 * x1 - y1 * y1
|
||||
if (t < 0)
|
||||
n1 = 0.0
|
||||
else {
|
||||
t *= t
|
||||
n1 = t * t * gradCoord2D(seed, i + i1, j + j1, x1, y1)
|
||||
}
|
||||
|
||||
t = 0.5 - x2 * x2 - y2 * y2
|
||||
if (t < 0)
|
||||
n2 = 0.0
|
||||
else {
|
||||
t *= t
|
||||
n2 = t * t * gradCoord2D(seed, i + 1, j + 1, x2, y2)
|
||||
}
|
||||
|
||||
return 50.0 * (n0 + n1 + n2)
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
|
||||
private val G2 = 1.0 / 4.0
|
||||
private val F2 = 1.0 / 2.0
|
||||
|
||||
fun simplex(seed: Int, x: Double, y: Double): Double {
|
||||
var t = (x + y) * F2
|
||||
val i = (x + t).fastFloor()
|
||||
val j = (y + t).fastFloor()
|
||||
|
||||
t = ((i + j) * G2)
|
||||
val X0 = i - t
|
||||
val Y0 = j - t
|
||||
|
||||
val x0 = x - X0
|
||||
val y0 = y - Y0
|
||||
|
||||
val i1: Int
|
||||
val j1: Int
|
||||
if (x0 > y0) {
|
||||
i1 = 1
|
||||
j1 = 0
|
||||
} else {
|
||||
i1 = 0
|
||||
j1 = 1
|
||||
}
|
||||
|
||||
val x1 = x0 - i1 + G2
|
||||
val y1 = y0 - j1 + G2
|
||||
val x2 = x0 - 1 + F2
|
||||
val y2 = y0 - 1 + F2
|
||||
|
||||
val n0: Double
|
||||
val n1: Double
|
||||
val n2: Double
|
||||
|
||||
t = 0.5 - x0 * x0 - y0 * y0
|
||||
if (t < 0)
|
||||
n0 = 0.0
|
||||
else {
|
||||
t *= t
|
||||
n0 = t * t * gradCoord2D(seed, i, j, x0, y0)
|
||||
}
|
||||
|
||||
t = 0.5 - x1 * x1 - y1 * y1
|
||||
if (t < 0)
|
||||
n1 = 0.0
|
||||
else {
|
||||
t *= t
|
||||
n1 = t * t * gradCoord2D(seed, i + i1, j + j1, x1, y1)
|
||||
}
|
||||
|
||||
t = 0.5 - x2 * x2 - y2 * y2
|
||||
if (t < 0)
|
||||
n2 = 0.0
|
||||
else {
|
||||
t *= t
|
||||
n2 = t * t * gradCoord2D(seed, i + 1, j + 1, x2, y2)
|
||||
}
|
||||
|
||||
return 50.0 * (n0 + n1 + n2)
|
||||
}
|
||||
@@ -1,94 +1,94 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
fun simplex(seed: Int, x: Double, y: Double, z: Double): Double {
|
||||
|
||||
var t = (x + y + z) / 3.0
|
||||
val i = (x + t).fastFloor()
|
||||
val j = (y + t).fastFloor()
|
||||
val k = (z + t).fastFloor()
|
||||
|
||||
val t2 = (i + j + k) / 6.0
|
||||
val x0 = x - (i - t2)
|
||||
val y0 = y - (j - t2)
|
||||
val z0 = z - (k - t2)
|
||||
|
||||
val i1: Int
|
||||
val j1: Int
|
||||
val k1: Int
|
||||
|
||||
val i2: Int
|
||||
val j2: Int
|
||||
val k2: Int
|
||||
|
||||
if (x0 >= y0) {
|
||||
when {
|
||||
y0 >= z0 -> {
|
||||
i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; }
|
||||
x0 >= z0 -> {
|
||||
i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; }
|
||||
else -> {
|
||||
i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; }
|
||||
}
|
||||
} else {
|
||||
when {
|
||||
y0 < z0 -> {
|
||||
i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; }
|
||||
x0 < z0 -> {
|
||||
i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; }
|
||||
else -> {
|
||||
i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; }
|
||||
}
|
||||
}
|
||||
val x1 = x0 - i1 + 1.0 / 6.0
|
||||
val y1 = y0 - j1 + 1.0 / 6.0
|
||||
val z1 = z0 - k1 + 1.0 / 6.0
|
||||
val x2 = x0 - i2 + 1.0 / 3.0
|
||||
val y2 = y0 - j2 + 1.0 / 3.0
|
||||
val z2 = z0 - k2 + 1.0 / 3.0
|
||||
val x3 = x0 + ((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 n0: Double
|
||||
run {
|
||||
var t = 0.6 * x0 * x0 - y0 * y0 - z0 * z0
|
||||
if (t < 0) {
|
||||
n0 = 0.0
|
||||
} else {
|
||||
t *= t
|
||||
n0 = t * t * gradCoord3D(seed, i, j, k, x0, y0, z0)
|
||||
}
|
||||
}
|
||||
val n1: Double
|
||||
run {
|
||||
var t = 0.6 * x1 * x1 - y1 * y1 - z1 * z1
|
||||
if (t < 0) {
|
||||
n1 = 0.0
|
||||
} else {
|
||||
t *= t
|
||||
n1 = t * t * gradCoord3D(seed, i + i1, j + j1, k + k1, x1, y1, z1)
|
||||
}
|
||||
}
|
||||
val n2: Double
|
||||
run {
|
||||
var t = 0.6 * x2 * x2 - y2 * y2 - z2 * z2
|
||||
if (t < 0) {
|
||||
n2 = 0.0
|
||||
} else {
|
||||
t *= t
|
||||
n2 = t * t * gradCoord3D(seed, i + i2, j + j2, k + k2, x2, y2, z2)
|
||||
}
|
||||
}
|
||||
|
||||
val n3: Double
|
||||
run {
|
||||
var t = 0.6 - x3 * x3 - y3 * y3 - z3 * z3
|
||||
if (t < 0)
|
||||
n3 = 0.0
|
||||
else {
|
||||
t *= t
|
||||
n3 = t * t * gradCoord3D(seed, i + 1, j + 1, k + 1, x3, y3, z3)
|
||||
}
|
||||
}
|
||||
return 32 * (n0 + n1 + n2 + n3)
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
fun simplex(seed: Int, x: Double, y: Double, z: Double): Double {
|
||||
|
||||
var t = (x + y + z) / 3.0
|
||||
val i = (x + t).fastFloor()
|
||||
val j = (y + t).fastFloor()
|
||||
val k = (z + t).fastFloor()
|
||||
|
||||
val t2 = (i + j + k) / 6.0
|
||||
val x0 = x - (i - t2)
|
||||
val y0 = y - (j - t2)
|
||||
val z0 = z - (k - t2)
|
||||
|
||||
val i1: Int
|
||||
val j1: Int
|
||||
val k1: Int
|
||||
|
||||
val i2: Int
|
||||
val j2: Int
|
||||
val k2: Int
|
||||
|
||||
if (x0 >= y0) {
|
||||
when {
|
||||
y0 >= z0 -> {
|
||||
i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; }
|
||||
x0 >= z0 -> {
|
||||
i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; }
|
||||
else -> {
|
||||
i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; }
|
||||
}
|
||||
} else {
|
||||
when {
|
||||
y0 < z0 -> {
|
||||
i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; }
|
||||
x0 < z0 -> {
|
||||
i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; }
|
||||
else -> {
|
||||
i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; }
|
||||
}
|
||||
}
|
||||
val x1 = x0 - i1 + 1.0 / 6.0
|
||||
val y1 = y0 - j1 + 1.0 / 6.0
|
||||
val z1 = z0 - k1 + 1.0 / 6.0
|
||||
val x2 = x0 - i2 + 1.0 / 3.0
|
||||
val y2 = y0 - j2 + 1.0 / 3.0
|
||||
val z2 = z0 - k2 + 1.0 / 3.0
|
||||
val x3 = x0 + ((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 n0: Double
|
||||
run {
|
||||
var t = 0.6 * x0 * x0 - y0 * y0 - z0 * z0
|
||||
if (t < 0) {
|
||||
n0 = 0.0
|
||||
} else {
|
||||
t *= t
|
||||
n0 = t * t * gradCoord3D(seed, i, j, k, x0, y0, z0)
|
||||
}
|
||||
}
|
||||
val n1: Double
|
||||
run {
|
||||
var t = 0.6 * x1 * x1 - y1 * y1 - z1 * z1
|
||||
if (t < 0) {
|
||||
n1 = 0.0
|
||||
} else {
|
||||
t *= t
|
||||
n1 = t * t * gradCoord3D(seed, i + i1, j + j1, k + k1, x1, y1, z1)
|
||||
}
|
||||
}
|
||||
val n2: Double
|
||||
run {
|
||||
var t = 0.6 * x2 * x2 - y2 * y2 - z2 * z2
|
||||
if (t < 0) {
|
||||
n2 = 0.0
|
||||
} else {
|
||||
t *= t
|
||||
n2 = t * t * gradCoord3D(seed, i + i2, j + j2, k + k2, x2, y2, z2)
|
||||
}
|
||||
}
|
||||
|
||||
val n3: Double
|
||||
run {
|
||||
var t = 0.6 - x3 * x3 - y3 * y3 - z3 * z3
|
||||
if (t < 0)
|
||||
n3 = 0.0
|
||||
else {
|
||||
t *= t
|
||||
n3 = t * t * gradCoord3D(seed, i + 1, j + 1, k + 1, x3, y3, z3)
|
||||
}
|
||||
}
|
||||
return 32 * (n0 + n1 + n2 + n3)
|
||||
}
|
||||
@@ -1,71 +1,71 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.Vector4
|
||||
|
||||
|
||||
fun Double.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Double {
|
||||
return (Math.random() * (max - min)) + min
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
fun Vector2.Companion.uniform(min: Double = -1.0, max: Double = 1.0) =
|
||||
Vector2.uniform(Vector2(min, min), Vector2(max, max))
|
||||
|
||||
fun Vector2.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector2 {
|
||||
while (true) {
|
||||
uniform(-outerRadius, outerRadius).let {
|
||||
val squaredLength = it.squaredLength
|
||||
if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) {
|
||||
return it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Vector3.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Vector3 =
|
||||
Vector3.uniform(Vector3(min, min, min), Vector3(max, max, max))
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
// squared length 'polyfill' for OPENRNDR 0.3.30
|
||||
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 {
|
||||
while (true) {
|
||||
uniform(-outerRadius, outerRadius).let {
|
||||
val squaredLength = it.squaredLength__
|
||||
if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) {
|
||||
return it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// squared length 'polyfill' for OPENRNDR 0.3.30
|
||||
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 =
|
||||
Vector4.uniform(Vector4(min, min, min, min), Vector4(max, max,max, max))
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
fun Vector4.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector4 {
|
||||
while (true) {
|
||||
uniform(-outerRadius, outerRadius).let {
|
||||
val squaredLength = it.squaredLength__
|
||||
if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) {
|
||||
return it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.Vector4
|
||||
|
||||
|
||||
fun Double.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Double {
|
||||
return (Math.random() * (max - min)) + min
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
fun Vector2.Companion.uniform(min: Double = -1.0, max: Double = 1.0) =
|
||||
Vector2.uniform(Vector2(min, min), Vector2(max, max))
|
||||
|
||||
fun Vector2.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector2 {
|
||||
while (true) {
|
||||
uniform(-outerRadius, outerRadius).let {
|
||||
val squaredLength = it.squaredLength
|
||||
if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) {
|
||||
return it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Vector3.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Vector3 =
|
||||
Vector3.uniform(Vector3(min, min, min), Vector3(max, max, max))
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
// squared length 'polyfill' for OPENRNDR 0.3.30
|
||||
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 {
|
||||
while (true) {
|
||||
uniform(-outerRadius, outerRadius).let {
|
||||
val squaredLength = it.squaredLength__
|
||||
if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) {
|
||||
return it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// squared length 'polyfill' for OPENRNDR 0.3.30
|
||||
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 =
|
||||
Vector4.uniform(Vector4(min, min, min, min), Vector4(max, max,max, max))
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
fun Vector4.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector4 {
|
||||
while (true) {
|
||||
uniform(-outerRadius, outerRadius).let {
|
||||
val squaredLength = it.squaredLength__
|
||||
if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) {
|
||||
return it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
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 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 {
|
||||
val x0 = x.fastFloor()
|
||||
val y0 = y.fastFloor()
|
||||
val x1 = x0 + 1
|
||||
val y1 = y0 + 1
|
||||
|
||||
val xs = interpolation(x - x0)
|
||||
val ys = interpolation(y - y0)
|
||||
|
||||
val xf0 = lerp(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), xs)
|
||||
val xf1 = lerp(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), xs)
|
||||
|
||||
return lerp(xf0, xf1, ys)
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
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 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 {
|
||||
val x0 = x.fastFloor()
|
||||
val y0 = y.fastFloor()
|
||||
val x1 = x0 + 1
|
||||
val y1 = y0 + 1
|
||||
|
||||
val xs = interpolation(x - x0)
|
||||
val ys = interpolation(y - y0)
|
||||
|
||||
val xf0 = lerp(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), xs)
|
||||
val xf1 = lerp(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), xs)
|
||||
|
||||
return lerp(xf0, xf1, ys)
|
||||
}
|
||||
@@ -1,29 +1,29 @@
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
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 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 {
|
||||
val x0 = x.fastFloor()
|
||||
val y0 = y.fastFloor()
|
||||
val z0 = z.fastFloor()
|
||||
val x1 = x0 + 1
|
||||
val y1 = y0 + 1
|
||||
val z1 = z0 + 1
|
||||
|
||||
val xs = interpolation(x - x0)
|
||||
val ys = interpolation(y - y0)
|
||||
val zs = interpolation(z - z0)
|
||||
|
||||
|
||||
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 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 yf0 = lerp(xf00, xf10, ys)
|
||||
val yf1 = lerp(xf01, xf11, ys)
|
||||
|
||||
return lerp(yf0, yf1, zs)
|
||||
package org.openrndr.extra.noise
|
||||
|
||||
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 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 {
|
||||
val x0 = x.fastFloor()
|
||||
val y0 = y.fastFloor()
|
||||
val z0 = z.fastFloor()
|
||||
val x1 = x0 + 1
|
||||
val y1 = y0 + 1
|
||||
val z1 = z0 + 1
|
||||
|
||||
val xs = interpolation(x - x0)
|
||||
val ys = interpolation(y - y0)
|
||||
val zs = interpolation(z - z0)
|
||||
|
||||
|
||||
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 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 yf0 = lerp(xf00, xf10, ys)
|
||||
val yf1 = lerp(xf01, xf11, ys)
|
||||
|
||||
return lerp(yf0, yf1, zs)
|
||||
}
|
||||
Reference in New Issue
Block a user