FX backend in progress

This commit is contained in:
Alexander Nozik 2019-12-15 10:56:44 +03:00
parent cef1a1ee6d
commit fd43ea4843
5 changed files with 46 additions and 34 deletions

View File

@ -1,8 +1,10 @@
package hep.dataforge.vis.spatial.fx package hep.dataforge.vis.spatial.demo
import hep.dataforge.context.Global import hep.dataforge.context.Global
import hep.dataforge.meta.number import hep.dataforge.meta.number
import hep.dataforge.vis.spatial.* import hep.dataforge.vis.spatial.*
import hep.dataforge.vis.spatial.fx.Canvas3D
import hep.dataforge.vis.spatial.fx.FX3DPlugin
import javafx.scene.Parent import javafx.scene.Parent
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -11,22 +13,21 @@ import kotlinx.coroutines.launch
import tornadofx.* import tornadofx.*
import kotlin.random.Random import kotlin.random.Random
class SpatialDemoApp: App(SpatialDemoView::class)
class RendererDemoApp : App(RendererDemoView::class) class SpatialDemoView: View(){
private val plugin = Global.plugins.fetch(FX3DPlugin)
private val canvas = Canvas3D(plugin)
class RendererDemoView : View() {
val plugin = Global.plugins.fetch(FX3DPlugin)
val renderer = Canvas3D(plugin)
override val root: Parent = borderpane { override val root: Parent = borderpane {
center = renderer.root center = canvas.root
} }
lateinit var group: VisualGroup3D lateinit var group: VisualGroup3D
init { init {
canvas.render {
renderer.render { box(100,100,100)
group = group { group = group {
box(100,100,100) box(100,100,100)
box(100,100,100) { box(100,100,100) {
@ -45,7 +46,7 @@ class RendererDemoView : View() {
} }
} }
renderer.apply { canvas.apply {
angleY = -30.0 angleY = -30.0
angleX = -15.0 angleX = -15.0
} }
@ -54,5 +55,5 @@ class RendererDemoView : View() {
fun main() { fun main() {
launch<RendererDemoApp>() launch<SpatialDemoApp>()
} }

View File

@ -19,13 +19,21 @@ import javafx.scene.input.KeyEvent
import javafx.scene.input.MouseEvent import javafx.scene.input.MouseEvent
import javafx.scene.input.ScrollEvent import javafx.scene.input.ScrollEvent
import javafx.scene.paint.Color import javafx.scene.paint.Color
import org.fxyz3d.scene.Axes
import org.fxyz3d.scene.CubeWorld
import org.fxyz3d.utils.CameraTransformer import org.fxyz3d.utils.CameraTransformer
import tornadofx.* import tornadofx.*
class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(), Renderer<VisualObject3D>, ContextAware { class Canvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) :
Fragment(), Renderer<VisualObject3D>, ContextAware {
override val context: Context get() = plugin.context override val context: Context get() = plugin.context
val world: Group = Group() val world = CubeWorld(true)
val axes = Axes().also {
it.setHeight(AXIS_LENGTH)
it.setRadius(LINE_WIDTH)
world.add(it)
}
private val camera = PerspectiveCamera().apply { private val camera = PerspectiveCamera().apply {
nearClip = CAMERA_NEAR_CLIP nearClip = CAMERA_NEAR_CLIP
@ -69,12 +77,12 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(),
768.0, 768.0,
true, true,
SceneAntialiasing.BALANCED SceneAntialiasing.BALANCED
).apply { ).also {scene->
fill = Color.GREY scene.fill = Color.GREY
this.camera = this@Canvas3D.camera scene.camera = camera
id = "canvas" id = "canvas"
handleKeyboard(this) handleKeyboard(scene)
handleMouse(this) handleMouse(scene)
} }
} }
@ -90,7 +98,7 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(),
cameraRotation.ry.angle = CAMERA_INITIAL_Y_ANGLE cameraRotation.ry.angle = CAMERA_INITIAL_Y_ANGLE
cameraRotation.rx.angle = CAMERA_INITIAL_X_ANGLE cameraRotation.rx.angle = CAMERA_INITIAL_X_ANGLE
} }
// KeyCode.X -> axisGroup.isVisible = !axisGroup.isVisible KeyCode.X -> axes.isVisible = !axes.isVisible
// KeyCode.S -> snapshot() // KeyCode.S -> snapshot()
// KeyCode.DIGIT1 -> pixelMap.filterKeys { it.getLayerNumber() == 1 }.values.forEach { // KeyCode.DIGIT1 -> pixelMap.filterKeys { it.getLayerNumber() == 1 }.values.forEach {
// toggleTransparency( // toggleTransparency(
@ -145,8 +153,8 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(),
} }
if (me.isPrimaryButtonDown) { if (me.isPrimaryButtonDown) {
cameraRotation.rz.angle = cameraRotation.ry.angle =
cameraRotation.rz.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED cameraRotation.ry.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED
cameraRotation.rx.angle = cameraRotation.rx.angle =
cameraRotation.rx.angle + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED cameraRotation.rx.angle + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED
} else if (me.isSecondaryButtonDown) { } else if (me.isSecondaryButtonDown) {
@ -162,7 +170,8 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(),
} }
override fun render(obj: VisualObject3D, meta: Meta) { override fun render(obj: VisualObject3D, meta: Meta) {
plugin.buildNode(obj)?.let { world.children.add(it) } val node = plugin.buildNode(obj) ?: kotlin.error("Can't render FX node for object $obj")
world.add(node)
} }
companion object { companion object {

View File

@ -84,7 +84,7 @@ class FX3DPlugin : AbstractPlugin() {
} }
if (this is Shape3D) { if (this is Shape3D) {
materialProperty().bind(binding["color"].transform { it.material() }) materialProperty().bind(binding[Material3D.MATERIAL_KEY].transform { it.material() })
} }
} }
} }

View File

@ -9,7 +9,7 @@ import javafx.scene.paint.Color
import javafx.scene.paint.Material import javafx.scene.paint.Material
import javafx.scene.paint.PhongMaterial import javafx.scene.paint.PhongMaterial
object Materials { object FXMaterials {
val RED = PhongMaterial().apply { val RED = PhongMaterial().apply {
diffuseColor = Color.DARKRED diffuseColor = Color.DARKRED
specularColor = Color.RED specularColor = Color.RED
@ -30,8 +30,9 @@ object Materials {
/** /**
* Infer color based on meta item * Infer color based on meta item
* @param opacity default opacity
*/ */
fun MetaItem<*>.color(): Color { fun MetaItem<*>.color(opacity: Double = 1.0): Color {
return when (this) { return when (this) {
is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) { is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) {
Color.web(this.value.string) Color.web(this.value.string)
@ -47,7 +48,7 @@ fun MetaItem<*>.color(): Color {
node["red"]?.int ?: 0, node["red"]?.int ?: 0,
node["green"]?.int ?: 0, node["green"]?.int ?: 0,
node["blue"]?.int ?: 0, node["blue"]?.int ?: 0,
node["opacity"]?.double ?: 1.0 node["opacity"]?.double ?: opacity
) )
} }
} }
@ -58,11 +59,13 @@ fun MetaItem<*>.color(): Color {
*/ */
fun MetaItem<*>?.material(): Material { fun MetaItem<*>?.material(): Material {
return when (this) { return when (this) {
null -> Materials.GREY null -> FXMaterials.GREY
is MetaItem.ValueItem -> PhongMaterial(color()) is MetaItem.ValueItem -> PhongMaterial(color())
is MetaItem.NodeItem -> PhongMaterial().apply { is MetaItem.NodeItem -> PhongMaterial().apply {
(node["color"]?: this@material).let { diffuseColor = it.color() } val opacity = node["opacity"].double ?: 1.0
node["specularColor"]?.let { specularColor = it.color() } (node["color"] ?: this@material).let { diffuseColor = it.color(opacity) }
node["specularColor"]?.let { specularColor = it.color(opacity) }
} }
} }
} }

View File

@ -7,6 +7,7 @@ import hep.dataforge.vis.spatial.Shape
import javafx.scene.shape.Mesh import javafx.scene.shape.Mesh
import javafx.scene.shape.MeshView import javafx.scene.shape.MeshView
import javafx.scene.shape.TriangleMesh import javafx.scene.shape.TriangleMesh
import org.fxyz3d.geometry.Face3
import kotlin.reflect.KClass import kotlin.reflect.KClass
object FXShapeFactory : FX3DFactory<Shape> { object FXShapeFactory : FX3DFactory<Shape> {
@ -18,11 +19,9 @@ object FXShapeFactory : FX3DFactory<Shape> {
} }
} }
private typealias Face = IntArray
private class FXGeometryBuilder : GeometryBuilder<Mesh> { private class FXGeometryBuilder : GeometryBuilder<Mesh> {
val vertices = ArrayList<Point3D>() val vertices = ArrayList<Point3D>()
val faces = ArrayList<Face>() val faces = ArrayList<Face3>()
private val vertexCache = HashMap<Point3D, Int>() private val vertexCache = HashMap<Point3D, Int>()
private fun append(vertex: Point3D): Int { private fun append(vertex: Point3D): Int {
@ -38,7 +37,7 @@ private class FXGeometryBuilder : GeometryBuilder<Mesh> {
override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) { override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) {
//adding vertices //adding vertices
val face: Face = intArrayOf(append(vertex1), append(vertex2), append(vertex3)) val face = Face3(append(vertex1), append(vertex2), append(vertex3))
faces.add(face) faces.add(face)
} }
@ -49,7 +48,7 @@ private class FXGeometryBuilder : GeometryBuilder<Mesh> {
mesh.points.addAll(it.x.toFloat(), it.y.toFloat(), it.z.toFloat()) mesh.points.addAll(it.x.toFloat(), it.y.toFloat(), it.z.toFloat())
} }
faces.forEach { faces.forEach {
mesh.faces.addAll(it[0], it[1], it[2]) mesh.faces.addAll(it.p0, it.p1, it.p2)
} }
return mesh return mesh
} }