Uploaded image for project: 'Qt 3D Studio'
  1. Qt 3D Studio
  2. QT3DS-112

Enablers for dynamic scene object changes

    XMLWordPrintable

Details

    Description

      This epic collects all tasks related to making the engine fully dynamic in the sense that Q3DSGraphObjects can be dynamically added and removed at any time. Besides enabling a future public API that allows spawning nodes like models or layers at run time, this also constitutes the basis of a potential future integration into the editor application.

      While property changes, for animatable properties at least, are handled already, this is not sufficient when the runtime is not merely used as a viewer: both arbitrary property changes and the apperance or disappearance of Q3DSGraphObjects needs to be handled as well. The system is modeled after the Qt Quick scenegraph, hence the goal is to have something similar to DirtyNodeAdded/Removed and friends. The way built-in and custom properties are handled may need some changes as well - the simple table of static getters/setters as currently used by the animation system is not sufficient then.

      In the end this allows constructing or amending presentations programatically, in the Qt way.

      Case 1: let's build a presentation from scratch in C++. This is what the editor would do, but it is not unreasonable to expose this to applications as well. (i.e. "Qt 3D Lite" is finally becoming a reality)

          Q3SUipPresentation presentation;
          presentation.setPresentationWidth(800);
          presentation.setPresentationHeight(480);
      
          Q3DSScene *scene = presentation.newObject<Q3DSScene>("scene");
          presentation.setScene(scene);
      
          Q3DSSlide *masterSlide = presentation.newObject<Q3DSSlide>("master");
          Q3DSSlide *slide1 = presentation.newObject<Q3DSSlide>("slide1");
          masterSlide->appendChildNode(slide1);
          Q3DSSlide *slide2 = presentation.newObject<Q3DSSlide>("slide2");
          masterSlide->appendChildNode(slide2);
          presentation.setMasterSlide(masterSlide);
      
          // a scene is expected to have at least one layer as its child
          Q3DSLayerNode *layer1 = presentation.newObject<Q3DSLayerNode>("layer1");
          // properties conveniently default a to a normal, full-size layer
          scene->appendChildNode(layer1);
      
          // each layer uses the first active camera encountered while walking depth-first
          Q3DSCameraNode *camera1 = presentation.newObject<Q3DSCameraNode>("camera1");
          // Defaults to a perspective camera with fov 60, near/far 10/5000. This is
          // good as it is in many cases.
          camera1->setPosition(QVector3D(0, 0, -600));
          layer1->appendChildNode(camera1);
      
          // let's have a light
          Q3DSLightNode *light1 = presentation.newObject<Q3DSLightNode>("light1");
          // Defaults to a white directional light.
          layer1->appendChildNode(light1);
      
          Q3DSModelNode *model1 = presentation.newObject<Q3DSModelNode>("model1");
          // A model needs a mesh. Meshes are retrieved via
          // Q3DSUipPresentation::mesh() which loads or returns a cached one.
          model1->setMesh(presentation.mesh(QLatin1String("#Cube"))); // let's use a built-in primitive
          layer1->appendChildNode(model1);
          // rotate the cube around the X and Y axes
          model1->setRotation(QVector3D(45, 30, 0));
      
          Q3DSDefaultMaterial *mat1 = presentation.newObject<Q3DSDefaultMaterial>("mat1");
          // defaults to a white material with no texture maps
          model1->appendChildNode(mat1);
          // now we have a white cube
      
          // associate objects with slides
          masterSlide->addObject(layer1);
          masterSlide->addObject(camera1);
          masterSlide->addObject(light1);
          // put model1 onto slide1, meaning it wont be visible on slide2
          slide1->addObject(model1);
          slide1->addObject(mat1);
      
          // done, this is a full presentation with a layer, camera, a light and a cube
      

      Case 1.1: It must be noted that the simple setters are not what the editor would use in many cases. It is rather expected to get the list of properties from the data model metadata.xml, and use Q3DSPropertyChange for setting values:

      model1->notifyPropertyChanges({ model1->setPosition(QVector3D(1, 2, 3)) });
      
      vs.
      
      Q3DSPropertyChangeList cl { Q3DSPropertyChange::fromVariant("position", QVector3D(1, 2, 3) };
      model1->applyPropertyChanges(cl);
      model1->notifyPropertyChanges(cl);
      

      Case 1.2: Image or other object references need some special care when using dynamic changes. Again, this is relevant mainly to the editor, the high level API is straightforward:

          Q3DSImage *img1 = ...
          material->notifyPropertyChange({ material->setDiffuseMap(img1) });
      
          vs.
      
          diffuseMapChange = Q3DSPropertyChange::fromVariant(QLatin1String("diffusemap"),
                                                             QLatin1String("#id_of_some_image"));
          material->applyPropertyChanges({ diffuseMapChange });
          material->resolveReferences(presentation); // !!
          material->notifyPropertyChanges({ diffuseMapChange });
      

      Case 2: What applications would really be interested in: Mirroring what other 3D tools would do: Import assets (meshes, texture maps) and design the static parts of the scene in the editor, and then:

         ... load up a .uia/.uip
         ... grab the Q3DSUipPresentation from the Q3DSEngine
         // look up any object by id or name
         auto model = presentation.objectByName<Q3DSModelNode>("NameSetInTheEditor");
         // change anything at any time:
         model->notifyPropertyChange({ model->setRotation(QVector3D(0, 0, 90)) });
         // or spawn new objects:
         Q3DSModel *childModel = presentation.newObject<Q3DSModel>("model2");
         childModel->setMesh(presentation.mesh("#Cube"));
         Q3DSDefaultMaterial *childModelMat = presentation.newObject<Q3DSDefaultMaterial>("mat2");
         childModel->appendChildNode(childModelMat);
         model->appendChildNode(childModel); // magic, a new cube shows up
      

      Which is pretty much what e.g. Unity3D does. (might be incorrect code, just shown here as the concept):

          GameObject obj = GameObject.Find("model1");
          obj.transform.Rotate(new Vector3(0, 0, 90));
          GameObject newObj = (GameObject) Instantiate(prefab);
          newObj.transform.parent = obj.transform;
      

      Finally, it is worth noting that the scope goes well beyond Q3DSUipPresentation. For instance, Q3DSEngine needs to be able to dynamically add and remove subpresentations at any time.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            lagocs Laszlo Agocs
            janichol Andy Nichols
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes