From 74af099265df4fc6b55c9f51f6924a20f2b19b22 Mon Sep 17 00:00:00 2001 From: "T.Alderighi" Date: Sat, 11 Jun 2016 11:48:27 +0200 Subject: [PATCH] SM as separate render pass, still have problems with visibility and zfight --- js/mlj/core/Core.js | 67 ++++++------- js/mlj/core/Scene.js | 16 ++++ js/mlj/plugins/rendering/SM.js | 96 ++++++++----------- .../plugins/rendering/shaders/ShadowFrag.glsl | 44 ++++----- .../rendering/shaders/ShadowVertex.glsl | 13 +-- 5 files changed, 117 insertions(+), 119 deletions(-) diff --git a/js/mlj/core/Core.js b/js/mlj/core/Core.js index f4295258..41b98a4e 100644 --- a/js/mlj/core/Core.js +++ b/js/mlj/core/Core.js @@ -1,39 +1,39 @@ /** * MLJLib * MeshLabJS Library - * + * * Copyright(C) 2015 - * Paolo Cignoni + * Paolo Cignoni * Visual Computing Lab * ISTI - CNR - * + * * All rights reserved. * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later * version. * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See theGNU General Public License + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See theGNU General Public License * (http://www.gnu.org/licenses/gpl.txt) for more details. - * + * */ /** - * @file Defines Emscripten Module object, MLJ.core namspace and the basic + * @file Defines Emscripten Module object, MLJ.core namspace and the basic * classes used to create a Scene * @author Stefano Gabriele */ /** * @global - * @description Module is a global JavaScript object with attributes that + * @description Module is a global JavaScript object with attributes that * Emscripten-generated code calls at various points in its execution. - * Developers can provide an implementation of Module to control - * the execution of code. For example, to define how notification - * messages from Emscripten are displayed, developers implement the + * Developers can provide an implementation of Module to control + * the execution of code. For example, to define how notification + * messages from Emscripten are displayed, developers implement the * Module.print attribute. * Note that parameter 'memoryInitializerPrefixURL' indicates path of file.js.mem */ @@ -54,45 +54,45 @@ var Module = { MLJ.core = { defaults: {}, - setDefaults: function(name, parameters) { - if(MLJ.core.defaults[name] !== undefined) { + setDefaults: function(name, parameters) { + if(MLJ.core.defaults[name] !== undefined) { console.warn("The default properties of "+name+" was overridden."); - } - MLJ.core.defaults[name] = parameters; + } + MLJ.core.defaults[name] = parameters; }, - getDefaults: function(name) { + getDefaults: function(name) { return MLJ.core.defaults[name]; } }; -/** +/** * @class Creates a new Ambient light * @param {THREE.Scene} scene The scene object * @param {THREE.Camera} camera The camera object * @param {THREE.WebGLRenderer} renderer The renderer object * @memberOf MLJ.core - * @author Stefano Gabriele + * @author Stefano Gabriele */ MLJ.core.AmbientLight = function (scene, camera, renderer) { var _on = true; //var _light = new THREE.AmbientLight("#ffffff"); var _light = new THREE.AmbientLight("#808080"); - + /** * Returns true if this ambient light is on - * @returns {Boolean} true if this ambient light is on, + * @returns {Boolean} true if this ambient light is on, * false otherwise - * @author Stefano Gabriele + * @author Stefano Gabriele */ this.isOn = function () { return _on; }; - + /** * Sets this ambient light on/off - * @param {Boolean} on If true, this ambient light is enabled; + * @param {Boolean} on If true, this ambient light is enabled; * otherwise this ambient light is disabled * @author Stefano Gabriele */ @@ -113,23 +113,22 @@ MLJ.core.AmbientLight = function (scene, camera, renderer) { }; -/** +/** * @class Creates a new Headlight * @param {THREE.Scene} scene The scene object * @param {THREE.Camera} camera The camera object * @param {THREE.WebGLRenderer} renderer The renderer object * @memberOf MLJ.core - * @author Stefano Gabriele + * @author Stefano Gabriele */ MLJ.core.Headlight = function (scene, camera, renderer) { var _on = true; - var _light = new THREE.DirectionalLight("#ffffff",0.5); + var _light = new THREE.DirectionalLight("#FFFF",0.5); _light.position.set( 0, -1, 0 ); - /** * Sets this headlight on/off - * @param {Boolean} on If true, this headlight is enabled; + * @param {Boolean} on If true, this headlight is enabled; * otherwise this headlight is disabled * @author Stefano Gabriele */ @@ -145,4 +144,8 @@ MLJ.core.Headlight = function (scene, camera, renderer) { //Init this.setOn(_on); + this.getPosition = () => { + return _light.position; + } + }; diff --git a/js/mlj/core/Scene.js b/js/mlj/core/Scene.js index ae27155f..795ed3a3 100644 --- a/js/mlj/core/Scene.js +++ b/js/mlj/core/Scene.js @@ -747,6 +747,19 @@ MLJ.core.Scene = {}; * before displaying the result. * @memberOf MLJ.core.Scene */ + this._shadowMapping = false; + this.shadowMappingContext = null; + + this.setupShadowMapping = function (context) { + this._shadowMapping = true; + this.shadowMappingContext = context; + } + + this.disposeShadowMapping = function () { + context = null + this._shadowMapping = false; + } + this.render = function (fromReqAnimFrame) { if (_stats.active && !fromReqAnimFrame) { @@ -773,6 +786,9 @@ MLJ.core.Scene = {}; } else { _renderer.render(_scene, _camera); } + if (this._shadowMapping) { + this.shadowMappingContext.renderShadow(); + } // render the 2D overlays _renderer.autoClear = false; diff --git a/js/mlj/plugins/rendering/SM.js b/js/mlj/plugins/rendering/SM.js index 0e0b6255..f88ae584 100644 --- a/js/mlj/plugins/rendering/SM.js +++ b/js/mlj/plugins/rendering/SM.js @@ -7,12 +7,11 @@ (function (plugin, core, scene) { - let SIZE = { w : window.innerWidth, h : window.innerHeight}; - + let SIZE = {width: window.innerWidth, height: window.innerHeight}; +// SIZE = scene.get3DSize(); let shadowPassUniforms = { - depthMap: { type: "t", value: null }, - positionMap: { type: "t", value: null }, - colorMap: { type: "t", value: null }, + lightDepthMap: { type: "t", value: null }, + eyeDepthMap: { type: "t", value: null }, lightViewProjection: { type: "m4", value: null}, }; @@ -45,19 +44,19 @@ in the render pass which draws the shadows */ // non posso specificare come solo depth?? su opengl mi pare si possa - let depthMapTarget = new THREE.WebGLRenderTarget(SIZE.w, SIZE.h, { + let eyeDepthMapTarget = new THREE.WebGLRenderTarget(SIZE.width, SIZE.height, { type: THREE.FloatType, minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter }); - let positionMapTarget = new THREE.WebGLRenderTarget(SIZE.w, SIZE.h, { + + let lightDepthMapTarget = new THREE.WebGLRenderTarget(SIZE.width, SIZE.height, { type: THREE.FloatType, minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter }); - /* material containing the depth pass shaders. The original scene will be rendered using this shaders to produce a depth map @@ -69,26 +68,19 @@ fragmentShader: plug.shaders.getByKey("SMFrag.glsl") }); - let positionMaterial = new THREE.RawShaderMaterial({ - uniforms: {}, - side: THREE.DoubleSide, - vertexShader: plug.shaders.getByKey("PositionVertex.glsl"), - fragmentShader: plug.shaders.getByKey("PositionFragment.glsl") - }); - /* - quad che disegno per il passo di defferred rendering - */ - let quad = new THREE.PlaneBufferGeometry(2,2, 1, 1); - let shadowMapMesh = new THREE.Mesh(quad, new THREE.RawShaderMaterial({ + let shadowMaterial = new THREE.RawShaderMaterial({ uniforms: shadowPassUniforms, + transparent: true, + opacity: 0.5, + blending: THREE["NormalBlending"], side: THREE.DoubleSide, vertexShader: plug.shaders.getByKey("ShadowVertex.glsl"), fragmentShader: plug.shaders.getByKey("ShadowFrag.glsl") - })); + }) + + - let shadowScene = new THREE.Scene(); - shadowScene.add(shadowMapMesh); // poi costruiscilo usando bbox let lightCamera = new THREE.OrthographicCamera( @@ -98,54 +90,50 @@ -20, 1, 25); + lightCamera.position.set(0, 0, 8); + lightCamera.lookAt(new THREE.Vector3(0, 0, 0)); + lightCamera.updateProjectionMatrix(); + let projScreenMatrix = new THREE.Matrix4(); + - lightCamera.position.set(8,0,0); - lightCamera.lookAt(new THREE.Vector3(0,0,0)); /* receives an input buffer in Scene.js and outputs an output buffer that will be used as a texture for the last pass of the deferred rendering pipe. */ - this.pass = (inBuffer, outBuffer) => { + this.renderShadow = () => { + //TODO : light is on camera!!! (didn't notice it).. + // things should be easier then.. let sceneGraph = scene.getScene(); let sceneCam = scene.getCamera(); let renderer = scene.getRenderer(); - //TODO : light is on camera!!! (didn't notice it).. - // things should be easier then.. - - // forces the renderer to use the depth mapping shaders for the whole scene - // lightCamera.position.set(sceneCam.position.x, sceneCam.position.y, sceneCam.position.z); - // lightCamera.lookAt(sceneCam.getWorldDirection()); - // lightCamera.updateProjectionMatrix(); - //renderer.setClearColor(0xFFFFFF); - let projScreenMatrix = new THREE.Matrix4(); - lightCamera.updateProjectionMatrix(); + let dpr = renderer.getPixelRatio(); + eyeDepthMapTarget.setSize(SIZE.width * dpr, SIZE.height * dpr); + lightDepthMapTarget.setSize(SIZE.width * dpr, SIZE.height * dpr); + // sceneGraph.overrideMaterial = new THREE.MeshDepthMaterial(); sceneGraph.overrideMaterial = depthMaterial; - renderer.render(sceneGraph, lightCamera, depthMapTarget, true); - //renderer.setClearColor(clearClr.getHex()); + renderer.render(sceneGraph, sceneCam, eyeDepthMapTarget, true); + renderer.render(sceneGraph, lightCamera, lightDepthMapTarget, true); - // render the position map - sceneGraph.overrideMaterial = positionMaterial; - renderer.render(sceneGraph, sceneCam, positionMapTarget, true); - sceneGraph.overrideMaterial = null; - - - - - projScreenMatrix.multiplyMatrices(lightCamera.projectionMatrix, lightCamera.matrixWorldInverse); + // renderer.render(sceneGraph,sceneCam); + projScreenMatrix.multiplyMatrices(lightCamera.projectionMatrix, lightCamera.matrixWorldInverse); + sceneGraph.overrideMaterial = shadowMaterial; shadowPassUniforms.lightViewProjection.value = projScreenMatrix; - shadowPassUniforms.depthMap.value = depthMapTarget; - shadowPassUniforms.positionMap.value = positionMapTarget; - shadowPassUniforms.colorMap.value = inBuffer; + shadowPassUniforms.lightDepthMap.value = lightDepthMapTarget; + shadowPassUniforms.eyeDepthMap.value = eyeDepthMapTarget.texture; - renderer.render(shadowScene, sceneCam, outBuffer, true); + renderer.autoClearColor = false; + renderer.render(sceneGraph, sceneCam); + renderer.autoClearColor = true; + shadowPassUniforms.lightViewProjection.value = null; + shadowPassUniforms.lightDepthMap.value = null; + shadowPassUniforms.eyeDepthMap.value = null; + sceneGraph.overrideMaterial = null; - shadowPassUniforms.depthMap.value = null; - shadowPassUniforms.colorMap.value = null; }; } @@ -153,10 +141,10 @@ plug._applyTo = (on) => { if (on) { context = new SMContext(); - scene.addPostProcessPass(plug.getName(), context.pass); + scene.setupShadowMapping(context); } else { - scene.removePostProcessPass(plug.getName()); context = null; + scene.disposeShadowMapping(); } }; diff --git a/js/mlj/plugins/rendering/shaders/ShadowFrag.glsl b/js/mlj/plugins/rendering/shaders/ShadowFrag.glsl index f2fd277d..55cc9a07 100644 --- a/js/mlj/plugins/rendering/shaders/ShadowFrag.glsl +++ b/js/mlj/plugins/rendering/shaders/ShadowFrag.glsl @@ -1,36 +1,30 @@ precision highp float; -uniform mat4 lightViewProjection; -uniform mat4 modelMatrix; -uniform sampler2D colorMap; -uniform sampler2D positionMap; -uniform sampler2D depthMap; +uniform sampler2D eyeDepthMap; +uniform sampler2D lightDepthMap; -varying vec2 vUv; +varying vec4 lightFragPos; -float shadowCalc(vec2 vUv){ - vec4 position = texture2D(positionMap, vUv); //posizione mondo - vec4 lightSpacePosition = lightViewProjection * position; - - lightSpacePosition.xyz /= lightSpacePosition.w; - - lightSpacePosition.xyz = lightSpacePosition.xyz * vec3(0.5) + vec3(0.5); - - float closest = texture2D(depthMap, lightSpacePosition.xy).r; - float current = lightSpacePosition.z; +void main(){ - float shadow = current - 0.005 > closest ? 1.0 : 0.0; + float eyeClosest = texture2D(eyeDepthMap, gl_FragCoord.xy).r; - return shadow; -} +// if (gl_FragCoord.z > eyeClosest ) discard; -void main(){ - vec4 color = texture2D(colorMap, vUv); + vec4 position = lightFragPos; + position.xyz /= position.w; + position.xyz = position.xyz * vec3(0.5) + vec3(0.5); - if (color.a == 0.0) discard; + float closest = texture2D(lightDepthMap, position.xy).r; + float current = position.z; - float lighting = (shadowCalc(vUv) > 0.0) ? 0.3 : 1.0; + //gl_FragColor.xyzw = vec4(vec3(eyeClosest), 1.0); + //return; + if (current - 0.005 > closest){ + gl_FragColor = vec4(0, 0, 0, 0.3); + } else { + gl_FragColor = vec4(1, 0, 0, 0.002); + } - gl_FragColor = vec4(color.rgb * lighting, color.a); -} + } diff --git a/js/mlj/plugins/rendering/shaders/ShadowVertex.glsl b/js/mlj/plugins/rendering/shaders/ShadowVertex.glsl index 6587dbe4..bc68633c 100644 --- a/js/mlj/plugins/rendering/shaders/ShadowVertex.glsl +++ b/js/mlj/plugins/rendering/shaders/ShadowVertex.glsl @@ -2,18 +2,15 @@ precision highp float; uniform mat4 modelMatrix; uniform mat4 viewMatrix; +uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; +uniform mat4 lightViewProjection; attribute vec3 position; -attribute vec2 uv; -uniform sampler2D depthMap; -uniform sampler2D positionMap; -uniform sampler2D colorMap; - -varying vec2 vUv; +varying vec4 lightFragPos; void main(){ - gl_Position = vec4(position, 1.0); - vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + lightFragPos = lightViewProjection * (modelMatrix * vec4(position, 1.0)); }