|
30 | 30 |
|
31 | 31 | <script type="module">
|
32 | 32 | import {defineElements, booleanAttribute, Element, element, attribute, html} from 'lume'
|
| 33 | + import {MeshPhysicalMaterial} from 'three' |
| 34 | + import {toCreasedNormals} from 'three/examples/jsm/utils/BufferGeometryUtils.js' |
33 | 35 |
|
34 | 36 | const bodyModelUrl = '/examples/nasa-astrobee-robot/astrobee/body.dae'
|
35 | 37 | const pmcModelUrl = '/examples/nasa-astrobee-robot/astrobee/pmc.dae'
|
|
44 | 46 |
|
45 | 47 | // Long live HTML elements!
|
46 | 48 |
|
47 |
| - element('astrobee-app')((() => { |
| 49 | + element('astrobee-app')( |
48 | 50 | class App extends Element {
|
49 |
| - constructor() { |
50 |
| - super() |
51 |
| - |
52 |
| - this.rotationDirection = 1 // clockwise |
53 |
| - this.rotationAmount = 0.2 // degrees |
| 51 | + static observedAttributeHandlers = { |
| 52 | + rotationDirection: attribute.number(), |
| 53 | + rotationAmount: attribute.number(), |
| 54 | + rotationEnabled: attribute.boolean(), |
| 55 | + view: attribute.string(), |
| 56 | + } |
54 | 57 |
|
55 |
| - this.rotationEnabled = true |
56 |
| - this.view = 'free' |
| 58 | + rotationDirection = 1 // clockwise |
| 59 | + rotationAmount = 0.2 // degrees |
| 60 | + rotationEnabled = true |
| 61 | + view = 'free' |
57 | 62 |
|
58 |
| - this.astrobee |
59 |
| - this.sceneContainer |
60 |
| - this.loading |
61 |
| - this.models = [] |
62 |
| - } |
| 63 | + astrobee |
| 64 | + sceneContainer |
| 65 | + loading |
| 66 | + models = [] |
63 | 67 |
|
64 | 68 | template = () => html`
|
65 | 69 | <>
|
66 | 70 | <loading-icon ref=${el => this.loading = el}></loading-icon>
|
67 | 71 |
|
68 | 72 | <div class="sceneContainer hidden" ref=${el => this.sceneContainer = el}>
|
69 |
| - <lume-scene webgl enable-css="false" environment=${() => lunaStation}> |
| 73 | + <lume-scene webgl enable-css="true" environment=${() => lunaStation}> |
70 | 74 | <lume-element3d align-point="0.5 0.5 0.5">
|
71 | 75 | <lume-camera-rig
|
72 | 76 | ref=${el => this.cameraRig = el}
|
|
82 | 86 | </lume-element3d>
|
83 | 87 | </lume-element3d>
|
84 | 88 |
|
85 |
| - <lume-point-light intensity="0.3" align-point="0.5 0.5 0.5" color="#a3ffff" position="0 90 0" /> |
86 |
| - <lume-point-light intensity="0.3" align-point="0.5 0.5 0.5" color="#a3ffff" position="0 -90 0" /> |
87 |
| - <lume-point-light intensity="0.3" align-point="0.5 0.5 0.5" color="#a3ffff" position="0 0 90" /> |
88 |
| - <lume-point-light intensity="0.3" align-point="0.5 0.5 0.5" color="#a3ffff" position="0 0 -90" /> |
89 |
| - <lume-point-light intensity="0.3" align-point="0.5 0.5 0.5" color="#a3ffff" position="90 80 0" /> |
90 |
| - <lume-point-light intensity="0.3" align-point="0.5 0.5 0.5" color="#a3ffff" position="90 -80 0" /> |
91 |
| - <lume-point-light intensity="0.3" align-point="0.5 0.5 0.5" color="#a3ffff" position="-90 80 0" /> |
92 |
| - <lume-point-light intensity="0.3" align-point="0.5 0.5 0.5" color="#a3ffff" position="-90 -80 0" /> |
| 89 | + <lume-point-light intensity="150" align-point="0.5 0.5 0.5" color="#a3ffff" position="0 90 0" ><lume-sphere has="basic-material" cast-shadow="false" mount-point="0.5 0.5 0.5" sidedness="front" size="2 2 2"/></lume-point-light> |
| 90 | + <lume-point-light intensity="150" align-point="0.5 0.5 0.5" color="#a3ffff" position="0 -90 0" ><lume-sphere has="basic-material" cast-shadow="false" mount-point="0.5 0.5 0.5" sidedness="front" size="2 2 2"/></lume-point-light> |
| 91 | + <lume-point-light intensity="150" align-point="0.5 0.5 0.5" color="#a3ffff" position="0 0 90" ><lume-sphere has="basic-material" cast-shadow="false" mount-point="0.5 0.5 0.5" sidedness="front" size="2 2 2"/></lume-point-light> |
| 92 | + <lume-point-light intensity="150" align-point="0.5 0.5 0.5" color="#a3ffff" position="0 0 -90" ><lume-sphere has="basic-material" cast-shadow="false" mount-point="0.5 0.5 0.5" sidedness="front" size="2 2 2"/></lume-point-light> |
| 93 | + <lume-point-light intensity="150" align-point="0.5 0.5 0.5" color="#a3ffff" position="90 80 0" ><lume-sphere has="basic-material" cast-shadow="false" mount-point="0.5 0.5 0.5" sidedness="front" size="2 2 2"/></lume-point-light> |
| 94 | + <lume-point-light intensity="150" align-point="0.5 0.5 0.5" color="#a3ffff" position="90 -80 0" ><lume-sphere has="basic-material" cast-shadow="false" mount-point="0.5 0.5 0.5" sidedness="front" size="2 2 2"/></lume-point-light> |
| 95 | + <lume-point-light intensity="150" align-point="0.5 0.5 0.5" color="#a3ffff" position="-90 80 0" ><lume-sphere has="basic-material" cast-shadow="false" mount-point="0.5 0.5 0.5" sidedness="front" size="2 2 2"/></lume-point-light> |
| 96 | + <lume-point-light intensity="150" align-point="0.5 0.5 0.5" color="#a3ffff" position="-90 -80 0" ><lume-sphere has="basic-material" cast-shadow="false" mount-point="0.5 0.5 0.5" sidedness="front" size="2 2 2"/></lume-point-light> |
93 | 97 |
|
94 | 98 | <lume-element3d ref=${el => this.astrobee = el} align-point="0.5 0.5 0.5" rotation=${() => this.astrobeeRotation}>
|
95 | 99 | <lume-collada-model ref=${el => this.models.push(el)} src=${() => bodyModelUrl} />
|
96 | 100 | <lume-collada-model ref=${el => this.models.push(el)} src=${() => pmcModelUrl} />
|
97 | 101 | <lume-collada-model ref=${el => this.models.push(el)} src=${() => pmcSkinModelUrl} />
|
98 | 102 | <lume-collada-model ref=${el => this.models.push(el)} src=${() => pmcBumperModelUrl} />
|
99 | 103 |
|
100 |
| - <comment style="display:none">The other side.</comment> |
| 104 | + <!-- The other side. --> |
101 | 105 | <lume-element3d scale="1 1 -1">
|
102 | 106 | <lume-collada-model ref=${el => this.models.push(el)} src=${() => pmcModelUrl} />
|
103 | 107 | <lume-collada-model ref=${el => this.models.push(el)} src=${() => pmcSkinModelUrl} />
|
|
111 | 115 | color="white"
|
112 | 116 | align-point="0.5 0.5 0.5"
|
113 | 117 | mount-point="0.5 0.5 0.5"
|
114 |
| - size="100 100 100" |
| 118 | + size="200 200 200" |
115 | 119 | sidedness="double"
|
116 | 120 | cast-shadow="false"
|
117 | 121 | receive-shadow="false"
|
|
228 | 232 |
|
229 | 233 | const rigCam = this.cameraRig.shadowRoot.querySelector('lume-perspective-camera')
|
230 | 234 | rigCam.near = this.freeCam.near = 0.1
|
231 |
| - rigCam.far = this.freeCam.far = 110 |
| 235 | + rigCam.far = this.freeCam.far = 150 |
232 | 236 |
|
233 | 237 | const promises = []
|
234 | 238 |
|
|
237 | 241 |
|
238 | 242 | await Promise.all(promises)
|
239 | 243 |
|
| 244 | + for (const model of this.models) { |
| 245 | + // Here we do some manipulation of the underlying Three.js objects directly. |
| 246 | + model.three.traverse(node => { |
| 247 | + if (node.isLight) node.visible = false |
| 248 | + |
| 249 | + function newMat(oldMat) { |
| 250 | + return new MeshPhysicalMaterial({ |
| 251 | + metalness: 0.5, |
| 252 | + roughness: 0.5, |
| 253 | + ...(oldMat.color ? {color: oldMat.color} : {}), |
| 254 | + ...(oldMat.map ? {map: oldMat.map.clone()} : {}), |
| 255 | + }) |
| 256 | + } |
| 257 | + |
| 258 | + if (node.isMesh) { |
| 259 | + if (Array.isArray(node.material)) |
| 260 | + for (const [i, mat] of node.material.entries()) node.material[i] = newMat(mat) |
| 261 | + else |
| 262 | + node.material = newMat(node.material) |
| 263 | + |
| 264 | + // smooth out the normals so the rendering is not flat-faced unless angle between faces is greater than 25 deg |
| 265 | + node.geometry = toCreasedNormals(node.geometry, (25 / 180) * Math.PI) |
| 266 | + } |
| 267 | + }) |
| 268 | + |
| 269 | + } |
| 270 | + |
240 | 271 | this.sceneContainer.classList.remove('hidden')
|
241 | 272 | this.loading.remove()
|
242 | 273 | }
|
243 | 274 | }
|
244 |
| - |
245 |
| - App.observedAttributes = { |
246 |
| - rotationDirection: attribute.number(1), |
247 |
| - rotationAmount: attribute.number(1), |
248 |
| - rotationEnabled: attribute.boolean(true), |
249 |
| - view: attribute.string('free'), |
250 |
| - } |
251 |
| - |
252 |
| - return App |
253 |
| - })()) |
| 275 | + ) |
254 | 276 | </script>
|
255 | 277 | </template>
|
256 | 278 | </live-code>
|
0 commit comments