# Re-using resources

Since Vue.js is designed for managing DOM elements and DOM objects cannot be re-used, each instance of a Vue.js component is unique. But we would often like to reduce resource usage when using WebGL especially handling much objects. We would also need to re-use instances when other component requires exactly same instance.

<VglDefs> and <VglUse> are special components for re-using Three.js instances. Any named slots under the <VglDefs> can be used in other place via <VglUse>.

# Resource usage reduction

The example below uses the same tetrahedron geometry for different mesh objects. It creates a tetrahedron geometry just once when the instance of <VglDefs> is created. Since the geometry is defined in tetrahedron slot, it is accessible with passing that name to href prop of the <VglUse> component.

<template>
  <vgl-renderer>
    <vgl-defs>
      <template #tetrahedron>
        <vgl-tetrahedron-geometry />
      </template>
    </vgl-defs>
    <template #scene>
      <vgl-scene>
        <vgl-mesh
          v-for="z, i of [-2.5, 0, 2.5]"
          :key="z"
          :position-z="z"
        >
          <template #geometry>
            <vgl-use href="tetrahedron" />
          </template>
          <template #material>
            <vgl-mesh-standard-material :color="(0x000088 << i * 8) + 0x777777" />
          </template>
        </vgl-mesh>
        <vgl-directional-light
          :position-x="2"
          :position-y="1.5"
          :position-z="1"
        />
      </vgl-scene>
    </template>
    <template #camera>
      <vgl-perspective-camera
        :position-x="5"
        :position-y="1.5"
        :position-z="1.5"
        rotation="lookAt"
      />
    </template>
  </vgl-renderer>
</template>

<script>
import {
  VglRenderer, VglDefs, VglUse, VglScene, VglTetrahedronGeometry, VglMeshStandardMaterial,
  VglDirectionalLight, VglMesh, VglPerspectiveCamera,
} from 'vue-gl';

export default {
  components: {
    VglRenderer,
    VglDefs,
    VglUse,
    VglScene,
    VglTetrahedronGeometry,
    VglMeshStandardMaterial,
    VglDirectionalLight,
    VglMesh,
    VglPerspectiveCamera,
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

# Sharing resources between multiple renderers

<VglDefs> can be defined also outside <VglRenderer>. It allows you to render a same scene on multiple canvases without cloning objects.

<VglDefs> and <VglUse> uses the root Vue.js instance as a namespace. So that you can share resources in the same Vue.js instance but not available in others.

The example below shows two canvases and draws the same scene with the same camera on them.

<template>
  <div>
    <vgl-defs>
      <template #scene>
        <vgl-scene>
          <vgl-mesh>
            <template #geometry>
              <vgl-torus-knot-geometry />
            </template>
            <template #material>
              <vgl-mesh-standard-material />
            </template>
          </vgl-mesh>
          <vgl-directional-light
            :position-x="2"
            :position-y="1.5"
            :position-z="1"
          />
        </vgl-scene>
      </template>
      <template #camera>
        <vgl-perspective-camera
          :position-x="5"
          :position-y="4"
          :position-z="3"
          rotation="lookAt"
        />
      </template>
    </vgl-defs>
    <vgl-renderer class="portrait">
      <template #scene>
        <vgl-use href="scene" />
      </template>
      <template #camera>
        <vgl-use href="camera" />
      </template>
    </vgl-renderer>
    <vgl-renderer class="landscape">
      <template #scene>
        <vgl-use href="scene" />
      </template>
      <template #camera>
        <vgl-use href="camera" />
      </template>
    </vgl-renderer>
  </div>
</template>

<script>
import {
  VglDefs, VglUse, VglRenderer, VglScene, VglPerspectiveCamera, VglMesh, VglTorusKnotGeometry,
  VglMeshStandardMaterial, VglDirectionalLight,
} from 'vue-gl';

export default {
  components: {
    VglDefs,
    VglUse,
    VglRenderer,
    VglScene,
    VglPerspectiveCamera,
    VglMesh,
    VglTorusKnotGeometry,
    VglMeshStandardMaterial,
    VglDirectionalLight,
  },
};
</script>

<style scoped>
.portrait {
  width: 150px;
  height: 300px;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

# When you have to take exact that instance

Some VueGL components need to get instances used in other component tree.

For example, <VglSpotLight> accepts target slot in that object the light faces to. Since the target object is usually a child of other object, you have to pass a same instance to both slots.

This is also a use case of <VglDefs> and <VglUse> because they internally handle the exact same instance.

The spot light in the following example always faces to the satellite icosahedron object.

<template>
  <vgl-renderer>
    <template #scene>
      <vgl-scene>
        <vgl-defs>
          <template #satellite>
            <vgl-mesh
              position="spherical"
              :position-radius="3"
              :position-phi="Math.PI/2"
              :position-theta="satellite"
            >
              <template #geometry>
                <vgl-icosahedron-geometry />
              </template>
              <template #material>
                <vgl-mesh-standard-material />
              </template>
            </vgl-mesh>
          </template>
        </vgl-defs>
        <vgl-mesh
          position="spherical"
          :position-radius="5"
          :position-phi="Math.PI/2"
          :position-theta="planet"
          :rotation-x="Math.PI/6"
        >
          <template #geometry>
            <vgl-octahedron-geometry />
          </template>
          <template #material>
            <vgl-mesh-standard-material />
          </template>
          <vgl-use href="satellite" />
        </vgl-mesh>
        <vgl-spot-light
          :position-y="10"
          :angle="0.3"
          :penumbra="0.5"
        >
          <template #target>
            <vgl-use href="satellite" />
          </template>
        </vgl-spot-light>
      </vgl-scene>
    </template>
    <template #camera>
      <vgl-perspective-camera
        :position-x="12"
        :position-y="8"
        rotation="lookAt"
      />
    </template>
  </vgl-renderer>
</template>

<script>
import {
  VglRenderer, VglDefs, VglUse, VglScene, VglMesh, VglIcosahedronGeometry, VglOctahedronGeometry,
  VglMeshStandardMaterial, VglSpotLight, VglPerspectiveCamera,
} from 'vue-gl';

export default {
  components: {
    VglRenderer,
    VglDefs,
    VglUse,
    VglScene,
    VglMesh,
    VglIcosahedronGeometry,
    VglOctahedronGeometry,
    VglMeshStandardMaterial,
    VglSpotLight,
    VglPerspectiveCamera,
  },
  data: () => ({ planet: 0.5, satellite: 0 }),
  mounted() {
    setInterval(() => {
      this.planet += 0.005;
      this.satellite += 0.02;
    }, 10);
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85