๐Ÿ”ง OPENRNDR์˜ ์šฐ์œ„์™€ ๊ธฐ์ˆ ์  ํŠน์ง•

BamgasiJMยท7์ผ ์ „

OPENRNDR

๋ชฉ๋ก ๋ณด๊ธฐ
2/17
post-thumbnail

https://api.openrndr.org/index.html

์ œ๋„ˆ๋ ˆ์ดํ‹ฐ๋ธŒ ์ฝ”๋”ฉ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์„ ํƒํ•  ๋•Œ ์ œ์ž‘์ž๋Š” ํ‘œํ˜„์˜ ์ž์œ ๋„, ์‹คํ–‰ ์„ฑ๋Šฅ, ์‹œ์Šคํ…œ์˜ ์•ˆ์ •์„ฑ ์‚ฌ์ด์—์„œ ์„ ํƒํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ์— ์ง๋ฉดํ•ฉ๋‹ˆ๋‹ค. p5.js, Processing, openFrameworks, Nannou ๋“ฑ ๋‹ค์–‘ํ•œ ๋„๊ตฌ๊ฐ€ ์กด์žฌํ•˜์ง€๋งŒ, OPENRNDR๋Š” Kotlin ๊ธฐ๋ฐ˜์˜ ํ˜„๋Œ€์ ์ธ ์„ค๊ณ„์™€ GPU ๊ฐ€์† ๊ตฌ์กฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ํ”„๋กœํ† ํƒ€์ดํ•‘๊ณผ ์ƒ์šฉ ์Šค์ผ€์ผ์˜ ์ƒ์‚ฐ ๋‹จ๊ณ„ ๋ชจ๋‘์—์„œ ๊ณ ์œ ํ•œ ๊ธฐ์ˆ ์  ์šฐ์œ„๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

OPENRNDR์˜ ์ง„๊ฐ€๋Š” ๋‹จ์ˆœํžˆ "๋„ํ˜•์„ ๊ทธ๋ฆฌ๊ณ  ์…ฐ์ด๋”๋ฅผ ๋ถ™์ธ๋‹ค"๋ฅผ ๋„˜์–ด, ์‹ค์ œ ์ŠคํŠœ๋””์˜ค ํ™˜๊ฒฝ ๋ฐ ๊ทธ๋ž˜ํ”ฝ ๋””์ž์ด๋„ˆ์˜ ๊ฐ€๊ณต ์ž‘์—…์— ํ•„์š”ํ•œ ๋””ํ…Œ์ผ์„ ์ •๊ตํ•˜๊ฒŒ ์ฑ™๊ฒผ๋‹ค๋Š” ์ ์— ์žˆ์Šต๋‹ˆ๋‹ค.


1. Vector Drawing API๋กœ์„œ์˜ ์šฐ์œ„

OPENRNDR์˜ Drawing API๋Š” ๊ณ ๋„ํ™”๋œ 2D/3D ๋ฒกํ„ฐ ๊ทธ๋ž˜ํ”ฝ ์—ฐ์‚ฐ๊ณผ ํ•˜๋“œ์›จ์–ด ๊ฐ€์† ๋ Œ๋”๋ง์„ ์™„์ „ํžˆ ๊ฒฐํ•ฉํ•œ ๊ตฌ์กฐ๋ฅผ ๊ฐ–์ถ”๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

1-1. ๊ฐ•๋ ฅํ•œ Shapelib๊ณผ 2D Vector Geometry ์—ฐ์‚ฐ

p5.js๋‚˜ Processing์˜ ๊ฒฝ์šฐ ๋ณต์žกํ•œ ๋ฒ ์ง€์–ด ๊ณก์„ (Bezier Curve) ๋ถ„ํ• , ๋ฉด ๊ต์ฐจ(Boolean Operations), ์˜คํ”„์…‹(Offset) ๊ณ„์‚ฐ, ํฐํŠธ์˜ ์•„์›ƒ๋ผ์ธ ์ถ”์ถœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ๋ณ„๋„์˜ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜์กดํ•˜๊ฑฐ๋‚˜ CPU ์—ฐ์‚ฐ ๋ณ‘๋ชฉ์ด ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด OPENRNDR๋Š” ๋‚ด์žฅ๋œ orx-shapes ๋ฐ ๋ฐฑ์—”๋“œ ์Šค์ผ€์ผ์˜ Vector Shape ์—”์ง„์„ ํ†ตํ•ด ๋ณต์žกํ•œ ํŒจ์Šค ์—ฐ์‚ฐ์„ ๋„ค์ดํ‹ฐ๋ธŒ ๋ ˆ๋ฒจ์—์„œ ๋†’์€ ์ •๋ฐ€๋„๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

  • ๋ฒ ์ง€์–ด ๊ณก์„  ๋ถ„ํ•  ๋ฐ ์ƒ˜ํ”Œ๋ง: Shape.contours๋ฅผ ํ†ตํ•ด ์ž„์˜์˜ ํ•ด์ƒ๋„๋กœ ๊ณก์„ ์„ ์ด์‚ฐํ™”ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ ์ ์˜ ์ ‘์„ ยท๋ฒ•์„  ๋ฒกํ„ฐ๊นŒ์ง€ ์ฆ‰์‹œ ์ถ”์ถœ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • Boolean ์—ฐ์‚ฐ (Union / Intersection / Difference): ๋‘ ๊ฐœ ์ด์ƒ์˜ Shape ๊ฐ์ฒด ๊ฐ„ ํ•ฉ์ง‘ํ•ฉยท๊ต์ง‘ํ•ฉยท์ฐจ์ง‘ํ•ฉ์„ ๋‹จ์ผ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด, ๋กœ๊ณ  ๋””์ž์ธ์ด๋‚˜ ๊ธฐํ•˜ํ•™์  ํŒจํ„ด ์ƒ์„ฑ์— ์ง์ ‘ ํ™œ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • Offset / Stroke-to-Fill ๋ณ€ํ™˜: ํŒจ์Šค์˜ ์™ธ๊ณฝ์„ ์„ ์ผ์ • ๋‘๊ป˜๋งŒํผ ํ™•์žฅยท์ถ•์†Œํ•˜๋Š” ์˜คํ”„์…‹ ์—ฐ์‚ฐ์ด ์ •๋ฐ€ํ•˜๊ฒŒ ์ง€์›๋˜์–ด, ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ ๋ณ€ํ˜•์ด๋‚˜ ์œ ๊ธฐ์  ํ˜•ํƒœ ์ƒ์„ฑ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

