Replace light model for 3ds

This commit is contained in:
Alexander Nozik 2022-01-27 12:10:00 +03:00
parent db5064f6ed
commit f828f86e29
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
27 changed files with 340 additions and 157 deletions

View File

@ -4,6 +4,8 @@
### Added ### Added
### Changed ### Changed
- Naming of Canvas3D options
- Lights are added to the scene instead of 3D options
### Deprecated ### Deprecated

View File

@ -8,7 +8,7 @@ val fxVersion by extra("11")
allprojects{ allprojects{
group = "space.kscience" group = "space.kscience"
version = "0.2.0" version = "0.2.1-dev-1"
} }
subprojects { subprojects {

View File

@ -1,6 +1,5 @@
import kotlinx.browser.document import kotlinx.browser.document
import kotlinx.css.* import kotlinx.css.*
import react.child
import react.dom.render import react.dom.render
import ringui.SmartTabs import ringui.SmartTabs
import ringui.Tab import ringui.Tab
@ -8,6 +7,7 @@ import space.kscience.dataforge.context.Context
import space.kscience.plotly.models.Trace import space.kscience.plotly.models.Trace
import space.kscience.plotly.scatter import space.kscience.plotly.scatter
import space.kscience.visionforge.Application import space.kscience.visionforge.Application
import space.kscience.visionforge.Colors
import space.kscience.visionforge.VisionClient import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.plotly.PlotlyPlugin import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.ring.ThreeCanvasWithControls import space.kscience.visionforge.ring.ThreeCanvasWithControls
@ -48,7 +48,7 @@ private class JsPlaygroundApp : Application {
} }
SmartTabs("gravity") { SmartTabs("gravity") {
Tab("gravity") { Tab("gravity") {
GravityDemo{ GravityDemo {
attrs { attrs {
this.context = playgroundContext this.context = playgroundContext
} }
@ -73,6 +73,9 @@ private class JsPlaygroundApp : Application {
attrs { attrs {
context = playgroundContext context = playgroundContext
solid { solid {
ambientLight {
color(Colors.white)
}
repeat(100) { repeat(100) {
sphere(5, name = "sphere[$it]") { sphere(5, name = "sphere[$it]") {
x = random.nextDouble(-300.0, 300.0) x = random.nextDouble(-300.0, 300.0)

View File

@ -7,6 +7,7 @@ import react.fc
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.plotly.layout import space.kscience.plotly.layout
import space.kscience.plotly.models.Trace import space.kscience.plotly.models.Trace
import space.kscience.visionforge.Colors
import space.kscience.visionforge.markup.VisionOfMarkup import space.kscience.visionforge.markup.VisionOfMarkup
import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.ring.ThreeCanvasWithControls import space.kscience.visionforge.ring.ThreeCanvasWithControls
@ -21,10 +22,10 @@ external interface DemoProps : Props {
} }
val GravityDemo = fc<DemoProps> { props -> val GravityDemo = fc<DemoProps> { props ->
val velocityTrace = Trace{ val velocityTrace = Trace {
name = "velocity" name = "velocity"
} }
val energyTrace = Trace{ val energyTrace = Trace {
name = "energy" name = "energy"
} }
val markup = VisionOfMarkup() val markup = VisionOfMarkup()
@ -41,6 +42,11 @@ val GravityDemo = fc<DemoProps> { props ->
attrs { attrs {
context = props.context context = props.context
solid { solid {
pointLight(200, 200, 200, name = "light"){
color(Colors.white)
}
ambientLight()
sphere(5.0, "ball") { sphere(5.0, "ball") {
detail = 16 detail = 16
color("red") color("red")
@ -91,7 +97,7 @@ val GravityDemo = fc<DemoProps> { props ->
height = 50.vh - 50.pt height = 50.vh - 50.pt
} }
plotly { plotly {
traces(velocityTrace,energyTrace) traces(velocityTrace, energyTrace)
layout { layout {
xaxis.title = "time" xaxis.title = "time"
} }

View File

@ -17,12 +17,13 @@ import react.fc
import react.useMemo import react.useMemo
import react.useState import react.useState
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.meta.invoke
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexColumn
import space.kscience.visionforge.react.flexRow import space.kscience.visionforge.react.flexRow
import space.kscience.visionforge.ring.ThreeCanvasWithControls import space.kscience.visionforge.ring.ThreeCanvasWithControls
import space.kscience.visionforge.ring.tab 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.specifications.Canvas3DOptions
import space.kscience.visionforge.solid.three.edges import space.kscience.visionforge.solid.three.edges
import styled.css import styled.css
@ -42,17 +43,19 @@ val MMApp = fc<MMAppProps>("Muon monitor") { props ->
val mmOptions = useMemo { val mmOptions = useMemo {
Canvas3DOptions { Canvas3DOptions {
camera = Camera { camera {
distance = 2100.0 distance = 2100.0
latitude = PI / 6 latitude = PI / 6
azimuth = PI + PI / 6 azimuth = PI + PI / 6
} }
} }
} }
val root = useMemo(props.model) { val root = useMemo(props.model) {
props.model.root.apply { props.model.root.apply {
edges() edges()
ambientLight()
} }
} }

View File

@ -18,7 +18,11 @@ fun VisionLayout<Solid>.demo(name: String, title: String = name, block: SolidGro
val meta = Meta { val meta = Meta {
"title" put title "title" put title
} }
val vision = SolidGroup(block) val vision = SolidGroup(block).apply {
ambientLight{
color(Colors.white)
}
}
render(Name.parse(name), vision, meta) render(Name.parse(name), vision, meta)
} }
@ -39,6 +43,7 @@ val canvasOptions = Canvas3DOptions {
@OptIn(DelicateCoroutinesApi::class) @OptIn(DelicateCoroutinesApi::class)
fun VisionLayout<Solid>.showcase() { fun VisionLayout<Solid>.showcase() {
demo("shapes", "Basic shapes") { demo("shapes", "Basic shapes") {
ambientLight()
box(100.0, 100.0, 100.0) { box(100.0, 100.0, 100.0) {
z = -110.0 z = -110.0
color("teal") color("teal")

View File

@ -59,7 +59,7 @@ box(10, 10, 10, name = "small box"){
rotation = Point3D(0, 0, 0) rotation = Point3D(0, 0, 0)
} }
``` ```
![](../docs/images/small-box.png) ![](../images/small-box.png)
The `big box` will have properties with custom values. The `big box` will have properties with custom values.
```kotlin ```kotlin
@ -72,7 +72,7 @@ box(40, 40, 40, name = "big box"){
rotation = Point3D(60, 80, 0) 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. If we compare these boxes, we will see all differences.
Here is the function `main` with both boxes. Here is the function `main` with both boxes.
@ -111,8 +111,8 @@ fun main(){
} }
} }
``` ```
![](../docs/images/two-boxes-1.png) ![](../images/two-boxes-1.png)
![](../docs/images/two-boxes-2.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.*** ***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) ![](../images/polyline-points.png)
![](../docs/images/polyline-points-2.png) ![](../images/polyline-points-2.png)
### 2) Box ### 2) Box
@ -165,7 +165,7 @@ Let's create just usual `box` with equal ribs.
color("pink") color("pink")
} }
``` ```
![](../docs/images/box.png) ![](../images/box.png)
Now, let's make `box` with bigger `y` value. Now, let's make `box` with bigger `y` value.
```kotlin ```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. 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. 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. Predictably, only the `x-axis` rib is bigger than other ribs.
![](../docs/images/wide-box.png) ![](../images/wide-box.png)
### 3) Sphere ### 3) Sphere
@ -206,7 +206,7 @@ As for `radius`, it has `Float` type, and, as you can guess, it sets the radius
color("blue") color("blue")
} }
``` ```
![](../docs/images/sphere.png) ![](../images/sphere.png)
### 4) Hexagon ### 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` 5) Edge with vertices `node1`, `node5`, `node8`, `node4`
6) Edge with vertices `node8`, `node5`, `node6`, `node7` 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. 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") color("green")
} }
``` ```
![](../docs/images/classic-hexagon.png) ![](../images/classic-hexagon.png)
Now, let's make a custom hexagon. Now, let's make a custom hexagon.
@ -258,7 +258,7 @@ hexagon(
color("brown") color("brown")
} }
``` ```
![](../docs/images/custom-hexagon.png) ![](../images/custom-hexagon.png)
### 3) Cone ### 3) Cone
It takes in six values: `bottomRadius`, `height`, `upperRadius`, `startAngle`, `angle`, and `name`. It takes in six values: `bottomRadius`, `height`, `upperRadius`, `startAngle`, `angle`, and `name`.
@ -274,8 +274,8 @@ Let's build a classic cone:
color("beige") color("beige")
} }
``` ```
![](../docs/images/cone-1.png) ![](../images/cone-1.png)
![](../docs/images/cone-2.png) ![](../images/cone-2.png)
First of all, we have to try to build a frustum cone: First of all, we have to try to build a frustum cone:
```kotlin ```kotlin
@ -283,7 +283,7 @@ cone(60, 80, name = "cone") {
color(0u, 40u, 0u) 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: 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) color(0u, 0u, 200u)
} }
``` ```
![](../docs/images/cone-segment-1.png) ![](../images/cone-segment-1.png)
![](../docs/images/cone-segment-2.png) ![](../images/cone-segment-2.png)
Finally, the segment of frustum cone is left for a try: Finally, the segment of frustum cone is left for a try:
```kotlin ```kotlin
@ -301,7 +301,7 @@ cone(60, 100, 20, PI*3/4, angle = PI/3, name = "cone") {
color(190u, 0u, 0u) color(190u, 0u, 0u)
} }
``` ```
![](../docs/images/frustum-cone-segment.png) ![](../images/frustum-cone-segment.png)
### 4) Cone Surface ### 4) Cone Surface
This solid is set by seven values:`bottomOuterRadius`, `bottomInnerRadius`, `height`, `topOuterRadius`, `topInnerRadius`, `startAngle`, and `angle`. 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) rotation = Point3D(2, 50, -9)
} }
``` ```
![](../docs/images/cone-surface-1.png) ![](../images/cone-surface-1.png)
![](../docs/images/cone-surface-2.png) ![](../images/cone-surface-2.png)
Now, let's create a cone surface and set all it's properties: 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) rotation = Point3D(2, 50, -9)
} }
``` ```
![](../docs/images/cone-surface-fragment.png) ![](../images/cone-surface-fragment.png)
![](../docs/images/cone-surface-fragment-2.png) ![](../images/cone-surface-fragment-2.png)
### 5) Cylinder ### 5) Cylinder
@ -344,8 +344,8 @@ cylinder(40, 100, "cylinder"){
color("indigo") color("indigo")
} }
``` ```
![](../docs/images/cylinder-1.png) ![](../images/cylinder-1.png)
![](../docs/images/cylinder-2.png) ![](../images/cylinder-2.png)
### 6) Tube ### 6) Tube
`tube` takes in `radius`, `height`, `innerRadius`, `startAngle`, `angle`, and `name`. *All values are familiar from `cone`, and `coneSurface` solids.* `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 opacity = 0.4
} }
``` ```
![](../docs/images/tube.png) ![](../images/tube.png)
This is an example of tube fragment: This is an example of tube fragment:
@ -365,7 +365,7 @@ tube(50, 40, 20, 0f, PI, name = "fragmented tube"){
color("white") color("white")
} }
``` ```
![](../docs/images/tube-fragment.png) ![](../images/tube-fragment.png)
### 7) Extruded ### 7) Extruded
`extruded` is set by two values: `shape`, and `layer`. `extruded` is set by two values: `shape`, and `layer`.

View File

@ -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) { public fun ThreeCanvasWithControlsProps.tab(title: String, block: RBuilder.() -> Unit) {
additionalTabs = (additionalTabs ?: emptyMap()) + (title to block) additionalTabs = (additionalTabs ?: emptyMap()) + (title to block)
} }

View File

@ -17,7 +17,7 @@ import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.max import kotlin.math.max
import kotlin.math.sin 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) { public class OrbitControls internal constructor(camera: Camera, canvas: SubScene, spec: CameraSpec) {

View File

@ -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<Solid>.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<Solid>.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)
}

View File

@ -72,9 +72,7 @@ public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder {
} }
@Suppress("FunctionName") @Suppress("FunctionName")
public fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup { public fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup = SolidGroup().apply(block)
return SolidGroup().apply(block)
}
@VisionBuilder @VisionBuilder
public fun VisionContainerBuilder<Vision>.group( public fun VisionContainerBuilder<Vision>.group(

View File

@ -27,7 +27,7 @@ public class SolidMaterial : Scheme() {
*/ */
public val specularColor: ColorAccessor = ColorAccessor(meta, SPECULAR_COLOR_KEY) 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 * Opacity
@ -43,12 +43,15 @@ public class SolidMaterial : Scheme() {
public val MATERIAL_KEY: Name = "material".asName() public val MATERIAL_KEY: Name = "material".asName()
public val COLOR_KEY: Name = "color".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 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 OPACITY_KEY: Name = "opacity".asName()
public val MATERIAL_OPACITY_KEY: Name = MATERIAL_KEY + OPACITY_KEY public val MATERIAL_OPACITY_KEY: Name = MATERIAL_KEY + OPACITY_KEY
public val WIREFRAME_KEY: Name = "wireframe".asName() 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 val MATERIAL_WIREFRAME_KEY: Name = MATERIAL_KEY + WIREFRAME_KEY
public override val descriptor: MetaDescriptor by lazy { public override val descriptor: MetaDescriptor by lazy {
@ -56,6 +59,12 @@ public class SolidMaterial : Scheme() {
MetaDescriptor { MetaDescriptor {
inherited = true inherited = true
value(TYPE_KEY, ValueType.STRING){
inherited = true
allowedValues = listOf("default".asValue(), "simple".asValue())
default("default")
}
value(COLOR_KEY, ValueType.STRING, ValueType.NUMBER) { value(COLOR_KEY, ValueType.STRING, ValueType.NUMBER) {
inherited = true inherited = true
widgetType = "color" widgetType = "color"
@ -67,6 +76,12 @@ public class SolidMaterial : Scheme() {
hide() hide()
} }
value(EMISSIVE_COLOR_KEY, ValueType.STRING, ValueType.NUMBER) {
inherited = true
widgetType = "color"
hide()
}
value(OPACITY_KEY, ValueType.NUMBER) { value(OPACITY_KEY, ValueType.NUMBER) {
inherited = true inherited = true
default(1.0) default(1.0)

View File

@ -39,6 +39,9 @@ public class Solids(meta: Meta) : VisionPlugin(meta) {
subclass(PolyLine.serializer()) subclass(PolyLine.serializer())
subclass(SolidLabel.serializer()) subclass(SolidLabel.serializer())
subclass(Sphere.serializer()) subclass(Sphere.serializer())
subclass(AmbientLightSource.serializer())
subclass(PointLightSource.serializer())
} }
public val serializersModuleForSolids: SerializersModule = SerializersModule { public val serializersModuleForSolids: SerializersModule = SerializersModule {

View File

@ -7,24 +7,24 @@ import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.value import space.kscience.dataforge.meta.descriptors.value
import space.kscience.dataforge.meta.double import space.kscience.dataforge.meta.double
public class Axes : Scheme() { public class AxesScheme : Scheme() {
public var visible: Boolean by boolean(false) public var visible: Boolean by boolean(false)
public var size: Double by double(AXIS_SIZE) public var size: Double by double(AXIS_SIZE)
public var width: Double by double(AXIS_WIDTH) public var width: Double by double(AXIS_WIDTH)
public companion object : SchemeSpec<Axes>(::Axes) { public companion object : SchemeSpec<AxesScheme>(::AxesScheme) {
public const val AXIS_SIZE: Double = 1000.0 public const val AXIS_SIZE: Double = 1000.0
public const val AXIS_WIDTH: Double = 3.0 public const val AXIS_WIDTH: Double = 3.0
override val descriptor: MetaDescriptor by lazy { override val descriptor: MetaDescriptor by lazy {
MetaDescriptor { MetaDescriptor {
value(Axes::visible){ value(AxesScheme::visible){
default(false) default(false)
} }
value(Axes::size){ value(AxesScheme::size){
default(AXIS_SIZE) default(AXIS_SIZE)
} }
value(Axes::width){ value(AxesScheme::width){
default(AXIS_WIDTH) default(AXIS_WIDTH)
} }
} }

View File

@ -8,7 +8,7 @@ import space.kscience.dataforge.meta.double
import space.kscience.dataforge.meta.int import space.kscience.dataforge.meta.int
import kotlin.math.PI import kotlin.math.PI
public class Camera : Scheme() { public class CameraScheme : Scheme() {
public var fov: Int by int(FIELD_OF_VIEW) public var fov: Int by int(FIELD_OF_VIEW)
//var aspect by double(1.0) //var aspect by double(1.0)
@ -19,7 +19,7 @@ public class Camera : Scheme() {
public var azimuth: Double by double(INITIAL_AZIMUTH) public var azimuth: Double by double(INITIAL_AZIMUTH)
public var latitude: Double by double(INITIAL_LATITUDE) public var latitude: Double by double(INITIAL_LATITUDE)
public companion object : SchemeSpec<Camera>(::Camera) { public companion object : SchemeSpec<CameraScheme>(::CameraScheme) {
public const val INITIAL_DISTANCE: Double = 300.0 public const val INITIAL_DISTANCE: Double = 300.0
public const val INITIAL_AZIMUTH: Double = 0.0 public const val INITIAL_AZIMUTH: Double = 0.0
public const val INITIAL_LATITUDE: Double = PI / 6 public const val INITIAL_LATITUDE: Double = PI / 6
@ -29,22 +29,22 @@ public class Camera : Scheme() {
override val descriptor: MetaDescriptor by lazy { override val descriptor: MetaDescriptor by lazy {
MetaDescriptor { MetaDescriptor {
value(Camera::fov) { value(CameraScheme::fov) {
default(FIELD_OF_VIEW) default(FIELD_OF_VIEW)
} }
value(Camera::nearClip) { value(CameraScheme::nearClip) {
default(NEAR_CLIP) default(NEAR_CLIP)
} }
value(Camera::farClip) { value(CameraScheme::farClip) {
default(FAR_CLIP) default(FAR_CLIP)
} }
value(Camera::distance) { value(CameraScheme::distance) {
default(INITIAL_DISTANCE) default(INITIAL_DISTANCE)
} }
value(Camera::azimuth) { value(CameraScheme::azimuth) {
default(INITIAL_AZIMUTH) default(INITIAL_AZIMUTH)
} }
value(Camera::latitude) { value(CameraScheme::latitude) {
default(INITIAL_LATITUDE) default(INITIAL_LATITUDE)
} }
} }
@ -52,4 +52,4 @@ public class Camera : Scheme() {
} }
} }
public val Camera.zenith: Double get() = PI / 2 - latitude public val CameraScheme.zenith: Double get() = PI / 2 - latitude

View File

@ -8,38 +8,34 @@ import space.kscience.dataforge.names.Name
import space.kscience.visionforge.hide import space.kscience.visionforge.hide
import space.kscience.visionforge.widgetType 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>(::Clipping) { public object Clipping : SchemeSpec<PointScheme>(::PointScheme) {
override val descriptor: MetaDescriptor = MetaDescriptor { override val descriptor: MetaDescriptor = MetaDescriptor {
value(Clipping::x) { value(PointScheme::x) {
widgetType = "range" widgetType = "range"
attributes["min"] = 0.0 attributes["min"] = 0.0
attributes["max"] = 1.0 attributes["max"] = 1.0
attributes["step"] = 0.01 attributes["step"] = 0.01
default(1.0) default(1.0)
} }
value(Clipping::y) { value(PointScheme::y) {
widgetType = "range" widgetType = "range"
attributes["min"] = 0.0 attributes["min"] = 0.0
attributes["max"] = 1.0 attributes["max"] = 1.0
attributes["step"] = 0.01 attributes["step"] = 0.01
default(1.0) default(1.0)
} }
value(Clipping::z) { value(PointScheme::z) {
widgetType = "range" widgetType = "range"
attributes["min"] = 0.0 attributes["min"] = 0.0
attributes["max"] = 1.0 attributes["max"] = 1.0
attributes["step"] = 0.01 attributes["step"] = 0.01
default(1.0) default(1.0)
}
} }
} }
} }
public class CanvasSize : Scheme() { public class CanvasSize : Scheme() {
public var minSize: Int by int(400) public var minSize: Int by int(400)
public var minWith: Number by number { minSize } public var minWith: Number by number { minSize }
@ -62,16 +58,15 @@ public class CanvasSize : Scheme() {
} }
public class Canvas3DOptions : Scheme() { public class Canvas3DOptions : Scheme() {
public var axes: Axes by spec(Axes) public var axes: AxesScheme by spec(AxesScheme)
public var light: Light by spec(Light) public var camera: CameraScheme by spec(CameraScheme)
public var camera: Camera by spec(Camera) public var controls: ControlsScheme by spec(ControlsScheme)
public var controls: Controls by spec(Controls)
public var size: CanvasSize by spec(CanvasSize) public var size: CanvasSize by spec(CanvasSize)
public var layers: List<Number> by numberList(0) public var layers: List<Number> by numberList(0)
public var clipping: Clipping by spec(Clipping) public var clipping: PointScheme by spec(Clipping)
public var onSelect: ((Name?) -> Unit)? = null public var onSelect: ((Name?) -> Unit)? = null
@ -79,7 +74,7 @@ public class Canvas3DOptions : Scheme() {
public companion object : SchemeSpec<Canvas3DOptions>(::Canvas3DOptions) { public companion object : SchemeSpec<Canvas3DOptions>(::Canvas3DOptions) {
override val descriptor: MetaDescriptor by lazy { override val descriptor: MetaDescriptor by lazy {
MetaDescriptor { MetaDescriptor {
scheme(Canvas3DOptions::axes, Axes) scheme(Canvas3DOptions::axes, AxesScheme)
value(Canvas3DOptions::layers) { value(Canvas3DOptions::layers) {
multiple = true multiple = true
@ -90,15 +85,11 @@ public class Canvas3DOptions : Scheme() {
scheme(Canvas3DOptions::clipping, Clipping) scheme(Canvas3DOptions::clipping, Clipping)
scheme(Canvas3DOptions::light, Light){ scheme(Canvas3DOptions::camera, CameraScheme) {
hide() hide()
} }
scheme(Canvas3DOptions::camera, Camera) { scheme(Canvas3DOptions::controls, ControlsScheme) {
hide()
}
scheme(Canvas3DOptions::controls, Controls) {
hide() hide()
} }

View File

@ -4,6 +4,6 @@ import space.kscience.dataforge.meta.Scheme
import space.kscience.dataforge.meta.SchemeSpec import space.kscience.dataforge.meta.SchemeSpec
public class Controls : Scheme() { public class ControlsScheme : Scheme() {
public companion object : SchemeSpec<Controls>(::Controls) public companion object : SchemeSpec<ControlsScheme>(::ControlsScheme)
} }

View File

@ -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>(::Light)
}

View File

@ -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>(::PointScheme)
}
public operator fun PointScheme.invoke(x: Number?, y: Number?, z: Number?){
this.x = x?.toDouble()
this.y = y?.toDouble()
this.z = z?.toDouble()
}

View File

@ -1,6 +1,7 @@
package space.kscience.visionforge.solid package space.kscience.visionforge.solid
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Colors
import space.kscience.visionforge.MutableVisionGroup import space.kscience.visionforge.MutableVisionGroup
import space.kscience.visionforge.get import space.kscience.visionforge.get
import kotlin.test.Test import kotlin.test.Test
@ -55,4 +56,18 @@ class SerializationTest {
assertEquals(group["cube"]?.meta, reconstructed["cube"]?.meta) 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())
}
} }

View File

@ -10,6 +10,7 @@ import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
import space.kscience.dataforge.values.boolean import space.kscience.dataforge.values.boolean
import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.computePropertyNode import space.kscience.visionforge.computePropertyNode
import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.setProperty import space.kscience.visionforge.setProperty
@ -75,6 +76,7 @@ public abstract class MeshThreeFactory<in T : Solid>(
} }
} }
@VisionBuilder
public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) { public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) {
setProperty(EDGES_ENABLED_KEY, enabled) setProperty(EDGES_ENABLED_KEY, enabled)
meta.getOrCreate(EDGES_MATERIAL_KEY).updateWith(SolidMaterial, block) meta.getOrCreate(EDGES_MATERIAL_KEY).updateWith(SolidMaterial, block)

View File

@ -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<AmbientLightSource> {
override val type: KClass<in AmbientLightSource> 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
}
}

View File

@ -8,12 +8,8 @@ import info.laht.threekt.external.controls.OrbitControls
import info.laht.threekt.external.controls.TrackballControls import info.laht.threekt.external.controls.TrackballControls
import info.laht.threekt.geometries.EdgesGeometry import info.laht.threekt.geometries.EdgesGeometry
import info.laht.threekt.helpers.AxesHelper import info.laht.threekt.helpers.AxesHelper
import info.laht.threekt.lights.AmbientLight
import info.laht.threekt.materials.LineBasicMaterial import info.laht.threekt.materials.LineBasicMaterial
import info.laht.threekt.math.Box3 import info.laht.threekt.math.*
import info.laht.threekt.math.Plane
import info.laht.threekt.math.Vector2
import info.laht.threekt.math.Vector3
import info.laht.threekt.objects.LineSegments import info.laht.threekt.objects.LineSegments
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
import info.laht.threekt.scenes.Scene import info.laht.threekt.scenes.Scene
@ -35,7 +31,7 @@ import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
/** /**
* * A canvas for three-js rendering
*/ */
public class ThreeCanvas( public class ThreeCanvas(
public val three: ThreePlugin, public val three: ThreePlugin,
@ -60,19 +56,19 @@ public class ThreeCanvas(
add(axesObject) add(axesObject)
} }
//Set up light // //Set up light
options.useProperty(Canvas3DOptions::light, this) { lightConfig -> // options.useProperty(Canvas3DOptions::light, this) { lightConfig ->
//remove old light if present // //remove old light if present
getObjectByName(LIGHT_NAME)?.let { remove(it) } // getObjectByName(LIGHT_NAME)?.let { remove(it) }
//add new light // //add new light
val lightObject = buildLight(lightConfig) // val lightObject = buildLight(lightConfig)
lightObject.name = LIGHT_NAME // lightObject.name = LIGHT_NAME
add(lightObject) // add(lightObject)
} // }
} }
private fun buildCamera(spec: Camera) = PerspectiveCamera( private fun buildCamera(spec: CameraScheme) = PerspectiveCamera(
spec.fov, spec.fov,
1.0, 1.0,
spec.nearClip, 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) { when (controls.meta["type"].string) {
"trackball" -> TrackballControls(camera, element) "trackball" -> TrackballControls(camera, element)
else -> OrbitControls(camera, element) else -> OrbitControls(camera, element)
@ -311,7 +322,7 @@ public class ThreeCanvas(
private const val SELECT_NAME = "@select" private const val SELECT_NAME = "@select"
private const val LIGHT_NAME = "@light" private const val LIGHT_NAME = "@light"
private const val AXES_NAME = "@axes" private const val AXES_NAME = "@axes"
private const val CLIP_HELPER_NAME = "@clipping" //private const val CLIP_HELPER_NAME = "@clipping"
} }
} }

View File

@ -8,7 +8,6 @@ import space.kscience.dataforge.misc.Type
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.computeProperty
import space.kscience.visionforge.solid.* import space.kscience.visionforge.solid.*
import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY import space.kscience.visionforge.solid.SolidMaterial.Companion.MATERIAL_KEY
import space.kscience.visionforge.solid.three.ThreeFactory.Companion.TYPE 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 * Update non-position non-geometry property
*/ */
public fun Object3D.updateProperty(source: Vision, propertyName: Name) { 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)) { if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) {
updateMaterialProperty(source, propertyName) updateMaterialProperty(source, propertyName)
} else if ( } else if (

View File

@ -3,39 +3,52 @@ package space.kscience.visionforge.solid.three
import info.laht.threekt.materials.LineBasicMaterial import info.laht.threekt.materials.LineBasicMaterial
import info.laht.threekt.materials.Material import info.laht.threekt.materials.Material
import info.laht.threekt.materials.MeshBasicMaterial import info.laht.threekt.materials.MeshBasicMaterial
import info.laht.threekt.materials.MeshStandardMaterial
import info.laht.threekt.math.Color import info.laht.threekt.math.Color
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.* import space.kscience.dataforge.values.*
import space.kscience.visionforge.Colors import space.kscience.visionforge.Colors
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.computePropertyNode import space.kscience.visionforge.computePropertyNode
import space.kscience.visionforge.getStyleNodes import space.kscience.visionforge.getStyleNodes
import space.kscience.visionforge.solid.ColorAccessor
import space.kscience.visionforge.solid.SolidMaterial import space.kscience.visionforge.solid.SolidMaterial
import space.kscience.visionforge.solid.SolidReference import space.kscience.visionforge.solid.SolidReference
public object ThreeMaterials { public object ThreeMaterials {
public val DEFAULT_COLOR: Color = Color(Colors.darkgreen) public val DEFAULT_COLOR: Color = Color(Colors.darkgreen)
public val DEFAULT: MeshBasicMaterial = MeshBasicMaterial().apply {
public val DEFAULT: MeshStandardMaterial = MeshStandardMaterial().apply {
color.set(DEFAULT_COLOR) color.set(DEFAULT_COLOR)
cached = true 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 { public val DEFAULT_LINE: LineBasicMaterial = LineBasicMaterial().apply {
color.set(DEFAULT_LINE_COLOR) color.set(DEFAULT_LINE_COLOR)
cached = true
} }
public val SELECTED_MATERIAL: LineBasicMaterial = LineBasicMaterial().apply { public val SELECTED_MATERIAL: LineBasicMaterial = LineBasicMaterial().apply {
color.set(Colors.ivory) color.set(Colors.ivory)
linewidth = 8.0 linewidth = 8.0
cached = true
} }
public val HIGHLIGHT_MATERIAL: LineBasicMaterial = LineBasicMaterial().apply { public val HIGHLIGHT_MATERIAL: LineBasicMaterial = LineBasicMaterial().apply {
color.set(Colors.blue) color.set(Colors.blue)
linewidth = 8.0 linewidth = 8.0
cached = true
} }
private val lineMaterialCache = HashMap<Meta, LineBasicMaterial>() private val lineMaterialCache = HashMap<Meta, LineBasicMaterial>()
@ -58,34 +71,21 @@ public object ThreeMaterials {
private val materialCache = HashMap<Meta, Material>() private val materialCache = HashMap<Meta, Material>()
internal fun buildMaterial(meta: Meta): Material = MeshBasicMaterial().apply { internal fun buildMaterial(meta: Meta): Material = when (meta[SolidMaterial.TYPE_KEY]?.string) {
color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR "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 opacity = meta[SolidMaterial.OPACITY_KEY]?.double ?: 1.0
transparent = opacity < 1.0 transparent = opacity < 1.0
wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false
needsUpdate = true 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) { internal fun cacheMaterial(meta: Meta): Material = materialCache.getOrPut(meta) {
buildMaterial(meta).apply { 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 private var Material.cached: Boolean
get() = userData["cached"] == true get() = userData["cached"] == true
set(value) { set(value) {
@ -139,7 +149,11 @@ public fun Mesh.updateMaterial(vision: Vision) {
} }
public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) { 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 //generate a new material since cached material should not be changed
updateMaterial(vision) updateMaterial(vision)
} else { } else {
@ -149,6 +163,16 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
?: ThreeMaterials.DEFAULT_COLOR ?: ThreeMaterials.DEFAULT_COLOR
material.needsUpdate = true 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 -> { SolidMaterial.MATERIAL_OPACITY_KEY -> {
val opacity = vision.getPropertyValue( val opacity = vision.getPropertyValue(
SolidMaterial.MATERIAL_OPACITY_KEY, SolidMaterial.MATERIAL_OPACITY_KEY,

View File

@ -1,7 +1,6 @@
package space.kscience.visionforge.solid.three package space.kscience.visionforge.solid.three
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import kotlinx.coroutines.CoroutineScope
import org.w3c.dom.Element import org.w3c.dom.Element
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
import space.kscience.dataforge.context.* import space.kscience.dataforge.context.*
@ -27,8 +26,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
private val objectFactories = HashMap<KClass<out Solid>, ThreeFactory<*>>() private val objectFactories = HashMap<KClass<out Solid>, ThreeFactory<*>>()
private val compositeFactory = ThreeCompositeFactory(this) 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 { init {
//Add specialized factories here //Add specialized factories here
@ -38,6 +36,8 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
objectFactories[ConeSegment::class] = ThreeConeFactory objectFactories[ConeSegment::class] = ThreeConeFactory
objectFactories[PolyLine::class] = ThreeLineFactory objectFactories[PolyLine::class] = ThreeLineFactory
objectFactories[SolidLabel::class] = ThreeCanvasLabelFactory objectFactories[SolidLabel::class] = ThreeCanvasLabelFactory
objectFactories[AmbientLightSource::class] = ThreeAmbientLightFactory
objectFactories[PointLightSource::class] = ThreePointLightFactory
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")

View File

@ -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<PointLightSource> {
override val type: KClass<in PointLightSource> 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
}
}