Skip to content

Instantly share code, notes, and snippets.

@ylegall
Created September 21, 2020 20:17
Show Gist options
  • Save ylegall/dc8d058ce4f52df3c5e5f7318c765804 to your computer and use it in GitHub Desktop.
Save ylegall/dc8d058ce4f52df3c5e5f7318c765804 to your computer and use it in GitHub Desktop.
Infinite Canyon. code for https://www.instagram.com/p/CFYRdIynt5l/
package org.ygl.openrndr.demos
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.color.mix
import org.openrndr.color.rgb
import org.openrndr.draw.LineCap
import org.openrndr.draw.LineJoin
import org.openrndr.draw.colorBuffer
import org.openrndr.draw.renderTarget
import org.openrndr.extra.compositor.compose
import org.openrndr.extra.compositor.draw
import org.openrndr.extra.compositor.layer
import org.openrndr.extra.compositor.post
import org.openrndr.extra.fx.blur.FrameBlur
import org.openrndr.extra.fx.blur.GaussianBlur
import org.openrndr.extra.fx.blur.HashBlur
import org.openrndr.extra.fx.color.ChromaticAberration
import org.openrndr.ffmpeg.ScreenRecorder
import org.openrndr.ffmpeg.VideoWriter
import org.openrndr.math.Vector2
import org.openrndr.math.mix
import org.openrndr.math.smoothstep
import org.openrndr.shape.ShapeContour
import org.openrndr.shape.compound
import org.ygl.fastnoise.FastNoise
import org.ygl.kxa.ease.Ease
import org.ygl.openrndr.demos.util.GlamourBlur
import org.ygl.openrndr.utils.cubicPulse
import org.ygl.openrndr.utils.isolatedWithTarget
import org.ygl.openrndr.utils.smoothCurve
import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.sin
private const val WIDTH = 920
private const val HEIGHT = 920
private const val TOTAL_FRAMES = 480 * 4
private const val DELAY_FRAMES = 60
private const val LOOPS = 1
private const val RECORDING = false
fun main() = application {
configure {
width = WIDTH
height = HEIGHT
}
program {
var time = 0.0
val noise = FastNoise()
val noiseScale = 0.5
val noiseRadius = 100.0
val numLines = 180
val pointsPerLine = 400
val contours = MutableList(numLines) { ShapeContour.EMPTY }
fun getNoise(angle: Double, seed: Int): Double {
noise.seed = seed
return noise.getSimplex(noiseRadius * cos(angle), noiseRadius * sin(angle))
}
val lines = List(numLines - 1) { i ->
val pct = i / (numLines - 1.0)
val noiseAngle = 2 * PI * pct
val centerNoise = getNoise(noiseAngle, seed = 6)
val centerX = (centerNoise * 0.45 + 0.5) * width
val widthNoise = getNoise(noiseAngle, seed = 2)
val centerWidth = 170 + 20 * widthNoise
(0 until pointsPerLine).map { j ->
val lineProgress = j / (pointsPerLine - 1.0)
val x = lineProgress * width
val noiseMagFactor = cubicPulse(centerX, centerWidth * 1.7, x)
val noiseY = 200 * noiseMagFactor * noise.getSimplex(
noiseScale * x,
noiseScale * pct * height * 4,
)
val depth = 650 * cubicPulse(centerX, centerWidth, x)
val y = mix(depth + noiseY, 0.0, abs(lineProgress - 0.5) * 2)
Vector2(x, y)
}
}.let {
listOf(it.last()) + it // fix the "z fighting" between first and last layer
}
fun update() {
for (i in 0 until numLines) {
val pct = i / (numLines - 1.0)
val timeOffset = (pct + time) % 1.0
val dist = Ease.CUBE_IN(timeOffset)
val baseY = -50.0 + (height + 50 + 30) * dist
val scaledPoints = lines[i].map {
val x = (it.x - width/2.0) * (dist + 0.2) + width/2.0
Vector2(x, baseY + it.y * (dist + 0.2))
}
val extendedPoints = listOf(
Vector2(-10.0, height + 10.0), Vector2(-10.0, baseY)) +
scaledPoints +
listOf(Vector2(width + 10.0, baseY), Vector2(width + 10.0, height + 10.0)
)
contours[i] = ShapeContour.fromPoints(extendedPoints, true)
}
}
val frame = compound {
difference {
shape(drawer.bounds.offsetEdges(10.0).shape)
shape(drawer.bounds.offsetEdges(-20.0).shape)
}
}
val composite = compose {
layer {
draw {
drawer.clear(ColorRGBa.WHITE)
drawer.lineJoin = LineJoin.ROUND
drawer.lineCap = LineCap.ROUND
drawer.fill = ColorRGBa.BLACK
drawer.stroke = ColorRGBa.WHITE
drawer.strokeWeight = 4.0
drawer.contours(contours.sortedBy { it.segments[1].start.y })
//val sorted = contours.sortedBy { it.segments[1].start.y }
//for (i in 0 until sorted.size) {
// drawer.strokeWeight = 0.5 + 3.5 * i / (sorted.size - 1.0)
// drawer.contour(sorted[i])
//}
}
post(GlamourBlur()) {}
post(FrameBlur())
}
layer {
draw {
// draw frame
drawer.fill = ColorRGBa.BLACK
drawer.stroke = ColorRGBa.WHITE
drawer.strokeWeight = 2.0
drawer.shapes(frame)
}
}
}
val videoTarget = renderTarget(width, height) { colorBuffer() }
val videoWriter = VideoWriter.create()
.size(width, height)
.frameRate(60)
.output("video/Canyon-2.mp4")
if (RECORDING) videoWriter.start()
extend {
time = ((frameCount - 1) % TOTAL_FRAMES) / TOTAL_FRAMES.toDouble()
update()
if (RECORDING) {
drawer.isolatedWithTarget(videoTarget) {
composite.draw(drawer)
}
drawer.image(videoTarget.colorBuffer(0))
if (frameCount > DELAY_FRAMES) {
videoWriter.frame(videoTarget.colorBuffer(0))
}
if (frameCount >= DELAY_FRAMES + LOOPS * TOTAL_FRAMES) {
videoWriter.stop()
application.exit()
}
} else {
composite.draw(drawer)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment