commonMain.functions.SDF.kt Maven / Gradle / Ivy
The newest version!
package org.openrndr.orsl.extension.sdf.functions
import org.openrndr.draw.Struct
import org.openrndr.orsl.shadergenerator.dsl.FunctionSymbol1
import org.openrndr.orsl.shadergenerator.dsl.ShaderBuilder
import org.openrndr.orsl.shadergenerator.dsl.Symbol
import org.openrndr.orsl.shadergenerator.dsl.functions.Functions
import org.openrndr.orsl.shadergenerator.dsl.staticType
import org.openrndr.orsl.shadergenerator.dsl.structs.getValue
import org.openrndr.orsl.shadergenerator.dsl.structs.setValue
import org.openrndr.math.Vector3
class MarchResult : Struct() {
var position by field()
var hit by field()
var travel by field()
var normal by field()
}
var Symbol.position by MarchResult::position
var Symbol.hit by MarchResult::hit
var Symbol.travel by MarchResult::travel
var Symbol.normal by MarchResult::normal
fun ShaderBuilder.march(
scene: (x: Symbol) -> FunctionSymbol1,
iterations: Int = 300,
tolerance: Double = 1E-2,
stepScale: Double = 0.5
) = Functions.Function2PropertyProvider(
true,
this@march, staticType(),
staticType(),
staticType()
) { origin, direction ->
val result by MarchResult()
val False by false
val True by true
result.hit = False
var position by variable(origin)
val i by variable()
i.for_(0 until iterations) {
val distance by scene(position)
doIf(abs(distance) lt tolerance) {
result.hit = True
result.position = position
break_()
}
position += direction * distance * stepScale
}
result
}
fun ShaderBuilder.calcAO(
scene: (x: Symbol) -> FunctionSymbol1,
iterations: Int = 5,
bias: Double = 0.01,
distance: Double = 0.15,
falloff : Double = 0.95,
intensity: Double = 1.5
): Functions.Function2PropertyProvider {
return Functions.Function2PropertyProvider(true,
this@calcAO, staticType(),
staticType(),
staticType()
) { origin, direction ->
var occ by variable(0.0)
var sca by variable(1.0)
val i by variable(0)
i.for_(0 until iterations) {
val h by bias + distance * (i / (iterations - 1.0))
val d by scene(origin + h * direction)
occ += (h - d) * sca
sca *= falloff
}
saturate(1.0 - intensity * occ)
}
}
fun ShaderBuilder.calcSoftShadow(
scene: (x: Symbol) -> FunctionSymbol1,
iterations: Int = 32,
): Functions.Function4PropertyProvider {
return Functions.Function4PropertyProvider(
true,
this@calcSoftShadow, staticType(),
staticType(),
staticType(),
staticType(),
staticType()
) { origin, direction, mint, tmax ->
var res by variable(1.0)
var t by variable(mint)
var ph by variable(1E10)
val i by variable(0)
i.for_(0 until iterations) {
val h by scene(origin + direction * t)
val y by h * h / (2.0 * ph)
val d by sqrt(h * h - y * y);
res = min(res, 10.0 * d / max(0.0, t - y));
ph = h
doIf(res lt 0.0001 or (t gt tmax)) {
break_()
}
t += h
}
res = saturate(res)
res * res * (3.0 - 2.0 * res)
}
}
fun ShaderBuilder.calcShadow(
scene: (x: Symbol) -> FunctionSymbol1,
iterations: Int = 32,
): Functions.Function4PropertyProvider {
return Functions.Function4PropertyProvider(
true, this@calcShadow, staticType(),
staticType(),
staticType(),
staticType(),
staticType()
) { origin, direction, mint, tmax ->
var res by variable(1.0)
var t by variable(mint)
val i by variable(0)
i.for_(0 until iterations) {
val h by scene(origin + direction * t)
doIf(h lt 1E-4) {
val z by 0.0
res = z
break_()
}
doIf((t gt tmax)) {
break_()
}
t += h * 0.5
}
res
}
}