|
|
@@ -24025,6 +24025,22 @@ class PhysicalLightingModel extends LightingModel {
|
|
|
*/
|
|
|
this.iridescenceF0 = null;
|
|
|
|
|
|
+ /**
|
|
|
+ * The iridescence F0 dielectric.
|
|
|
+ *
|
|
|
+ * @type {?Node}
|
|
|
+ * @default null
|
|
|
+ */
|
|
|
+ this.iridescenceF0Dielectric = null;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The iridescence F0 metallic.
|
|
|
+ *
|
|
|
+ * @type {?Node}
|
|
|
+ * @default null
|
|
|
+ */
|
|
|
+ this.iridescenceF0Metallic = null;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -24054,15 +24070,28 @@ class PhysicalLightingModel extends LightingModel {
|
|
|
|
|
|
const dotNVi = normalView.dot( positionViewDirection ).clamp();
|
|
|
|
|
|
- this.iridescenceFresnel = evalIridescence( {
|
|
|
+ const iridescenceFresnelDielectric = evalIridescence( {
|
|
|
outsideIOR: float( 1.0 ),
|
|
|
eta2: iridescenceIOR,
|
|
|
cosTheta1: dotNVi,
|
|
|
thinFilmThickness: iridescenceThickness,
|
|
|
- baseF0: specularColorBlended
|
|
|
+ baseF0: specularColor
|
|
|
} );
|
|
|
|
|
|
- this.iridescenceF0 = Schlick_to_F0( { f: this.iridescenceFresnel, f90: 1.0, dotVH: dotNVi } );
|
|
|
+ const iridescenceFresnelMetallic = evalIridescence( {
|
|
|
+ outsideIOR: float( 1.0 ),
|
|
|
+ eta2: iridescenceIOR,
|
|
|
+ cosTheta1: dotNVi,
|
|
|
+ thinFilmThickness: iridescenceThickness,
|
|
|
+ baseF0: diffuseColor.rgb
|
|
|
+ } );
|
|
|
+
|
|
|
+ this.iridescenceFresnel = mix( iridescenceFresnelDielectric, iridescenceFresnelMetallic, metalness );
|
|
|
+
|
|
|
+ this.iridescenceF0Dielectric = Schlick_to_F0( { f: iridescenceFresnelDielectric, f90: 1.0, dotVH: dotNVi } );
|
|
|
+ this.iridescenceF0Metallic = Schlick_to_F0( { f: iridescenceFresnelMetallic, f90: 1.0, dotVH: dotNVi } );
|
|
|
+
|
|
|
+ this.iridescenceF0 = mix( this.iridescenceF0Dielectric, this.iridescenceF0Metallic, metalness );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -24106,13 +24135,13 @@ class PhysicalLightingModel extends LightingModel {
|
|
|
// Approximates multi-scattering in order to preserve energy.
|
|
|
// http://www.jcgt.org/published/0008/01/03/
|
|
|
|
|
|
- computeMultiscattering( singleScatter, multiScatter, specularF90, f0 ) {
|
|
|
+ computeMultiscattering( singleScatter, multiScatter, specularF90, f0, iridescenceF0 = null ) {
|
|
|
|
|
|
const dotNV = normalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
|
|
|
|
|
|
const fab = DFGApprox( { roughness, dotNV } );
|
|
|
|
|
|
- const Fr = this.iridescenceF0 ? iridescence.mix( f0, this.iridescenceF0 ) : f0;
|
|
|
+ const Fr = iridescenceF0 ? iridescence.mix( f0, iridescenceF0 ) : f0;
|
|
|
|
|
|
const FssEss = Fr.mul( fab.x ).add( specularF90.mul( fab.y ) );
|
|
|
|
|
|
@@ -24269,8 +24298,8 @@ class PhysicalLightingModel extends LightingModel {
|
|
|
const singleScatteringMetallic = vec3().toVar( 'singleScatteringMetallic' );
|
|
|
const multiScatteringMetallic = vec3().toVar( 'multiScatteringMetallic' );
|
|
|
|
|
|
- this.computeMultiscattering( singleScatteringDielectric, multiScatteringDielectric, specularF90, specularColor );
|
|
|
- this.computeMultiscattering( singleScatteringMetallic, multiScatteringMetallic, specularF90, diffuseColor.rgb );
|
|
|
+ this.computeMultiscattering( singleScatteringDielectric, multiScatteringDielectric, specularF90, specularColor, this.iridescenceF0Dielectric );
|
|
|
+ this.computeMultiscattering( singleScatteringMetallic, multiScatteringMetallic, specularF90, diffuseColor.rgb, this.iridescenceF0Metallic );
|
|
|
|
|
|
// Mix based on metalness
|
|
|
const singleScattering = mix( singleScatteringDielectric, singleScatteringMetallic, metalness );
|
|
|
@@ -47028,7 +47057,21 @@ class Background extends DataMap {
|
|
|
getTextureLevel: () => backgroundBlurriness
|
|
|
} );
|
|
|
|
|
|
- let viewProj = modelViewProjection;
|
|
|
+ // when using orthographic cameras, we must scale the skybox sphere
|
|
|
+ // up to exceed the dimensions of the camera's viewing box.
|
|
|
+ const isOrtho = cameraProjectionMatrix.element( 3 ).element( 3 ).equal( 1.0 );
|
|
|
+
|
|
|
+ // calculate the orthographic scale
|
|
|
+ // projectionMatrix[1][1] is (1 / top). Invert it to get the height and multiply by 3.0
|
|
|
+ // (an arbitrary safety factor) to ensure the skybox is large enough to cover the corners
|
|
|
+ // of the rectangular screen
|
|
|
+ const orthoScale = div( 1.0, cameraProjectionMatrix.element( 1 ).element( 1 ) ).mul( 3.0 );
|
|
|
+
|
|
|
+ // compute vertex position
|
|
|
+ const modifiedPosition = isOrtho.select( positionLocal.mul( orthoScale ), positionLocal );
|
|
|
+ let viewProj = cameraProjectionMatrix.mul( modelViewMatrix.mul( vec4( modifiedPosition, 1.0 ) ) );
|
|
|
+
|
|
|
+ // force background to far plane so it does not occlude objects
|
|
|
viewProj = viewProj.setZ( viewProj.w );
|
|
|
|
|
|
const nodeMaterial = new NodeMaterial();
|