Skip to content

Commit 72ddc0c

Browse files
committed
v0.13.0 release
1 parent 2cf54a3 commit 72ddc0c

7 files changed

Lines changed: 87 additions & 42 deletions

File tree

README.md

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ Feel free to join the [Discord Server](https://discord.gg/GvsJj2Pk3K)!
4343
- [Creative Coding](https://fabmax.github.io/kool/kool-js/?demo=creative-coding): A few relatively simple demos
4444
showcasing different techniques of generating procedural geometry.
4545
- [Procedural Geometry](https://fabmax.github.io/kool/kool-js/?demo=procedural): Small test-case for
46-
procedural geometry; all geometry is generated in code (even the roses! Textures are regular images though). Also, some glass
47-
shading (shaft of the wine glass, the wine itself looks quite odd when shaded with refractions and is therefore opaque).
46+
procedural geometry; all geometry is generated in code (even the roses! Textures are regular images though). Also,
47+
some glass shading (shaft of the wine glass, the wine itself looks quite odd when shaded with refractions and is
48+
therefore opaque).
4849
- [glTF Models](https://fabmax.github.io/kool/kool-js/?demo=gltf): Various demo models loaded from glTF / glb format
4950
- Flight Helmet from [glTF sample models](https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/FlightHelmet)
5051
- Polly from [Blender](https://github.com/KhronosGroup/glTF-Blender-Exporter/tree/master/polly)
@@ -172,13 +173,13 @@ fun main() = KoolApplication { ctx ->
172173
}
173174

174175
// Load a glTF 2.0 model
175-
Assets.launch {
176+
launchOnMainThread {
176177
val materialCfg = GltfFile.ModelMaterialConfig(
177178
shadowMaps = listOf(shadowMap),
178179
scrSpcAmbientOcclusionMap = aoPipeline.aoMap
179180
)
180181
val modelCfg = GltfFile.ModelGenerateConfig(materialConfig = materialCfg)
181-
val model = loadGltfModel("path/to/model.glb", modelCfg)
182+
val model = Assets.loadGltfModel("path/to/model.glb", modelCfg)
182183

183184
model.transform.translate(0f, 0.5f, 0f)
184185
if (model.animations.isNotEmpty()) {
@@ -188,10 +189,8 @@ fun main() = KoolApplication { ctx ->
188189
}
189190
}
190191

191-
// Add model to scene, use RenderLoop coroutine context to make sure insertion happens at a safe time
192-
withContext(Dispatchers.RenderLoop) {
193-
addNode(model)
194-
}
192+
// Add loaded model to scene
193+
addNode(model)
195194
}
196195
}
197196
}
@@ -212,17 +211,18 @@ use the ambient occlusion and shadow maps we created before. Moreover, the shade
212211
attribute, but a simple pre-defined color (white in this case).
213212

214213
Finally, we want to load a glTF 2.0 model. Resources are loaded via the `Assets` object. Since resource loading is a
215-
potentially long-running operation we do that from within a coroutine launched with the asset manager:
216-
`Assets.launch { ... }`. By default, the built-in glTF parser creates shaders for all models it loads. The
214+
potentially long-running operation we do that from within a coroutine launched with `launchOnMainThread { ... }`.
215+
By default, the built-in glTF parser creates shaders for all models it loads. The
217216
created shaders can be customized via a provided material configuration, which we use to pass the shadow and
218217
ambient occlusion maps we created during light setup. After we created the custom model / material configuration
219-
we can load the model with `loadGltfModel("path/to/model.glb", modelCfg)`. This (suspending) function returns the
218+
we can load the model with `Assets.loadGltfModel("path/to/model.glb", modelCfg)`. This suspending function returns the
220219
loaded model, which can then be customized and inserted into the scene. Here we move the model 0.5 units along the
221220
y-axis (up). If the model contains any animations, these can be easily activated. This example checks whether there
222221
are any animations and if so activates the first one. The `model.onUpdate { }` block is executed on every frame and
223-
updates the enabled animation. The model is inserted into the scene with `addNode(model)`, however we do that from
224-
the `Dispatchers.RenderLoop` context to avoid threading issues (on JVM the asset loader coroutines run on a different
225-
thread than the render-loop).
222+
updates the enabled animation. The model is inserted into the scene with `addNode(model)`. Calling `addNode(model)`
223+
from within the coroutine is fine, since the coroutine is launched via `launchOnMainThread { ... }` and therefor
224+
is executed by the main render thread. If a different coroutine context / thread were used, we had to be careful to
225+
not modify the scene content while it is rendered.
226226

227227
The resulting scene looks like [this](https://fabmax.github.io/kool/kool-js/?demo=helloGltf). Here, the
228228
[Animated Box](https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/BoxAnimated) from the glTF sample
@@ -264,8 +264,6 @@ controlled by their `modifier`s.
264264

265265
Whenever the button is clicked we increment a `clickCount` which is then displayed by the text field. This works
266266
because the `Panel`-block is executed each time any `remember`ed state (or `mutableStateOf()`) within the block changes.
267-
The mechanics behind that are somewhat similar to how Jetpack-Compose works, although my implementation is much less
268-
sophisticated. On the plus-side we don't need a dedicated compiler-plugin and there is a bit less magic involved.
269267

270268
The resulting scene looks like [this](https://fabmax.github.io/kool/kool-js/?demo=hello-ui).
271269

@@ -274,15 +272,57 @@ More complex layouts can be created by nesting `Row { }` and `Column { }` object
274272

275273
## Kool Shader Language
276274

277-
I'm currently working on my own shader language (called ksl), which is implemented as a
275+
Kool comes with its own shader language (called ksl), which is implemented as a
278276
[Kotlin Type-safe builder / DSL](https://kotlinlang.org/docs/type-safe-builders.html). The ksl shader code you write is
279277
used to generate the actual GLSL shader code. The benefit with this approach is that there is no hard-coded GLSL
280278
code in common code, and it should be relatively easy to add different generators which generate shader code for
281279
different backends in the future (e.g. WGSL, or metal).
282280

283-
This is still work in progress. However, in case you are curious, you can take a look at
284-
[KslLitShader](kool-core/src/commonMain/kotlin/de/fabmax/kool/modules/ksl/KslLitShader.kt), which
285-
uses the new ksl approach (the interesting stuff happens in the `LitShaderModel` inner class).
281+
Writing shaders in ksl is very similar to GLSL, here's how a hello-world style shader looks like:
282+
283+
```kotlin
284+
fun main() = KoolApplication { ctx ->
285+
ctx.scenes += scene {
286+
defaultOrbitCamera()
287+
288+
addColorMesh {
289+
generate {
290+
cube {
291+
colored()
292+
}
293+
}
294+
shader = KslShader("Hello world shader") {
295+
val interStageColor = interStageFloat4()
296+
vertexStage {
297+
main {
298+
val mvp = mvpMatrix()
299+
val localPosition = float3Var(vertexAttribFloat3(Attribute.POSITIONS))
300+
outPosition set mvp.matrix * float4Value(localPosition, 1f.const)
301+
interStageColor.input set vertexAttribFloat4(Attribute.COLORS)
302+
}
303+
}
304+
fragmentStage {
305+
main {
306+
colorOutput(interStageColor.output)
307+
}
308+
}
309+
}
310+
}
311+
}
312+
}
313+
```
314+
The interesting part starts at `shader = KslShader() = { ... }`. Here a new shader is created and assigned to the mesh
315+
created before. If you ever wrote a shader before the structure should be familiar: The shader consists of a vertex
316+
stage (responsible for projecting the individual mesh vertices onto the screen) and a fragment stage (responsible
317+
for computing the output-color for each pixel covered by the mesh). This example shader is almost as simple as a valid
318+
shader can be: It uses a pre-multiplied MVP matrix to project the vertex position attribute to the screen. Moreover,
319+
the color attribute is taken from the vertex input and forwarded to the fragment shader via `interStageColor`. The
320+
fragment stage then simply takes the color from `interStageColor` and writes it to the screen.
321+
322+
A little more complex example is available in [HelloKsl](kool-demo/src/commonMain/kotlin/de/fabmax/kool/demo/helloworld/HelloKsl.kt),
323+
which looks like [this](https://fabmax.github.io/kool/kool-js/?demo=helloksl).
324+
Of course, shaders can get more complex than that, you can dig further into the code. All shaders currently used in kool
325+
are written in ksl.
286326

287327
## Physics Simulation
288328

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ buildscript {
1414

1515
allprojects {
1616
group = "de.fabmax.kool"
17-
version = "0.13.0-SNAPSHOT"
17+
version = "0.13.0"
1818

1919
repositories {
2020
mavenLocal()

kool-core/src/commonMain/kotlin/de/fabmax/kool/KoolContext.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,6 @@ abstract class KoolContext {
146146

147147
companion object {
148148
// automatically updated by gradle script on build
149-
const val KOOL_VERSION = "0.13.0-SNAPSHOT"
149+
const val KOOL_VERSION = "0.13.0"
150150
}
151151
}

kool-core/src/commonMain/kotlin/de/fabmax/kool/modules/ksl/blocks/GetLinearDepth.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ class GetLinearDepth(parentScope: KslScopeBuilder) :
1111
val camFar = paramFloat1("camFar")
1212

1313
body {
14-
val depthN = float1Var(2f.const * depth - 1f.const)
15-
return@body 2f.const * camNear * camFar / (camFar + camNear - depthN * (camFar - camNear))
14+
return@body camNear * camFar / (camFar - depth * (camFar - camNear))
1615
}
1716
}
1817

kool-demo/src/commonMain/kotlin/de/fabmax/kool/demo/helloworld/HelloGltf.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class HelloGltf : DemoScene("Hello glTF") {
6060
}
6161
}
6262

63+
// Add loaded model to scene
6364
addNode(model)
6465
}
6566
}

kool-demo/src/commonMain/kotlin/de/fabmax/kool/demo/helloworld/HelloWorld.kt

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ package de.fabmax.kool.demo.helloworld
22

33
import de.fabmax.kool.KoolContext
44
import de.fabmax.kool.demo.DemoScene
5-
import de.fabmax.kool.math.Vec3f
6-
import de.fabmax.kool.math.deg
7-
import de.fabmax.kool.modules.ksl.KslPbrShader
5+
import de.fabmax.kool.modules.ksl.KslShader
6+
import de.fabmax.kool.modules.ksl.blocks.mvpMatrix
7+
import de.fabmax.kool.modules.ksl.lang.times
8+
import de.fabmax.kool.pipeline.Attribute
9+
import de.fabmax.kool.pipeline.vertexAttribFloat3
10+
import de.fabmax.kool.pipeline.vertexAttribFloat4
811
import de.fabmax.kool.scene.Scene
912
import de.fabmax.kool.scene.addColorMesh
1013
import de.fabmax.kool.scene.defaultOrbitCamera
11-
import de.fabmax.kool.util.Color
12-
import de.fabmax.kool.util.Time
1314

1415
class HelloWorld : DemoScene("Hello World") {
1516
override fun Scene.setupMainScene(ctx: KoolContext) {
@@ -21,19 +22,23 @@ class HelloWorld : DemoScene("Hello World") {
2122
colored()
2223
}
2324
}
24-
shader = KslPbrShader {
25-
color { vertexColor() }
26-
metallic(0f)
27-
roughness(0.25f)
28-
}
29-
onUpdate {
30-
transform.rotate(45f.deg * Time.deltaT, Vec3f.X_AXIS)
31-
}
32-
}
25+
shader = KslShader("Hello world shader") {
26+
val interStageColor = interStageFloat4()
3327

34-
lighting.singleDirectionalLight {
35-
setup(Vec3f(-1f, -1f, -1f))
36-
setColor(Color.WHITE, 5f)
28+
vertexStage {
29+
main {
30+
val mvp = mvpMatrix()
31+
val localPosition = float3Var(vertexAttribFloat3(Attribute.POSITIONS))
32+
outPosition set mvp.matrix * float4Value(localPosition, 1f.const)
33+
interStageColor.input set vertexAttribFloat4(Attribute.COLORS)
34+
}
35+
}
36+
fragmentStage {
37+
main {
38+
colorOutput(interStageColor.output)
39+
}
40+
}
41+
}
3742
}
3843
}
3944
}

kool-demo/src/commonMain/kotlin/de/fabmax/kool/demo/physics/terrain/OceanShader.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ object OceanShader {
182182

183183
// 2nd depth sample - water depth at refracted position
184184
val oceanDepth2 = float1Var(sampleTexture(texture2d("tOceanFloorDepth"), refractUv).x)
185-
oceanDepth2 set getLinearDepth(oceanDepth2, camData.clipNear, camData.clipFar) - fragDepth
185+
oceanDepth2 set getLinearDepth(oceanDepth2, OceanFloorRenderPass.DEPTH_CAM_NEAR.const, OceanFloorRenderPass.DEPTH_CAM_FAR.const) - fragDepth
186186

187187
`if`(oceanDepth2 lt 0f.const) {
188188
// we hit something which above water surface, use original uv as fallback

0 commit comments

Comments
 (0)