1313 * limitations under the License.
1414 */
1515
16- import { Color } from 'three' ;
16+ import { BackSide , BoxBufferGeometry , Color , Mesh , ShaderLib , ShaderMaterial , UniformsUtils } from 'three' ;
1717
1818import { $needsRender , $onModelLoad , $renderer , $scene , $tick } from '../model-viewer-base.js' ;
19+
1920const DEFAULT_BACKGROUND_COLOR = '#ffffff' ;
20- const GAMMA_TO_LINEAR = 2.2 ;
2121
2222const WHITE = new Color ( '#ffffff' ) ;
2323
24- const $currentCubemap = Symbol ( 'currentCubemap ' ) ;
24+ const $currentEnvMap = Symbol ( 'currentEnvMap ' ) ;
2525const $setEnvironmentImage = Symbol ( 'setEnvironmentImage' ) ;
2626const $setEnvironmentColor = Symbol ( 'setEnvironmentColor' ) ;
2727const $setShadowLightColor = Symbol ( 'setShadowLightColor' ) ;
2828const $hasBackgroundImage = Symbol ( 'hasBackgroundImage' ) ;
2929const $hasBackgroundColor = Symbol ( 'hasBackgroundColor' ) ;
3030const $deallocateTextures = Symbol ( 'deallocateTextures' ) ;
3131
32+ // TODO remove in #196
33+ const $setBackground = Symbol ( 'setBackground' ) ;
34+ const $backgroundMesh = Symbol ( 'backgroundMesh' ) ;
35+ const $activeBackground = Symbol ( 'activeBackground' ) ;
36+
3237export const EnvironmentMixin = ( ModelViewerElement ) => {
3338 return class extends ModelViewerElement {
3439 static get properties ( ) {
@@ -75,17 +80,11 @@ export const EnvironmentMixin = (ModelViewerElement) => {
7580 }
7681 }
7782
78- [ $tick ] ( time , delta ) {
79- super [ $tick ] ( time , delta ) ;
80- const camera = this [ $scene ] . getCamera ( ) ;
81- this [ $scene ] . skysphere . position . copy ( camera . position ) ;
82- }
83-
8483 [ $onModelLoad ] ( e ) {
8584 super [ $onModelLoad ] ( e ) ;
8685
87- if ( this [ $currentCubemap ] ) {
88- this [ $scene ] . model . applyEnvironmentMap ( this [ $currentCubemap ] ) ;
86+ if ( this [ $currentEnvMap ] ) {
87+ this [ $scene ] . model . applyEnvironmentMap ( this [ $currentEnvMap ] ) ;
8988 this [ $needsRender ] ( ) ;
9089 }
9190 }
@@ -95,7 +94,7 @@ export const EnvironmentMixin = (ModelViewerElement) => {
9594 */
9695 async [ $setEnvironmentImage ] ( url ) {
9796 const textureUtils = this [ $renderer ] . textureUtils ;
98- const textures = await textureUtils . toCubemapAndEquirect ( url ) ;
97+ const textures = await textureUtils . generateEnvironmentTextures ( url ) ;
9998
10099 // If the background image has changed
101100 // while fetching textures, abort and defer to that
@@ -113,13 +112,13 @@ export const EnvironmentMixin = (ModelViewerElement) => {
113112 return ;
114113 }
115114
116- const { cubemap , equirect } = textures ;
115+ const { skybox , envmap } = textures ;
117116
118- this [ $scene ] . skysphere . material . color = new Color ( 0xffffff ) ;
119- this [ $scene ] . skysphere . material . map = equirect ;
120- this [ $scene ] . skysphere . material . needsUpdate = true ;
121- this [ $currentCubemap ] = cubemap ;
122- this [ $scene ] . model . applyEnvironmentMap ( cubemap ) ;
117+ // TODO #196
118+ this [ $setBackground ] ( skybox ) ;
119+
120+ this [ $currentEnvMap ] = envmap ;
121+ this [ $scene ] . model . applyEnvironmentMap ( envmap ) ;
123122
124123 this [ $setShadowLightColor ] ( WHITE ) ;
125124
@@ -134,35 +133,97 @@ export const EnvironmentMixin = (ModelViewerElement) => {
134133
135134 this [ $deallocateTextures ] ( ) ;
136135
137- const skysphereColor = this [ $scene ] . skysphere . material . color =
138- new Color ( color ) ;
139- skysphereColor . convertGammaToLinear ( GAMMA_TO_LINEAR ) ;
140- this [ $setShadowLightColor ] ( skysphereColor ) ;
136+ const parsedColor = new Color ( color ) ;
137+
138+ // TODO #196
139+ this [ $setBackground ] ( parsedColor ) ;
141140
142- this [ $scene ] . skysphere . material . map = null ;
143- this [ $scene ] . skysphere . material . needsUpdate = true ;
141+ this [ $setShadowLightColor ] ( parsedColor ) ;
144142
145143 // TODO can cache this per renderer and color
146- const cubemap = textureUtils . generateDefaultEnvMap ( ) ;
147- this [ $currentCubemap ] = cubemap ;
148- this [ $scene ] . model . applyEnvironmentMap ( this [ $currentCubemap ] ) ;
144+ const envmap = textureUtils . generateDefaultEnvMap ( ) ;
145+ this [ $currentEnvMap ] = envmap ;
146+ this [ $scene ] . model . applyEnvironmentMap ( this [ $currentEnvMap ] ) ;
149147
150148 this [ $needsRender ] ( ) ;
151149 }
152150
151+ /**
152+ * Work around for #196, can remove this function
153+ * and set backgrounds on `scene.background` directly
154+ * once upgraded to r100. Most of the logic from
155+ * three's WebGLBackground for WebGLRenderTargetCubes.
156+ */
157+ [ $setBackground ] ( background ) {
158+ // We only support cube maps and colors for backgrounds
159+ const isCube = ! ! ( background && background . isWebGLRenderTargetCube ) ;
160+
161+ if ( isCube && ! this [ $backgroundMesh ] ) {
162+ const mesh = this [ $backgroundMesh ] =
163+ new Mesh ( new BoxBufferGeometry ( 1 , 1 , 1 ) , new ShaderMaterial ( {
164+ type : 'BackgroundCubeMaterial' ,
165+ uniforms : UniformsUtils . clone ( ShaderLib . cube . uniforms ) ,
166+ vertexShader : ShaderLib . cube . vertexShader ,
167+ fragmentShader : ShaderLib . cube . fragmentShader ,
168+ side : BackSide ,
169+ depthTest : false ,
170+ depthWrite : false ,
171+ fog : false
172+ } ) ) ;
173+
174+ mesh . name = 'SceneBackgroundHack' ;
175+ mesh . geometry . removeAttribute ( 'normal' ) ;
176+ mesh . geometry . removeAttribute ( 'uv' ) ;
177+
178+ mesh . onBeforeRender = function ( renderer , scene , camera ) {
179+ this . matrixWorld . copyPosition ( camera . matrixWorld ) ;
180+ } ;
181+
182+ // enable code injection for non-built-in material
183+ Object . defineProperty ( mesh . material , 'map' , {
184+ get : function ( ) {
185+ return this . uniforms . tCube . value ;
186+ }
187+ } ) ;
188+
189+ // WebGLBackground can manually place the background to render
190+ // first -- we don't have access to that here -- set the render order.
191+ mesh . renderOrder = 1 ;
192+ }
193+
194+ if ( isCube ) {
195+ this [ $backgroundMesh ] . material . uniforms . tCube . value =
196+ background . texture ;
197+ this [ $backgroundMesh ] . material . uniforms . tFlip . value = 1 ;
198+ this [ $backgroundMesh ] . material . needsUpdate = true ;
199+ this [ $scene ] . add ( this [ $backgroundMesh ] ) ;
200+ // Remove any color background
201+ this [ $scene ] . background = null ;
202+ // scene.background expects a WebGLRenderTargetCube
203+ this [ $activeBackground ] = background ;
204+ } else {
205+ // `scene.background` works for colors
206+ this [ $scene ] . background = background ;
207+ this [ $scene ] . remove ( this [ $backgroundMesh ] ) ;
208+ this [ $activeBackground ] = background ;
209+ }
210+ }
211+
153212 [ $setShadowLightColor ] ( color ) {
154213 this [ $scene ] . shadowLight . color . copy ( color ) ;
155214 this [ $scene ] . shadowLight . color . lerpHSL ( WHITE , 0.5 ) ;
156215 }
157216
158217 [ $deallocateTextures ] ( ) {
159- if ( this [ $scene ] . skysphere . material . map ) {
160- this [ $scene ] . skysphere . material . map . dispose ( ) ;
161- this [ $scene ] . skysphere . material . map = null ;
218+ // TODO Re-enable in #196
219+ // const background = this[$scene].background;
220+ const background = this [ $activeBackground ] ;
221+ if ( background && background . dispose ) {
222+ background . dispose ( ) ;
162223 }
163- if ( this [ $currentCubemap ] ) {
164- this [ $currentCubemap ] . dispose ( ) ;
165- this [ $currentCubemap ] = null ;
224+ if ( this [ $currentEnvMap ] ) {
225+ this [ $currentEnvMap ] . dispose ( ) ;
226+ this [ $currentEnvMap ] = null ;
166227 }
167228 }
168229 }
0 commit comments