Skip to content

Instantly share code, notes, and snippets.

@ylegall
Created February 6, 2024 04:14
Show Gist options
  • Save ylegall/e14a12450921b6af71e8bfb2567ff265 to your computer and use it in GitHub Desktop.
Save ylegall/e14a12450921b6af71e8bfb2567ff265 to your computer and use it in GitHub Desktop.
openRNDR code for genuary 2024 day 30: meromorphic shader
import org.intellij.lang.annotations.Language
import org.openrndr.application
import org.openrndr.draw.ColorFormat
import org.openrndr.draw.ColorType
import org.openrndr.draw.bufferTexture
import org.openrndr.draw.shadeStyle
import org.openrndr.extra.noise.simplex
import org.openrndr.ffmpeg.H264Profile
import org.openrndr.ffmpeg.ScreenRecorder
import org.openrndr.math.Vector2
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
import kotlin.random.Random
fun main() = application {
configure {
width = 1024
height = 1024
}
program {
@Language("GLSL")
val shaderCode = """
#define PI 3.1415926535897932384626433832795
#define TAU 2*PI
#define SQRT3 1.73205080757
// complex math
#define cx_mul(a, b) vec2(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x)
#define cx_div(a, b) vec2(((a.x*b.x + a.y*b.y)/(b.x*b.x + b.y*b.y)),((a.y*b.x - a.x*b.y)/(b.x*b.x + b.y*b.y)))
#define cx_sin(a) vec2(sin(a.x) * cosh(a.y), cos(a.x) * sinh(a.y))
#define cx_cos(a) vec2(cos(a.x) * cosh(a.y), -sin(a.x) * sinh(a.y))
vec2 cx_tan(vec2 a) { return cx_div(cx_sin(a), cx_cos(a)); }
vec2 cx_log(vec2 a) {
float rpart = (a.x*a.x)+(a.y*a.y);
float ipart = atan(a.y,a.x);
if (ipart > PI) ipart=ipart-(2.0*PI);
return vec2(log(rpart)/2.0,ipart);
}
vec2 polar(vec2 z) { return vec2(length(z), atan(z.y, z.x)); }
vec2 cx_pow(vec2 v, float p) {
vec2 z = polar(v);
return pow(z.x, p) * vec2(cos(z.y * p), sin(z.y * p));
}
// from https://www.shadertoy.com/view/MlXyDl
float hex_grid(vec2 uv, float scale) {
uv *= scale;
vec2 s = vec2(1., SQRT3);
vec2 a = mod(uv, s) * 2. - s;
vec2 b = mod(uv + s * .5, s) * 2. - s;
return 0.5 * min(dot(a,a), dot(b,b));
}
""".trimIndent()
@Language("GLSL")
val fragmentShaderMain = """
vec2 uv = c_boundsPosition.xy;
vec2 z = (uv - vec2(0.5)) * 3.0;
vec2 totalA = vec2(0.0, 0.0);
for (int i=0; i<p_numPoints1; i++) {
vec2 pt1 = texelFetch(p_points1, i).rg;
vec2 zp = cx_pow(z, float(i));
totalA += cx_mul(vec2(pt1.x, pt1.y), zp);
}
vec2 totalB = vec2(0.0, 0.0);
for (int i=0; i<p_numPoints2; i++) {
vec2 pt2 = texelFetch(p_points2, i).rg;
vec2 zp = cx_pow(z, float(i));
totalB += cx_mul(vec2(pt2.x, pt2.y), zp);
}
// from https://hturan.com/writing/complex-numbers-glsl
vec2 result = cx_log(cx_div(totalA, totalB));
// --- hex circle pack
float c = hex_grid(result, 0.832);
// float c = hex_grid(result, p_scale);
c = smoothstep(0.47, 0.49, c);
c = mix(0.1, 0.9, c);
x_fill = vec4(vec3(c), 1.0);
"""
val totalFrames = 360
val recording = true
val numPoints1 = 7
val numPoints2 = 11
val pointsBuffer1 = bufferTexture(numPoints1, ColorFormat.RG, ColorType.FLOAT32)
val pointsBuffer2 = bufferTexture(numPoints2, ColorFormat.RG, ColorType.FLOAT32)
fun noisePoints(seed: Int, n: Int, t: Double): List<Vector2> {
val rng = Random(seed)
val offset = List(n) { rng.nextDouble() }
val radii = List(n * 2) { rng.nextDouble(-0.5, 0.5) }
val centers = List(n * 2) { rng.nextDouble(-0.3, 0.3) }
return List(n) { i ->
val pct = i / (n - 0.0)
val angle = 2 * PI * (t + pct + offset[i])
val x = centers[2*i] + radii[2*i] * cos(angle)
val y = centers[2*i+1] + radii[2*i+1] * sin(angle)
Vector2(
simplex(seed + i*2 + 0, x, y),
simplex(seed + i*2 + 1, x, y),
)
}
}
fun updatePoints(t: Double) {
val points1 = noisePoints(123, numPoints1, t)
val points2 = noisePoints(456, numPoints2, t)
pointsBuffer1.put {
points1.forEach { write(it) }
}
pointsBuffer2.put {
points2.forEach { write(it) }
}
}
updatePoints(0.0)
//val params = object {
// @DoubleParameter("scale", 0.0, 2.0)
// var scale = 1.0
//}
//extend(GUI()) {
// add(params)
//}
if (recording) {
// uncomment to record video
extend(ScreenRecorder()) {
outputFile = "shader.mp4"
this.profile = H264Profile().apply {
this.preset = "veryslow"
this.pixelFormat = "yuv420p"
}
frameRate = 30
maximumFrames = totalFrames.toLong()
quitAfterMaximum = true
}
}
extend {
val t = ((frameCount - 1) % totalFrames) / totalFrames.toDouble()
updatePoints(t)
drawer.shadeStyle = shadeStyle {
@Language("GLSL")
fragmentPreamble = shaderCode
fragmentTransform = fragmentShaderMain
parameter("numPoints1", numPoints1)
parameter("numPoints2", numPoints2)
parameter("points1", pointsBuffer1)
parameter("points2", pointsBuffer2)
//parameter("scale", params.scale)
parameter("time", t)
}
drawer.rectangle(drawer.bounds)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment