Skip to content

Instantly share code, notes, and snippets.

@ylegall
Last active August 12, 2020 04:55
Show Gist options
  • Save ylegall/f9573cf1bd1262532c6ce29fa7571545 to your computer and use it in GitHub Desktop.
Save ylegall/f9573cf1bd1262532c6ce29fa7571545 to your computer and use it in GitHub Desktop.
openRNDR blackhole sketch
package org.ygl.openrndr.demos
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.color.mix
import org.openrndr.draw.LineCap
import org.openrndr.draw.LineJoin
import org.openrndr.extra.compositor.compose
import org.openrndr.extra.compositor.draw
import org.openrndr.extra.compositor.post
import org.openrndr.extra.fx.blur.GaussianBloom
import org.openrndr.ffmpeg.ScreenRecorder
import org.openrndr.math.Polar
import org.openrndr.math.Vector2
import org.openrndr.math.transforms.transform
import org.openrndr.shape.LineSegment
import org.openrndr.shape.contour
import org.ygl.openrndr.demos.util.RadialChromaticAberration
import org.ygl.openrndr.utils.cubicPulse
import kotlin.random.Random
private const val WIDTH = 920
private const val HEIGHT = 920
private const val TOTAL_FRAMES = 480
private const val RECORDING = true
fun main() = application {
configure {
width = WIDTH
height = HEIGHT
}
program {
var time = 0.0
val innerRadius = 100.0
val numParticles = 8000
val perspectiveFactor = 0.4
val trailLength = 0.015
class Particle(
val radius: Double,
val offset: Double
) {
val distFactor = innerRadius / radius
val velFactor = (0.3 * (5 - (1 / distFactor)))
}
val particles = (0 until numParticles).map {
val radius = Random.nextDouble(innerRadius, width * 1.3)
val angleOffset = Random.nextDouble()
Particle(radius, angleOffset)
}
val segments = MutableList(numParticles) { LineSegment(Vector2.ZERO, Vector2.ZERO) }
val segmentColors = MutableList(numParticles) { 0.0 }
val halfArc = contour {
moveTo(-innerRadius, 0.0)
arcTo(1.0, 1.0, 180.0, true, true, innerRadius, 0.0)
close()
}.transform(transform {
translate(0.0, 10.0)
scale(0.95)
})
fun drawParticles() {
for (i in particles.indices) {
val particle = particles[i]
val t = (time + particle.offset) % 1.0
val t2 = (t - trailLength).coerceAtLeast(0.0)
val startAngle = 1080 * particle.offset
val angleRange = 360 * particle.distFactor
val angle = startAngle + angleRange * t * particle.velFactor
val angle2 = startAngle + angleRange * t2 * particle.velFactor
val start = Vector2.fromPolar(Polar(angle2, particle.radius)) * Vector2(1.0, perspectiveFactor)
val stop = Vector2.fromPolar(Polar(angle, particle.radius)) * Vector2(1.0, perspectiveFactor)
segments[i] = LineSegment(start, stop)
segmentColors[i] = cubicPulse(0.5, 0.5, t)
}
drawer.lineCap = LineCap.ROUND
drawer.lineJoin = LineJoin.ROUND
particles.indices.groupBy({ segmentColors[it] }, { segments[it] }).forEach { (color, segmentList) ->
drawer.stroke = mix(ColorRGBa.BLACK, ColorRGBa.WHITE, color)
drawer.strokeWeight = 2.5 * color
drawer.lineSegments(segmentList)
}
}
val composite = compose {
draw {
drawer.clear(ColorRGBa.BLACK)
drawParticles()
// draw the top arc
drawer.stroke = null
drawer.fill = ColorRGBa.BLACK
drawer.contour(halfArc)
}
post(RadialChromaticAberration()) {
aberrationFactor = 0.005
}
post(GaussianBloom()) {
sigma = 0.5
gain = 0.5
}
}
if (RECORDING) {
extend(ScreenRecorder()) {
outputFile = "video/Orbit.mp4"
frameRate = 60
frameClock = true
}
}
extend {
time = ((frameCount - 1) % TOTAL_FRAMES) / TOTAL_FRAMES.toDouble()
drawer.translate(drawer.bounds.center)
composite.draw(drawer)
if (RECORDING) {
if (frameCount >= TOTAL_FRAMES) {
application.exit()
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment