solar system
This commit is contained in:
parent
ceff79a18f
commit
c8a2cfa483
@ -25,15 +25,19 @@ import android.support.v7.app.AppCompatActivity
|
||||
import android.view.MotionEvent
|
||||
import com.google.ar.core.HitResult
|
||||
import com.google.ar.core.Plane
|
||||
import com.google.ar.sceneform.Node
|
||||
import com.google.ar.sceneform.math.Vector3
|
||||
import com.google.ar.sceneform.rendering.ModelRenderable
|
||||
import com.google.ar.sceneform.ux.ArFragment
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private val TAG = MainActivity::class.java.canonicalName
|
||||
private val AU_TO_METERS = 1.1f
|
||||
|
||||
private lateinit var arFragment: ArFragment
|
||||
private var isModelAdded = false
|
||||
private lateinit var planets: Map<Planet, ModelRenderable>
|
||||
private lateinit var renderablePlanets: Map<Planet, ModelRenderable>
|
||||
private lateinit var loadPlanetsJob: Job
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -45,17 +49,65 @@ class MainActivity : AppCompatActivity() {
|
||||
setContentView(R.layout.activity_main)
|
||||
arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as ArFragment
|
||||
|
||||
loadPlanetsJob = GlobalScope.launch (Dispatchers.Main) {
|
||||
planets = loadPlanets(this@MainActivity)
|
||||
loadPlanetsJob = GlobalScope.launch(Dispatchers.Main) {
|
||||
renderablePlanets = loadPlanets(this@MainActivity)
|
||||
}
|
||||
|
||||
arFragment.setOnTapArPlaneListener(this::placeSolarSystem)
|
||||
}
|
||||
|
||||
private fun placeSolarSystem(hitResult: HitResult, plane: Plane, motionEvent: MotionEvent) {
|
||||
if (isModelAdded)
|
||||
return
|
||||
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
loadPlanetsJob.join()
|
||||
addTransformableNodeToScene(arFragment, hitResult.createAnchor(), planets[Planet.EARTH]!!)
|
||||
val solarSystem = createSolarSystem(renderablePlanets)
|
||||
addNodeToScene(arFragment, hitResult.createAnchor(), solarSystem)
|
||||
isModelAdded = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSolarSystem(renderablePlanets: Map<Planet, ModelRenderable>): Node {
|
||||
val base = Node()
|
||||
|
||||
val sun = Node()
|
||||
sun.setParent(base)
|
||||
sun.localPosition = Vector3(0.0f, 0.5f, 0.0f)
|
||||
|
||||
val sunVisual = Node()
|
||||
sunVisual.setParent(sun)
|
||||
sunVisual.renderable = renderablePlanets[Planet.SUN]
|
||||
sunVisual.localScale = Vector3(0.5f, 0.5f, 0.5f)
|
||||
|
||||
createPlanetNode(Planet.MERCURY, sun, 0.4f, 47f, renderablePlanets)
|
||||
createPlanetNode(Planet.VENUS, sun, 0.7f, 35f, renderablePlanets)
|
||||
createPlanetNode(Planet.EARTH, sun, 1.0f, 29f, renderablePlanets)
|
||||
createPlanetNode(Planet.MARS, sun, 1.5f, 24f, renderablePlanets)
|
||||
createPlanetNode(Planet.JUPITER, sun, 2.2f, 13f, renderablePlanets)
|
||||
createPlanetNode(Planet.SATURN, sun, 3.5f, 9f, renderablePlanets)
|
||||
createPlanetNode(Planet.URANUS, sun, 5.2f, 7f, renderablePlanets)
|
||||
createPlanetNode(Planet.NEPTUNE, sun, 6.1f, 5f, renderablePlanets)
|
||||
|
||||
return base
|
||||
}
|
||||
|
||||
private fun createPlanetNode(
|
||||
planet: Planet,
|
||||
parent: Node,
|
||||
auFromParent: Float,
|
||||
orbitDegreesPerSecond: Float,
|
||||
renderablePlanets: Map<Planet, ModelRenderable>
|
||||
) {
|
||||
val orbit = RotationNode()
|
||||
orbit.degreesPerSecond = orbitDegreesPerSecond
|
||||
orbit.setParent(parent)
|
||||
|
||||
val renderable = renderablePlanets[planet] ?: return
|
||||
val planetNode = PlanetNode(renderable)
|
||||
planetNode.setParent(orbit)
|
||||
planetNode.localPosition = Vector3(AU_TO_METERS * auFromParent, 0.0f, 0.0f)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2019, norangebit
|
||||
*
|
||||
* This file is part of solar-system.
|
||||
*
|
||||
* solar-system is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* solar-system is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with solar-system. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
package it.norangeb.solarsystem
|
||||
|
||||
import com.google.ar.sceneform.FrameTime
|
||||
import com.google.ar.sceneform.Node
|
||||
import com.google.ar.sceneform.math.Vector3
|
||||
import com.google.ar.sceneform.rendering.ModelRenderable
|
||||
|
||||
class PlanetNode(
|
||||
private val planetRenderable: ModelRenderable
|
||||
) : Node() {
|
||||
private val planetScale = 0.6f
|
||||
private var planetVisual: RotationNode? = null
|
||||
|
||||
override fun onActivate() {
|
||||
if (scene == null)
|
||||
throw IllegalStateException("Scene is null!")
|
||||
|
||||
if (planetVisual == null)
|
||||
initRotationNode()
|
||||
|
||||
}
|
||||
|
||||
override fun onUpdate(frameTime: FrameTime?) {
|
||||
if (scene == null)
|
||||
return
|
||||
}
|
||||
|
||||
fun initRotationNode() {
|
||||
planetVisual = RotationNode(false)
|
||||
planetVisual?.setParent(this)
|
||||
planetVisual?.renderable = planetRenderable
|
||||
planetVisual?.localScale = Vector3(planetScale, planetScale, planetScale)
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2019, norangebit
|
||||
*
|
||||
* This file is part of solar-system.
|
||||
*
|
||||
* solar-system is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* solar-system is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with solar-system. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
package it.norangeb.solarsystem
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.view.animation.LinearInterpolator
|
||||
import com.google.ar.sceneform.FrameTime
|
||||
import com.google.ar.sceneform.Node
|
||||
import com.google.ar.sceneform.math.Quaternion
|
||||
import com.google.ar.sceneform.math.QuaternionEvaluator
|
||||
import com.google.ar.sceneform.math.Vector3
|
||||
|
||||
class RotationNode(private val isOrbit: Boolean = true) : Node() {
|
||||
val SPEED_MULTIPLIER = 1
|
||||
val ROTATION_MULTIPLIER = 1
|
||||
|
||||
private var orbitAnimation: ObjectAnimator? = null
|
||||
var degreesPerSecond = 90.0f
|
||||
|
||||
private val animationDuration: Long
|
||||
get() = (1000 * 360 / (degreesPerSecond * if (isOrbit)
|
||||
SPEED_MULTIPLIER
|
||||
else
|
||||
ROTATION_MULTIPLIER))
|
||||
.toLong()
|
||||
|
||||
override fun onUpdate(frameTime: FrameTime?) {
|
||||
super.onUpdate(frameTime)
|
||||
|
||||
if (orbitAnimation == null)
|
||||
return
|
||||
}
|
||||
|
||||
override fun onActivate() {
|
||||
startAnimation()
|
||||
}
|
||||
|
||||
override fun onDeactivate() {
|
||||
stopAnimation()
|
||||
}
|
||||
|
||||
private fun startAnimation() {
|
||||
if (orbitAnimation != null) {
|
||||
return
|
||||
}
|
||||
orbitAnimation = createAnimator()
|
||||
orbitAnimation!!.target = this
|
||||
orbitAnimation!!.duration = animationDuration
|
||||
orbitAnimation!!.start()
|
||||
}
|
||||
|
||||
private fun stopAnimation() {
|
||||
if (orbitAnimation == null) {
|
||||
return
|
||||
}
|
||||
orbitAnimation!!.cancel()
|
||||
orbitAnimation = null
|
||||
}
|
||||
|
||||
private fun createAnimator(): ObjectAnimator {
|
||||
val orientation1 = Quaternion.axisAngle(Vector3(0.0f, 1.0f, 0.0f), 0f)
|
||||
val orientation2 = Quaternion.axisAngle(Vector3(0.0f, 1.0f, 0.0f), 120f)
|
||||
val orientation3 = Quaternion.axisAngle(Vector3(0.0f, 1.0f, 0.0f), 240f)
|
||||
val orientation4 = Quaternion.axisAngle(Vector3(0.0f, 1.0f, 0.0f), 360f)
|
||||
|
||||
val orbitAnimation = ObjectAnimator()
|
||||
orbitAnimation.setObjectValues(orientation1, orientation2, orientation3, orientation4)
|
||||
|
||||
orbitAnimation.propertyName = "localRotation"
|
||||
|
||||
orbitAnimation.setEvaluator(QuaternionEvaluator())
|
||||
|
||||
orbitAnimation.repeatCount = ObjectAnimator.INFINITE
|
||||
orbitAnimation.repeatMode = ObjectAnimator.RESTART
|
||||
orbitAnimation.interpolator = LinearInterpolator()
|
||||
orbitAnimation.setAutoCancel(true)
|
||||
|
||||
return orbitAnimation
|
||||
}
|
||||
}
|
@ -34,7 +34,6 @@ import com.google.ar.sceneform.Node
|
||||
import com.google.ar.sceneform.assets.RenderableSource
|
||||
import com.google.ar.sceneform.rendering.*
|
||||
import com.google.ar.sceneform.ux.ArFragment
|
||||
import com.google.ar.sceneform.ux.TransformableNode
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@ -98,9 +97,9 @@ fun loadPlanet(context: Context, planet: Planet): Deferred<ModelRenderable> {
|
||||
)
|
||||
|
||||
return GlobalScope.async(Dispatchers.IO) {
|
||||
threadLog("start load: $planet")
|
||||
threadLog("start loading: $planet")
|
||||
val renderable = futureRenderable.get()
|
||||
threadLog("end load: $planet")
|
||||
threadLog("end loading: $planet")
|
||||
renderable
|
||||
}
|
||||
}
|
||||
@ -124,14 +123,10 @@ fun fetchModel(
|
||||
.setRecenterMode(RenderableSource.RecenterMode.ROOT)
|
||||
.build()
|
||||
|
||||
fun addTransformableNodeToScene(arFragment: ArFragment, anchor: Anchor, renderable: ModelRenderable): Node {
|
||||
fun addNodeToScene(arFragment: ArFragment, anchor: Anchor, node: Node) {
|
||||
val anchorNode = AnchorNode(anchor)
|
||||
val transformableNode = TransformableNode(arFragment.transformationSystem)
|
||||
transformableNode.renderable = renderable
|
||||
transformableNode.setParent(anchorNode)
|
||||
anchorNode.addChild(node)
|
||||
arFragment.arSceneView.scene.addChild(anchorNode)
|
||||
transformableNode.select()
|
||||
return transformableNode
|
||||
}
|
||||
|
||||
enum class Planet(val value: String) {
|
||||
@ -149,4 +144,4 @@ enum class Planet(val value: String) {
|
||||
fun threadLog(message: String) = Log.d(
|
||||
"COROUTINES",
|
||||
"[${Thread.currentThread().name}]: $message"
|
||||
)
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user