1-2. ๋ Œ๋”๋ง ํƒ€๊นƒ(RenderTarget)๊ณผ ์˜คํ”„์Šคํฌ๋ฆฐ ๋ฒ„ํผ ๊ด€๋ฆฌ

openFrameworks๋‚˜ Processing์—์„œ FBO(Frame Buffer Object)๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ…์Šค์ฒ˜๋ฅผ ์ด์ค‘ ๋ฐ”์ธ๋”ฉํ•˜์—ฌ ๋ Œ๋”๋ง ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๊ณผ์ •์€ ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ง€๊ณ  ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์˜ ์œ„ํ—˜์ด ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

OPENRNDR๋Š” renderTarget ๊ฐœ๋…์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์„ ์–ธํ•˜๊ณ , ๋ฐ”์ธ๋”ฉ ๋ฐ ์ปจํ…์ŠคํŠธ ์ „ํ™˜์„ ํ•จ์ˆ˜ํ˜• ๋ธ”๋ก(draw {}) ๋‚ด์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ๊ฒฉ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

val offscreen = renderTarget(width, height) {
    colorBuffer(0)
    depthBuffer()
}

offscreen.draw {
    drawer.clear(ColorRGBa.BLACK)
    drawer.fill = ColorRGBa.WHITE
    drawer.circle(width / 2.0, height / 2.0, 150.0)
}

// ๋ฉ”์ธ ์บ”๋ฒ„์Šค์— ์˜คํ”„์Šคํฌ๋ฆฐ ๊ฒฐ๊ณผ๋ฅผ ํ•ฉ์„ฑ
drawer.image(offscreen.colorBuffer(0))

์ด๋ฅผ ํ†ตํ•ด ๋ณต์žกํ•œ ๋ฉ€ํ‹ฐ ํŒจ์Šค ๋ Œ๋”๋ง ์‹œ์Šคํ…œ์„ ์ž‘์„ฑํ•  ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” OpenGL ์ƒํƒœ ์˜ค์—ผ์„ ๋ฐฉ์ง€ํ•˜๊ณ , ๋ฆฌ์†Œ์Šค ํ•ด์ œ(destroy()) ์‹œ์ ๋„ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1-3. 60 FPS ์ด์ƒ์˜ ๊ณ ์„ฑ๋Šฅ LWJGL ๊ธฐ๋ฐ˜ ๋ Œ๋”๋ง

ํ”„๋ ˆ์ž„์›Œํฌ๋ Œ๋”๋ง ๋ฐฑ์—”๋“œํ•œ๊ณ„์ 
openFrameworks (C++)OpenGL / Vulkan์šฐ์ˆ˜ํ•œ ์„ฑ๋Šฅ์ด๋‚˜ ๋นŒ๋“œ ์†๋„ ๋А๋ฆผ, ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊นŒ๋‹ค๋กœ์›€
p5.js (JavaScript)WebGL (๋ธŒ๋ผ์šฐ์ €)์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ํ•œ๊ณ„, ์ˆ˜๋งŒ ๊ฐœ ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ ์‹ค์‹œ๊ฐ„ ์ฒ˜๋ฆฌ ๊ณค๋ž€
OPENRNDR (Kotlin/JVM)LWJGL โ†’ OpenGL 3.3+C++์— ์œก๋ฐ•ํ•˜๋Š” ์„ฑ๋Šฅ + ์ฆ‰๊ฐ์ ์ธ ์ปดํŒŒ์ผ ํ™˜๊ฒฝ ๋™์‹œ ํ™•๋ณด

OPENRNDR๋Š” JVM ์œ„์—์„œ LWJGL(Lightweight Java Game Library)์„ ํ†ตํ•ด OpenGL 3.3+์— ์ง์ ‘ ์ ‘๊ทผํ•˜๋ฏ€๋กœ, ๋ณต์žกํ•œ ํŒŒํ‹ฐํด ์‹œ์Šคํ…œ์ด๋‚˜ ๋Œ€๊ทœ๋ชจ ๋ฒกํ„ฐ ์—ฐ์‚ฐ์—์„œ๋„ ์•ˆ์ •์ ์ธ ํ”„๋ ˆ์ž„ ๋ ˆ์ดํŠธ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.


2. GLSL ์…ฐ์ด๋” ์•„ํŠธ์›Œํฌ ๋ฉ”์ด์ปค๋กœ์„œ์˜ ์šฐ์œ„

OPENRNDR๋Š” ๋‹จ์ˆœํžˆ GLSL ์ฝ”๋“œ๋ฅผ ํ…์Šค์ฒ˜ ํŒจ์Šค ํ˜•ํƒœ๋กœ ๋กœ๋“œํ•˜๋Š” ์ˆ˜์ค€์„ ๋„˜์–ด, ์…ฐ์ด๋” ์ฝ”๋“œ์™€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒํƒœ๋ฅผ ์œ ๊ธฐ์ ์œผ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ์‹œ์Šคํ…œ์„ ๊ฐ–์ถ”๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

2-1. ShadeStyle: ์…ฐ์ด๋” ํ…œํ”Œ๋ฆฟ ์—”์ง„

๊ธฐ์กด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ปค์Šคํ…€ GLSL ์…ฐ์ด๋”๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋ฒ„ํ…์Šค ์…ฐ์ด๋”์™€ ํ”„๋ž˜๊ทธ๋จผํŠธ ์…ฐ์ด๋”์˜ ์ „์ฒด ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

OPENRNDR์˜ ShadeStyle์€ ํŒŒ์ดํ”„๋ผ์ธ ๋‚ด๋ถ€์˜ ํŠน์ • ๋‹จ๊ณ„(Vertex Transform, Fragment Color ๋“ฑ)์—๋งŒ ์‚ฌ์šฉ์ž๊ฐ€ ์ž‘์„ฑํ•œ GLSL ์กฐ๊ฐ์„ ์ฃผ์ž…(inject) ํ•˜๋Š” ๋ฐฉ์‹์„ ์ทจํ•ฉ๋‹ˆ๋‹ค.

// ๊ธฐ๋ณธ 2D ๋„ํ˜• Drawing API ์œ„์— GLSL ํ”„๋ž˜๊ทธ๋จผํŠธ ๋กœ์ง์„ ์ง์ ‘ ์ฃผ์ž…
drawer.shadeStyle = shadeStyle {
    fragmentPreamble = """
        float noise(vec2 st) {
            return fract(sin(dot(st, vec2(12.9898, 78.233))) * 43758.5453123);
        }
    """
    fragmentTransform = """
        vec2 st = c_boundsPosition.xy;
        x_fill.rgb *= noise(st * p_scale + p_time);
    """
    parameter("scale", 10.0)
    parameter("time", seconds)
}
drawer.rectangle(100.0, 100.0, 400.0, 400.0)

์ด ๊ตฌ์กฐ์˜ ํ•ต์‹ฌ ์ด์ :

  • ๊ธฐ๋ณธ ์ œ๊ณต๋˜๋Š” 2D ๋ฒกํ„ฐ ๋ Œ๋”๋ง ๊ธฐ๋Šฅ(Fill, Stroke, Transform)์„ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋ฉด์„œ, ๋‚ด๋ถ€ ์ ˆ์ฐจ์  ํŒจํ„ด์ด๋‚˜ ์ฐฉ์ƒ‰ ๋กœ์ง๋งŒ GLSL๋กœ ๊ต์ฒด ๊ฐ€๋Šฅ
  • ๋ฒ„ํ…์Šค/ํ”„๋ž˜๊ทธ๋จผํŠธ ์…ฐ์ด๋” ์ „์ฒด๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ์ž‘์„ฑํ•  ํ•„์š” ์—†์ด, ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•œ ๋‹จ๊ณ„๋งŒ ์„ ํƒ์ ์œผ๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œ
  • vertexTransform, fragmentTransform, fragmentPreamble ๋“ฑ ์„ธ๋ถ„ํ™”๋œ ์ฃผ์ž… ํฌ์ธํŠธ ์ œ๊ณต

2-2. ์ž๋™ Uniform ๋งคํ•‘ ๋ฐ ํƒ€์ž… ์•ˆ์ „์„ฑ

Kotlin ์ฝ”๋“œ์—์„œ parameter("name", value) ํ˜•ํƒœ๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜๋Š” GLSL ์…ฐ์ด๋” ๋‚ด์˜ p_name ๋ณ€์ˆ˜๋กœ ์ž๋™ ๋งคํ•‘๋ฉ๋‹ˆ๋‹ค.

parameter("scale", 10.0)          // GLSL: uniform float p_scale;
parameter("offset", Vector2(1.0, 2.0))  // GLSL: uniform vec2 p_offset;
parameter("tint", ColorRGBa.PINK)       // GLSL: uniform vec4 p_tint;
parameter("tex", colorBuffer)           // GLSL: uniform sampler2D p_tex;

Float, Vector, Color, Matrix, BufferImage(Texture) ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ ํƒ€์ž…์ด OpenGL Uniform ์ „๋‹ฌ ๊ณผ์ •์˜ ์ˆ˜๋™ ๋ฐ”์ธ๋”ฉ ์ฝ”๋“œ ์—†์ด ์ฆ‰์‹œ ๋™๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” openFrameworks์—์„œ shader.setUniform1f(...), shader.setUniform2f(...) ๋“ฑ์„ ์ผ์ผ์ด ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์„ ์™„์ „ํžˆ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.


3. Drawing API์™€ Shader์˜ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๊ฒฐํ•ฉ์ด ์ œ๊ณตํ•˜๋Š” ์žฅ์ 

์ œ๋„ˆ๋ ˆ์ดํ‹ฐ๋ธŒ ์•„ํŠธ ์ž‘์—… ์‹œ:

  • ์ˆœ์ˆ˜ GLSL๋งŒ ์‚ฌ์šฉ โ†’ ํ…์ŠคํŠธ ๋ ˆ์ด์•„์›ƒ, ๋ณต์žกํ•œ ๋ฒ ์ง€์–ด ํŒจ์Šค ์ œ์–ด, ๋งˆ์šฐ์Šค/ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ฐ€ ๊นŒ๋‹ค๋กœ์›€
  • ์ˆœ์ˆ˜ CPU Drawing API๋งŒ ์‚ฌ์šฉ โ†’ ์ˆ˜๋งŒ ๊ฐœ์˜ ํŒŒํ‹ฐํด ์—ฐ์‚ฐ์ด๋‚˜ ๋ฆฌ์–ผํƒ€์ž„ ํ™”์†Œ ๋‹จ์œ„ ์—ฐ์‚ฐ์—์„œ ์„ฑ๋Šฅ ํ•œ๊ณ„ ๋„๋‹ฌ

OPENRNDR๋Š” ์ด ๋‘ ์˜์—ญ์˜ ๊ฒฝ๊ณ„๋ฅผ ์—†์•ค ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

3-1. ๋ฒกํ„ฐ ๊ฒฝ๋กœ ๋ฐ์ดํ„ฐ์˜ ์…ฐ์ด๋” ์ž…๋ ฅํ™”

Shape ๊ตฌ์กฐ์ฒด๋กœ ์ƒ์„ฑํ•œ ์ˆ˜ํ•™์  ๋ฒ ์ง€์–ด ํŒจ์Šค ๋ฐ์ดํ„ฐ๋ฅผ GPU ๋ฒ„ํผ๋กœ ๋ณด๋‚ธ ๋’ค, ํ”„๋ž˜๊ทธ๋จผํŠธ ์…ฐ์ด๋”์—์„œ SDF(Signed Distance Field) ๊ธฐ์ˆ ๊ณผ ๊ฒฐํ•ฉํ•˜์—ฌ ์‹ค์‹œ๊ฐ„ ํ•„ํ„ฐ ๋ฐ ๋ณ€ํ˜• ํšจ๊ณผ๋ฅผ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

[CPU: Shape/Contour ์ƒ์„ฑ] โ†’ [GPU Buffer ์—…๋กœ๋“œ] โ†’ [Fragment Shader: SDF ๋ Œ๋”๋ง + ๋ณ€ํ˜•]

3-2. Post-processing ํŒŒ์ดํ”„๋ผ์ธ์˜ ๊ฐ„๊ฒฐ์„ฑ

orx-fx ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๋ฉด Drawing API๋กœ ๊ทธ๋ ค์ง„ ์บ”๋ฒ„์Šค์— GLSL ๊ธฐ๋ฐ˜ ๋ธ”๋Ÿฌ, ๊ธ€๋กœ์šฐ, ํ”ผ๋“œ๋ฐฑ ๋…ธ์ด์ฆˆ ํšจ๊ณผ๋ฅผ ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹ ํ˜•ํƒœ๋กœ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

val post = Post(window)
post.add(ApproximateGaussianBlur()).apply {
    window = 5
    gain.set(1.0, 1.0)
}
post.add(ChromaticAberration())
post.add(FilmGrain())

extend(post)

3-3. ์ƒํƒœ ๊ด€๋ฆฌ์™€ ๊ทธ๋ž˜ํ”ฝ์Šค ํŒŒ์ดํ”„๋ผ์ธ์˜ ๋ถ„๋ฆฌ

์—ญํ• ๋‹ด๋‹น ๊ณ„์ธต
์ขŒํ‘œ๊ณ„, ๋งคํŠธ๋ฆญ์Šค ์—ฐ์‚ฐ, ๋„ํ˜• ๋ฐฐ์น˜Drawing API ๋ช…๋ น์–ด
๋‚ด๋ถ€ ์งˆ๊ฐ, ์ปฌ๋Ÿฌ ํ•„๋“œ, ํ™”์†Œ ๋‹จ์œ„ ์—ฐ์‚ฐGLSL ์…ฐ์ด๋”

์ด ๋ถ„๋ฆฌ ๊ตฌ์กฐ ๋•๋ถ„์— ๊ทธ๋ž˜ํ”ฝ ์ œ์–ด ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์„ฑ๋Šฅ์„ ๋™์‹œ์— ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


4. ํƒ€ ํ”„๋ ˆ์ž„์›Œํฌ ๋Œ€๋น„ ์žฅ์ 

openFrameworks, Processing, p5.js, Nannou ๋“ฑ ํƒ€ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ๋น„๊ตํ–ˆ์„ ๋•Œ OPENRNDR๊ฐ€ ์šฐ์œ„์— ์žˆ๋Š” ํ•ต์‹ฌ ์š”์†Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

4-1. ๊ฐ•๋ ฅํ•œ ORX (OPENRNDR Extra) ํ™•์žฅ ์ƒํƒœ๊ณ„

OPENRNDR๋Š” ์ฝ”์–ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งค์šฐ ๊ฐ€๋ณ๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๋Œ€์‹ , ORX๋ผ๋Š” ๊ณต์‹ ํ™•์žฅ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ƒํƒœ๊ณ„๋ฅผ ํ†ตํ•ด ์ œ๋„ˆ๋ ˆ์ดํ‹ฐ๋ธŒ ์•„ํŠธ์— ํ•„์š”ํ•œ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์„ ๋ชจ๋“ˆ์‹์œผ๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

orx-gui โ€” ์ž๋™ UI ์ƒ์„ฑ

์ฝ”๋“œ ๋‚ด์˜ ๋ณ€์ˆ˜์— @DoubleParameter ๊ฐ™์€ ์–ด๋…ธํ…Œ์ด์…˜๋งŒ ๋ถ™์ด๋ฉด, ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๋Š” ์Šฌ๋ผ์ด๋”ยท์ปฌ๋Ÿฌํ”ฝ์ปค GUI ์ฐฝ์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

class Settings {
    @DoubleParameter("Scale", 0.1, 20.0)
    var scale: Double = 5.0

    @ColorParameter("Base Color")
    var baseColor: ColorRGBa = ColorRGBa.PINK

    @DoubleParameter("Speed", 0.0, 3.0)
    var speed: Double = 1.0
}

p5.js์—์„œ dat.GUI๋‚˜ quicksettings๋ฅผ ๋ณ„๋„๋กœ ์ž„ํฌํŠธยท์—ฐ๊ฒฐํ•˜๊ฑฐ๋‚˜, C++์—์„œ ofxGui๋ฅผ ์ˆ˜๋™ ๋ฐฐ์น˜ํ•ด์•ผ ํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์ด ์ „ํ˜€ ์—†์Šต๋‹ˆ๋‹ค.

orx-fx โ€” ํฌ์ŠคํŠธ ํ”„๋กœ์„ธ์‹ฑ ํ•„ํ„ฐ

๋ธ”๋Ÿฌ, ๋””์Šคํ† ์…˜, ๋ธ”๋ฃธ, ํฌ๋กœ๋งคํ‹ฑ ์•„๋ฒ ๋ ˆ์ด์…˜(์ƒ‰์ˆ˜์ฐจ), ํ•ผํ”„ํŠธ๋ก , ํ”ผ๋“œ๋ฐฑ ๋ฒ„ํผ ๋“ฑ ์ˆ˜์‹ญ ๊ฐ€์ง€ ๊ทธ๋ž˜ํ”ฝ ํ•„ํ„ฐ๋ฅผ ๋‹จ ํ•œ ์ค„์˜ ์ฝ”๋“œ๋กœ ์ฒด์ด๋‹ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ ํ•„ํ„ฐ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์ตœ์ ํ™”๋œ GLSL ํŒจ์Šค๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ์–ด, ๋ณต์žกํ•œ ์…ฐ์ด๋” ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ํ”„๋กœ๋•์…˜ ํ’ˆ์งˆ์˜ ๋น„์ฃผ์–ผ์„ ๋น ๋ฅด๊ฒŒ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

orx-camera / orx-marching-cubes

  • orx-camera: 3D ์”ฌ์—์„œ์˜ ๊ถค๋„(Orbit), ํŒฌ(Pan), ์คŒ(Zoom) ์นด๋ฉ”๋ผ ์กฐ์ž‘์„ ์ฆ‰์‹œ ์ œ๊ณต
  • orx-marching-cubes: SDF ํ•„๋“œ๋กœ๋ถ€ํ„ฐ ์ ˆ์ฐจ์  3D ๋ฉ”์‰ฌ๋ฅผ ์‹ค์‹œ๊ฐ„ ์ƒ์„ฑํ•˜๋Š” Marching Cubes ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋‚ด์žฅ

4-2. ์ƒ‰์ƒํ•™(Color Science)์˜ ๊นŠ์ด ์žˆ๋Š” ์ง€์›

๋Œ€๋ถ€๋ถ„์˜ ํฌ๋ฆฌ์—์ดํ‹ฐ๋ธŒ ์ฝ”๋”ฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” RGB ๋˜๋Š” HSB/HSL ์ƒ‰์ƒ ๊ณต๊ฐ„๋งŒ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
๋ฐ˜๋ฉด OPENRNDR๋Š” ๋””์ž์ด๋„ˆ ์‹œ๊ฐ ์ค‘์‹ฌ์˜ ์ƒ‰์ƒ ๊ณต๊ฐ„์„ ๊ธฐ๋ณธ ํƒ€์ž…์œผ๋กœ ํƒ‘์žฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ง€์› ์ƒ‰์ƒ ๊ณต๊ฐ„์šฉ๋„
ColorRGBaํ‘œ์ค€ sRGB ์ถœ๋ ฅ
ColorHSVa์ง๊ด€์  ์ƒ‰์ƒ ์„ ํƒ
ColorXSVaํ™•์žฅ๋œ HSV ๋ณ€ํ˜•
ColorLABa (CIE Lab)์ง€๊ฐ ๊ท ๋“ฑ ๋ณด๊ฐ„
ColorOKLaba / ColorOKLCHa์ตœ์‹  OKLab/OKLCH โ€” ๊ฐ€์žฅ ์ž์—ฐ์Šค๋Ÿฌ์šด ๊ทธ๋ผ๋ฐ์ด์…˜
ColorXYZaCIE XYZ ์ƒ‰์—ญ ๊ด€๋ฆฌ

์‹œ๊ฐ์  ์ธ์ง€(Perceptual Uniformity)์— ๋งž์ถ˜ ๋ณด๊ฐ„

