Преглед изворни кода

Merge pull request #3559 from DavidHGillen/master

360 video support - In progress
David Catuhe пре 7 година
родитељ
комит
36957bafac

+ 13 - 2
Tools/Gulp/config.json

@@ -86,7 +86,8 @@
             "nullEngine",
             "nullEngine",
             "instrumentation",
             "instrumentation",
             "backgroundMaterial",
             "backgroundMaterial",
-            "environmentHelper"
+            "environmentHelper",
+            "videoDome"
         ],
         ],
         "minimal": [
         "minimal": [
             "freeCamera",
             "freeCamera",
@@ -1120,6 +1121,16 @@
                 "backgroundMaterial",
                 "backgroundMaterial",
                 "additionalTextures"
                 "additionalTextures"
             ]
             ]
+        },
+        "videoDome": {
+            "files": [
+                "../../src/Helpers/babylon.videoDome.js"
+            ],
+            "dependUpon": [
+                "core",
+                "meshBuilder",
+                "additionalTextures"
+            ]
         }
         }
     },
     },
     "typescript": [
     "typescript": [
@@ -1681,4 +1692,4 @@
             ]
             ]
         }
         }
     }
     }
-}
+}

+ 2 - 0
dist/preview release/what's new.md

@@ -51,6 +51,8 @@
 - (Viewer) It is now possible to update parts of the configuration without rcreating the objects. ([RaananW](https://github.com/RaananW))
 - (Viewer) It is now possible to update parts of the configuration without rcreating the objects. ([RaananW](https://github.com/RaananW))
 - (Viewer) Model can be normalized using configuration. ([RaananW](https://github.com/RaananW))
 - (Viewer) Model can be normalized using configuration. ([RaananW](https://github.com/RaananW))
 - (Gulp) extra/external declarations can be prepended to final NPM declarations during build. ([RaananW](https://github.com/RaananW))
 - (Gulp) extra/external declarations can be prepended to final NPM declarations during build. ([RaananW](https://github.com/RaananW))
+- Added FOV system to background material for zoom effects in skyboxes without adjusting camera FOV ([DavidHGillen](https://github.com/DavidHGillen))
+- Added VideoDomeHelper class to provide a template for a common scenario, and gave it FOV control ([DavidHGillen](https://github.com/DavidHGillen))
 
 
 ## Bug fixes
 ## Bug fixes
 
 

+ 94 - 0
src/Helpers/babylon.videoDome.ts

@@ -0,0 +1,94 @@
+module BABYLON {
+    /**
+     * Display a 360 degree video on an approximately spherical surface, useful for VR applications or skyboxes.
+     * As a subclass of Node, this allow parenting to the camera or multiple videos with different locations in the scene.
+     * This class achieves its effect with a VideoTexture and a correctly configured BackgroundMaterial on an inverted sphere.
+     * Potential additions to this helper include zoom and and non-infinite distance rendering effects.
+     */
+    export class VideoDome extends Node {
+
+        /**
+         * The video texture being displayed on the sphere
+         */
+        protected _videoTexture: VideoTexture;
+
+        /**
+         * The skybox material
+         */
+        protected _material: BackgroundMaterial;
+
+        /**
+         * The surface used for the skybox
+         */
+        protected _mesh: Mesh;
+
+        /**
+         * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
+         * Also see the options.resolution property.
+         */
+        public get fovMultiplier(): number {
+            return this._material.fovMultiplier;
+        }
+        public set fovMultiplier(value: number) {
+            this._material.fovMultiplier = value;
+        }
+
+        /**
+         * Create an instance of this class and pass through the parameters to the relevant classes, VideoTexture, StandardMaterial, and Mesh.
+         * @param name Element's name, child elements will append suffixes for their own names.
+         * @param urlsOrVideo
+         * @param options An object containing optional or exposed sub element properties:
+         * @param options **resolution=12** Integer, lower resolutions have more artifacts at extreme fovs
+         * @param options **clickToPlay=false** Add a click to play listener to the video, does not prevent autoplay.
+         * @param options **autoPlay=true** Automatically attempt to being playing the video.
+         * @param options **loop=true** Automatically loop video on end.
+         * @param options **size=1000** Physical radius to create the dome at, defaults to approximately half the far clip plane.
+         */
+        constructor(name: string, urlsOrVideo: string[] | HTMLVideoElement, options: {
+            resolution?: number,
+            clickToPlay?: boolean,
+            autoPlay?: boolean,
+            loop?: boolean,
+            size?: number
+        }, scene: Scene) {
+            super(name, scene);
+
+            // set defaults and manage values
+            name = name || "videoDome";
+            options.resolution = (Math.abs(options.resolution as any) | 0) || 12;
+            options.clickToPlay = Boolean(options.clickToPlay);
+            options.autoPlay = options.autoPlay === undefined ? true : Boolean(options.autoPlay);
+            options.loop = options.loop === undefined ? true : Boolean(options.loop);
+            options.size = Math.abs(options.size as any) || (scene.activeCamera ? scene.activeCamera.maxZ * 0.48 : 1000);
+
+            // create
+            let tempOptions:VideoTextureSettings = {loop: options.loop, autoPlay: options.autoPlay, autoUpdateTexture: true};
+            let material = this._material = new BABYLON.BackgroundMaterial(name+"_material", scene);
+            let texture = this._videoTexture = new BABYLON.VideoTexture(name+"_texture", urlsOrVideo, scene, false, false, Texture.TRILINEAR_SAMPLINGMODE, tempOptions);
+            this._mesh = BABYLON.MeshBuilder.CreateIcoSphere(name+"_mesh", {
+                flat: false, // saves on vertex data
+                radius: options.size,
+                subdivisions: options.resolution,
+                sideOrientation: BABYLON.Mesh.BACKSIDE // needs to be inside out
+            }, scene);
+
+            // configure material
+            texture.coordinatesMode = BABYLON.Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE; // matches orientation
+            texture.wrapV = Texture.CLAMP_ADDRESSMODE; // always clamp the up/down
+            material.reflectionTexture = this._videoTexture;
+            material.useEquirectangularFOV = true;
+            material.fovMultiplier = 1.0;
+
+            // configure mesh
+            this._mesh.material = material;
+            this._mesh.parent = this;
+
+            // optional configuration
+            if(options.clickToPlay) {
+                scene.onPointerUp = () => {
+                    this._videoTexture.video.play();
+                }
+            }
+        }
+    }
+}

+ 29 - 2
src/Materials/Background/babylon.backgroundMaterial.ts

@@ -95,6 +95,7 @@
         public REFLECTIONMAP_OPPOSITEZ = false;
         public REFLECTIONMAP_OPPOSITEZ = false;
         public LODINREFLECTIONALPHA = false;
         public LODINREFLECTIONALPHA = false;
         public GAMMAREFLECTION = false;
         public GAMMAREFLECTION = false;
+        public EQUIRECTANGULAR_RELFECTION_FOV = false;
 
 
         // Default BJS.
         // Default BJS.
         public MAINUV1 = false;
         public MAINUV1 = false;
@@ -330,6 +331,28 @@
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         @expandToProperty("_markAllSubMeshesAsTexturesDirty")
         public enableNoise: boolean = false;
         public enableNoise: boolean = false;
 
 
+        /**
+         * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
+         * Best used when trying to implement visual zoom effects like fish-eye or binoculars while not adjusting camera fov.
+         * Recommended to be keep at 1.0 except for special cases.
+         */
+        public get fovMultiplier(): number {
+            return this._fovMultiplier;
+        }
+        public set fovMultiplier(value: number) {
+            if (isNaN(value)) {
+                value = 1.0;
+            }
+            this._fovMultiplier = Math.max(0.0, Math.min(2.0, value));
+        }
+        private _fovMultiplier: float = 1.0;
+
+        /**
+         * Enable the FOV adjustment feature controlled by fovMultiplier.
+         * @type {boolean}
+         */
+        public useEquirectangularFOV: boolean = false;
+
         @serialize()
         @serialize()
         private _maxSimultaneousLights: int = 4;
         private _maxSimultaneousLights: int = 4;
         /**
         /**
@@ -611,6 +634,7 @@
                         defines.REFLECTIONBLUR = this._reflectionBlur > 0;
                         defines.REFLECTIONBLUR = this._reflectionBlur > 0;
                         defines.REFLECTIONMAP_OPPOSITEZ = this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ;
                         defines.REFLECTIONMAP_OPPOSITEZ = this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ;
                         defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha;
                         defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha;
+                        defines.EQUIRECTANGULAR_RELFECTION_FOV = this.useEquirectangularFOV;
 
 
                         if (reflectionTexture.coordinatesMode === Texture.INVCUBIC_MODE) {
                         if (reflectionTexture.coordinatesMode === Texture.INVCUBIC_MODE) {
                             defines.INVERTCUBICMAP = true;
                             defines.INVERTCUBICMAP = true;
@@ -756,7 +780,7 @@
                     "vClipPlane", "mBones",
                     "vClipPlane", "mBones",
 
 
                     "vPrimaryColor", "vSecondaryColor", "vTertiaryColor",
                     "vPrimaryColor", "vSecondaryColor", "vTertiaryColor",
-                    "vReflectionInfos", "reflectionMatrix", "vReflectionMicrosurfaceInfos",
+                    "vReflectionInfos", "reflectionMatrix", "vReflectionMicrosurfaceInfos", "fFovMultiplier",
 
 
                     "shadowLevel", "alpha",
                     "shadowLevel", "alpha",
 
 
@@ -826,6 +850,7 @@
             this._uniformBuffer.addUniform("diffuseMatrix", 16);
             this._uniformBuffer.addUniform("diffuseMatrix", 16);
             this._uniformBuffer.addUniform("reflectionMatrix", 16);
             this._uniformBuffer.addUniform("reflectionMatrix", 16);
             this._uniformBuffer.addUniform("vReflectionMicrosurfaceInfos", 3);
             this._uniformBuffer.addUniform("vReflectionMicrosurfaceInfos", 3);
+            this._uniformBuffer.addUniform("fFovMultiplier", 1);
             this._uniformBuffer.addUniform("pointSize", 1);
             this._uniformBuffer.addUniform("pointSize", 1);
             this._uniformBuffer.addUniform("shadowLevel", 1);
             this._uniformBuffer.addUniform("shadowLevel", 1);
             this._uniformBuffer.addUniform("alpha", 1);
             this._uniformBuffer.addUniform("alpha", 1);
@@ -925,6 +950,8 @@
                     this._uniformBuffer.updateColor4("vTertiaryColor", this._tertiaryColor, this._tertiaryLevel);
                     this._uniformBuffer.updateColor4("vTertiaryColor", this._tertiaryColor, this._tertiaryLevel);
                 }
                 }
 
 
+                this._uniformBuffer.updateFloat("fFovMultiplier", this._fovMultiplier);
+
                 // Textures
                 // Textures
                 if (scene.texturesEnabled) {
                 if (scene.texturesEnabled) {
                     if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
                     if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
@@ -1039,4 +1066,4 @@
             return SerializationHelper.Parse(() => new BackgroundMaterial(source.name, scene), source, scene, rootUrl);
             return SerializationHelper.Parse(() => new BackgroundMaterial(source.name, scene), source, scene, rootUrl);
         }
         }
     }
     }
-}
+}

+ 1 - 0
src/Shaders/ShadersInclude/backgroundUboDeclaration.fx

@@ -10,6 +10,7 @@ uniform Material
 	uniform mat4 diffuseMatrix;
 	uniform mat4 diffuseMatrix;
 	uniform mat4 reflectionMatrix;
 	uniform mat4 reflectionMatrix;
 	uniform vec3 vReflectionMicrosurfaceInfos;
 	uniform vec3 vReflectionMicrosurfaceInfos;
+	uniform float fFovMultiplier;
 
 
 	uniform float pointSize;
 	uniform float pointSize;
 	uniform float shadowLevel;
 	uniform float shadowLevel;

+ 1 - 0
src/Shaders/ShadersInclude/backgroundVertexDeclaration.fx

@@ -11,6 +11,7 @@ uniform vec2 vDiffuseInfos;
     uniform vec2 vReflectionInfos;
     uniform vec2 vReflectionInfos;
     uniform mat4 reflectionMatrix;
     uniform mat4 reflectionMatrix;
     uniform vec3 vReflectionMicrosurfaceInfos;
     uniform vec3 vReflectionMicrosurfaceInfos;
+    uniform float fFovMultiplier;
 #endif
 #endif
 
 
 #ifdef POINTSIZE
 #ifdef POINTSIZE

+ 1 - 1
src/Shaders/ShadersInclude/reflectionFunction.fx

@@ -1,7 +1,7 @@
 vec3 computeReflectionCoords(vec4 worldPos, vec3 worldNormal)
 vec3 computeReflectionCoords(vec4 worldPos, vec3 worldNormal)
 {
 {
 #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
 #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
-	vec3 direction = normalize(vDirectionW);
+	vec3 direction = vDirectionW;
 
 
 	float t = clamp(direction.y * -0.5 + 0.5, 0., 1.0);
 	float t = clamp(direction.y * -0.5 + 0.5, 0., 1.0);
 	float s = atan(direction.z, direction.x) * RECIPROCAL_PI2 + 0.5;
 	float s = atan(direction.z, direction.x) * RECIPROCAL_PI2 + 0.5;

+ 3 - 1
src/Shaders/background.fragment.fx

@@ -6,6 +6,8 @@ precision highp float;
 
 
 #include<__decl__backgroundFragment>
 #include<__decl__backgroundFragment>
 
 
+#define RECIPROCAL_PI2 0.15915494
+
 // Constants
 // Constants
 uniform vec3 vEyePosition;
 uniform vec3 vEyePosition;
 
 
@@ -286,4 +288,4 @@ vec4 color = vec4(finalColor, finalAlpha);
 #endif
 #endif
 
 
     gl_FragColor = color;
     gl_FragColor = color;
-}
+}

+ 13 - 0
src/Shaders/background.vertex.fx

@@ -2,6 +2,8 @@
 
 
 #include<__decl__backgroundVertex>
 #include<__decl__backgroundVertex>
 
 
+#include<helperFunctions>
+
 // Attributes
 // Attributes
 attribute vec3 position;
 attribute vec3 position;
 #ifdef NORMAL
 #ifdef NORMAL
@@ -78,6 +80,17 @@ void main(void) {
 
 
 #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
 #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
     vDirectionW = normalize(vec3(finalWorld * vec4(position, 0.0)));
     vDirectionW = normalize(vec3(finalWorld * vec4(position, 0.0)));
+
+
+    #ifdef EQUIRECTANGULAR_RELFECTION_FOV
+        mat3 screenToWorld = inverseMat3(mat3(finalWorld * viewProjection));
+        vec3 segment = mix(vDirectionW, screenToWorld * vec3(0.0,0.0, 1.0), abs(fFovMultiplier - 1.0));
+        if (fFovMultiplier <= 1.0) {
+            vDirectionW = normalize(segment);
+        } else {
+            vDirectionW = normalize(vDirectionW + (vDirectionW - segment));
+        }
+    #endif
 #endif
 #endif
 
 
 #ifndef UV1
 #ifndef UV1