import { Reporter } from '../reporter/reporter.js';
import { checkPropTypes } from '../lib.js';
import { BuildableComponent } from '../package/component/buildable_component.js';
import {
Camera,
Scene,
Color,
WebGLRenderer,
MeshBasicMaterial,
WebGLRenderTarget,
MeshDepthMaterial,
RGBAFormat,
PlaneBufferGeometry,
ShaderMaterial,
Mesh,
OrthographicCamera,
Group,
WireframeGeometry,
LineSegments
} from '../../node_modules/three/build/three.module.js';
//THREE SHADERS
import { HorizontalBlurShader } from '../../node_modules/three/examples/jsm/shaders/HorizontalBlurShader.js';
import { VerticalBlurShader } from '../../node_modules/three/examples/jsm/shaders/VerticalBlurShader.js';
class ContactShadow extends BuildableComponent {
/**
* @param {Reporter} reporter
* @param {Object} settings
* @param {Object} [settings.contactShadow]
* @param {UUID} [settings.id]
* @param {Scene} [settings.scene]
* @param {Camera} [settings.camera]
* @param {WebGLRenderer} [settings.renderer]
*/
constructor( reporter, settings ){
super(reporter, settings);
checkPropTypes(
settings,
{
},
{
contactShadow: Object,
scene: Scene,
camera: Camera,
renderer: WebGLRenderer
}
);
//console.log( settings )
//SETTINGS
this.name = "ContactShadow";
this.planeWidth = 30;
this.planeHeight = 30;
this.planeColor = "#ffffff";
this.planeOpacity = 1,
this.cameraHeight = 0.35;
this.shadowDarkness = 1;
this.shadowOpacity = 1;
this.blurAmount = 0.25;
this.showWireframe = true;
this._scene = settings.scene
this._camera = settings.camera
this._renderer = settings.renderer
}
async _build(){
// PLANE GEO
const shadowPlaneGeometry = new PlaneBufferGeometry( this.planeWidth, this.planeHeight ).rotateX( Math.PI / 2 ); //settings.plane.width, settings.plane.height
shadowPlaneGeometry.name = "ContactShadow Plane";
//PLANE MATERIAL
const shadowPlaneMaterial = new MeshBasicMaterial( {
name: "ContactShadow Material",
//map: renderTarget.texture,
opacity: this.shadowOpacity,
transparent: true,
envMap: null
} );
// PLANE MESH
const shadowPlaneMesh = new Mesh( shadowPlaneGeometry, shadowPlaneMaterial );
shadowPlaneMesh.name = "ContactShadow Plane"
shadowPlaneMesh.scale.y = - 1; // the y from the texture is flipped!
shadowPlaneMesh.receiveShadow = true;
//shadowPlaneMesh.showWireframe = this.showWireframe
// BLUR PLANE - onto which to blur the texture
const shadowBlurPlane = new Mesh( shadowPlaneGeometry );
shadowBlurPlane.name = "ContactShadow Blur Plane";
shadowBlurPlane.visible = false;
// CAMERA - to render the depth material from
const shadowCamera = new OrthographicCamera( - this.planeWidth / 2, this.planeHeight / 2, this.planeHeight / 2, - this.planeHeight / 2, 0, this.cameraHeight );
shadowCamera.rotation.x = Math.PI / 2; // get the camera to look up
// DEPTHMATERIAL -- like MeshDepthMaterial, but goes from black to transparent
const depthMaterial = new MeshDepthMaterial();
depthMaterial.userData.darkness = { value: this.shadowDarkness };
depthMaterial.onBeforeCompile = function ( shader ) {
shader.uniforms.darkness = depthMaterial.userData.darkness;
shader.fragmentShader = `
uniform float darkness;
${shader.fragmentShader.replace(
'gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );',
'gl_FragColor = vec4( vec3( 0.0 ), ( 1.0 - fragCoordZ ) * darkness );'
)}
`;
};
depthMaterial.depthTest = false;
depthMaterial.depthWrite = false;
//BLUR SHADERS
const horizontalBlurMaterial = new ShaderMaterial( HorizontalBlurShader );
horizontalBlurMaterial.depthTest = false;
const verticalBlurMaterial = new ShaderMaterial( VerticalBlurShader );
verticalBlurMaterial.depthTest = false;
//GROUP
const shadowGroup = new Group();
shadowGroup.name = "ContactShadow Group"
shadowGroup.position.y = - 0;
shadowGroup.children = [ shadowPlaneMesh, shadowBlurPlane, shadowCamera ]; //scene.add( line ); line
shadowGroup.layers.set( 1 );
shadowGroup.receiveShadow = true;
this._shadowGroup = shadowGroup;
//this.layers = 1
this._shadowBlurPlane = shadowBlurPlane
this._horizontalBlurMaterial = horizontalBlurMaterial
this._verticalBlurMaterial = verticalBlurMaterial
//this._renderTargets = renderTargets
//this._renderTargetBlur = renderTargetBlur
this._shadowCamera = shadowCamera
this._depthMaterial = depthMaterial
this._shadowPlaneMaterial = shadowPlaneMaterial
return this;
}
_blur( blurAmount ){
//console.log( this._shadowBlurPlane )
this._shadowBlurPlane.visible = true;
this._shadowPlaneMaterial.map = this._renderTargets[0]
// RENDERTARGET A - blur vertically and draw in the main renderTarget
this._shadowBlurPlane.material = this._verticalBlurMaterial;
this._shadowBlurPlane.material.uniforms.tDiffuse.value = this._renderTargets[0].texture //this._renderTargetBlur.texture;
this._verticalBlurMaterial.uniforms.v.value = blurAmount * 1 / 256;
this._renderer.setRenderTarget( this._renderTargets[1] );
this._renderer.render( this._shadowBlurPlane, this._shadowCamera );
// RENDERTARGET B - blur horizontally and draw in the renderTargetBlur
this._shadowBlurPlane.material = this._horizontalBlurMaterial;
this._shadowBlurPlane.material.uniforms.tDiffuse.value = this._renderTargets[1].texture //this._renderTarget.texture;
this._horizontalBlurMaterial.uniforms.h.value = blurAmount * 1 / 256;
this._renderer.setRenderTarget( this._renderTargets[0] ); //this._renderTargetBlur
this._renderer.render( this._shadowBlurPlane, this._shadowCamera );
this._shadowBlurPlane.visible = false;
return this._renderTargets
}
_update( exclude ){
//console.log( exclude)
// RENDERTARGET - the render target that will show the shadows in the plane texture
const renderTarget = new WebGLRenderTarget( 512, 512 );
renderTarget.texture.format = RGBAFormat;
renderTarget.texture.generateMipmaps = false;
// RENDERTARGET BLUR - the render target that we will use to blur the first render target
const renderTargetBlur = new WebGLRenderTarget( 512, 512 );
renderTargetBlur.texture.generateMipmaps = false;
const renderTargets = [ renderTarget, renderTargetBlur ]
this._renderTargets = renderTargets
// REMOVE BACKGROUND
const initialBackground = this._scene.background;
this._scene.background = null;
// REMOVE/EXCLUDE OBJECTS FROM SCENE/CONTACTSHADOW HERE
if ( exclude instanceof Array ){
for ( var i = 0; i < exclude.length; i++ ){
exclude[i].visible = false;
}
};
// force the depthMaterial to everything
this._scene.overrideMaterial = this._depthMaterial;
// render to the rendertarget to get the depths
this._renderer.autoClear = false;
this._renderer.setRenderTarget( renderTarget );
this._renderer.render( this._scene, this._shadowCamera );
// reset the override material
this._scene.overrideMaterial = null;
//RE INCLUDE OBJECTS FROM SCENE/SHADOW HERE
if ( exclude instanceof Array){
for ( var i = 0; i < exclude.length; i++ ){
exclude[i].visible = true;
};
};
//BLUR PASS 1
this._blur( this.blurAmount );
//BLUR PASS 2
// a second pass to reduce the artifacts (0.4 is the minimum blur amout so that the artifacts are gone)
this._blur( this.blurAmount * 0.4 );
// reset and render the normal scene
this._renderer.setRenderTarget( null );
this._scene.background = initialBackground;
};
};
export { ContactShadow }