Optimized materials allocation

This commit is contained in:
Alexander Nozik 2020-12-21 21:45:29 +03:00
parent eefc036dcb
commit 66ea23ad60
11 changed files with 181 additions and 91 deletions

View File

@ -11,7 +11,6 @@ import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.Solid.Companion.GEOMETRY_KEY import hep.dataforge.vision.solid.Solid.Companion.GEOMETRY_KEY
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
import hep.dataforge.vision.solid.three.* import hep.dataforge.vision.solid.three.*
import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial
import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import info.laht.threekt.geometries.BoxBufferGeometry import info.laht.threekt.geometries.BoxBufferGeometry
@ -31,8 +30,8 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV
scaleX = xSize scaleX = xSize
scaleY = ySize scaleY = ySize
scaleZ = zSize scaleZ = zSize
getProperty(MeshThreeFactory.EDGES_ENABLED_KEY, false) // getProperty(MeshThreeFactory.EDGES_ENABLED_KEY, inherit = false, includeStyles = false)
getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY, false) // getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY, inherit = false, includeStyles = false)
} }
override fun render(three: ThreePlugin): Object3D { override fun render(three: ThreePlugin): Object3D {
@ -44,9 +43,10 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV
//JS sometimes tries to pass Geometry as BufferGeometry //JS sometimes tries to pass Geometry as BufferGeometry
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected") @Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
val mesh = Mesh(geometry, getMaterial(this@VariableBox, true)).apply { val mesh = Mesh(geometry, ThreeMaterials.DEFAULT).apply {
updateMaterial(this@VariableBox)
applyEdges(this@VariableBox) applyEdges(this@VariableBox)
applyWireFrame(this@VariableBox) //applyWireFrame(this@VariableBox)
//set position for mesh //set position for mesh
updatePosition(this@VariableBox) updatePosition(this@VariableBox)
@ -69,10 +69,10 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV
mesh.scale.set(newXSize, newYSize, newZSize) mesh.scale.set(newXSize, newYSize, newZSize)
mesh.updateMatrix() mesh.updateMatrix()
} }
name.startsWith(MeshThreeFactory.WIREFRAME_KEY) -> mesh.applyWireFrame(this@VariableBox) //name.startsWith(MeshThreeFactory.WIREFRAME_KEY) -> mesh.applyWireFrame(this@VariableBox)
name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox) name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox)
name.startsWith(MATERIAL_COLOR_KEY) -> { name.startsWith(MATERIAL_COLOR_KEY) -> {
mesh.material = getMaterial(this, true) mesh.updateMaterial(this)
} }
else -> mesh.updateProperty(this@VariableBox, name) else -> mesh.updateProperty(this@VariableBox, name)
} }

View File

