firtoz / react-three-renderer

Render into a three.js canvas using React.
https://toxicfork.github.com/react-three-renderer-example/
MIT License
1.49k stars 155 forks source link

What are the rules for <resources /> ? #22

Open AndrewRayCode opened 8 years ago

AndrewRayCode commented 8 years ago

Can you clarify what the rules for the <resources /> object is? I'm not sure when I can access a resources from a different part of my component tree, etc. Some specific questions are below.

  1. In individual component, can I reference a resourceId declared a parent component?
  2. Can I use a resource not defined in a parent component, but defined in a sibling component? As in, are resource names considered global to the render tree?
  3. Can I define multiple <resouce> tags in the same component?
  4. What happens if, in any place, I duplicate a resource / resourceId between components? Will the user of the resource look up the render tree until it finds one, or are they global and the "last" one wins?
  5. To what degree does render order matter for resources? If I referenceId a resource in a sibling component, the sibling might not have been created yet. Will this fail, or does it all get batched together at render time and sorted before render?
  6. What happens if I modify runtime properties of a resource at runtime? For example, I want to change the opacity of a material. Is this allowed / safe / efficient?
toxicFork commented 8 years ago
  1. In individual component, can I reference a resourceId declared a parent component?
    • Yes
  2. Can I use a resource not defined in a parent component, but defined in a sibling component? As in, are resource names considered global to the render tree?
    • Not siblings, resources aren't global
  3. Can I define multiple tags in the same component?
  4. What happens if, in any place, I duplicate a resource / resourceId between components? Will the user of the resource look up the render tree until it finds one, or are they global and the "last" one wins?

    • This is a fun one. If a parent P has let's say resource for id 'foo', and a child C has resource for id 'foo', the references within the child C (and its children and grandchildren and so on) will use the inner foo. The parent's children (e.g. any siblings of child and these siblings' children) excluding this child C will use the outer one. So the 'nearest above' wins.

      <group> // group 1 start
      <resources>
       <meshBasicMaterial resourceId='foo' color={redColor}/>
      </resources>
      <mesh>
       <materialResource 
         resourceId='foo'
         // this will be red
       /> 
      </mesh>
      <group> // group 2 start
       <resources>
         <meshBasicMaterial resourceId='foo' color={greenColor}/>
       </resources>
       <mesh>
         <materialResource 
           resourceId='foo'
           // this will be green
         /> 
       </mesh>
       <group> // group 3 start 
         <resources>
           <meshBasicMaterial resourceId='foo' color={blueColor}/>
         </resources>
         <mesh>
           <materialResource 
             resourceId='foo'
             // this will be blue
           /> 
         </mesh>
         <group> // group 4 start
           <mesh>
             <materialResource 
               resourceId='foo'
               // this will be blue too
             /> 
           </mesh>
           <group> // group 5 start
             <mesh>
               <materialResource 
                 resourceId='foo'
                 // this will be blue too
               /> 
             </mesh>
           </group> // group 5 end
         </group> // group 4 end
         <mesh>
           <materialResource 
             resourceId='foo'
             // this will be blue
           /> 
         </mesh>
       </group> // group 3 end
       <mesh>
         <materialResource 
           resourceId='foo'
           // this will be green
         /> 
       </mesh>
      </group> // group 2 end
      <mesh>
       <materialResource 
         resourceId='foo'
         // this will be red
       /> 
      </mesh>
      </group> // group 1 end
      
  5. To what degree does render order matter for resources? If I referenceId a resource in a sibling component, the sibling might not have been created yet. Will this fail, or does it all get batched together at render time and sorted before render?

    • It is recommend to place <resources/> as the first element of any component because of multiple reasons:

      • It will be constructed before any other siblings, and anything within them will also be constructed first.

      e.g. render order

       <group> // 7
         <resources> // 3
           <a/> // 1
           <b/> // 2
         </resources>
         <mesh> // 4
         </mesh>
         <group> // 6
           <mesh/> // 5
         </group>
       </group>
      
      • This is not a huge issue, since after the resources are constructed the previous siblings references will be filled in, but it's not really nice as they may be re-rendered which can be expensive.
      • If any of the siblings BEFORE it get added or removed, then (because of how react renders) ALL of the resources within may get re-constructed which is super expensive and against all that is good in the world. This CAN be prevented if you place a key property on the resource, but that still means the objects before this may not be properly initialized.
    • Resources within a sibling cannot be referred to.

      <parent>
      <child-a>
       <resources>
       </resources>
      </child-a>
      <child-b>
       You cannot refer to anything in `<child a/>` here
      </child-b>
      </parent>
      
  6. What happens if I modify runtime properties of a resource at runtime? For example, I want to change the opacity of a material. Is this allowed / safe / efficient?

    • It's not only safe and efficient, it's even recommended! That's one of the main purposes for resources. You can use resources to change the color of a material for any number of meshes this way, e.g.

      <group>
      <resources>
       <meshBasicMaterial resourceId="mat1" color={>>change this<<}/>
       // ... geometry... resourceId="geom1"
      </resources>
      <Meshes/>
      </group>
      
      Meshes.prototype.render = () => {
      // all meshes refer to the same material and geometry instances
      return (<group>
       <mesh>
         <materialResource resourceId="mat1"/>
         <geometryResource resourceId="geom1"/>
       </mesh>
       <mesh>
         <materialResource resourceId="mat1"/>
         <geometryResource resourceId="geom1"/>
       </mesh>
       <mesh>
         <materialResource resourceId="mat1"/>
         <geometryResource resourceId="geom1"/>
       </mesh>
       // ... and so on
      </group>)
      }

I will add these in a FAQ :) It's a complex little beast!

toxicFork commented 8 years ago

Updated comment above