More universal treatment of highlighting in three

This commit is contained in:
Alexander Nozik 2022-08-19 11:22:10 +03:00
parent 67afa4e45b
commit 40b784f551
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
8 changed files with 79 additions and 31 deletions

View File

@ -67,7 +67,7 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?)
* List of names of styles applied to this object. Order matters. Not inherited.
*/
public var Vision.styles: List<String>
get() = properties.getValue(Vision.STYLE_KEY, inherit = false, includeStyles = false)?.stringList ?: emptyList()
get() = properties.own?.getValue(Vision.STYLE_KEY)?.stringList ?: emptyList()
set(value) {
properties.setValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue())
}

View File

@ -143,8 +143,11 @@ private class VisionPropertiesItem(
override fun hashCode(): Int = Meta.hashCode(this)
}
/**
* A base implementation of [MutableVisionProperties]
*/
public abstract class AbstractVisionProperties(
private val vision: Vision,
public val vision: Vision,
) : MutableVisionProperties {
override val descriptor: MetaDescriptor? get() = vision.descriptor

View File

@ -58,6 +58,8 @@ public interface Solid : Vision {
public val ROTATION_KEY: Name = "rotation".asName()
public val QUATERNION_KEY: Name = "quaternion".asName()
public val X_ROTATION_KEY: Name = ROTATION_KEY + X_KEY
public val Y_ROTATION_KEY: Name = ROTATION_KEY + Y_KEY
public val Z_ROTATION_KEY: Name = ROTATION_KEY + Z_KEY

View File

@ -20,9 +20,12 @@ import three.external.controls.OrbitControls
import three.external.controls.TrackballControls
import three.geometries.EdgesGeometry
import three.helpers.AxesHelper
import three.materials.Material
import three.math.*
import three.meshline.MeshLine
import three.meshline.MeshLineMaterial
import three.meshline.isMeshLineMaterial
import three.objects.LineSegments
import three.objects.Mesh
import three.scenes.Scene
import kotlin.math.cos
@ -276,7 +279,7 @@ public class ThreeCanvas(
private fun Object3D.toggleHighlight(
highlight: Boolean,
edgesName: String,
material: MeshLineMaterial,
material: Material,
) {
if (userData[DO_NOT_HIGHLIGHT_TAG] == true) {
@ -284,16 +287,21 @@ public class ThreeCanvas(
}
if (isMesh(this)) {
val highlightMesh = getObjectByName(edgesName) ?: Mesh(
MeshLine(EdgesGeometry(geometry)),
material
).also {
val highlightMesh = getObjectByName(edgesName) ?: if (isMeshLineMaterial(material)) {
Mesh(
MeshLine(EdgesGeometry(geometry)),
material
)
} else {
LineSegments(EdgesGeometry(geometry), material)
}.also {
it.name = edgesName
add(it)
}
highlightMesh.visible = highlight
} else {
children.filter { !it.name.startsWith("@") && it.name != edgesName }.forEach {
//ignore service objects if they are not statics
children.filter { it.name.startsWith("@static") || !it.name.startsWith("@") }.forEach {
it.toggleHighlight(highlight, edgesName, material)
}
}
@ -319,15 +327,25 @@ public class ThreeCanvas(
public companion object {
public val SELECTED_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply {
color.set(Colors.ivory)
linewidth = 2.0
thickness = 2f
cached = true
}
public val HIGHLIGHT_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply {
color.set(Colors.blue)
linewidth = 2.0
thickness = 2f
cached = true
}
//
// public val SELECTED_MATERIAL: LineBasicMaterial = LineBasicMaterial().apply {
// color.set(Colors.ivory)
// cached = true
// }
//
// public val HIGHLIGHT_MATERIAL: LineBasicMaterial = LineBasicMaterial().apply {
// color.set(Colors.blue)
// cached = true
// }
public const val DO_NOT_HIGHLIGHT_TAG: String = "doNotHighlight"

View File

@ -1,14 +1,14 @@
package space.kscience.visionforge.solid.three
import three.core.Object3D
import three.geometries.TextBufferGeometry
import three.objects.Mesh
import kotlinx.js.jso
import space.kscience.dataforge.context.logger
import space.kscience.dataforge.context.warn
import space.kscience.visionforge.onPropertyChange
import space.kscience.visionforge.solid.SolidLabel
import three.core.Object3D
import three.geometries.TextBufferGeometry
import three.objects.Mesh
import kotlin.reflect.KClass
/**
@ -25,7 +25,7 @@ public object ThreeLabelFactory : ThreeFactory<SolidLabel> {
curveSegments = 1
})
return Mesh(textGeo, ThreeMaterials.DEFAULT).apply {
createMaterial(vision)
setMaterial(vision)
updatePosition(vision)
if(observe) {
vision.onPropertyChange(three.context) {

View File

@ -60,6 +60,7 @@ public object ThreeMaterials {
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
@ -71,10 +72,18 @@ public object ThreeMaterials {
needsUpdate = true
}
private val materialCache = HashMap<Int, Material>()
// private val materialCache = HashMap<Int, Material>()
//
// internal fun cacheMaterial(meta: Meta): Material = materialCache.getOrPut(meta.hashCode()) {
// buildMaterial(meta).apply {
// cached = true
// }
// }
internal fun cacheMaterial(meta: Meta): Material = materialCache.getOrPut(meta.hashCode()) {
buildMaterial(meta).apply {
private val visionMaterialCache = HashMap<Vision, Material>()
internal fun cacheMaterial(vision: Vision): Material = visionMaterialCache.getOrPut(vision) {
buildMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY)).apply {
cached = true
}
}
@ -84,7 +93,7 @@ public object ThreeMaterials {
* Compute color
*/
public fun Meta.threeColor(): Color? {
if(isEmpty()) return null
if (isEmpty()) return null
val value = value
return if (isLeaf) {
when {
@ -118,13 +127,19 @@ internal var Material.cached: Boolean
userData["cached"] = value
}
public fun Mesh.createMaterial(vision: Vision) {
val ownMaterialMeta = vision.properties.own?.get(SolidMaterial.MATERIAL_KEY)
if (ownMaterialMeta == null) {
if (vision is SolidReference && vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty()) {
createMaterial(vision.prototype)
public fun Mesh.setMaterial(vision: Vision) {
if (
vision.properties.own?.get(SolidMaterial.MATERIAL_KEY) == null
&& vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty()
) {
//if this is a reference, use material of the prototype
if (vision is SolidReference) {
ThreeMaterials.cacheMaterial(vision.prototype)
} else {
material = ThreeMaterials.cacheMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY))
material = vision.parent?.let { parent ->
//TODO cache parent material
ThreeMaterials.buildMaterial(parent.properties.getProperty(SolidMaterial.MATERIAL_KEY))
} ?: ThreeMaterials.cacheMaterial(vision)
}
} else {
material = ThreeMaterials.buildMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY))
@ -138,22 +153,27 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
|| propertyName == SolidMaterial.MATERIAL_KEY + SolidMaterial.TYPE_KEY
) {
//generate a new material since cached material should not be changed
createMaterial(vision)
setMaterial(vision)
} else {
when (propertyName) {
SolidMaterial.MATERIAL_COLOR_KEY -> {
material.asDynamic().color = vision.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).threeColor()
?: ThreeMaterials.DEFAULT_COLOR
material.asDynamic().color =
vision.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).threeColor()
?: ThreeMaterials.DEFAULT_COLOR
}
SolidMaterial.SPECULAR_COLOR_KEY -> {
material.asDynamic().specular = vision.properties.getProperty(SolidMaterial.SPECULAR_COLOR_KEY).threeColor()
?: ThreeMaterials.DEFAULT_COLOR
material.asDynamic().specular =
vision.properties.getProperty(SolidMaterial.SPECULAR_COLOR_KEY).threeColor()
?: ThreeMaterials.DEFAULT_COLOR
}
SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY -> {
material.asDynamic().emissive = vision.properties.getProperty(SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY)
.threeColor()
?: ThreeMaterials.BLACK_COLOR
}
SolidMaterial.MATERIAL_OPACITY_KEY -> {
val opacity = vision.properties.getValue(
SolidMaterial.MATERIAL_OPACITY_KEY,
@ -162,12 +182,14 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
material.opacity = opacity
material.transparent = opacity < 1.0
}
SolidMaterial.MATERIAL_WIREFRAME_KEY -> {
material.asDynamic().wireframe = vision.properties.getValue(
SolidMaterial.MATERIAL_WIREFRAME_KEY,
inherit = true,
)?.boolean ?: false
}
else -> console.warn("Unrecognized material property: $propertyName")
}
material.needsUpdate = true

View File

@ -85,7 +85,7 @@ public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit
}
internal fun Mesh.applyProperties(vision: Solid): Mesh = apply {
createMaterial(vision)
setMaterial(vision)
applyEdges(vision)
//applyWireFrame(obj)
layers.set(vision.layer)

View File

@ -1,8 +1,11 @@
package three.meshline
import three.core.BufferGeometry
import three.materials.Material
import three.math.Vector3
public fun MeshLine(geometry: BufferGeometry): MeshLine = MeshLine().apply { setGeometry(geometry) }
public fun MeshLine(points: Array<Vector3>): MeshLine = MeshLine().apply { setPoints(points) }
public fun MeshLine(points: Array<Vector3>): MeshLine = MeshLine().apply { setPoints(points) }
internal fun isMeshLineMaterial(material: Material): Boolean = material.asDynamic().isMeshLineMaterial == true