@ -4,6 +4,7 @@ import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.MutableItemProvider import hep.dataforge.meta.MutableItemProvider
import hep.dataforge.meta.descriptors.Described import hep.dataforge.meta.descriptors.Described
import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.descriptors.get
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.toName import hep.dataforge.names.toName
@ -45,8 +46,8 @@ public interface Vision : Described {
*/ */
public fun getProperty( public fun getProperty(
name: Name, name: Name,
inherit: Boolean? = null, inherit: Boolean = false,
includeStyles: Boolean? = null, includeStyles: Boolean = true,
includeDefaults: Boolean = true, includeDefaults: Boolean = true,
): MetaItem<*>? ): MetaItem<*>?
@ -63,7 +64,8 @@ public interface Vision : Described {
* if it should include inherited properties etc. * if it should include inherited properties etc.
*/ */
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
public val propertyChanges: Flow<Name> get() = callbackFlow<Name> { public val propertyChanges: Flow<Name>
get() = callbackFlow<Name> {
coroutineScope { coroutineScope {
onPropertyChange(this) { onPropertyChange(this) {
send(it) send(it)
@ -93,7 +95,7 @@ public interface Vision : Described {
} }
} }
public fun Vision.asyncNotifyPropertyChange(propertyName: Name){ public fun Vision.asyncNotifyPropertyChange(propertyName: Name) {
scope.launch { scope.launch {
notifyPropertyChanged(propertyName) notifyPropertyChanged(propertyName)
} }
@ -120,8 +122,8 @@ public fun Vision.allProperties(
): MutableItemProvider = object : MutableItemProvider { ): MutableItemProvider = object : MutableItemProvider {
override fun getItem(name: Name): MetaItem<*>? = getProperty( override fun getItem(name: Name): MetaItem<*>? = getProperty(
name, name,
inherit = inherit, inherit = inherit ?: (descriptor?.get(name)?.inherited != false),
includeStyles = includeStyles, includeStyles = includeStyles ?: (descriptor?.get(name)?.usesStyles == true),
includeDefaults = includeDefaults includeDefaults = includeDefaults
) )
@ -133,8 +135,8 @@ public fun Vision.allProperties(
*/ */
public fun Vision.getProperty( public fun Vision.getProperty(
key: String, key: String,
inherit: Boolean? = null, inherit: Boolean = false,
includeStyles: Boolean? = null, includeStyles: Boolean = true,
includeDefaults: Boolean = true, includeDefaults: Boolean = true,
): MetaItem<*>? = getProperty(key.toName(), inherit, includeStyles, includeDefaults) ): MetaItem<*>? = getProperty(key.toName(), inherit, includeStyles, includeDefaults)

View File

@ -65,15 +65,15 @@ public open class VisionBase : Vision {
override fun getProperty( override fun getProperty(
name: Name, name: Name,
inherit: Boolean?, inherit: Boolean,
includeStyles: Boolean?, includeStyles: Boolean,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem<*>? = sequence { ): MetaItem<*>? = sequence {
yield(getOwnProperty(name)) yield(getOwnProperty(name))
if (includeStyles ?: descriptor?.get(name)?.usesStyles != false) { if (includeStyles) {
yieldAll(getStyleItems(name)) yieldAll(getStyleItems(name))
} }
if (inherit ?: descriptor?.get(name)?.inherited == true) { if (inherit) {
yield(parent?.getProperty(name, inherit, includeStyles, includeDefaults)) yield(parent?.getProperty(name, inherit, includeStyles, includeDefaults))
} }
yield(descriptor?.get(name)?.defaultItem()) yield(descriptor?.get(name)?.defaultItem())

View File

@ -6,8 +6,7 @@ import hep.dataforge.values.asValue
@DslMarker @DslMarker
public annotation class VisionBuilder public annotation class VisionBuilder
public fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>? { public fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>? = when (val first = firstOrNull { it != null }) {
return when (val first = firstOrNull { it != null }) {
null -> null null -> null
is MetaItem.ValueItem -> first //fast search for first entry if it is value is MetaItem.ValueItem -> first //fast search for first entry if it is value
is MetaItem.NodeItem -> { is MetaItem.NodeItem -> {
@ -15,7 +14,6 @@ public fun Sequence<MetaItem<*>?>.merge(): MetaItem<*>? {
val laminate: Laminate = Laminate(mapNotNull { it.node }.toList()) val laminate: Laminate = Laminate(mapNotNull { it.node }.toList())
MetaItem.NodeItem(laminate) MetaItem.NodeItem(laminate)
} }
}
} }
@DFExperimental @DFExperimental

View File

@ -109,8 +109,8 @@ internal class Prototypes(
override fun getProperty( override fun getProperty(
name: Name, name: Name,
inherit: Boolean?, inherit: Boolean,
includeStyles: Boolean?, includeStyles: Boolean,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem<*>? = null ): MetaItem<*>? = null

View File

@ -2,7 +2,6 @@ package hep.dataforge.vision.solid
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.descriptors.get
import hep.dataforge.names.* import hep.dataforge.names.*
import hep.dataforge.vision.* import hep.dataforge.vision.*
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -15,17 +14,17 @@ public interface SolidReference : Vision {
private fun SolidReference.getRefProperty( private fun SolidReference.getRefProperty(
name: Name, name: Name,
inherit: Boolean?, inherit: Boolean,
includeStyles: Boolean?, includeStyles: Boolean,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem<*>? { ): MetaItem<*>? {
return sequence { return sequence {
yield(getOwnProperty(name)) yield(getOwnProperty(name))
if (includeStyles ?: descriptor?.get(name)?.usesStyles != false) { if (includeStyles) {
yieldAll(getStyleItems(name)) yieldAll(getStyleItems(name))
} }
yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults)) yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
if (inherit ?: descriptor?.get(name)?.inherited == true) { if (inherit) {
yield(parent?.getProperty(name, inherit)) yield(parent?.getProperty(name, inherit))
} }
}.merge() }.merge()
@ -77,8 +76,8 @@ public class SolidReferenceGroup(
override fun getProperty( override fun getProperty(
name: Name, name: Name,
inherit: Boolean?, inherit: Boolean,
includeStyles: Boolean?, includeStyles: Boolean,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem<*>? = getRefProperty(name, inherit, includeStyles, includeDefaults) ): MetaItem<*>? = getRefProperty(name, inherit, includeStyles, includeDefaults)
@ -108,8 +107,8 @@ public class SolidReferenceGroup(
override fun getProperty( override fun getProperty(
name: Name, name: Name,
inherit: Boolean?, inherit: Boolean,
includeStyles: Boolean?, includeStyles: Boolean,
includeDefaults: Boolean, includeDefaults: Boolean,
): MetaItem<*>? = getRefProperty(name, inherit, includeStyles, includeDefaults) ): MetaItem<*>? = getRefProperty(name, inherit, includeStyles, includeDefaults)

View File

@ -9,10 +9,8 @@ import hep.dataforge.names.startsWith
import hep.dataforge.vision.solid.Solid import hep.dataforge.vision.solid.Solid
import hep.dataforge.vision.solid.SolidMaterial import hep.dataforge.vision.solid.SolidMaterial
import hep.dataforge.vision.solid.layer import hep.dataforge.vision.solid.layer
import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial
import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.geometries.EdgesGeometry import info.laht.threekt.geometries.EdgesGeometry
import info.laht.threekt.geometries.WireframeGeometry
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 kotlin.reflect.KClass import kotlin.reflect.KClass
@ -36,7 +34,7 @@ public abstract class MeshThreeFactory<in T : Solid>(
//val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty //val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty
val mesh = Mesh(geometry, null).apply { val mesh = Mesh(geometry, ThreeMaterials.DEFAULT).apply {
matrixAutoUpdate = false matrixAutoUpdate = false
//set position for mesh //set position for mesh
updatePosition(obj) updatePosition(obj)
@ -49,11 +47,11 @@ public abstract class MeshThreeFactory<in T : Solid>(
val oldGeometry = mesh.geometry as BufferGeometry val oldGeometry = mesh.geometry as BufferGeometry
val newGeometry = buildGeometry(obj) val newGeometry = buildGeometry(obj)
oldGeometry.attributes = newGeometry.attributes oldGeometry.attributes = newGeometry.attributes
mesh.applyWireFrame(obj) //mesh.applyWireFrame(obj)
mesh.applyEdges(obj) mesh.applyEdges(obj)
newGeometry.dispose() newGeometry.dispose()
} }
name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj) //name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj)
name.startsWith(EDGES_KEY) -> mesh.applyEdges(obj) name.startsWith(EDGES_KEY) -> mesh.applyEdges(obj)
else -> mesh.updateProperty(obj, name) else -> mesh.updateProperty(obj, name)
} }
@ -64,19 +62,19 @@ public abstract class MeshThreeFactory<in T : Solid>(
public companion object { public companion object {
public val EDGES_KEY: Name = "edges".asName() public val EDGES_KEY: Name = "edges".asName()
public val WIREFRAME_KEY: Name = "wireframe".asName() //public val WIREFRAME_KEY: Name = "wireframe".asName()
public val ENABLED_KEY: Name = "enabled".asName() public val ENABLED_KEY: Name = "enabled".asName()
public val EDGES_ENABLED_KEY: Name = EDGES_KEY + ENABLED_KEY public val EDGES_ENABLED_KEY: Name = EDGES_KEY + ENABLED_KEY
public val EDGES_MATERIAL_KEY: Name = EDGES_KEY + SolidMaterial.MATERIAL_KEY public val EDGES_MATERIAL_KEY: Name = EDGES_KEY + SolidMaterial.MATERIAL_KEY
public val WIREFRAME_ENABLED_KEY: Name = WIREFRAME_KEY + ENABLED_KEY //public val WIREFRAME_ENABLED_KEY: Name = WIREFRAME_KEY + ENABLED_KEY
public val WIREFRAME_MATERIAL_KEY: Name = WIREFRAME_KEY + SolidMaterial.MATERIAL_KEY //public val WIREFRAME_MATERIAL_KEY: Name = WIREFRAME_KEY + SolidMaterial.MATERIAL_KEY
} }
} }
internal fun Mesh.applyProperties(obj: Solid): Mesh = apply { internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
material = getMaterial(obj, true) updateMaterial(obj)
applyEdges(obj) applyEdges(obj)
applyWireFrame(obj) //applyWireFrame(obj)
layers.enable(obj.layer) layers.enable(obj.layer)
children.forEach { children.forEach {
it.layers.enable(obj.layer) it.layers.enable(obj.layer)
@ -86,9 +84,16 @@ internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
public fun Mesh.applyEdges(obj: Solid) { public fun Mesh.applyEdges(obj: Solid) {
val edges = children.find { it.name == "@edges" } as? LineSegments val edges = children.find { it.name == "@edges" } as? LineSegments
//inherited edges definition, enabled by default //inherited edges definition, enabled by default
if (obj.getProperty(MeshThreeFactory.EDGES_ENABLED_KEY).boolean != false) { if (obj.getProperty(MeshThreeFactory.EDGES_ENABLED_KEY, inherit = true, includeStyles = true).boolean != false) {
val bufferGeometry = geometry as? BufferGeometry ?: return val bufferGeometry = geometry as? BufferGeometry ?: return
val material = ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node, true) val material = ThreeMaterials.getLineMaterial(
obj.getProperty(
MeshThreeFactory.EDGES_MATERIAL_KEY,
inherit = true,
includeStyles = true
).node,
true
)
if (edges == null) { if (edges == null) {
add( add(
LineSegments( LineSegments(
@ -109,23 +114,23 @@ public fun Mesh.applyEdges(obj: Solid) {
} }
} }
public fun Mesh.applyWireFrame(obj: Solid) { //public fun Mesh.applyWireFrame(obj: Solid) {
children.find { it.name == "@wireframe" }?.let { // children.find { it.name == "@wireframe" }?.let {
remove(it) // remove(it)
(it as LineSegments).dispose() // (it as LineSegments).dispose()
} // }
//inherited wireframe definition, disabled by default // //inherited wireframe definition, disabled by default
if (obj.getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY).boolean == true) { // if (obj.getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY).boolean == true) {
val bufferGeometry = geometry as? BufferGeometry ?: return // val bufferGeometry = geometry as? BufferGeometry ?: return
val material = // val material =
ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.WIREFRAME_MATERIAL_KEY).node, true) // ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.WIREFRAME_MATERIAL_KEY).node, true)
add( // add(
LineSegments( // LineSegments(
WireframeGeometry(bufferGeometry), // WireframeGeometry(bufferGeometry),
material // material
).apply { // ).apply {
name = "@wireframe" // name = "@wireframe"
} // }
) // )
} // }
} //}

View File

@ -7,7 +7,6 @@ import hep.dataforge.vision.Vision
import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_KEY import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_KEY
import hep.dataforge.vision.solid.three.ThreeFactory.Companion.TYPE import hep.dataforge.vision.solid.three.ThreeFactory.Companion.TYPE
import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial
import hep.dataforge.vision.visible import hep.dataforge.vision.visible
import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.BufferGeometry
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
@ -34,7 +33,7 @@ public interface ThreeFactory<in T : Vision> {
*/ */
public fun Object3D.updatePosition(obj: Vision) { public fun Object3D.updatePosition(obj: Vision) {
visible = obj.visible ?: true visible = obj.visible ?: true
if(obj is Solid) { if (obj is Solid) {
position.set(obj.x, obj.y, obj.z) position.set(obj.x, obj.y, obj.z)
setRotationFromEuler(obj.euler) setRotationFromEuler(obj.euler)
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ) scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)
@ -47,7 +46,7 @@ public fun Object3D.updatePosition(obj: Vision) {
*/ */
public fun Object3D.updateProperty(source: Vision, propertyName: Name) { public fun Object3D.updateProperty(source: Vision, propertyName: Name) {
if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) { if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) {
this.material = getMaterial(source, true) updateMaterialProperty(source, propertyName)
} else if ( } else if (
propertyName.startsWith(Solid.POSITION_KEY) propertyName.startsWith(Solid.POSITION_KEY)
|| propertyName.startsWith(Solid.ROTATION) || propertyName.startsWith(Solid.ROTATION)

View File

@ -3,7 +3,6 @@ package hep.dataforge.vision.solid.three
import hep.dataforge.context.logger import hep.dataforge.context.logger
import hep.dataforge.vision.solid.SolidLabel import hep.dataforge.vision.solid.SolidLabel
import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial
import info.laht.threekt.core.Object3D import info.laht.threekt.core.Object3D
import info.laht.threekt.geometries.TextBufferGeometry import info.laht.threekt.geometries.TextBufferGeometry
import info.laht.threekt.objects.Mesh import info.laht.threekt.objects.Mesh
@ -23,11 +22,12 @@ public object ThreeLabelFactory : ThreeFactory<SolidLabel> {
height = 1 height = 1
curveSegments = 1 curveSegments = 1
}) })
return Mesh(textGeo, getMaterial(obj, true)).apply { return Mesh(textGeo, ThreeMaterials.DEFAULT).apply {
updateMaterial(obj)
updatePosition(obj) updatePosition(obj)
obj.onPropertyChange(three.updateScope){ _ -> obj.onPropertyChange(three.updateScope) { _ ->
//TODO //TODO
three.logger.warn{"Label parameter change not implemented"} three.logger.warn { "Label parameter change not implemented" }
} }
} }
} }

View File

@ -1,23 +1,28 @@
package hep.dataforge.vision.solid.three package hep.dataforge.vision.solid.three
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.names.Name
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import hep.dataforge.values.int import hep.dataforge.values.int
import hep.dataforge.values.string import hep.dataforge.values.string
import hep.dataforge.vision.Colors import hep.dataforge.vision.Colors
import hep.dataforge.vision.Vision import hep.dataforge.vision.Vision
import hep.dataforge.vision.allStyles
import hep.dataforge.vision.merge
import hep.dataforge.vision.solid.SolidMaterial import hep.dataforge.vision.solid.SolidMaterial
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.MeshPhongMaterial import info.laht.threekt.materials.MeshPhongMaterial
import info.laht.threekt.math.Color import info.laht.threekt.math.Color
import info.laht.threekt.objects.Mesh
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: MeshBasicMaterial = MeshBasicMaterial().apply {
color.set(DEFAULT_COLOR) color.set(DEFAULT_COLOR)
cached = true
} }
public val DEFAULT_LINE_COLOR: Color = Color(Colors.black) public val DEFAULT_LINE_COLOR: Color = Color(Colors.black)
public val DEFAULT_LINE: LineBasicMaterial = LineBasicMaterial().apply { public val DEFAULT_LINE: LineBasicMaterial = LineBasicMaterial().apply {
@ -54,7 +59,7 @@ public object ThreeMaterials {
private val materialCache = HashMap<Meta, Material>() private val materialCache = HashMap<Meta, Material>()
private fun buildMaterial(meta: Meta): Material { internal fun buildMaterial(meta: Meta): Material {
return if (meta[SolidMaterial.SPECULAR_COLOR_KEY] != null) { return if (meta[SolidMaterial.SPECULAR_COLOR_KEY] != null) {
MeshPhongMaterial().apply { MeshPhongMaterial().apply {
color = meta[SolidMaterial.COLOR_KEY]?.getColor() ?: DEFAULT_COLOR color = meta[SolidMaterial.COLOR_KEY]?.getColor() ?: DEFAULT_COLOR
@ -79,15 +84,26 @@ public object ThreeMaterials {
} }
} }
public fun getMaterial(vision3D: Vision, cache: Boolean): Material { internal fun cacheMeta(meta: Meta): Material = materialCache.getOrPut(meta) {
val meta = vision3D.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node ?: return DEFAULT buildMaterial(meta).apply {
return if (cache) { cached = true
materialCache.getOrPut(meta) { buildMaterial(meta) }
} else {
buildMaterial(meta)
} }
} }
// internal fun getMaterial(vision: Vision, cache: Boolean): Material {
// val meta = vision.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node ?: return DEFAULT
// return if (cache) {
// materialCache.getOrPut(meta) {
// buildMaterial(meta).apply {
// cached = true
// }
// }
// } else {
// buildMaterial(meta)
// }
// }
} }
/** /**
@ -111,3 +127,74 @@ public fun MetaItem<*>.getColor(): Color {
} }
} }
private var Material.cached: Boolean
get() = userData["cached"] == true
set(value) {
userData["cached"] = value
}
public fun Mesh.updateMaterial(vision: Vision) {
//val meta = vision.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node
val ownMaterialMeta = vision.getOwnProperty(SolidMaterial.MATERIAL_KEY)
val stylesMaterialMeta = vision.allStyles[SolidMaterial.MATERIAL_KEY]
val parentMaterialMeta = vision.parent?.getProperty(
SolidMaterial.MATERIAL_KEY,
inherit = true,
includeStyles = false,
includeDefaults = false
)
material = when {
ownMaterialMeta == null && stylesMaterialMeta == null && parentMaterialMeta == null -> {
//use default is not material properties are defined
ThreeMaterials.DEFAULT
}
ownMaterialMeta == null && parentMaterialMeta == null -> {
//If material is style-based, use cached
ThreeMaterials.cacheMeta(stylesMaterialMeta.node ?: Meta.EMPTY)
}
else -> {
val merge = sequenceOf(ownMaterialMeta, stylesMaterialMeta, parentMaterialMeta).merge().node ?: Meta.EMPTY
ThreeMaterials.buildMaterial(merge)
}
}
}
public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
if (material.cached) {
//generate a new material since cached material should not be changed
updateMaterial(vision)
} else {
when (propertyName) {
SolidMaterial.MATERIAL_COLOR_KEY -> {
material.asDynamic().color = vision.getProperty(
SolidMaterial.MATERIAL_COLOR_KEY,
inherit = true,
includeStyles = true,
includeDefaults = false
)?.getColor() ?: ThreeMaterials.DEFAULT_COLOR
material.needsUpdate = true
}
SolidMaterial.MATERIAL_OPACITY_KEY -> {
val opacity = vision.getProperty(
SolidMaterial.MATERIAL_OPACITY_KEY,
inherit = true,
includeStyles = true,
includeDefaults = false
).double ?: 1.0
material.asDynamic().opacity = opacity
material.transparent = opacity < 1.0
material.needsUpdate = true
}
SolidMaterial.MATERIAL_WIREFRAME_KEY -> {
material.asDynamic().wireframe = vision.getProperty(
SolidMaterial.MATERIAL_WIREFRAME_KEY,
inherit = true,
includeStyles = true,
includeDefaults = false
).boolean ?: false
material.needsUpdate = true
}
else -> console.warn("Unrecognized material property: $propertyName")
}
}
}

View File

@ -111,7 +111,7 @@ open external class Material {
var visible: Boolean var visible: Boolean
var userData: Map<String, Any> var userData: dynamic
/** /**
* Specifies that the material needs to be updated at the WebGL level. Set it to true if you made changes that need to be reflected in WebGL. * Specifies that the material needs to be updated at the WebGL level. Set it to true if you made changes that need to be reflected in WebGL.