Skip to content

Commit 0884936

Browse files
committed
v0.18.0
1 parent f30ebd1 commit 0884936

File tree

4 files changed

+77
-64
lines changed

4 files changed

+77
-64
lines changed

README.md

Lines changed: 58 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# kool - A Vulkan / WebGPU / OpenGL graphics engine written in Kotlin
22
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/kool-engine/kool/blob/master/LICENSE)
3-
[![Maven Central](https://img.shields.io/maven-central/v/de.fabmax.kool/kool-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22de.fabmax.kool%22%20AND%20a:%22kool-core%22)
3+
[![Maven Central](https://img.shields.io/maven-central/v/de.fabmax.kool/kool-core.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/de.fabmax.kool/kool-core)
44
![Build](https://github.com/kool-engine/kool/workflows/Build/badge.svg)
55

66
A multi-platform Vulkan / WebGPU / OpenGL game engine that works on Desktop Java, Android and browsers.
@@ -87,15 +87,22 @@ More editor related documentation is available in [the editor docs](https://kool
8787
| Platform | Backend | Implementation Status |
8888
|-------------|-------------|---------------------------------------------------------|
8989
| Desktop JVM | OpenGL | :white_check_mark: Fully working |
90-
| Desktop JVM | Vulkan | :white_check_mark: Fully working (v0.17.0-SNAPSHOT) |
90+
| Desktop JVM | Vulkan | :white_check_mark: Fully working |
91+
| Desktop JVM | WebGPU | :sparkles: Mostly working (using the `wgpu4k` backend) |
9192
| Browser | WebGL 2 | :white_check_mark: Fully working |
9293
| Browser | WebGPU | :white_check_mark: Fully working |
9394
| Android | OpenGL ES 3 | :sparkles: kool-core fully working (but no physics yet) |
9495

9596
**Supported desktop platforms are:**
96-
- Windows (x64): Vulkan and OpenGL
97-
- Linux (x64): Vulkan and OpenGL
98-
- macOS (ARM + x64): Vulkan only
97+
- Windows (x64): Vulkan, WebGPU and OpenGL
98+
- Linux (x64): Vulkan, WebGPU and OpenGL
99+
- macOS (ARM + x64): Vulkan and WebGPU (no OpenGL)
100+
101+
### Java Version
102+
103+
On Desktop, Kool currently uses Java 17 as the minimum language level except the `kool-backend-wgpu4k` module, which
104+
requires Java 22 (because it uses [Project Panama](https://openjdk.org/projects/panama/) features under the hood, which
105+
became stable in Java 22). In case Java 22 is a problem for you, you can exclude `kool-backend-wgpu4k` from the project.
99106

100107
### Android Support
101108

@@ -118,12 +125,12 @@ repositories {
118125
maven("https://oss.sonatype.org/content/repositories/snapshots")
119126
}
120127
dependencies {
121-
implementation("de.fabmax.kool:kool-core:0.17.0")
122-
implementation("de.fabmax.kool:kool-physics:0.17.0")
128+
implementation("de.fabmax.kool:kool-core:0.18.0")
129+
implementation("de.fabmax.kool:kool-physics:0.18.0")
123130
}
124131
```
125132

126-
There is also a separate repo containing a minimal template project to get you started:
133+
There is also a separate repo containing minimal template projects to get you started:
127134

128135
[https://github.com/kool-engine/kool-templates](https://github.com/kool-engine/kool-templates)
129136

@@ -166,6 +173,7 @@ the libs are resolved and added to the IntelliJ module classpath.
166173
- Lighting with multiple point, spot and directional lights
167174
- Shadow mapping for multiple light sources (only spot and directional lights for now)
168175
- Basic audio support
176+
- Decoupled frontend (i.e., game-logic) and backend (i.e., rendering) threads
169177

170178
## A Hello World Example
171179

@@ -209,9 +217,9 @@ X-axis.
209217
Finally, we set up a single directional scene light (of white color and an intensity of 5), so that our cube can shine
210218
in its full glory. The resulting scene looks like [this](https://kool-engine.github.io/live/demos/?demo=helloWorld).
211219

212-
## Model Loading and Advanced Lighting
220+
## Texture & Model Loading and Advanced Lighting
213221

214-
Model loading, animation and more advanced lighting with shadow mapping and ambient occlusion requires only a few more
222+
Asset loading, animation and more advanced lighting with shadow mapping and ambient occlusion require only a few more
215223
lines of code:
216224
```kotlin
217225
fun main() = KoolApplication {
@@ -226,42 +234,41 @@ fun main() = KoolApplication {
226234
val shadowMap = SimpleShadowMap(this, lighting.lights[0])
227235
val aoPipeline = AoPipeline.createForward(this)
228236

229-
// Add a ground plane
230-
addColorMesh {
237+
// Add a textured ground plane
238+
val texture = Assets.loadTexture2d("path/to/texture.png").getOrThrow()
239+
addTextureMesh {
231240
generate {
232241
grid { }
233242
}
234243
shader = KslPbrShader {
235-
color { constColor(Color.WHITE) }
244+
color { textureColor(texture) }
236245
lighting { addShadowMap(shadowMap) }
237246
enableSsao(aoPipeline.aoMap)
238247
}
239248
}
240249

241250
// Load a glTF 2.0 model
242-
coroutineScope.launch {
243-
val materialCfg = GltfMaterialConfig(
244-
shadowMaps = listOf(shadowMap),
245-
scrSpcAmbientOcclusionMap = aoPipeline.aoMap
246-
)
247-
val modelCfg = GltfLoadConfig(materialConfig = materialCfg)
248-
val model = Assets.loadGltfModel("path/to/model.glb", modelCfg).getOrThrow()
249-
250-
model.transform.translate(0f, 0.5f, 0f)
251-
if (model.animations.isNotEmpty()) {
252-
model.enableAnimation(0)
253-
model.onUpdate {
254-
model.applyAnimation(Time.deltaT)
255-
}
251+
val materialCfg = GltfMaterialConfig(
252+
shadowMaps = listOf(shadowMap),
253+
scrSpcAmbientOcclusionMap = aoPipeline.aoMap
254+
)
255+
val modelCfg = GltfLoadConfig(materialConfig = materialCfg)
256+
val model = Assets.loadGltfModel("path/to/model.glb", modelCfg).getOrThrow()
257+
258+
model.transform.translate(0f, 0.5f, 0f)
259+
if (model.animations.isNotEmpty()) {
260+
model.enableAnimation(0)
261+
model.onUpdate {
262+
model.applyAnimation(Time.deltaT)
256263
}
257-
258-
// Add loaded model to scene
259-
addNode(model)
260264
}
265+
266+
// Add loaded model to scene
267+
addNode(model)
261268
}
262269
}
263270
```
264-
First we set up the lighting. This is very similar to the previous example but this time we use a spot-light, which
271+
First we set up the lighting. This is very similar to the previous example, but this time we use a spot-light, which
265272
requires a position, direction and opening angle. Other than directional lights, point and spot-lights have a distinct
266273
(point-) position and objects are affected less by them, the farther they are away. This usually results in a much
267274
higher required light intensity: Here we use an intensity of 300.
@@ -270,29 +277,31 @@ Next we create a `SimpleShadowMap` which computes the shadows cast by the light
270277
Moreover, the created `AoPipeline` computes an ambient occlusion map, which is later used by the shaders to
271278
further improve the visual appearance of the scene.
272279

273-
After light setup we can add objects to our scene. First we generate a grid mesh as ground plane. Default size and
274-
position of the generated grid are fine, therefore `grid { }` does not need any more configuration. Similar to the
280+
After light setup we can add objects to our scene. First, we load a texture that we are going to use as a ground plane.
281+
Textures and all other resources are loaded via the `Assets` API. Asset loading functions are suspending and return a
282+
`Result` object, which can be used to check whether the loading was successful. In this case we use the `getOrThrow()`
283+
function to throw an exception if the loading failed.
284+
285+
To draw the texture, we need to generate a mesh where the texture is put on. We add that by calling
286+
`addTextureMesh { }` and generate a grid geometry in it. Default size and position of the generated grid are fine for
287+
our ground plane, therefore `grid { }` does not need any more configuration. Similar to the
275288
color cube from the previous example, the ground plane uses a PBR shader. However, this time we tell the shader to
276289
use the ambient occlusion and shadow maps we created before. Moreover, the shader should not use the vertex color
277290
attribute, but a simple pre-defined color (white in this case).
278291

279-
Finally, we want to load a glTF 2.0 model. Resources are loaded via the `Assets` object. Since resource loading
280-
functions suspend until the resource is loaded (or loading has failed), we need to launch a coroutine, which does
281-
the model loading. We do that using the scene's own `coroutineScioe`, which makes sure that the loading runs in sync
282-
with the render loop (by using `KoolDispatchers.Frontend`) so that we can directly add our loaded model to the scene
283-
after it is loaded.
292+
Notice we used add**Texture**Mesh here instead of the add**Color**Mesh from before. `addColorMesh`
293+
and `addTextureMesh` are convenience functions which create and add meshes with all the mesh attributes needed for their
294+
respective purpose. It is also possible to create completely custom meshes with arbitrary attributes, but that is
295+
out-of-scope for this basic example.
284296

285-
By default, the built-in glTF parser creates shaders for all models it loads. The
286-
created shaders can be customized via a provided material configuration, which we use to pass the shadow and
297+
Finally, we want to load a glTF 2.0 model. By default, the built-in glTF parser creates shaders for all models it loads.
298+
The created shaders can be customized via a provided material configuration, which we use to pass the shadow and
287299
ambient occlusion maps we created during light setup. After we created the custom model / material configuration
288300
we can load the model with `Assets.loadGltfModel("path/to/model.glb", modelCfg)`. This suspending function returns the
289301
loaded model, which can then be customized and inserted into the scene. Here we move the model 0.5 units along the
290302
y-axis (up). If the model contains any animations, these can be easily activated. This example checks whether there
291303
are any animations and if so activates the first one. The `model.onUpdate { }` block is executed on every frame and
292-
updates the enabled animation. The model is inserted into the scene with `addNode(model)`. Calling `addNode(model)`
293-
from within the coroutine is fine, since the coroutine is launched via `launchOnMainThread { ... }` and therefor
294-
is executed by the main render thread. If a different coroutine context / thread were used, we had to be careful to
295-
not modify the scene content while it is rendered.
304+
updates the enabled animation. The model is inserted into the scene with `addNode(model)`.
296305

297306
The resulting scene looks like [this](https://kool-engine.github.io/live/demos/?demo=helloGltf). Here, the
298307
[Animated Box](https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/BoxAnimated) from the glTF sample
@@ -344,7 +353,7 @@ More complex layouts can be created by nesting `Row { }` and `Column { }` object
344353
[kool editor](https://kool-engine.github.io/live/kool-editor/) as well as the
345354
[full UI demo](https://kool-engine.github.io/live/demos/?demo=ui) should give you an impression on what's possible.
346355

347-
## Kool Shader Language
356+
## Kool Shader DSL
348357

349358
Kool comes with its own shader language (called ksl), which is implemented as a
350359
[Kotlin Type-safe builder / DSL](https://kotlinlang.org/docs/type-safe-builders.html). The ksl shader code you write is
@@ -386,8 +395,8 @@ fun main() = KoolApplication {
386395
}
387396
}
388397
```
389-
The interesting part starts at `shader = KslShader() = { ... }`. Here a new shader is created and assigned to the mesh
390-
created before. If you ever wrote a shader before the structure should be familiar: The shader consists of a vertex
398+
The interesting part starts at `shader = KslShader() = { ... }`. Here, a new shader is created and assigned to the mesh
399+
created before. If you ever wrote a shader before, the structure should be familiar: The shader consists of a vertex
391400
stage (responsible for projecting the individual mesh vertices onto the screen) and a fragment stage (responsible
392401
for computing the output-color for each pixel covered by the mesh). This example shader is almost as simple as a valid
393402
shader can be: It uses a pre-multiplied MVP matrix to project the vertex position attribute to the screen. Moreover,
@@ -404,8 +413,8 @@ are written in ksl.
404413
After playing around with various different engines on javascript and JVM I came to the
405414
conclusion that all of them had some kind of flaw. So I decided to write my own bindings for
406415
[Nvidia PhysX](https://github.com/NVIDIA-Omniverse/PhysX): [physx-jni](https://github.com/fabmax/physx-jni) for JVM, and
407-
[physx-js-webidl](https://github.com/fabmax/physx-js-webidl) for javascript.
416+
[physx-js-webidl](https://github.com/fabmax/physx-js-webidl) for JavaScript.
408417

409418
This was quite a bit of work, but I think it was worth it: By writing my own bindings
410-
I get the features I need, and, even better, I get the same features for javascript and JVM, which makes the
419+
I get the features I need, and, even better, I get the same features for JavaScript and JVM, which makes the
411420
multiplatform approach much easier.

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ plugins {
88

99
allprojects {
1010
group = "de.fabmax.kool"
11-
version = "0.18.0-SNAPSHOT"
11+
version = "0.18.0"
1212
}
1313

1414
tasks.register<UnCommentTask>("disableAndroidPlatform") {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,6 @@ abstract class KoolContext {
126126
}
127127

128128
companion object {
129-
const val KOOL_VERSION = "0.18.0-SNAPSHOT"
129+
const val KOOL_VERSION = "0.18.0"
130130
}
131131
}

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

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import de.fabmax.kool.Assets
44
import de.fabmax.kool.KoolContext
55
import de.fabmax.kool.demo.DemoLoader
66
import de.fabmax.kool.demo.DemoScene
7+
import de.fabmax.kool.loadTexture2d
78
import de.fabmax.kool.math.Vec3f
89
import de.fabmax.kool.math.deg
910
import de.fabmax.kool.modules.gltf.GltfLoadConfig
@@ -12,11 +13,12 @@ import de.fabmax.kool.modules.gltf.loadGltfModel
1213
import de.fabmax.kool.modules.ksl.KslPbrShader
1314
import de.fabmax.kool.pipeline.ao.AoPipeline
1415
import de.fabmax.kool.scene.Scene
15-
import de.fabmax.kool.scene.addColorMesh
16+
import de.fabmax.kool.scene.addTextureMesh
1617
import de.fabmax.kool.scene.defaultOrbitCamera
1718
import de.fabmax.kool.util.Color
1819
import de.fabmax.kool.util.SimpleShadowMap
1920
import de.fabmax.kool.util.Time
21+
import de.fabmax.kool.util.releaseWith
2022
import kotlinx.coroutines.launch
2123

2224
class HelloGltf : DemoScene("Hello glTF") {
@@ -31,20 +33,22 @@ class HelloGltf : DemoScene("Hello glTF") {
3133
val shadowMap = SimpleShadowMap(this, lighting.lights[0])
3234
val aoPipeline = AoPipeline.createForward(this)
3335

34-
// Add a ground plane
35-
addColorMesh {
36-
generate {
37-
grid { }
38-
}
39-
shader = KslPbrShader {
40-
color { constColor(Color.WHITE) }
41-
lighting { addShadowMap(shadowMap) }
42-
enableSsao(aoPipeline.aoMap)
36+
coroutineScope.launch {
37+
// Add a ground plane
38+
val texture = Assets.loadTexture2d("${DemoLoader.materialPath}/kool-test-tex.png").getOrThrow()
39+
texture.releaseWith(this@setupMainScene)
40+
addTextureMesh {
41+
generate {
42+
grid { }
43+
}
44+
shader = KslPbrShader {
45+
color { textureColor(texture) }
46+
lighting { addShadowMap(shadowMap) }
47+
enableSsao(aoPipeline.aoMap)
48+
}
4349
}
44-
}
4550

46-
// Load a glTF 2.0 model
47-
coroutineScope.launch {
51+
// Load a glTF 2.0 model
4852
val materialCfg = GltfMaterialConfig(
4953
shadowMaps = listOf(shadowMap),
5054
scrSpcAmbientOcclusionMap = aoPipeline.aoMap

0 commit comments

Comments
 (0)