From b8f2ca3816ac7a7b83a841b38b2506636652c64f Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Sun, 10 Nov 2019 06:34:16 +0000 Subject: [PATCH] Reverse Depth Buffer for Projection matrix --- dist/preview release/what's new.md | 1 + src/Cameras/camera.ts | 23 +++++++------ src/Engines/thinEngine.ts | 12 ++++++- src/Maths/math.vector.ts | 53 ++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/dist/preview release/what's new.md b/dist/preview release/what's new.md index 50960e235fc..e7c49452df7 100644 --- a/dist/preview release/what's new.md +++ b/dist/preview release/what's new.md @@ -15,6 +15,7 @@ - WebXR webVR parity helpers (Vive, WMR, Oculus Rift) ([TrevorDev](https://github.com/TrevorDev)) - Added support for Offscreen canvas [Doc](https://doc.babylonjs.com/how_to/using_offscreen_canvas) ([Deltakosh](https://github.com/deltakosh/) - Added support for multiple canvases with one engine [Doc](https://doc.babylonjs.com/how_to/multi_canvases) ([Deltakosh](https://github.com/deltakosh/) +- Added useReverseDepthBuffer to Engine which can provide greater z depth for distant objects without the cost of a logarithmic depth buffer ([BenAdams](https://github.com/benaadams/)) ## Updates diff --git a/src/Cameras/camera.ts b/src/Cameras/camera.ts index a2c413c9586..c6d384b11a0 100644 --- a/src/Cameras/camera.ts +++ b/src/Cameras/camera.ts @@ -719,21 +719,20 @@ export class Camera extends Node { this.minZ = 0.1; } + const reverseDepth = engine.useReverseDepthBuffer; + let getProjectionMatrix: (fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed: boolean) => void; if (scene.useRightHandedSystem) { - Matrix.PerspectiveFovRHToRef(this.fov, - engine.getAspectRatio(this), - this.minZ, - this.maxZ, - this._projectionMatrix, - this.fovMode === Camera.FOVMODE_VERTICAL_FIXED); + getProjectionMatrix = reverseDepth ? Matrix.PerspectiveFovReverseRHToRef : Matrix.PerspectiveFovRHToRef; } else { - Matrix.PerspectiveFovLHToRef(this.fov, - engine.getAspectRatio(this), - this.minZ, - this.maxZ, - this._projectionMatrix, - this.fovMode === Camera.FOVMODE_VERTICAL_FIXED); + getProjectionMatrix = reverseDepth ? Matrix.PerspectiveFovReverseLHToRef : Matrix.PerspectiveFovLHToRef; } + + getProjectionMatrix(this.fov, + engine.getAspectRatio(this), + this.minZ, + this.maxZ, + this._projectionMatrix, + this.fovMode === Camera.FOVMODE_VERTICAL_FIXED); } else { var halfWidth = engine.getRenderWidth() / 2.0; var halfHeight = engine.getRenderHeight() / 2.0; diff --git a/src/Engines/thinEngine.ts b/src/Engines/thinEngine.ts index 9b5c044af20..b88588773e3 100644 --- a/src/Engines/thinEngine.ts +++ b/src/Engines/thinEngine.ts @@ -201,6 +201,11 @@ export class ThinEngine { /** Gets or sets a boolean indicating if the engine should validate programs after compilation */ public validateShaderPrograms = false; + /** + * Gets or sets a boolean indicating if depth buffer should be reverse, going from far to near. + * This can provide greater z depth for distant objects. + */ + public useReverseDepthBuffer = false; // Uniform buffers list /** @@ -1136,7 +1141,12 @@ export class ThinEngine { mode |= this._gl.COLOR_BUFFER_BIT; } if (depth) { - this._gl.clearDepth(1.0); + if (this.useReverseDepthBuffer) { + this._depthCullingState.depthFunc = this._gl.GREATER; + this._gl.clearDepth(0.0); + } else { + this._gl.clearDepth(1.0); + } mode |= this._gl.DEPTH_BUFFER_BIT; } if (stencil) { diff --git a/src/Maths/math.vector.ts b/src/Maths/math.vector.ts index 76a494a83bc..b26b9436d8e 100644 --- a/src/Maths/math.vector.ts +++ b/src/Maths/math.vector.ts @@ -4996,6 +4996,29 @@ export class Matrix { result._updateIdentityStatus(false); } + /** + * Stores a left-handed perspective projection into a given matrix with depth reversed + * @param fov defines the horizontal field of view + * @param aspect defines the aspect ratio + * @param znear defines the near clip plane + * @param zfar not used as infinity is used as far clip + * @param result defines the target matrix + * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally + */ + public static PerspectiveFovReverseLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed = true): void { + let t = 1.0 / (Math.tan(fov * 0.5)); + let a = isVerticalFovFixed ? (t / aspect) : t; + let b = isVerticalFovFixed ? t : (t * aspect); + Matrix.FromValuesToRef( + a, 0.0, 0.0, 0.0, + 0.0, b, 0.0, 0.0, + 0.0, 0.0, -znear, 1.0, + 0.0, 0.0, 1.0, 0.0, + result + ); + result._updateIdentityStatus(false); + } + /** * Creates a right-handed perspective projection matrix * @param fov defines the horizontal field of view @@ -5045,6 +5068,36 @@ export class Matrix { result._updateIdentityStatus(false); } + /** + * Stores a right-handed perspective projection into a given matrix + * @param fov defines the horizontal field of view + * @param aspect defines the aspect ratio + * @param znear defines the near clip plane + * @param zfar not used as infinity is used as far clip + * @param result defines the target matrix + * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally + */ + public static PerspectiveFovReverseRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed = true): void { + //alternatively this could be expressed as: + // m = PerspectiveFovLHToRef + // m[10] *= -1.0; + // m[11] *= -1.0; + + let t = 1.0 / (Math.tan(fov * 0.5)); + let a = isVerticalFovFixed ? (t / aspect) : t; + let b = isVerticalFovFixed ? t : (t * aspect); + + Matrix.FromValuesToRef( + a, 0.0, 0.0, 0.0, + 0.0, b, 0.0, 0.0, + 0.0, 0.0, -znear, -1.0, + 0.0, 0.0, -1.0, 0.0, + result + ); + + result._updateIdentityStatus(false); + } + /** * Stores a perspective projection for WebVR info a given matrix * @param fov defines the field of view