美文网首页
官方例子---SolarSystem

官方例子---SolarSystem

作者: 爱做梦的严重精神病患者 | 来源:发表于2019-01-22 16:38 被阅读0次

    与HelloSceneform的区别

    • HelloSceneform使用的包是ux:sceneform-ux:1.6.0,并且在布局上使用了ArFragment,自动完成了一些相关配置(初步估计有Camera权限申请)。

    1.SolarActivity

     首先,同样是检测设备支持,之后加载布局、获取视图实例:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        if (!DemoUtils.checkIsSupportedDeviceOrFinish(this)) {
          // Not a supported device.
          return;
        }
    
        setContentView(R.layout.activity_solar);
        arSceneView = findViewById(R.id.ar_scene_view);
    }
    

     与HellowSceneform不同的是,SolarSystem使用的视图是ArSceneView,而不是ArFragment。使用ArFragment会自动配置ArSceneView和ArSession等。

     接下来,创建渲染对象:

    // Build all the planet models.
        CompletableFuture<ModelRenderable> sunStage =
            ModelRenderable.builder().setSource(this, Uri.parse("Sol.sfb")).build();
        CompletableFuture<ModelRenderable> mercuryStage =
            ModelRenderable.builder().setSource(this, Uri.parse("Mercury.sfb")).build();
    ...
        // Build a renderable from a 2D View.
        CompletableFuture<ViewRenderable> solarControlsStage =
            ViewRenderable.builder().setView(this, R.layout.solar_controls).build();
    
    CompletableFuture.allOf(
                sunStage,
                mercuryStage,
               ...
                solarControlsStage)
            .handle(
                (notUsed, throwable) -> {
                  // When you build a Renderable, Sceneform loads its resources in the background while
                  // returning a CompletableFuture. Call handle(), thenAccept(), or check isDone()
                  // before calling get().
    
                  if (throwable != null) {
                    DemoUtils.displayError(this, "Unable to load renderable", throwable);
                    return null;
                  }
    
                  try {
                    sunRenderable = sunStage.get();
                    mercuryRenderable = mercuryStage.get();
                  ...
                    solarControlsRenderable = solarControlsStage.get();
    
                    // Everything finished loading successfully.
                    hasFinishedLoading = true;
    
                  } catch (InterruptedException | ExecutionException ex) {
                    DemoUtils.displayError(this, "Unable to load renderable", ex);
                  }
    
                  return null;
                });
    

     创建可渲染对象都是利用CompletableFuture<?>。其中在SolarSystem中分别创建了3D和2D的模型,差别在于分别是CompleteableFuture<ModelRenderable>和CompleteableFuture<ViewRenderable>。同时,构建方法也不同,ModelRenderable.builder().setSource()和ViewRenderable.builder().setView()。

     然后,添加监听器,响应手指在屏幕上的各种动作:

    gestureDetector =
            new GestureDetector(
                this,
                new GestureDetector.SimpleOnGestureListener() {
                  @Override
                  public boolean onSingleTapUp(MotionEvent e) {
                    onSingleTap(e);
                    return true;
                  }
    
                  @Override
                  public boolean onDown(MotionEvent e) {
                    return true;
                  }
                });
    
    private void onSingleTap(MotionEvent tap) {
        if (!hasFinishedLoading) {
          // We can't do anything yet.
          return;
        }
    
        Frame frame = arSceneView.getArFrame();
        if (frame != null) {
          if (!hasPlacedSolarSystem && tryPlaceSolarSystem(tap, frame)) {
            hasPlacedSolarSystem = true;
          }
        }
      }
    

     其中具体的逻辑判断比较复杂,涉及的东西较多,主要就是以下3个方法:

    private boolean tryPlaceSolarSystem(MotionEvent tap, Frame frame) {
        if (tap != null && frame.getCamera().getTrackingState() == TrackingState.TRACKING) {
          for (HitResult hit : frame.hitTest(tap)) {
            Trackable trackable = hit.getTrackable();
            if (trackable instanceof Plane && ((Plane) trackable).isPoseInPolygon(hit.getHitPose())) {
              // Create the Anchor.
              Anchor anchor = hit.createAnchor();
              AnchorNode anchorNode = new AnchorNode(anchor);
              anchorNode.setParent(arSceneView.getScene());
              Node solarSystem = createSolarSystem();
              anchorNode.addChild(solarSystem);
              return true;
            }
          }
        }
    
        return false;
      }
    
     private Node createSolarSystem() {
        //创建一个基础节点
        Node base = new Node();
    
        //创建太阳节点
        Node sun = new Node();
        sun.setParent(base);
        sun.setLocalPosition(new Vector3(0.0f, 0.5f, 0.0f));
    
        Node sunVisual = new Node();
        sunVisual.setParent(sun);
        //创建sunVisual的模型对象
        sunVisual.setRenderable(sunRenderable);
        sunVisual.setLocalScale(new Vector3(0.5f, 0.5f, 0.5f));
    
        Node solarControls = new Node();
        solarControls.setParent(sun);
        //创建控制器的模型对象
        solarControls.setRenderable(solarControlsRenderable);
        solarControls.setLocalPosition(new Vector3(0.0f, 0.25f, 0.0f));
    
        //获取ViewRenderable的View对象
        View solarControlsView = solarControlsRenderable.getView();
        SeekBar orbitSpeedBar = solarControlsView.findViewById(R.id.orbitSpeedBar);
        orbitSpeedBar.setProgress((int) (solarSettings.getOrbitSpeedMultiplier() * 10.0f));
        orbitSpeedBar.setOnSeekBarChangeListener(
            new SeekBar.OnSeekBarChangeListener() {
              @Override
              public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                float ratio = (float) progress / (float) orbitSpeedBar.getMax();
                solarSettings.setOrbitSpeedMultiplier(ratio * 10.0f);
              }
    
              @Override
              public void onStartTrackingTouch(SeekBar seekBar) {}
    
              @Override
              public void onStopTrackingTouch(SeekBar seekBar) {}
            });
    
        SeekBar rotationSpeedBar = solarControlsView.findViewById(R.id.rotationSpeedBar);
        rotationSpeedBar.setProgress((int) (solarSettings.getRotationSpeedMultiplier() * 10.0f));
        rotationSpeedBar.setOnSeekBarChangeListener(
            new SeekBar.OnSeekBarChangeListener() {
              @Override
              public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                float ratio = (float) progress / (float) rotationSpeedBar.getMax();
                solarSettings.setRotationSpeedMultiplier(ratio * 10.0f);
              }
    
              @Override
              public void onStartTrackingTouch(SeekBar seekBar) {}
    
              @Override
              public void onStopTrackingTouch(SeekBar seekBar) {}
            });
    
        // Toggle the solar controls on and off by tapping the sun.
        sunVisual.setOnTapListener(
            (hitTestResult, motionEvent) -> solarControls.setEnabled(!solarControls.isEnabled()));
    
        //创建模型对象
        createPlanet("Mercury", sun, 0.4f, 47f, mercuryRenderable, 0.019f);
    
        createPlanet("Venus", sun, 0.7f, 35f, venusRenderable, 0.0475f);
    
        Node earth = createPlanet("Earth", sun, 1.0f, 29f, earthRenderable, 0.05f);
    
        createPlanet("Moon", earth, 0.15f, 100f, lunaRenderable, 0.018f);
    
        createPlanet("Mars", sun, 1.5f, 24f, marsRenderable, 0.0265f);
    
        createPlanet("Jupiter", sun, 2.2f, 13f, jupiterRenderable, 0.16f);
    
        createPlanet("Saturn", sun, 3.5f, 9f, saturnRenderable, 0.1325f);
    
        createPlanet("Uranus", sun, 5.2f, 7f, uranusRenderable, 0.1f);
    
        createPlanet("Neptune", sun, 6.1f, 5f, neptuneRenderable, 0.074f);
    
        return base;
      }
    
     private Node createPlanet(String name, Node parent, float auFromParent,
      float orbitDegreesPerSecond, ModelRenderable renderable, float planetScale) {
        // Orbit is a rotating node with no renderable positioned at the sun.
        // The planet is positioned relative to the orbit so that it appears to rotate around the sun.
        // This is done instead of making the sun rotate so each planet can orbit at its own speed.
        RotatingNode orbit = new RotatingNode(solarSettings, true);
        orbit.setDegreesPerSecond(orbitDegreesPerSecond);
        orbit.setParent(parent);
    
        // Create the planet and position it relative to the sun.
        Planet planet = new Planet(this, name, planetScale, renderable, solarSettings);
        planet.setParent(orbit);
        planet.setLocalPosition(new Vector3(auFromParent * AU_TO_METERS, 0.0f, 0.0f));
    
        return planet;
      }
    

     其中createSolarSystem()和createPlanet()方法相对复杂,需要进一步拆解。而tryPlaceSolarSystem()方法主要的功能就是将建立好的SolarSystem放入场景之中,不难看懂。

     对于自转和公转都是靠ObjectAnimator实现,具体实现不详细展开。

     个人理解:Node都存在parent,可以把parent理解为一个空间坐标系。在这个程序例子中,orbit为planet的parent,orbit的绕Y轴转形成了公转,而planet的绕Y轴转形成了自转。


    个人理解图.jpg

    相关文章

      网友评论

          本文标题:官方例子---SolarSystem

          本文链接:https://www.haomeiwen.com/subject/fewljqtx.html