RGB ๊ณต๊ฐ„์—์„œ ํŒŒ๋ž‘(#0000FF)๊ณผ ๋…ธ๋ž‘(#FFFF00)์„ ์„ ํ˜• ๋ณด๊ฐ„ํ•˜๋ฉด ์ค‘๊ฐ„์— ํƒํ•œ ํšŒ์ƒ‰์ด ๋“ฑ์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ OKLab/LCH ๊ณต๊ฐ„์—์„œ ๋™์ผ ๋ณด๊ฐ„์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ์ฑ„๋„๊ฐ€ ์œ ์ง€๋œ ์ž์—ฐ์Šค๋Ÿฝ๊ณ  ์œ ๊ธฐ์ ์ธ ๊ทธ๋ผ๋ฐ์ด์…˜์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

val c1 = ColorOKLCHa(0.7, 0.15, 240.0)  // ํŒŒ๋ž€ ๊ณ„์—ด
val c2 = ColorOKLCHa(0.7, 0.15, 90.0)   // ๋…ธ๋ž€ ๊ณ„์—ด
val gradient = mix(c1, c2, t)           // ์ž์—ฐ์Šค๋Ÿฌ์šด ์ƒ‰์ƒ ์ „์ด

๋””์ž์ธ ์ •๋ฐ€๋„ ํ™•๋ณด

๋ธŒ๋žœ๋”ฉ ์•„ํŠธ์›Œํฌ, ๊ทธ๋ž˜ํ”ฝ ํฌ์Šคํ„ฐ, ์ธ์‡„ ๋งค์ฒด ์—ฐ๊ณ„ ์ž‘์—… ์‹œ ํƒ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ์ฐจ๋ณ„ํ™”๋˜๋Š” ๊ฐ๊ฐ์ ์ธ ์ƒ‰๊ฐ์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, Pantone ๋˜๋Š” ํŠน์ • ๋ธŒ๋žœ๋“œ ์ปฌ๋Ÿฌ์™€์˜ ์ •ํ•ฉ์„ฑ ๊ด€๋ฆฌ์—๋„ ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

4-3. ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ ๋ฐ ๋ฒกํ„ฐ ๊ฒฝ๋กœ(Path/Contour) ์ •๋ฐ€ ์ œ์–ด

Processing์ด๋‚˜ p5.js๋Š” ๊ธ€์ž๋ฅผ ์ด๋ฏธ์ง€ ํ”ฝ์…€ ์ •๋„๋กœ๋งŒ ๋‹ค๋ฃจ๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
OPENRNDR๋Š” ํฐํŠธ๋ฅผ ๋ฒกํ„ฐ ์ปจํˆฌ์–ด(Vector Outline)๋กœ ์ง์ ‘ ๋ถ„ํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ‚ค๋„คํ‹ฑ ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ(Kinetic Typography) ์ตœ์ ํ™”

val writer = FontImageMap.fromUrl("data/fonts/Inter-Bold.ttf", 120.0)
val textShape = writer.shapesFor("OPENRNDR")

textShape.forEach { shape ->
    shape.contours.forEach { contour ->
        contour.equidistantPositions(64).forEachIndexed { i, pt ->
            // ๊ฐ ์ ์— ํŒŒํ‹ฐํด ๋ฐฐ์น˜, ์ˆ˜ํ•™์  ์™œ๊ณก ์ ์šฉ ๋“ฑ
            drawer.circle(pt + Vector2(sin(i * 0.3) * 10.0, 0.0), 2.0)
        }
    }
}
  • ๊ธ€์ž์˜ ์™ธ๊ณฝ์„  ์ (Point) ์ขŒํ‘œ๋ฅผ ์ถ”์ถœํ•ด ์ˆ˜ํ•™์ ์œผ๋กœ ์™œ๊ณก
  • ํฐํŠธ ๊ถค์ ์„ ๋”ฐ๋ผ ํŒŒํ‹ฐํด์„ ๋ฟŒ๋ฆฌ๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜
  • ๊ธ€์ž ๋‚ด๋ถ€ ์˜์—ญ์„ Shape๋กœ ํ™œ์šฉํ•˜์—ฌ ํด๋ฆฌํ•‘ ๋งˆ์Šคํฌ ๋˜๋Š” ํŒจํ„ด ์ฑ„์šฐ๊ธฐ

์ •๊ตํ•œ ๋ฒกํ„ฐ ์ž…์ถœ๋ ฅ ํŒŒ์ดํ”„๋ผ์ธ

  1. SVG Import: loadSVG()๋กœ ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์™€ ๋ ˆ์ด์–ด๋ณ„ Shape ๋ฐ์ดํ„ฐ๋กœ ๋ถ„ํ•ด
  2. ์ •์  ํŽธ์ง‘: ๊ฐ Contour์˜ ์ œ์–ด์ ์„ ์ˆ˜์ •, ์Šค๋ฌด๋”ฉ, ์„œ๋ธŒ๋””๋น„์ „
  3. SVG/PDF Export: ์ˆ˜์ •๋œ ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์†์‹ค ์—†์ด saveSVG() / PDF ํฌ๋งท์œผ๋กœ ์ถœ๋ ฅ

์ด ํŒŒ์ดํ”„๋ผ์ธ์€ ์ธ์‡„์šฉ ํฌ์Šคํ„ฐ, ๋ ˆ์ด์ € ์ปคํŒ… ๋ฐ์ดํ„ฐ, CNC ๊ฐ€๊ณต ๊ฒฝ๋กœ ์ƒ์„ฑ ๋“ฑ ๋ฌผ๋ฆฌ์  ์ถœ๋ ฅ ์›Œํฌํ”Œ๋กœ์šฐ์— ์ง์ ‘ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

4-4. Kotlin ์–ธ์–ด ํŠน์œ ์˜ ํ‘œํ˜„๋ ฅ๊ณผ ์ƒ์‚ฐ์„ฑ

C++(openFrameworks)๋ณด๋‹ค ํ›จ์”ฌ ์•ˆ์ „ํ•˜๊ณ  ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์œผ๋ฉด๋ฉด์„œ, Java/JS๋ณด๋‹ค ๋ฌธ๋ฒ•์ด ๊ฐ„๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

DSL (Domain Specific Language) ๊ตฌ์กฐ

drawer.isolated { ... } ๊ฐ™์€ ๋ธ”๋ก ๊ตฌ๋ฌธ ๋•๋ถ„์— ๊ทธ๋ž˜ํ”ฝ ๋ณ€ํ™˜ Matrix(Translate, Rotate, Scale)์˜ ์Šค์ฝ”ํ”„๋ฅผ pushMatrix/popMatrixํ•  ํ•„์š” ์—†์ด ์ง๊ด€์ ์œผ๋กœ ๊ฒฉ๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

drawer.isolated {
    drawer.translate(width / 2.0, height / 2.0)
    drawer.rotate(45.0)
    drawer.fill = ColorRGBa.RED
    drawer.rectangle(-50.0, -50.0, 100.0, 100.0)
}
// ๋ธ”๋ก ์ข…๋ฃŒ ํ›„ ๋ชจ๋“  ๋ณ€ํ™˜ ์ƒํƒœ๊ฐ€ ์ž๋™์œผ๋กœ ๋ณต์›๋จ

Null Safety ๋ฐ ํ™•์žฅ ํ•จ์ˆ˜

์ฝ”ํ‹€๋ฆฐ์˜ ํƒ€์ž… ์‹œ์Šคํ…œ ๋•๋ถ„์— ๋Ÿฐํƒ€์ž„ ํฌ๋ž˜์‹œ๊ฐ€ ๋Œ€ํญ ์ค„์–ด๋“ค๊ณ , ์ˆ˜ํ•™ ๋ฐ ๋ฒกํ„ฐ ์—ฐ์‚ฐ ํ‘œํ˜„์‹์ด ๋งค์šฐ ๊น”๋”ํ•˜๊ฒŒ ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค.

val position = Vector2(10.0, 20.0)
val velocity = Vector2(1.5, 0.8)
val newPosition = position + velocity * 2.0  // ์—ฐ์‚ฐ์ž ์˜ค๋ฒ„๋กœ๋”ฉ

// Null Safety: ์ปดํŒŒ์ผ ์‹œ์ ์— ๋„ ๊ฐ€๋Šฅ์„ฑ ์ฐจ๋‹จ
val config: Settings? = loadConfig()
config?.let { applySettings(it) }  // NullPointerException ์›์ฒœ ๋ฐฉ์ง€

๋ถˆ๋ณ€์„ฑ ๋ณด์žฅ๊ณผ ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค

data class Particle(
    val position: Vector2,
    val velocity: Vector2,
    val color: ColorRGBa
)

val moved = particle.copy(position = particle.position + particle.velocity)

data class์˜ copy() ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๊ฐ์ฒด์˜ ๋ณต์‚ฌ ๋ฐ ๋ณ€ํ˜• ์—ฐ์‚ฐ์„ ์•ˆ์ „ํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ถˆ๋ณ€ ๊ฐ์ฒด ์ค‘์‹ฌ์˜ ์„ค๊ณ„๋กœ ๋ณต์žกํ•œ ํŒŒํ‹ฐํด ์‹œ์Šคํ…œ์ด๋‚˜ ์ˆ˜์น˜ ์—ฐ์‚ฐ ์‹œ ์ƒํƒœ ๋ณ€๊ฒฝ ์˜ค๋ฅ˜๋ฅผ ์›์ฒœ์ ์œผ๋กœ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

4-5. ์ŠคํŠœ๋””์˜ค๊ธ‰ ์ต์ŠคํฌํŠธ(Export) ์‹œ์Šคํ…œ

๋ฏธ๋””์–ด ์•„ํŠธ ์ „์‹œ๋‚˜ ์ƒ์—… ๊ทธ๋ž˜ํ”ฝ ์ž‘์—… ์‹œ ํ•„์ˆ˜์ ์ธ ์ถœ๋ ฅ ์‹œ์Šคํ…œ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Screenshots / VideoWriter ์ต์Šคํฌํ„ฐ

์ถœ๋ ฅ ํฌ๋งท์šฉ๋„
PNG / TIFF๊ณ ํ•ด์ƒ๋„ ์ •์ง€ ์ด๋ฏธ์ง€ (์ธ์‡„, ํฌํŠธํด๋ฆฌ์˜ค)
SVG๋ฒกํ„ฐ ํŒŒ์ผ (๋ ˆ์ด์ € ์ปคํŒ…, ์ธ์‡„ ๋งค์ฒด)
H.264 (MP4)์›น ๊ณต์œ ์šฉ ๋™์˜์ƒ
ProRes 422 / 4444๋ฐฉ์†กยท์ „์‹œ์šฉ ๊ณ ํ™”์งˆ ๋™์˜์ƒ
EXR ์‹œํ€€์ŠคHDR ํ•ฉ์„ฑ์šฉ ํ”„๋ ˆ์ž„ ์‹œํ€€์Šค
// ํ•œ ์ค„๋กœ ๊ณ ํ•ด์ƒ๋„ ์Šคํฌ๋ฆฐ์ƒท
extend(Screenshots())

// ํ”„๋ ˆ์ž„ ๋“œ๋ž ์—†๋Š” ๋™์˜์ƒ ๋…นํ™”
extend(VideoWriter()).apply {
    codec = "h264"
    bitrate = 20_000_000
    output = "output.mp4"
}

์˜คํ”„๋ผ์ธ ๋ Œ๋”๋ง (Offline Rendering)

์ปดํ“จํ„ฐ ํ”„๋ ˆ์ž„ ๋ ˆ์ดํŠธ๊ฐ€ ์ˆœ๊ฐ„์ ์œผ๋กœ ๋–จ์–ด์ง€๋”๋ผ๋„, ์‹œ๊ฐ„ ์ถ•์„ ๊ณ ์ •ํ•œ ์ฑ„ ์ •ํ™•ํ•œ FPS๋กœ ๋ Œ๋”๋ง ๋™์˜์ƒ์„ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

extend(VideoWriter()).apply {
    realTime = false  // ์˜คํ”„๋ผ์ธ ๋ชจ๋“œ: ํ”„๋ ˆ์ž„ ๋“œ๋ž ๋ฌด์‹œ
    frameRate = 60.0
}

์ด ๊ธฐ๋Šฅ์€ ๋ณต์žกํ•œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์ด๋‚˜ ๊ณ ๋ถ€ํ•˜ ์…ฐ์ด๋” ์ž‘์—… ์‹œ์—๋„ ์™„๋ฒฝํžˆ ๋งค๋„๋Ÿฌ์šด ์ตœ์ข… ๊ฒฐ๊ณผ๋ฌผ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.


5. OPENRNDR์—์„œ ์“ฐ์ด๋Š” Kotlin ์–ธ์–ด์˜ ํŠน์ง•

OPENRNDR์˜ API ๋””์ž์ธ์€ Kotlin์˜ ์–ธ์–ด์  ํŠน์„ฑ์„ ์ ๊ทน ํ™œ์šฉํ•˜๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

Kotlin ํŠน์ง•OPENRNDR์—์„œ์˜ ํ™œ์šฉ
์ˆ˜์‹  ๊ฐ์ฒด ์ง€์ • ๋žŒ๋‹คdrawer.isolated { }, renderTarget.draw { } ๋“ฑ ์ปจํ…์ŠคํŠธ ๊ฒฉ๋ฆฌ
ํ™•์žฅ ํ•จ์ˆ˜Vector2.rotate90() ๋“ฑ ๊ธฐ์กด ํƒ€์ž…์— ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
๋„ ์•ˆ์ „์„ฑ (Type?)๋ฆฌ์†Œ์Šค ๋ฏธ์ดˆ๊ธฐํ™”ยท๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ์˜ค๋ฅ˜ ์ปดํŒŒ์ผ ํƒ€์ž„ ์ฐจ๋‹จ
์—ฐ์‚ฐ์ž ์˜ค๋ฒ„๋กœ๋”ฉposition + velocity * 2.0 ๋“ฑ ์ง๊ด€์  ๋ฒกํ„ฐยท์ƒ‰์ƒ ์—ฐ์‚ฐ
๋ฐ์ดํ„ฐ ํด๋ž˜์Šค / ๋ถˆ๋ณ€์„ฑํŒŒํ‹ฐํดยท์ƒํƒœ ๊ฐ์ฒด์˜ ์•ˆ์ „ํ•œ ๋ณต์‚ฌยท๋ณ€ํ˜•

6. ์š”์•ฝ: ํƒ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€์˜ ๋น„๊ต ์šฐ์œ„

๋น„๊ต ๋Œ€์ƒOPENRNDR๊ฐ€ ๋›ฐ์–ด๋‚œ ์ 
vs p5.js / ProcessingJVM ๊ธฐ๋ฐ˜์˜ ์••๋„์ ์ธ ์„ฑ๋Šฅ, ๊ณ ๊ธ‰ ์ƒ‰์ƒํ•™(OKLab/OKLCH), ์ž๋™ GUI ์ƒ์„ฑ(orx-gui), ํ˜„๋Œ€์  Kotlin DSL ๋ฌธ๋ฒ•, ์ •๋ฐ€ ๋ฒกํ„ฐ ์—ฐ์‚ฐ
vs openFrameworks (C++)CMake/C++ ์ปดํŒŒ์ผ ์ŠคํŠธ๋ ˆ์Šค ์—†์Œ, ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์•ˆ์ „์„ฑ(๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜), ๋น ๋ฅด๊ฒŒ ๋ถ™์ผ ์ˆ˜ ์žˆ๋Š” UIยทํ•„ํ„ฐ ์ฒด์ธ, ์…ฐ์ด๋” ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ตœ์†Œํ™”
vs Nannou (Rust)์ง„์ž… ์žฅ๋ฒฝ์ด ๋‚ฎ์Œ(Kotlin ํ•™์Šต ๊ณก์„  ์™„๋งŒ), ํฌ์ŠคํŠธ ํ”„๋กœ์„ธ์‹ฑ ๋ฐ ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ/SVG ๋ฒกํ„ฐ ๊ฐ€๊ณต ํˆด์…‹์ด ๋” ํ’๋ถ€, ORX ์ƒํƒœ๊ณ„์˜ ์„ฑ์ˆ™๋„

๊ฒฐ๋ก 

OPENRNDR๋Š” ํ”„๋กœํ† ํƒ€์ดํ•‘ ๋„๊ตฌ์ธ Processing๊ณผ, ์„ค์ • ๋ฐ ๋นŒ๋“œ ํ™˜๊ฒฝ์ด ๋ณต์žกํ•œ openFrameworks ์‚ฌ์ด์—์„œ ๊ธฐ์ˆ ์  ๊ท ํ˜•์„ ์ด๋ฃจ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.

  • ๊ฐ•๋ ฅํ•œ 2D/3D Vector Drawing API โ€” ์ •๋ฐ€ํ•œ ๊ธฐํ•˜ ์—ฐ์‚ฐ๊ณผ ํ•˜๋“œ์›จ์–ด ๊ฐ€์† ๋ Œ๋”๋ง
  • ํ•˜๋“œ์›จ์–ด ๊ฐ€์† ์…ฐ์ด๋” ์—”์ง„ โ€” ShadeStyle ๊ธฐ๋ฐ˜ ์ง๊ด€์  GLSL ํ†ตํ•ฉ
  • ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์›Œํฌํ”Œ๋กœ์šฐ โ€” CPU ๋ฒกํ„ฐ ์—ฐ์‚ฐ๊ณผ GPU ํ™”์†Œ ์—ฐ์‚ฐ์˜ ๊ฒฝ๊ณ„ ์—†๋Š” ๊ฒฐํ•ฉ
  • ์ŠคํŠœ๋””์˜ค๊ธ‰ ๊ฐ€๊ณตยท์ต์ŠคํฌํŠธ ๊ธฐ๋Šฅ โ€” SVG/PDF/ProRes/์˜คํ”„๋ผ์ธ ๋ Œ๋”๋ง๊นŒ์ง€ ์›์Šคํ†ฑ ์ฒ˜๋ฆฌ

์ด ๋ชจ๋“  ์š”์†Œ๋ฅผ ํ•˜๋‚˜์˜ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ํ†ตํ•ฉ ์ œ๊ณตํ•˜์—ฌ, ์ „๋ฌธ์ ์ธ ์ œ๋„ˆ๋ ˆ์ดํ‹ฐ๋ธŒ ์•„ํŠธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

profile
Coding Art with Blender / Three.js / p5.js / GLSL Shader / Processing / nannou

0๊ฐœ์˜ ๋Œ“๊ธ€