Skip to content

Instantly share code, notes, and snippets.

@ylegall
Created September 3, 2020 17:45
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ylegall/40a150bdcb1af53ff723583623320800 to your computer and use it in GitHub Desktop.
Save ylegall/40a150bdcb1af53ff723583623320800 to your computer and use it in GitHub Desktop.
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.DrawPrimitive
import org.openrndr.draw.VertexElementType
import org.openrndr.draw.shadeStyle
import org.openrndr.draw.vertexBuffer
import org.openrndr.draw.vertexFormat
import org.openrndr.extra.compositor.compose
import org.openrndr.extra.compositor.draw
import org.openrndr.extra.compositor.post
import org.openrndr.extra.fx.blur.FrameBlur
import org.openrndr.extra.fx.blur.ZoomBlur
import org.openrndr.extras.camera.OrbitalCamera
import org.openrndr.extras.camera.OrbitalControls
import org.openrndr.extras.camera.applyTo
import org.openrndr.extras.meshgenerators.boxMesh
import org.openrndr.ffmpeg.ScreenRecorder
import org.openrndr.math.Matrix44
import org.openrndr.math.Spherical
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.mix
import org.openrndr.math.transforms.transform
import org.openrndr.shape.Segment3D
import org.ygl.kxa.ease.Ease
import org.ygl.openrndr.utils.ColorMap
import kotlin.math.PI
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 * 3
private const val LOOPS = 2
private const val RECORDING = true
fun main() = application {
configure {
width = WIDTH
height = HEIGHT
}
program {
var time = 0.0
val numBoxes = 120
val centralBoxSize = 75.0
val maxStreamLength = 1200.0
val boxSize = 16.0
val bgColor = rgb("282440")
val strokeColor = rgb("8B0F51") //rgb("ff6cce")
val rng = Random(2)
val colors = ColorMap(listOf(
//"61988e","cbef43","b2abf2","6a5d7b","eccfc3"
"f4f1de","ea7555","ab64b7","544e92","b2d67a"
))
val camera = OrbitalCamera(
//eye = Vector3(0.0, 0.0, 350.0),
eye = Vector3.fromSpherical(Spherical(45.0, 90.0, 300.0)),
far = 1400.0
)
fun boxSegments(size: Double): List<Segment3D> {
val leftTopFront = Vector3(-size, -size, -size)
val rightTopFront = Vector3(size, -size, -size)
val leftBottomFront = Vector3(-size, size, -size)
val rightBottomFront = Vector3(size, size, -size)
val leftTopBack = Vector3(-size, -size, size)
val rightTopBack = Vector3(size, -size, size)
val leftBottomBack = Vector3(-size, size, size)
val rightBottomBack = Vector3(size, size, size)
return listOf(
Segment3D(leftTopFront, rightTopFront),
Segment3D(rightTopFront, rightBottomFront),
Segment3D(rightBottomFront, leftBottomFront),
Segment3D(leftBottomFront, leftTopFront),
Segment3D(leftTopBack, rightTopBack),
Segment3D(rightTopBack, rightBottomBack),
Segment3D(rightBottomBack, leftBottomBack),
Segment3D(leftBottomBack, leftTopBack),
Segment3D(leftTopFront, leftTopBack),
Segment3D(rightTopFront, rightTopBack),
Segment3D(rightBottomFront, rightBottomBack),
Segment3D(leftBottomFront, leftBottomBack),
)
}
val boxMesh = boxMesh()
val baseSegments = boxSegments(0.5)
class Box(
val dir: Vector3,
val posOffset: Vector2,
val timeOffset: Double,
val size: Double,
val color: Double
)
val boxes = listOf(Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z).flatMap { dir ->
val maxBounds = centralBoxSize / 3
listOf(1.0, -1.0).flatMap { sign ->
List(numBoxes) {
Box(
dir * sign,
Vector2(rng.nextDouble(-maxBounds, maxBounds), rng.nextDouble(-maxBounds, maxBounds)),
rng.nextDouble(),
boxSize * rng.nextDouble(0.7, 1.1),
rng.nextDouble()
)
}
}
}
val edges = MutableList(boxes.size) { listOf<Segment3D>() }
val transforms = vertexBuffer(vertexFormat {
attribute("transform", VertexElementType.MATRIX44_FLOAT32)
attribute("color", VertexElementType.VECTOR4_FLOAT32)
}, boxes.size + 1)
fun computeTransforms() {
transforms.put {
// central box:
write(transform {
scale(centralBoxSize)
})
write(bgColor)
for (i in boxes.indices) {
val box = boxes[i]
val t = (box.timeOffset + 4 * time) % 1.0
val translation = (box.timeOffset * centralBoxSize / 2) + maxStreamLength * Ease.CUBE_IN(t)
val stretch = Vector3(1 + 15.0 * Ease.QUAD_IN(t), 1.0, 1.0)
val tx = transform {
when (box.dir) {
Vector3.UNIT_Y -> rotate(Vector3.UNIT_Z, 90.0)
Vector3.UNIT_Z -> rotate(Vector3.UNIT_Y, 90.0)
-Vector3.UNIT_X -> rotate(Vector3.UNIT_Y, 180.0)
-Vector3.UNIT_Y -> rotate(Vector3.UNIT_Z, -90.0)
-Vector3.UNIT_Z -> rotate(Vector3.UNIT_Y, -90.0)
}
translate(translation, 0.0, 0.0)
translate(0.0, box.posOffset.x, box.posOffset.y)
scale(stretch)
scale(box.size)
}
write(tx)
write(colors[box.color])
edges[i] = baseSegments.map { it.transform(tx) }
}
}
}
val composite = compose {
draw {
drawer.clear(bgColor)
computeTransforms()
drawer.fill = ColorRGBa.BLACK
drawer.shadeStyle = shadeStyle {
//vertexTransform = "x_viewMatrix = x_viewMatrix * i_transform;"
vertexTransform = "x_modelMatrix = x_modelMatrix * i_transform;"
fragmentTransform = """
//float dist = clamp(distance(va_position, v_viewPosition)/800, 0, 1);
//x_fill = mix(vi_color, p_bgcolor, dist);
float dist = clamp(length(v_worldPosition)/800, 0, 1);
x_fill = mix(vi_color, p_bgcolor, dist);
""".trimIndent()
parameter("bgcolor", bgColor)
}
drawer.vertexBufferInstances(
listOf(boxMesh),
listOf(transforms),
DrawPrimitive.TRIANGLES,
transforms.vertexCount
)
drawer.shadeStyle = null
drawer.shadeStyle = shadeStyle {
fragmentTransform = """
x_stroke.a = 1 - clamp(length(va_position)/400, 0, 1);
//x_stroke = mix(p_stroke, p_bgcolor, length(va_position)/400);
""".trimIndent()
parameter("stroke", strokeColor)
parameter("bgcolor", bgColor)
}
drawer.stroke = strokeColor
drawer.strokeWeight = 3.0
drawer.segments(edges.flatten())
}
post(FrameBlur()) {
blend = 0.5
}
}
if (RECORDING) {
extend(ScreenRecorder()) {
outputFile = "video/CubeStream.mp4"
frameRate = 120
frameClock = true
}
} else {
extend(OrbitalControls(camera))
}
extend {
time = ((frameCount - 1) % TOTAL_FRAMES) / TOTAL_FRAMES.toDouble()
val angle = 2 * PI * time
val spherical = Spherical(
45 + 60 * sin(angle),
90 + 20 * sin(2 * angle),
300.0
)
camera.setView(camera.lookAt, spherical, camera.fov)
camera.update(deltaTime)
camera.applyTo(drawer)
drawer.rotate(360 * time)
composite.draw(drawer)
if (RECORDING && frameCount >= TOTAL_FRAMES * LOOPS) {
application.exit()
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment