Skip to content

Instantly share code, notes, and snippets.

@ylegall
Created October 3, 2020 02:01
Show Gist options
  • Save ylegall/ef626717bc83631eeae77bdc5e74d341 to your computer and use it in GitHub Desktop.
Save ylegall/ef626717bc83631eeae77bdc5e74d341 to your computer and use it in GitHub Desktop.
package org.ygl.openrndr.demos
import org.openrndr.Application
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.draw.renderTarget
import org.openrndr.draw.shadeStyle
import org.openrndr.extra.compositor.blend
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.blend.Screen
import org.openrndr.extra.fx.blur.GaussianBloom
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.extra.shapes.regularPolygon
import org.openrndr.ffmpeg.VideoWriter
import org.openrndr.math.transforms.transform
import org.ygl.kxa.ease.Ease
import org.ygl.openrndr.utils.ColorMap
import org.ygl.openrndr.utils.isolatedWithTarget
import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.sin
import kotlin.random.Random
private const val WIDTH = 920
private const val HEIGHT = 920
private const val TOTAL_FRAMES = 360 * 4
private const val DELAY_FRAMES = 360 * 2
private const val RECORDING = true
fun main() = application {
configure {
width = WIDTH
height = HEIGHT
}
program {
var time = 0.0
val colors = ColorMap(listOf(
//"fee7a7","fc7757","fe3c63","c11cad","9447ff","3bb0ff"
"ff9e78","f2355b","640ff7","1d92ff","17f2ce"
))
var amplitude = 0.0
var strokeSize = 0.0
val noiseShaderFunction = Application::class.java.getResource("/shaders/simplexNoise4D.glsl").readText()
val image1 = renderTarget(width, height) { colorBuffer(); depthBuffer() }
val image2 = renderTarget(width, height) { colorBuffer(); depthBuffer() }
var curr = image1
var prev = image2
fun swapBuffer() {
val tmp = prev
curr = prev
prev = tmp
}
val numPoints = 180
val colorValues = List(numPoints) { Random.nextDouble() }
val offsets = List(numPoints) { Random.nextDouble() }
var edgeColor = ColorRGBa.WHITE
val outerShape = regularPolygon(3, drawer.bounds.center, radius = 400.0, phase = 90.0)
val innerShape = regularPolygon(3, drawer.bounds.center, radius = 150.0, phase = 90.0)
val params = @Description("params") object {
@DoubleParameter("scale", 0.0, 20.0, precision = 2)
var scale = 5.0
@DoubleParameter("radius", 1.0, 100.0, precision = 1)
var radius = 2.0
@DoubleParameter("rotationMag", 0.0, 2.0, precision = 2)
var rotation = 1.0
@DoubleParameter("offset mag", 0.0, 0.1, precision = 4)
var offsetMag = 0.0015
}
fun updateParams() {
val phase = sin(2 * PI * time)
edgeColor = colors[0.5 + 0.5 * phase]
amplitude = Ease.CUBE_IN(1 - abs(cos(16 * PI * time)))
strokeSize = 4.0 + 2 * amplitude
params.scale = 9.0 + 5 * phase
params.rotation = 0.5 + 0.5 * phase
//params.offsetMag = 0.0012 + 0.0004 * cos(2 * PI * time)
params.offsetMag = 0.0012 + 0.0004 * amplitude
}
val composite = compose {
layer {
draw {
drawer.isolatedWithTarget(curr) {
shadeStyle = shadeStyle {
fragmentPreamble = noiseShaderFunction + """
vec2 rotate(vec2 v, float a) {
float s = sin(a);
float c = cos(a);
mat2 m = mat2(c, -s, s, c);
return m * v;
}
""".trimIndent()
fragmentTransform = """
const float PI = 3.14159265359;
vec2 pos = vec2(c_boundsPosition.x, 1 - c_boundsPosition.y);
float angle = 2 * PI * p_time;
vec4 noiseParams = vec4(
p_scale * pos.x,
p_scale * pos.y,
p_radius * cos(angle),
p_radius * sin(angle)
);
float noiseAngle = p_rotationMag * PI * snoise(noiseParams);
vec2 delta = p_offsetMag * normalize(vec2(0.5, 0.5) - pos);
vec2 offset = rotate(delta, noiseAngle);
vec4 color = texture(p_image, pos + offset);
color *= vec4(0.999, 0.999, 0.999, 1.0);
x_fill = color;
""".trimIndent()
parameter("rotationMag", params.rotation)
parameter("scale", params.scale)
parameter("radius", params.radius)
parameter("offsetMag", params.offsetMag)
parameter("time", time)
parameter("image", prev.colorBuffer(0))
}
rectangle(bounds)
}
// render image
drawer.lineCap = LineCap.ROUND
drawer.isolatedWithTarget(curr) {
for (i in 0 until numPoints) {
val pct = i / (numPoints - 0.0)
val positionOffset = (pct + time) % 1.0
val p1 = positionOffset
val p2 = 1 - positionOffset
val timeOffset = (offsets[i] + time) % 1.0
//val pos1 = innerShape.position(1 - positionOffset)
//val pos2 = outerShape.position(positionOffset)
var color = mix(edgeColor, colors[colorValues[i]], 0.7)
color = mix(ColorRGBa.BLACK, color, 0.5 + 0.5 * sin(20 * PI * timeOffset))
drawer.fill = null
drawer.stroke = color
drawer.strokeWeight = 3.0
drawer.contour(innerShape.sub(p1, p1 + 1.0/numPoints))
drawer.contour(outerShape.sub(p2, p2 - 1.0/numPoints))
}
}
drawer.image(curr.colorBuffer(0))
drawer.fill = ColorRGBa.BLACK
drawer.contour(innerShape)
}
}
layer {
draw {
drawer.clear(ColorRGBa.BLACK)
// draw contours
drawer.lineCap = LineCap.ROUND
drawer.lineJoin = LineJoin.ROUND
drawer.stroke = colors[0.5 + 0.5 * sin(2 * PI * time)]
drawer.strokeWeight = strokeSize
drawer.fill = null
drawer.contour(outerShape)
drawer.contour(innerShape)
}
post(GaussianBloom()) {
sigma = 0.1
shape = 4.0
}
blend(Screen())
}
layer {
draw {
// draw contours
drawer.lineCap = LineCap.ROUND
drawer.lineJoin = LineJoin.ROUND
drawer.stroke = edgeColor // colors[0.5 + 0.5 * sin(2 * PI * time)]
drawer.strokeWeight = strokeSize
drawer.fill = null
drawer.contour(outerShape)
drawer.contour(innerShape)
drawer.contour(innerShape.transform(transform {
translate(drawer.bounds.center)
scale(0.6 + 0.3 * amplitude)
translate(-drawer.bounds.center)
}))
}
}
}
val videoTarget = renderTarget(width, height) { colorBuffer() }
val videoWriter = VideoWriter.create()
.size(width, height)
.frameRate(60)
.output("video/Liquid-Iridescent.mp4")
if (RECORDING) {
videoWriter.start()
}
extend {
time = ((frameCount - 1) % TOTAL_FRAMES) / TOTAL_FRAMES.toDouble()
updateParams()
if (RECORDING) {
drawer.isolatedWithTarget(videoTarget) {
composite.draw(this)
}
drawer.image(videoTarget.colorBuffer(0))
if (frameCount > DELAY_FRAMES) {
videoWriter.frame(videoTarget.colorBuffer(0))
}
if (frameCount > TOTAL_FRAMES + DELAY_FRAMES) {
videoWriter.stop()
application.exit()
}
} else {
composite.draw(drawer)
}
swapBuffer()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment