diff options
| author | Akshay Nair <phenax5@gmail.com> | 2026-09-27 12:06:00 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2026-09-28 01:48:05 +0530 |
| commit | 5f41d4cded56121af66b18c232c7f557ab803f94 (patch) | |
| tree | b0b48b4e3b453f7786ba0e1a21c0b2301b06d895 /src/main | |
| parent | aff909363f2fb647420105862432ab3e9d6ca1ed (diff) | |
| download | art-playground-openrndr-5f41d4cded56121af66b18c232c7f557ab803f94.tar.gz art-playground-openrndr-5f41d4cded56121af66b18c232c7f557ab803f94.zip | |
Add headless screenshot + fix scaling for antialiasing for vacation
Diffstat (limited to 'src/main')
| -rw-r--r-- | src/main/kotlin/org/openrndr/Preload.kt | 7 | ||||
| -rw-r--r-- | src/main/kotlin/phenax/extensions/CameraManager.kt | 6 | ||||
| -rw-r--r-- | src/main/kotlin/phenax/extensions/HeadlessScreenshot.kt | 30 | ||||
| -rw-r--r-- | src/main/kotlin/phenax/utils/program.kt | 7 | ||||
| -rw-r--r-- | src/main/kotlin/seigaiha/SeigaihaProgram.kt | 2 | ||||
| -rw-r--r-- | src/main/kotlin/vacation/VacationProgram.kt | 16 | ||||
| -rw-r--r-- | src/main/resources/shaders/vacation.glsl | 123 |
7 files changed, 124 insertions, 67 deletions
diff --git a/src/main/kotlin/org/openrndr/Preload.kt b/src/main/kotlin/org/openrndr/Preload.kt index 1bbd673..9664416 100644 --- a/src/main/kotlin/org/openrndr/Preload.kt +++ b/src/main/kotlin/org/openrndr/Preload.kt @@ -1,14 +1,19 @@ package org.openrndr import org.openrndr.draw.* +import org.openrndr.extensions.Screenshots +import org.openrndr.extra.olive.* import phenax.extensions.HeadlessRecorder -import phenax.utils.recordingEnabled +import phenax.extensions.HeadlessScreenshot +import phenax.utils.* class Preload : ApplicationPreload() { override fun onProgramSetup(program: Program) { println("BACKEND(${program.name}): ${program.application::class.qualifiedName}") if (recordingEnabled) { program.extend(HeadlessRecorder()) + } else if (screenshotEnabled) { + program.extend(HeadlessScreenshot()) } } } diff --git a/src/main/kotlin/phenax/extensions/CameraManager.kt b/src/main/kotlin/phenax/extensions/CameraManager.kt index d14205f..5112332 100644 --- a/src/main/kotlin/phenax/extensions/CameraManager.kt +++ b/src/main/kotlin/phenax/extensions/CameraManager.kt @@ -7,7 +7,7 @@ import org.openrndr.draw.* import org.openrndr.math.Quaternion import org.openrndr.math.Vector2 import org.openrndr.math.Vector3 -import phenax.utils.recordingEnabled +import phenax.utils.* enum class ActionType { PAN, @@ -35,7 +35,7 @@ class CameraManager(public var cameraPosition: Vector3, public var cameraRotatio } override fun setup(program: Program) { - if (recordingEnabled) return + if (recordingEnabled || screenshotEnabled) return cameraQuaternion = Quaternion.fromAngles(cameraRotation.x, cameraRotation.y, cameraRotation.z) @@ -99,7 +99,7 @@ class CameraManager(public var cameraPosition: Vector3, public var cameraRotatio override fun beforeDraw(drawer: Drawer, program: Program) {} override fun afterDraw(drawer: Drawer, program: Program) { - if (recordingEnabled) return + if (recordingEnabled || screenshotEnabled) return drawer.fontMap = font drawer.fill = ColorRGBa.WHITE diff --git a/src/main/kotlin/phenax/extensions/HeadlessScreenshot.kt b/src/main/kotlin/phenax/extensions/HeadlessScreenshot.kt new file mode 100644 index 0000000..35de05d --- /dev/null +++ b/src/main/kotlin/phenax/extensions/HeadlessScreenshot.kt @@ -0,0 +1,30 @@ +package phenax.extensions + +import org.openrndr.* +import org.openrndr.draw.* +import org.openrndr.extensions.SingleScreenshot +import org.openrndr.ffmpeg.VideoWriter + +class HeadlessScreenshot : Extension { + override var enabled: Boolean = true + + var screenshots: SingleScreenshot? = null + var videoWriter: VideoWriter? = null + var maxFrameCount: Int? = null + + override fun setup(program: Program) { + val scr = SingleScreenshot() + screenshots = scr + program.extend(scr) { + outputFile = "screenshot/${program.name}.png" + } + } + + override fun beforeDraw(drawer: Drawer, program: Program) {} + + override fun afterDraw(drawer: Drawer, program: Program) { + screenshots?.trigger() + + // program.application.exit() + } +} diff --git a/src/main/kotlin/phenax/utils/program.kt b/src/main/kotlin/phenax/utils/program.kt index fe48351..cfbe9c9 100644 --- a/src/main/kotlin/phenax/utils/program.kt +++ b/src/main/kotlin/phenax/utils/program.kt @@ -19,7 +19,8 @@ fun recordDuration(millis: Int) { fun recordDuration(): Int? = System.getProperty("phenax.record.frameCount")?.toIntOrNull() -val recordingEnabled: Boolean by lazy { System.getenv("RECORD") != null } +val recordingEnabled: Boolean by lazy { System.getenv("PHENAX_RECORD") != null } +val screenshotEnabled: Boolean by lazy { System.getenv("PHENAX_SCREENSHOT") != null } // fun classDir(): String = // "src/main/kotlin/${stackRootClassName(sanitize = @@ -30,7 +31,7 @@ val recordingEnabled: Boolean by lazy { System.getenv("RECORD") != null } // Have to keep the same name (oliveProgram) to get update on save to work fun ApplicationBuilder.oliveProgram(init: Program.() -> Unit) { - if (recordingEnabled) { + if (recordingEnabled || screenshotEnabled) { program(init) } else { // TODO: Make watching shader files work @@ -88,7 +89,7 @@ fun Program.liveComputeShader(name: String): ReadOnlyProperty<Any?, ComputeShade var cs: ComputeShader = ComputeShader.fromCode(shaderCode, name) - if (!recordingEnabled) { + if (!recordingEnabled || screenshotEnabled) { var lastCompiledCode: String = shaderCode program.extend { diff --git a/src/main/kotlin/seigaiha/SeigaihaProgram.kt b/src/main/kotlin/seigaiha/SeigaihaProgram.kt index 8894664..ae3e411 100644 --- a/src/main/kotlin/seigaiha/SeigaihaProgram.kt +++ b/src/main/kotlin/seigaiha/SeigaihaProgram.kt @@ -10,7 +10,7 @@ import phenax.utils.* fun main() = application { recordDuration(5.seconds()) - if (recordingEnabled) { + if (recordingEnabled || screenshotEnabled) { configure { width = 1920 height = 1080 diff --git a/src/main/kotlin/vacation/VacationProgram.kt b/src/main/kotlin/vacation/VacationProgram.kt index 041c009..b4d9d12 100644 --- a/src/main/kotlin/vacation/VacationProgram.kt +++ b/src/main/kotlin/vacation/VacationProgram.kt @@ -10,10 +10,18 @@ import phenax.utils.* fun main() = application { recordDuration(5.seconds()) - configure { - width = 640 - height = 480 - windowResizable = false + if (recordingEnabled || screenshotEnabled) { + configure { + width = 1920 + height = 1080 + windowResizable = false + } + } else { + configure { + width = 640 + height = 360 + windowResizable = false + } } oliveProgram { diff --git a/src/main/resources/shaders/vacation.glsl b/src/main/resources/shaders/vacation.glsl index c343691..c1aeb2a 100644 --- a/src/main/resources/shaders/vacation.glsl +++ b/src/main/resources/shaders/vacation.glsl @@ -9,11 +9,17 @@ uniform float seconds = 0; layout(rgba8) uniform readonly image2D noise_texture; layout(rgba8) uniform writeonly image2D output_image; +const float antialiasing = 0.28; + float sample_noise(in vec2 p) { vec4 noise = imageLoad(noise_texture, ivec2(p * imageSize(noise_texture))); return noise.x; } +mat2x2 rot_matrix(float angle) { + return mat2x2(cos(angle), -sin(angle), sin(angle), cos(angle)); +} + vec3 image(vec2 uv) { const vec3 sky_color = srgb(0.57, 0.7, 0.91); const vec3 dark_water_color = srgb(0.02, 0.36, 0.6); @@ -32,19 +38,21 @@ vec3 image(vec2 uv) { vec3 color = sky_color; - vec2 sunpos = vec2(0.2, 0.08); + vec2 sunpos = vec2(0.2, 0.1); float sunsize = 0.05; float sun = sdf_circle(uv - sunpos, sunsize); float sunshine = sdf_circle((uv - sunpos) * vec2(0.4, 1.2), sunsize) * 3; color = mix(color, sunshine_color, 1 - clamp(sunshine, 0, 1)); color = mix(color, sun_color, step(sun, 0)); - float dark_cloud = clamp(sample_noise((uv + 0.4) * 0.8 + vec2(0.28, 0)) - 0.1, 0, 1); - color = mix(color, dark_cloud_color, dark_cloud); - float cloud = clamp(sample_noise((uv + vec2(0.5, 0.5)) * 0.6 + vec2(0.18, 0)) - 0.2, 0, 1); - color = mix(color, mix(cloud_color, sunshine_cloud_color, 1. - clamp(sunshine * 2, 0, 1)), cloud); + { + float dark_cloud = clamp(sample_noise((uv + 0.4) * 0.8 + vec2(0.28, 0)) - 0.1, 0, 1); + color = mix(color, dark_cloud_color, dark_cloud); + float cloud = clamp(sample_noise((uv + vec2(0.5, 0.5)) * 0.6 + vec2(0.18, 0)) - 0.2, 0, 1); + color = mix(color, mix(cloud_color, sunshine_cloud_color, 1. - clamp(sunshine * 2, 0, 1)), cloud); + } - float water = uv.y + sin(uv.x * 3 - 1) * 0.01 + fbm(uv * 40) * 0.004; + float water = uv.y - 0.03 + sin(uv.x * 3 - 1) * 0.01 + fbm(uv * 40) * 0.004; vec2 water_noise_seed = uv - 2; vec3 shaded_water_color = water_color; shaded_water_color = mix(shaded_water_color, dark_water_color, clamp(exp((uv.y - 0.03) / 0.1), 0, 1)); @@ -60,72 +68,77 @@ vec3 image(vec2 uv) { shaded_wet_sand_color = mix(shaded_wet_sand_color, clamp(dark_sand_color * 1.5, 0, 1), clamp(abs(uv.y * (uv.x - 0.3)) * 4, 0, 1)); shaded_wet_sand_color = mix(shaded_wet_sand_color, dark_sand_color, clamp(fbm(uv * 600) * fbm(uv * 10 - 8), 0, 1)); - float wet_sand = uv.y + 0.03; - color = mix(color, mix(shaded_wet_sand_color, shaded_water_color, clamp(((uv.y - 0.04) * 3 + 1.2), 0, 1)), step(wet_sand, 0)); + float wet_sand = uv.y + 0.; + color = mix(color, mix(shaded_wet_sand_color, shaded_water_color, clamp(((uv.y - 0.04) * 4 + 1.2), 0, 1)), step(wet_sand, 0)); float wshadow_noise = clamp(fbm(80 * water_noise_seed) * noise(8 * water_noise_seed), 0, 1); - color = mix(color, dark_water_color, step(-uv.y - 0.26, 0) * step(water, 0) * clamp((uv.y - 0.08) * sin((uv.x / 3 + wshadow_noise - 1.84) * sin(uv.y) * 40), 0, 1)); + color = mix(color, dark_water_color, step(-uv.y - 0.19, 0) * step(water, 0) * clamp((uv.y - 0.08) * sin((uv.x / 5 + wshadow_noise - 1.84) * sin(uv.y * 2.4) * 40), 0, 1)); float wfoam_noise = clamp(fbm(100 * water_noise_seed) * noise(8 * water_noise_seed), 0, 1); - color = mix(color, vec3(1), step(water, 0) * clamp((uv.y - 0.01) * sin((uv.x / 3 + wfoam_noise - 2.2) * sin(uv.y * 1.4) * 25), 0, 1)); + color = mix(color, vec3(1), step(water, 0) * clamp((uv.y - 0.0) * sin((uv.x / 5 + wfoam_noise - 2.2) * sin(uv.y * 2.4) * 25), 0, 1)); - float sand = uv.y + sin(uv.x * 3 + 0.) * 0.07 + fbm(uv * 40) * 0.012; - vec3 shaded_sand_color = sand_color; - float sand_shine = clamp(abs((uv.y + 0.5) * (uv.x + 0.5) * 12), 0, 1); - shaded_sand_color = mix(shaded_sand_color, mix(sunshine_color, sand_color, 0.5), sand_shine); - float sand_shadow = sdf_circle(uv * vec2(0.3, 1) + vec2(0.16, 0.4), 0.1); - shaded_sand_color = mix(shaded_sand_color, sand_shadow_color, 1 - smoothstep(sand_shadow, -0.1, -0.04)); - shaded_sand_color = mix(shaded_sand_color, dark_sand_color, clamp(fbm(uv * 600) * fbm(uv * 40 + 9), 0, 1)); - color = mix(color, shaded_sand_color, step(sand, -0.33)); + { + float sand = uv.y - 0.08 + sin(uv.x * 3 + 0.) * 0.09 + fbm(uv * 40) * 0.012 + fbm(uv * 4) * 0.034; + vec3 shaded_sand_color = sand_color; + float sand_shine = clamp(abs((uv.y + 0.5) * (uv.x + 0.5) * 12), 0, 1); + shaded_sand_color = mix(shaded_sand_color, mix(sunshine_color, sand_color, 0.5), sand_shine); + float sand_shadow = sdf_circle(uv * vec2(0.3, 1) + vec2(0.16, 0.4), 0.1); + shaded_sand_color = mix(shaded_sand_color, sand_shadow_color, 1 - smoothstep(sand_shadow, -0.1, -0.04)); + shaded_sand_color = mix(shaded_sand_color, dark_sand_color, clamp(fbm(uv * 600) * fbm(uv * 40 + 9), 0, 1)); + color = mix(color, shaded_sand_color, step(sand, -0.33)); + } - vec2 boatpos = uv - vec2(0.14, -0.02); - float boatrefgap = 0.012; - float boatid = clamp(round(boatpos.y / boatrefgap), -1, 0); - boatpos.y -= boatid * boatrefgap; - boatid += 1; - boatpos.y *= boatid * 2 - 1 + (1 - boatid) * 0.4; - boatpos.x += (1 - boatid) * (0.02 * wfoam_noise + boatpos.y * 0.3); - float boatsize = 0.005; - float boatsail = sdf_box(boatpos - vec2(-1.8 + boatpos.y * 20, 5.2) * boatsize, vec2(2 * (1 - boatpos.y * 18), 4) * boatsize, 0.004); - boatsail = min(boatsail, sdf_box(boatpos - vec2(-1.0, 1) * boatsize, vec2(0.4, 2) * boatsize, 0.0)); - float boat = sdf_box(boatpos - vec2(boatpos.y * 50, -0.1) * boatsize, vec2(5 * (1 + boatpos.y * 20), 1.2) * boatsize, 0.0); - vec3 boat_refl_color = mix(shaded_water_color, vec3(0), clamp(uv.y * 2 + 0.5, 0, 1)); - color = mix(color, mix(boat_refl_color, vec3(0), boatid), step(min(boatsail, boat), 0)); + { + vec2 boatpos = uv - vec2(0.14, 0.0); + float boatrefgap = 0.012; + float boatid = clamp(round(boatpos.y / boatrefgap), -1, 0); + boatpos.y -= boatid * boatrefgap; + boatid += 1; + boatpos.y *= boatid * 2 - 1 + (1 - boatid) * 0.4; + boatpos.x += (1 - boatid) * (0.02 * wfoam_noise + boatpos.y * 0.3); + float boatsize = 0.005; + float boatsail = sdf_box(boatpos - vec2(-1.8 + boatpos.y * 20, 5.3) * boatsize, vec2(2 * (1 - boatpos.y * 18), 4) * boatsize, 0.006); + boatsail = min(boatsail, sdf_box(boatpos - vec2(-1.0, 1) * boatsize, vec2(0.4, 2) * boatsize, 0.0)); + float boat = sdf_box(boatpos - vec2(boatpos.y * 50, -0.1) * boatsize, vec2(5 * (1 + boatpos.y * 20), 1.2) * boatsize, 0.0); + vec3 boat_refl_color = mix(shaded_water_color, vec3(0), clamp(uv.y * 2 + 0.5, 0, 1)); + color = mix(color, mix(boat_refl_color, vec3(0), boatid), step(min(boatsail, boat), 0)); + } - float island = sdf_circle(uv * vec2(0.25, 1.0) + vec2(0.06, 0), 0.05 - fbm((uv + 0.06) * 25) * 0.04); - vec3 shaded_island_color = sand_color; - shaded_island_color = mix(shaded_island_color, clamp(dark_sand_color * 1.5, 0, 1), clamp(abs(uv.y * (uv.x - 0.3)) * 4, 0, 1)); - shaded_island_color = mix(shaded_island_color, dark_sand_color, clamp(fbm(uv * 600) * fbm(uv * 10 - 8), 0, 1)); - color = mix(color, shaded_island_color, step(island, -0.01)); + { + vec2 islandpos = uv * vec2(0.25, 1.0) + vec2(0.06, -0.00); + float island = sdf_circle(islandpos, 0.05 - fbm((islandpos + 0.09) * 27) * 0.04); + vec3 shaded_island_color = sand_color; + shaded_island_color = mix(shaded_island_color, clamp(dark_sand_color * 1.5, 0, 1), clamp(abs(uv.y * (uv.x - 0.3)) * 4, 0, 1)); + shaded_island_color = mix(shaded_island_color, dark_sand_color, clamp(fbm(uv * 600) * fbm(uv * 10 - 8), 0, 1)); + color = mix(color, shaded_island_color, step(island, -0.01)); + } - float tree_size = 0.01; - float trunk = sdf_box(uv - vec2(-0.15 + sin(uv.y * 30 - 1.5) * 0.01, 0.03), - tree_size * vec2(0.2 + abs((uv.y - 0.03) * 5 - 0.3) * 0.3, 2.4), - 0.001); - vec3 shaded_trunk_color = dark_tree_trunk_color; - color = mix(color, shaded_trunk_color, step(trunk, 0)); + { + float treesize = 0.01; + vec2 treepos = uv - vec2(-15, 3) * treesize; + float trunk = sdf_box(treepos - vec2(sin(uv.y * 30 - 1.5), 0) * treesize, + treesize * vec2(0.2 + abs((uv.y - 0.03) * 5 - 0.3) * 0.3, 2.4), + 0.003); + vec3 shaded_trunk_color = dark_tree_trunk_color; + color = mix(color, shaded_trunk_color, step(trunk, 0)); - // float leafbranchcurve = sin(-uv.x * 8 + 0.2) * 0.06; - // float leafsizecurve = (sin(uv.x * 8 - 6.9) + 0.16) * 0.05; - // vec2 leafpos = uv; - // leafpos -= vec2(-0.26 + sin(uv.y * 8 + 0.5) * 0.06, 0.18 + leafbranchcurve + leafsizecurve); - // float leafgap = 0.012; - // float leafindex = clamp(round(leafpos.x / leafgap), -7, 21); - // leafpos.x = leafpos.x - leafgap * leafindex; - // float leaf = sdf_box(leafpos, vec2(abs(leafpos.y * 0.1 + 0.014) * 0.26, 0.02 - leafsizecurve), 0.0); - // color = mix(color, vec3(0.0, 0.3, 0.0), step(leaf, 0)); - // float leaf_stick = sdf_box(uv - vec2(-0.13, 0.20 + leafbranchcurve), vec2(0.19, 0.008), 0.02); - // color = mix(color, vec3(0.0, 0.06, 0.0), step(leaf_stick, 0)); + { + vec2 leafpos = treepos - vec2(0.1, 3.1) * treesize; + float leafs = sdf_box(leafpos - vec2(0), vec2(2.1, 1.6) * treesize, 1.4 * treesize); + color = mix(color, srgb(0.0, 0.4, 0.0), step(leafs, 0)); + } + } return color; } vec3 antialiased_image(vec2 uv) { - float anti_aliasing = 0.0006; + vec2 resolution = vec2(imageSize(output_image).xy); + float s = antialiasing / max(resolution.x, resolution.y); vec3 sum = vec3(0); int count = 0; for (int i = -2; i < 2; i++) for (int j = -2; j < 2; j++, count++) - sum += image(uv + vec2(i, j) * anti_aliasing); + sum += image(uv + vec2(i, j) * s); return sum / count; } |
