From f828f86e290f1a359c8b73a49337534ac3eb7cb3 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 27 Jan 2022 12:10:00 +0300 Subject: [PATCH] Replace light model for 3ds --- CHANGELOG.md | 2 + build.gradle.kts | 2 +- .../src/main/kotlin/JsPlaygroundApp.kt | 7 +- .../src/main/kotlin/gravityDemo.kt | 12 ++- .../mipt/npm/muon/monitor/MMAppComponent.kt | 7 +- .../kscience/visionforge/solid/demo/demo.kt | 7 +- .../tutorial-solids.md} | 54 ++++++------- .../ThreeViewWithControls.kt | 4 + .../visionforge/solid/OrbitControls.kt | 2 +- .../kscience/visionforge/solid/LightSource.kt | 44 +++++++++++ .../kscience/visionforge/solid/SolidGroup.kt | 4 +- .../visionforge/solid/SolidMaterial.kt | 21 ++++- .../kscience/visionforge/solid/Solids.kt | 3 + .../specifications/{Axes.kt => AxesScheme.kt} | 10 +-- .../{Camera.kt => CameraScheme.kt} | 18 ++--- .../solid/specifications/Canvas3DOptions.kt | 69 +++++++--------- .../{Controls.kt => ControlsScheme.kt} | 4 +- .../visionforge/solid/specifications/Light.kt | 8 -- .../solid/specifications/PointScheme.kt | 19 +++++ .../visionforge/solid/SerializationTest.kt | 15 ++++ .../solid/three/MeshThreeFactory.kt | 2 + .../solid/three/ThreeAmbientLightFactory.kt | 19 +++++ .../visionforge/solid/three/ThreeCanvas.kt | 49 +++++++----- .../visionforge/solid/three/ThreeFactory.kt | 3 +- .../visionforge/solid/three/ThreeMaterials.kt | 78 ++++++++++++------- .../visionforge/solid/three/ThreePlugin.kt | 6 +- .../solid/three/ThreePointLightFactory.kt | 28 +++++++ 27 files changed, 340 insertions(+), 157 deletions(-) rename docs/{tutorial.md => tutorials/tutorial-solids.md} (91%) create mode 100644 visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt rename visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/{Axes.kt => AxesScheme.kt} (79%) rename visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/{Camera.kt => CameraScheme.kt} (77%) rename visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/{Controls.kt => ControlsScheme.kt} (56%) delete mode 100644 visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Light.kt create mode 100644 visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/PointScheme.kt create mode 100644 visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeAmbientLightFactory.kt create mode 100644 visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePointLightFactory.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ffcb3c9..d2cf0882 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Added ### Changed +- Naming of Canvas3D options +- Lights are added to the scene instead of 3D options ### Deprecated diff --git a/build.gradle.kts b/build.gradle.kts index 0f892c76..0cd9f7da 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ val fxVersion by extra("11") allprojects{ group = "space.kscience" - version = "0.2.0" + version = "0.2.1-dev-1" } subprojects { diff --git a/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt b/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt index a1ffa4ff..5e09911b 100644 --- a/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt +++ b/demo/js-playground/src/main/kotlin/JsPlaygroundApp.kt @@ -1,6 +1,5 @@ import kotlinx.browser.document import kotlinx.css.* -import react.child import react.dom.render import ringui.SmartTabs import ringui.Tab @@ -8,6 +7,7 @@ import space.kscience.dataforge.context.Context import space.kscience.plotly.models.Trace import space.kscience.plotly.scatter import space.kscience.visionforge.Application +import space.kscience.visionforge.Colors import space.kscience.visionforge.VisionClient import space.kscience.visionforge.plotly.PlotlyPlugin import space.kscience.visionforge.ring.ThreeCanvasWithControls @@ -48,7 +48,7 @@ private class JsPlaygroundApp : Application { } SmartTabs("gravity") { Tab("gravity") { - GravityDemo{ + GravityDemo { attrs { this.context = playgroundContext } @@ -73,6 +73,9 @@ private class JsPlaygroundApp : Application { attrs { context = playgroundContext solid { + ambientLight { + color(Colors.white) + } repeat(100) { sphere(5, name = "sphere[$it]") { x = random.nextDouble(-300.0, 300.0) diff --git a/demo/js-playground/src/main/kotlin/gravityDemo.kt b/demo/js-playground/src/main/kotlin/gravityDemo.kt index 716cc2c3..4d420cc7 100644 --- a/demo/js-playground/src/main/kotlin/gravityDemo.kt +++ b/demo/js-playground/src/main/kotlin/gravityDemo.kt @@ -7,6 +7,7 @@ import react.fc import space.kscience.dataforge.context.Context import space.kscience.plotly.layout import space.kscience.plotly.models.Trace +import space.kscience.visionforge.Colors import space.kscience.visionforge.markup.VisionOfMarkup import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.ring.ThreeCanvasWithControls @@ -21,10 +22,10 @@ external interface DemoProps : Props { } val GravityDemo = fc { props -> - val velocityTrace = Trace{ + val velocityTrace = Trace { name = "velocity" } - val energyTrace = Trace{ + val energyTrace = Trace { name = "energy" } val markup = VisionOfMarkup() @@ -41,6 +42,11 @@ val GravityDemo = fc { props -> attrs { context = props.context solid { + pointLight(200, 200, 200, name = "light"){ + color(Colors.white) + } + ambientLight() + sphere(5.0, "ball") { detail = 16 color("red") @@ -91,7 +97,7 @@ val GravityDemo = fc { props -> height = 50.vh - 50.pt } plotly { - traces(velocityTrace,energyTrace) + traces(velocityTrace, energyTrace) layout { xaxis.title = "time" } diff --git a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt index 558317cb..350d25f3 100644 --- a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt +++ b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt @@ -17,12 +17,13 @@ import react.fc import react.useMemo import react.useState import space.kscience.dataforge.context.Context +import space.kscience.dataforge.meta.invoke import space.kscience.dataforge.names.Name import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.ring.ThreeCanvasWithControls import space.kscience.visionforge.ring.tab -import space.kscience.visionforge.solid.specifications.Camera +import space.kscience.visionforge.solid.ambientLight import space.kscience.visionforge.solid.specifications.Canvas3DOptions import space.kscience.visionforge.solid.three.edges import styled.css @@ -42,17 +43,19 @@ val MMApp = fc("Muon monitor") { props -> val mmOptions = useMemo { Canvas3DOptions { - camera = Camera { + camera { distance = 2100.0 latitude = PI / 6 azimuth = PI + PI / 6 } + } } val root = useMemo(props.model) { props.model.root.apply { edges() + ambientLight() } } diff --git a/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt b/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt index a0ab9273..5631de56 100644 --- a/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt +++ b/demo/solid-showcase/src/commonMain/kotlin/space/kscience/visionforge/solid/demo/demo.kt @@ -18,7 +18,11 @@ fun VisionLayout.demo(name: String, title: String = name, block: SolidGro val meta = Meta { "title" put title } - val vision = SolidGroup(block) + val vision = SolidGroup(block).apply { + ambientLight{ + color(Colors.white) + } + } render(Name.parse(name), vision, meta) } @@ -39,6 +43,7 @@ val canvasOptions = Canvas3DOptions { @OptIn(DelicateCoroutinesApi::class) fun VisionLayout.showcase() { demo("shapes", "Basic shapes") { + ambientLight() box(100.0, 100.0, 100.0) { z = -110.0 color("teal") diff --git a/docs/tutorial.md b/docs/tutorials/tutorial-solids.md similarity index 91% rename from docs/tutorial.md rename to docs/tutorials/tutorial-solids.md index 8989bd49..2b1e7b57 100644 --- a/docs/tutorial.md +++ b/docs/tutorials/tutorial-solids.md @@ -59,7 +59,7 @@ box(10, 10, 10, name = "small box"){ rotation = Point3D(0, 0, 0) } ``` -![](../docs/images/small-box.png) +![](../images/small-box.png) The `big box` will have properties with custom values. ```kotlin @@ -72,7 +72,7 @@ box(40, 40, 40, name = "big box"){ rotation = Point3D(60, 80, 0) } ``` -![](../docs/images/big-rotated-box.png) +![](../images/big-rotated-box.png) If we compare these boxes, we will see all differences. Here is the function `main` with both boxes. @@ -111,8 +111,8 @@ fun main(){ } } ``` -![](../docs/images/two-boxes-1.png) -![](../docs/images/two-boxes-2.png) +![](../images/two-boxes-1.png) +![](../images/two-boxes-2.png) ***There is plenty of other properties, especially those, which you can create by yourself. Here we mention just a small part.*** @@ -142,8 +142,8 @@ polyline(Point3D(30, 20, 10), Point3D(30, -100, 30), Point3D(30, -100, 30), Poin } ``` -![](../docs/images/polyline-points.png) -![](../docs/images/polyline-points-2.png) +![](../images/polyline-points.png) +![](../images/polyline-points-2.png) ### 2) Box @@ -165,7 +165,7 @@ Let's create just usual `box` with equal ribs. color("pink") } ``` - ![](../docs/images/box.png) + ![](../images/box.png) Now, let's make `box` with bigger `y` value. ```kotlin @@ -175,7 +175,7 @@ Now, let's make `box` with bigger `y` value. ``` As you can see, only the rib of `y-axis` differs from other ribs. - ![](../docs/images/high-box.png) + ![](../images/high-box.png) For a final trial, let's create a `box` with a bigger `x` value. @@ -189,7 +189,7 @@ For a final trial, let's create a `box` with a bigger `x` value. ``` Predictably, only the `x-axis` rib is bigger than other ribs. - ![](../docs/images/wide-box.png) + ![](../images/wide-box.png) ### 3) Sphere @@ -206,7 +206,7 @@ As for `radius`, it has `Float` type, and, as you can guess, it sets the radius color("blue") } ``` - ![](../docs/images/sphere.png) + ![](../images/sphere.png) ### 4) Hexagon @@ -220,7 +220,7 @@ It is solid which has six edges. It is set by eight values: `node1`,..., `node8` 5) Edge with vertices `node1`, `node5`, `node8`, `node4` 6) Edge with vertices `node8`, `node5`, `node6`, `node7` -![](../docs/images/scheme.png) +![](../images/scheme.png) As the hexagon takes in specific points, we understand that this solid cannot be moved, it is fixed in space, and it can't make pivots. @@ -239,7 +239,7 @@ Let's make classic parallelepiped. color("green") } ``` - ![](../docs/images/classic-hexagon.png) + ![](../images/classic-hexagon.png) Now, let's make a custom hexagon. @@ -258,7 +258,7 @@ hexagon( color("brown") } ``` - ![](../docs/images/custom-hexagon.png) + ![](../images/custom-hexagon.png) ### 3) Cone It takes in six values: `bottomRadius`, `height`, `upperRadius`, `startAngle`, `angle`, and `name`. @@ -274,8 +274,8 @@ Let's build a classic cone: color("beige") } ``` - ![](../docs/images/cone-1.png) - ![](../docs/images/cone-2.png) + ![](../images/cone-1.png) + ![](../images/cone-2.png) First of all, we have to try to build a frustum cone: ```kotlin @@ -283,7 +283,7 @@ cone(60, 80, name = "cone") { color(0u, 40u, 0u) } ``` -![](../docs/images/frustum-cone.png) +![](../images/frustum-cone.png) Now, we need to make a try to build a cone segment: @@ -292,8 +292,8 @@ cone(60, 80, angle = PI, name = "cone") { color(0u, 0u, 200u) } ``` -![](../docs/images/cone-segment-1.png) -![](../docs/images/cone-segment-2.png) +![](../images/cone-segment-1.png) +![](../images/cone-segment-2.png) Finally, the segment of frustum cone is left for a try: ```kotlin @@ -301,7 +301,7 @@ cone(60, 100, 20, PI*3/4, angle = PI/3, name = "cone") { color(190u, 0u, 0u) } ``` -![](../docs/images/frustum-cone-segment.png) +![](../images/frustum-cone-segment.png) ### 4) Cone Surface This solid is set by seven values:`bottomOuterRadius`, `bottomInnerRadius`, `height`, `topOuterRadius`, `topInnerRadius`, `startAngle`, and `angle`. @@ -318,8 +318,8 @@ Let's build usual cone surface with almost all properties set: rotation = Point3D(2, 50, -9) } ``` -![](../docs/images/cone-surface-1.png) -![](../docs/images/cone-surface-2.png) +![](../images/cone-surface-1.png) +![](../images/cone-surface-2.png) Now, let's create a cone surface and set all it's properties: @@ -329,8 +329,8 @@ coneSurface(30, 25, 10, 10, 8,0f, pi*3/4, name = "cone surface") { rotation = Point3D(2, 50, -9) } ``` -![](../docs/images/cone-surface-fragment.png) -![](../docs/images/cone-surface-fragment-2.png) +![](../images/cone-surface-fragment.png) +![](../images/cone-surface-fragment-2.png) ### 5) Cylinder @@ -344,8 +344,8 @@ cylinder(40, 100, "cylinder"){ color("indigo") } ``` -![](../docs/images/cylinder-1.png) -![](../docs/images/cylinder-2.png) +![](../images/cylinder-1.png) +![](../images/cylinder-2.png) ### 6) Tube `tube` takes in `radius`, `height`, `innerRadius`, `startAngle`, `angle`, and `name`. *All values are familiar from `cone`, and `coneSurface` solids.* @@ -356,7 +356,7 @@ tube(50, 40, 20, name = "usual tube"){ opacity = 0.4 } ``` -![](../docs/images/tube.png) +![](../images/tube.png) This is an example of tube fragment: @@ -365,7 +365,7 @@ tube(50, 40, 20, 0f, PI, name = "fragmented tube"){ color("white") } ``` -![](../docs/images/tube-fragment.png) +![](../images/tube-fragment.png) ### 7) Extruded `extruded` is set by two values: `shape`, and `layer`. diff --git a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt index 5cdcf5c0..fa3fab99 100644 --- a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt +++ b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ThreeViewWithControls.kt @@ -38,6 +38,10 @@ public fun ThreeCanvasWithControlsProps.solid(block: SolidGroup.() -> Unit) { } } +public fun ThreeCanvasWithControlsProps.options(block: Canvas3DOptions.() -> Unit){ + options = Canvas3DOptions(block) +} + public fun ThreeCanvasWithControlsProps.tab(title: String, block: RBuilder.() -> Unit) { additionalTabs = (additionalTabs ?: emptyMap()) + (title to block) } diff --git a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt index 2fe573e0..9c4ab664 100644 --- a/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt +++ b/visionforge-fx/src/main/kotlin/space/kscience/visionforge/solid/OrbitControls.kt @@ -17,7 +17,7 @@ import kotlin.math.PI import kotlin.math.cos import kotlin.math.max import kotlin.math.sin -import space.kscience.visionforge.solid.specifications.Camera as CameraSpec +import space.kscience.visionforge.solid.specifications.CameraScheme as CameraSpec public class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: CameraSpec) { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt new file mode 100644 index 00000000..3b85b469 --- /dev/null +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt @@ -0,0 +1,44 @@ +package space.kscience.visionforge.solid + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient +import space.kscience.dataforge.names.asName +import space.kscience.visionforge.VisionBuilder +import space.kscience.visionforge.VisionContainerBuilder +import space.kscience.visionforge.numberProperty +import space.kscience.visionforge.set + +@Serializable +public abstract class LightSource : SolidBase() { + @Transient + public val color: ColorAccessor = ColorAccessor(meta, "color".asName()) + public var intensity: Number by numberProperty(includeStyles = false) { 1.0 } +} + +@Serializable +@SerialName("solid.light.ambient") +public class AmbientLightSource : LightSource() + +@VisionBuilder +public fun VisionContainerBuilder.ambientLight( + name: String? = "@ambientLight", + block: AmbientLightSource.() -> Unit = {}, +): AmbientLightSource = AmbientLightSource().apply(block).also { set(name, it) } + +@Serializable +@SerialName("solid.light.point") +public class PointLightSource : LightSource() + + +@VisionBuilder +public fun VisionContainerBuilder.pointLight( + x: Number, + y: Number, + z: Number, + name: String? = null, + block: PointLightSource.() -> Unit = {}, +): PointLightSource = PointLightSource().apply(block).also { + it.position = Point3D(x, y, z) + set(name, it) +} \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt index a501f7a0..76d0708b 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidGroup.kt @@ -72,9 +72,7 @@ public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder { } @Suppress("FunctionName") -public fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup { - return SolidGroup().apply(block) -} +public fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup = SolidGroup().apply(block) @VisionBuilder public fun VisionContainerBuilder.group( diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt index fa5b0d76..75d1f5a3 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidMaterial.kt @@ -27,7 +27,7 @@ public class SolidMaterial : Scheme() { */ public val specularColor: ColorAccessor = ColorAccessor(meta, SPECULAR_COLOR_KEY) - public val emissiveColor: ColorAccessor = ColorAccessor(meta, "emissiveColor".asName()) + public val emissiveColor: ColorAccessor = ColorAccessor(meta, EMISSIVE_COLOR_KEY) /** * Opacity @@ -43,12 +43,15 @@ public class SolidMaterial : Scheme() { public val MATERIAL_KEY: Name = "material".asName() public val COLOR_KEY: Name = "color".asName() - public val MATERIAL_COLOR_KEY: Name = MATERIAL_KEY + COLOR_KEY + public val TYPE_KEY: Name = "type".asName() public val SPECULAR_COLOR_KEY: Name = "specularColor".asName() - public val MATERIAL_SPECULAR_COLOR_KEY: Name = MATERIAL_KEY + SPECULAR_COLOR_KEY + public val EMISSIVE_COLOR_KEY: Name = "emissiveColor".asName() public val OPACITY_KEY: Name = "opacity".asName() public val MATERIAL_OPACITY_KEY: Name = MATERIAL_KEY + OPACITY_KEY public val WIREFRAME_KEY: Name = "wireframe".asName() + public val MATERIAL_COLOR_KEY: Name = MATERIAL_KEY + COLOR_KEY + public val MATERIAL_EMISSIVE_COLOR_KEY: Name = MATERIAL_KEY + EMISSIVE_COLOR_KEY + public val MATERIAL_SPECULAR_COLOR_KEY: Name = MATERIAL_KEY + SPECULAR_COLOR_KEY public val MATERIAL_WIREFRAME_KEY: Name = MATERIAL_KEY + WIREFRAME_KEY public override val descriptor: MetaDescriptor by lazy { @@ -56,6 +59,12 @@ public class SolidMaterial : Scheme() { MetaDescriptor { inherited = true + value(TYPE_KEY, ValueType.STRING){ + inherited = true + allowedValues = listOf("default".asValue(), "simple".asValue()) + default("default") + } + value(COLOR_KEY, ValueType.STRING, ValueType.NUMBER) { inherited = true widgetType = "color" @@ -67,6 +76,12 @@ public class SolidMaterial : Scheme() { hide() } + value(EMISSIVE_COLOR_KEY, ValueType.STRING, ValueType.NUMBER) { + inherited = true + widgetType = "color" + hide() + } + value(OPACITY_KEY, ValueType.NUMBER) { inherited = true default(1.0) diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt index 12a22ab6..7e52d709 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solids.kt @@ -39,6 +39,9 @@ public class Solids(meta: Meta) : VisionPlugin(meta) { subclass(PolyLine.serializer()) subclass(SolidLabel.serializer()) subclass(Sphere.serializer()) + + subclass(AmbientLightSource.serializer()) + subclass(PointLightSource.serializer()) } public val serializersModuleForSolids: SerializersModule = SerializersModule { diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Axes.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/AxesScheme.kt similarity index 79% rename from visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Axes.kt rename to visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/AxesScheme.kt index 485cc8bd..d4eb8e2b 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Axes.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/AxesScheme.kt @@ -7,24 +7,24 @@ import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.value import space.kscience.dataforge.meta.double -public class Axes : Scheme() { +public class AxesScheme : Scheme() { public var visible: Boolean by boolean(false) public var size: Double by double(AXIS_SIZE) public var width: Double by double(AXIS_WIDTH) - public companion object : SchemeSpec(::Axes) { + public companion object : SchemeSpec(::AxesScheme) { public const val AXIS_SIZE: Double = 1000.0 public const val AXIS_WIDTH: Double = 3.0 override val descriptor: MetaDescriptor by lazy { MetaDescriptor { - value(Axes::visible){ + value(AxesScheme::visible){ default(false) } - value(Axes::size){ + value(AxesScheme::size){ default(AXIS_SIZE) } - value(Axes::width){ + value(AxesScheme::width){ default(AXIS_WIDTH) } } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Camera.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/CameraScheme.kt similarity index 77% rename from visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Camera.kt rename to visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/CameraScheme.kt index b8cb05d4..f884bc1e 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Camera.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/CameraScheme.kt @@ -8,7 +8,7 @@ import space.kscience.dataforge.meta.double import space.kscience.dataforge.meta.int import kotlin.math.PI -public class Camera : Scheme() { +public class CameraScheme : Scheme() { public var fov: Int by int(FIELD_OF_VIEW) //var aspect by double(1.0) @@ -19,7 +19,7 @@ public class Camera : Scheme() { public var azimuth: Double by double(INITIAL_AZIMUTH) public var latitude: Double by double(INITIAL_LATITUDE) - public companion object : SchemeSpec(::Camera) { + public companion object : SchemeSpec(::CameraScheme) { public const val INITIAL_DISTANCE: Double = 300.0 public const val INITIAL_AZIMUTH: Double = 0.0 public const val INITIAL_LATITUDE: Double = PI / 6 @@ -29,22 +29,22 @@ public class Camera : Scheme() { override val descriptor: MetaDescriptor by lazy { MetaDescriptor { - value(Camera::fov) { + value(CameraScheme::fov) { default(FIELD_OF_VIEW) } - value(Camera::nearClip) { + value(CameraScheme::nearClip) { default(NEAR_CLIP) } - value(Camera::farClip) { + value(CameraScheme::farClip) { default(FAR_CLIP) } - value(Camera::distance) { + value(CameraScheme::distance) { default(INITIAL_DISTANCE) } - value(Camera::azimuth) { + value(CameraScheme::azimuth) { default(INITIAL_AZIMUTH) } - value(Camera::latitude) { + value(CameraScheme::latitude) { default(INITIAL_LATITUDE) } } @@ -52,4 +52,4 @@ public class Camera : Scheme() { } } -public val Camera.zenith: Double get() = PI / 2 - latitude \ No newline at end of file +public val CameraScheme.zenith: Double get() = PI / 2 - latitude \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Canvas3DOptions.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Canvas3DOptions.kt index 4a819ff7..e74b47f0 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Canvas3DOptions.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Canvas3DOptions.kt @@ -8,38 +8,34 @@ import space.kscience.dataforge.names.Name import space.kscience.visionforge.hide import space.kscience.visionforge.widgetType -public class Clipping : Scheme() { - public var x: Double? by double() - public var y: Double? by double() - public var z: Double? by double() - public companion object : SchemeSpec(::Clipping) { - override val descriptor: MetaDescriptor = MetaDescriptor { - value(Clipping::x) { - widgetType = "range" - attributes["min"] = 0.0 - attributes["max"] = 1.0 - attributes["step"] = 0.01 - default(1.0) - } - value(Clipping::y) { - widgetType = "range" - attributes["min"] = 0.0 - attributes["max"] = 1.0 - attributes["step"] = 0.01 - default(1.0) - } - value(Clipping::z) { - widgetType = "range" - attributes["min"] = 0.0 - attributes["max"] = 1.0 - attributes["step"] = 0.01 - default(1.0) - } +public object Clipping : SchemeSpec(::PointScheme) { + override val descriptor: MetaDescriptor = MetaDescriptor { + value(PointScheme::x) { + widgetType = "range" + attributes["min"] = 0.0 + attributes["max"] = 1.0 + attributes["step"] = 0.01 + default(1.0) + } + value(PointScheme::y) { + widgetType = "range" + attributes["min"] = 0.0 + attributes["max"] = 1.0 + attributes["step"] = 0.01 + default(1.0) + } + value(PointScheme::z) { + widgetType = "range" + attributes["min"] = 0.0 + attributes["max"] = 1.0 + attributes["step"] = 0.01 + default(1.0) } } } + public class CanvasSize : Scheme() { public var minSize: Int by int(400) public var minWith: Number by number { minSize } @@ -62,16 +58,15 @@ public class CanvasSize : Scheme() { } public class Canvas3DOptions : Scheme() { - public var axes: Axes by spec(Axes) - public var light: Light by spec(Light) - public var camera: Camera by spec(Camera) - public var controls: Controls by spec(Controls) + public var axes: AxesScheme by spec(AxesScheme) + public var camera: CameraScheme by spec(CameraScheme) + public var controls: ControlsScheme by spec(ControlsScheme) public var size: CanvasSize by spec(CanvasSize) public var layers: List by numberList(0) - public var clipping: Clipping by spec(Clipping) + public var clipping: PointScheme by spec(Clipping) public var onSelect: ((Name?) -> Unit)? = null @@ -79,7 +74,7 @@ public class Canvas3DOptions : Scheme() { public companion object : SchemeSpec(::Canvas3DOptions) { override val descriptor: MetaDescriptor by lazy { MetaDescriptor { - scheme(Canvas3DOptions::axes, Axes) + scheme(Canvas3DOptions::axes, AxesScheme) value(Canvas3DOptions::layers) { multiple = true @@ -90,15 +85,11 @@ public class Canvas3DOptions : Scheme() { scheme(Canvas3DOptions::clipping, Clipping) - scheme(Canvas3DOptions::light, Light){ + scheme(Canvas3DOptions::camera, CameraScheme) { hide() } - scheme(Canvas3DOptions::camera, Camera) { - hide() - } - - scheme(Canvas3DOptions::controls, Controls) { + scheme(Canvas3DOptions::controls, ControlsScheme) { hide() } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Controls.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/ControlsScheme.kt similarity index 56% rename from visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Controls.kt rename to visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/ControlsScheme.kt index ee8ebb9d..5e68f37c 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Controls.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/ControlsScheme.kt @@ -4,6 +4,6 @@ import space.kscience.dataforge.meta.Scheme import space.kscience.dataforge.meta.SchemeSpec -public class Controls : Scheme() { - public companion object : SchemeSpec(::Controls) +public class ControlsScheme : Scheme() { + public companion object : SchemeSpec(::ControlsScheme) } \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Light.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Light.kt deleted file mode 100644 index 39b79466..00000000 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/Light.kt +++ /dev/null @@ -1,8 +0,0 @@ -package space.kscience.visionforge.solid.specifications - -import space.kscience.dataforge.meta.Scheme -import space.kscience.dataforge.meta.SchemeSpec - -public class Light : Scheme() { - public companion object : SchemeSpec(::Light) -} \ No newline at end of file diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/PointScheme.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/PointScheme.kt new file mode 100644 index 00000000..33b8c180 --- /dev/null +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/specifications/PointScheme.kt @@ -0,0 +1,19 @@ +package space.kscience.visionforge.solid.specifications + +import space.kscience.dataforge.meta.Scheme +import space.kscience.dataforge.meta.SchemeSpec +import space.kscience.dataforge.meta.double + +public class PointScheme: Scheme(){ + public var x: Double? by double() + public var y: Double? by double() + public var z: Double? by double() + + public companion object: SchemeSpec(::PointScheme) +} + +public operator fun PointScheme.invoke(x: Number?, y: Number?, z: Number?){ + this.x = x?.toDouble() + this.y = y?.toDouble() + this.z = z?.toDouble() +} \ No newline at end of file diff --git a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt index f8af54a0..558d005c 100644 --- a/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt +++ b/visionforge-solid/src/commonTest/kotlin/space/kscience/visionforge/solid/SerializationTest.kt @@ -1,6 +1,7 @@ package space.kscience.visionforge.solid import space.kscience.dataforge.names.Name +import space.kscience.visionforge.Colors import space.kscience.visionforge.MutableVisionGroup import space.kscience.visionforge.get import kotlin.test.Test @@ -55,4 +56,18 @@ class SerializationTest { assertEquals(group["cube"]?.meta, reconstructed["cube"]?.meta) } + @Test + fun lightSerialization(){ + val group = SolidGroup { + ambientLight { + color(Colors.white) + intensity = 100.0 + } + } + val serialized = Solids.encodeToString(group) + + val reconstructed = Solids.decodeFromString(serialized) as SolidGroup + assertEquals(100.0, (reconstructed["@ambientLight"] as AmbientLightSource).intensity.toDouble()) + } + } \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt index 1d5fd3d9..7ac4f13e 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/MeshThreeFactory.kt @@ -10,6 +10,7 @@ import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.values.boolean +import space.kscience.visionforge.VisionBuilder import space.kscience.visionforge.computePropertyNode import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.setProperty @@ -75,6 +76,7 @@ public abstract class MeshThreeFactory( } } +@VisionBuilder public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) { setProperty(EDGES_ENABLED_KEY, enabled) meta.getOrCreate(EDGES_MATERIAL_KEY).updateWith(SolidMaterial, block) diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeAmbientLightFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeAmbientLightFactory.kt new file mode 100644 index 00000000..c3d6bfa0 --- /dev/null +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeAmbientLightFactory.kt @@ -0,0 +1,19 @@ +package space.kscience.visionforge.solid.three + +import info.laht.threekt.lights.AmbientLight +import info.laht.threekt.math.Color +import space.kscience.visionforge.solid.AmbientLightSource +import kotlin.reflect.KClass + +public object ThreeAmbientLightFactory : ThreeFactory { + override val type: KClass get() = AmbientLightSource::class + + override fun invoke(three: ThreePlugin, obj: AmbientLightSource): AmbientLight { + val res = AmbientLight().apply { + color = obj.color.threeColor() ?: Color(0x404040) + intensity = obj.intensity.toDouble() + } + + return res + } +} \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt index ef9944e0..586abe32 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt @@ -8,12 +8,8 @@ import info.laht.threekt.external.controls.OrbitControls import info.laht.threekt.external.controls.TrackballControls import info.laht.threekt.geometries.EdgesGeometry import info.laht.threekt.helpers.AxesHelper -import info.laht.threekt.lights.AmbientLight import info.laht.threekt.materials.LineBasicMaterial -import info.laht.threekt.math.Box3 -import info.laht.threekt.math.Plane -import info.laht.threekt.math.Vector2 -import info.laht.threekt.math.Vector3 +import info.laht.threekt.math.* import info.laht.threekt.objects.LineSegments import info.laht.threekt.objects.Mesh import info.laht.threekt.scenes.Scene @@ -35,7 +31,7 @@ import kotlin.math.cos import kotlin.math.sin /** - * + * A canvas for three-js rendering */ public class ThreeCanvas( public val three: ThreePlugin, @@ -60,19 +56,19 @@ public class ThreeCanvas( add(axesObject) } - //Set up light - options.useProperty(Canvas3DOptions::light, this) { lightConfig -> - //remove old light if present - getObjectByName(LIGHT_NAME)?.let { remove(it) } - //add new light - val lightObject = buildLight(lightConfig) - lightObject.name = LIGHT_NAME - add(lightObject) - } +// //Set up light +// options.useProperty(Canvas3DOptions::light, this) { lightConfig -> +// //remove old light if present +// getObjectByName(LIGHT_NAME)?.let { remove(it) } +// //add new light +// val lightObject = buildLight(lightConfig) +// lightObject.name = LIGHT_NAME +// add(lightObject) +// } } - private fun buildCamera(spec: Camera) = PerspectiveCamera( + private fun buildCamera(spec: CameraScheme) = PerspectiveCamera( spec.fov, 1.0, spec.nearClip, @@ -231,9 +227,24 @@ public class ThreeCanvas( } } - private fun buildLight(spec: Light?): info.laht.threekt.lights.Light = AmbientLight(0x404040) +// private fun buildLight(spec: AmbientLightScheme?): info.laht.threekt.lights.Light = when (spec?.type) { +// AmbientLightScheme.Type.POINT -> PointLight().apply { +// position.x = spec.position.x ?: 0.0 +// position.y = spec.position.y ?: 0.0 +// position.z = spec.position.z ?: 0.0 +// } +// else -> AmbientLight().apply { +// +// } +// }.apply { +// this.color = spec?.color?.threeColor() ?: Color(0x404040) +// +// spec?.intensity?.coerceIn(0.0, 1.0)?.let { +// this.intensity = it +// } +// } - private fun addControls(element: Node, controls: Controls) { + private fun addControls(element: Node, controls: ControlsScheme) { when (controls.meta["type"].string) { "trackball" -> TrackballControls(camera, element) else -> OrbitControls(camera, element) @@ -311,7 +322,7 @@ public class ThreeCanvas( private const val SELECT_NAME = "@select" private const val LIGHT_NAME = "@light" private const val AXES_NAME = "@axes" - private const val CLIP_HELPER_NAME = "@clipping" + //private const val CLIP_HELPER_NAME = "@clipping" } } diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeFactory.kt index df9f2c94..6e540f71 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeFactory.kt @@ -8,7 +8,6 @@ import space.kscience.dataforge.misc.Type import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.startsWith import space.kscience.visionforge.Vision -import space.kscience.visionforge.computeProperty import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY import space.kscience.visionforge.solid.three.ThreeFactory.Companion.TYPE @@ -58,7 +57,7 @@ public fun Object3D.updatePosition(obj: Vision) { * Update non-position non-geometry property */ public fun Object3D.updateProperty(source: Vision, propertyName: Name) { - console.log("$source updated $propertyName with ${source.computeProperty(propertyName)}") + // console.log("$source updated $propertyName with ${source.computeProperty(propertyName)}") if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) { updateMaterialProperty(source, propertyName) } else if ( diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt index 522c0362..5b4fa220 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt @@ -3,39 +3,52 @@ package space.kscience.visionforge.solid.three import info.laht.threekt.materials.LineBasicMaterial import info.laht.threekt.materials.Material import info.laht.threekt.materials.MeshBasicMaterial +import info.laht.threekt.materials.MeshStandardMaterial import info.laht.threekt.math.Color import info.laht.threekt.objects.Mesh import space.kscience.dataforge.meta.* import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName +import space.kscience.dataforge.names.plus import space.kscience.dataforge.values.* import space.kscience.visionforge.Colors import space.kscience.visionforge.Vision import space.kscience.visionforge.computePropertyNode import space.kscience.visionforge.getStyleNodes +import space.kscience.visionforge.solid.ColorAccessor import space.kscience.visionforge.solid.SolidMaterial import space.kscience.visionforge.solid.SolidReference public object ThreeMaterials { public val DEFAULT_COLOR: Color = Color(Colors.darkgreen) - public val DEFAULT: MeshBasicMaterial = MeshBasicMaterial().apply { + + public val DEFAULT: MeshStandardMaterial = MeshStandardMaterial().apply { color.set(DEFAULT_COLOR) cached = true } - public val DEFAULT_LINE_COLOR: Color = Color(Colors.black) + + public val BLACK_COLOR: Color = Color(Colors.black) + + public val DEFAULT_EMISSIVE_COLOR: Color = BLACK_COLOR + + public val DEFAULT_LINE_COLOR: Color get() = BLACK_COLOR + public val DEFAULT_LINE: LineBasicMaterial = LineBasicMaterial().apply { color.set(DEFAULT_LINE_COLOR) + cached = true } public val SELECTED_MATERIAL: LineBasicMaterial = LineBasicMaterial().apply { color.set(Colors.ivory) linewidth = 8.0 + cached = true } public val HIGHLIGHT_MATERIAL: LineBasicMaterial = LineBasicMaterial().apply { color.set(Colors.blue) linewidth = 8.0 + cached = true } private val lineMaterialCache = HashMap() @@ -58,34 +71,21 @@ public object ThreeMaterials { private val materialCache = HashMap() - internal fun buildMaterial(meta: Meta): Material = MeshBasicMaterial().apply { - color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR + internal fun buildMaterial(meta: Meta): Material = when (meta[SolidMaterial.TYPE_KEY]?.string) { + "simple" -> MeshBasicMaterial().apply { + color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR + wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false + } + else -> MeshStandardMaterial().apply { + color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR + emissive = meta[SolidMaterial.EMISSIVE_COLOR_KEY]?.threeColor() ?: DEFAULT_EMISSIVE_COLOR + wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false + } + }.apply { opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0 transparent = opacity < 1.0 - wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false needsUpdate = true } -// val material = SolidMaterial.read(meta) -// return meta[SolidMaterial.SPECULAR_COLOR_KEY]?.let { specularColor -> -// MeshPhongMaterial().apply { -// color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR -// specular = specularColor.threeColor() -// emissive = material.emissiveColor.threeColor() ?: specular -// reflectivity = 0.5 -// refractionRatio = 1.0 -// shininess = 100.0 -// opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0 -// transparent = opacity < 1.0 -// wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false -// needsUpdate = true -// } -// } ?: MeshBasicMaterial().apply { -// color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR -// opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0 -// transparent = opacity < 1.0 -// wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false -// needsUpdate = true -// } internal fun cacheMaterial(meta: Meta): Material = materialCache.getOrPut(meta) { buildMaterial(meta).apply { @@ -115,6 +115,16 @@ public fun Meta.threeColor(): Color? { } } +public fun ColorAccessor.threeColor(): Color? { + val value = value + return when { + value == null -> null + value === Null -> null + value.type == ValueType.NUMBER -> Color(value.int) + else -> Color(value.string) + } +} + private var Material.cached: Boolean get() = userData["cached"] == true set(value) { @@ -139,7 +149,11 @@ public fun Mesh.updateMaterial(vision: Vision) { } public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) { - if (material.cached || propertyName == SolidMaterial.MATERIAL_KEY) { + if ( + material.cached + || propertyName == SolidMaterial.MATERIAL_KEY + || propertyName == SolidMaterial.MATERIAL_KEY + SolidMaterial.TYPE_KEY + ) { //generate a new material since cached material should not be changed updateMaterial(vision) } else { @@ -149,6 +163,16 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) { ?: ThreeMaterials.DEFAULT_COLOR material.needsUpdate = true } + SolidMaterial.SPECULAR_COLOR_KEY -> { + material.asDynamic().specular = vision.computePropertyNode(SolidMaterial.SPECULAR_COLOR_KEY)?.threeColor() + ?: ThreeMaterials.DEFAULT_COLOR + material.needsUpdate = true + } + SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY -> { + material.asDynamic().emissive = vision.computePropertyNode(SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY)?.threeColor() + ?: ThreeMaterials.BLACK_COLOR + material.needsUpdate = true + } SolidMaterial.MATERIAL_OPACITY_KEY -> { val opacity = vision.getPropertyValue( SolidMaterial.MATERIAL_OPACITY_KEY, diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt index aa5c2a14..8c32551a 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePlugin.kt @@ -1,7 +1,6 @@ package space.kscience.visionforge.solid.three import info.laht.threekt.core.Object3D -import kotlinx.coroutines.CoroutineScope import org.w3c.dom.Element import org.w3c.dom.HTMLElement import space.kscience.dataforge.context.* @@ -27,8 +26,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { private val objectFactories = HashMap, ThreeFactory<*>>() private val compositeFactory = ThreeCompositeFactory(this) - //TODO generate a separate supervisor update scope - internal val updateScope: CoroutineScope get() = context +// internal val updateScope: CoroutineScope get() = context init { //Add specialized factories here @@ -38,6 +36,8 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { objectFactories[ConeSegment::class] = ThreeConeFactory objectFactories[PolyLine::class] = ThreeLineFactory objectFactories[SolidLabel::class] = ThreeCanvasLabelFactory + objectFactories[AmbientLightSource::class] = ThreeAmbientLightFactory + objectFactories[PointLightSource::class] = ThreePointLightFactory } @Suppress("UNCHECKED_CAST") diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePointLightFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePointLightFactory.kt new file mode 100644 index 00000000..a7a6d758 --- /dev/null +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreePointLightFactory.kt @@ -0,0 +1,28 @@ +package space.kscience.visionforge.solid.three + +import info.laht.threekt.lights.PointLight +import info.laht.threekt.math.Color +import space.kscience.visionforge.onPropertyChange +import space.kscience.visionforge.solid.PointLightSource +import kotlin.reflect.KClass + +public object ThreePointLightFactory : ThreeFactory { + override val type: KClass get() = PointLightSource::class + + override fun invoke(three: ThreePlugin, obj: PointLightSource): PointLight { + val res = PointLight().apply { + matrixAutoUpdate = false + color = obj.color.threeColor() ?: Color(0x404040) + intensity = obj.intensity.toDouble() + updatePosition(obj) + } + + obj.onPropertyChange { name -> + when { + else -> res.updateProperty(obj, name) + } + } + + return res + } +} \ No newline at end of file