diff --git a/js/scripts/JSRootGeoPainter.js b/js/scripts/JSRootGeoPainter.js index 7b68b4fcb8ffd..178f592a9c712 100644 --- a/js/scripts/JSRootGeoPainter.js +++ b/js/scripts/JSRootGeoPainter.js @@ -851,8 +851,6 @@ TGeoPainter.prototype.createSSAO = function() { if (!this._webgl || this._ssaoPass) return; - // var renderPass = new THREE.RenderPass( this._scene, this._camera ); - // this._depthRenderTarget = new THREE.WebGLRenderTarget( this._scene_width, this._scene_height, { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter } ); // Setup SSAO pass this._ssaoPass = new THREE.SSAOPass( this._scene, this._camera, this._scene_width, this._scene_height ); @@ -860,8 +858,6 @@ this._ssaoPass.renderToScreen = true; // Add pass to effect composer - this._effectComposer = new THREE.EffectComposer( this._renderer ); - //this._effectComposer.addPass( renderPass ); this._effectComposer.addPass( this._ssaoPass ); } @@ -1922,6 +1918,9 @@ this._enableSSAO = this.options.ssao; this._enableClipping = !this._enableSSAO; + this._effectComposer = new THREE.EffectComposer( this._renderer ); + this._effectComposer.addPass( new THREE.RenderPass( this._scene, this._camera ) ); + if (this._enableSSAO) this.createSSAO(); @@ -3058,8 +3057,8 @@ this.TestCameraPosition(tmout === -1); - // do rendering, most consuming time - if (this._webgl && this._enableSSAO && this._ssaoPass) { + // its needed for outlinePass - do rendering, most consuming time + if (this._effectComposer.passes.length > 1 || this._webgl && this._enableSSAO && this._ssaoPass) { this._effectComposer.render(); } else { // this._renderer.logarithmicDepthBuffer = true; @@ -3609,7 +3608,7 @@ this._camera.aspect = this._scene_width / this._scene_height; this._camera.updateProjectionMatrix(); this._renderer.setSize( this._scene_width, this._scene_height, !this._fit_main_area ); - if (this._ssaoPass) this._ssaoPass.setSize( this._scene_width, this._scene_height ); + this._effectComposer.setSize( this._scene_width, this._scene_height ); if (!this.drawing_stage) this.Render3D(); } diff --git a/tutorials/eve7/event_demo.C b/tutorials/eve7/event_demo.C index 906052e9cb75c..1a0e5492e416d 100644 --- a/tutorials/eve7/event_demo.C +++ b/tutorials/eve7/event_demo.C @@ -57,7 +57,7 @@ REX::REvePointSet *getPointSet(int npoints = 2, float s=2, int color=28) ps->SetNextPoint(r.Uniform(-s,s), r.Uniform(-s,s), r.Uniform(-s,s)); ps->SetMarkerColor(color); - ps->SetMarkerSize(3+r.Uniform(1, 2)); + ps->SetMarkerSize(3+r.Uniform(1, 7)); ps->SetMarkerStyle(4); return ps; } @@ -71,11 +71,11 @@ void addPoints() auto ps1 = getPointSet(20, 100); ps1->SetName("Points_1"); pntHolder->AddElement(ps1); - /* + auto ps2 = getPointSet(10, 200, 4); - ps2->SetElementName("Points_2"); + ps2->SetName("Points_2"); pntHolder->AddElement(ps2); - */ + event->AddElement(pntHolder); } diff --git a/ui5/eve7/controller/GL.controller.js b/ui5/eve7/controller/GL.controller.js index 056a238890280..1d196c1c37fa8 100644 --- a/ui5/eve7/controller/GL.controller.js +++ b/ui5/eve7/controller/GL.controller.js @@ -43,7 +43,7 @@ sap.ui.define([ var pthis = this; // one only can load EveScene after geometry painter - sap.ui.define(['rootui5/eve7/lib/EveScene'], function (_EveScene) { + sap.ui.define(['rootui5/eve7/lib/EveScene', 'rootui5/eve7/lib/OutlinePass', 'rootui5/eve7/lib/FXAAShader'], function (_EveScene) { EveScene = _EveScene; pthis._load_scripts = true; pthis.checkViewReady(); @@ -325,6 +325,25 @@ sap.ui.define([ // this.geo_painter._highlight_handlers = [ this ]; // register ourself for highlight handling this.last_highlight = null; + this.composer = this.geo_painter._effectComposer; + let width = this.geo_painter._scene_width; + let height = this.geo_painter._scene_height; + + this.outlinePass = new THREE.OutlinePass( new THREE.Vector2( width, height ), this.geo_painter._scene, this.geo_painter._camera ); + this.outlinePass.edgeStrength = 7.5; + this.outlinePass.edgeGlow = 0.5; + this.outlinePass.edgeThickness = 1.0; + this.outlinePass.usePatternTexture = false; + this.outlinePass.downSampleRatio = 2; + this.outlinePass.visibleEdgeColor.set('#dd1111'); + this.outlinePass.hiddenEdgeColor.set('#1111dd'); + this.composer.addPass( this.outlinePass ); + + this.effectFXAA = new THREE.ShaderPass( THREE.FXAAShader ); + this.effectFXAA.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height ); + this.effectFXAA.renderToScreen = true; + this.composer.addPass( this.effectFXAA ); + // create only when geo painter is ready this.createScenes(); this.redrawScenes(); @@ -343,8 +362,10 @@ sap.ui.define([ // TODO: should be specified somehow in XML file this.getView().$().css("overflow", "hidden").css("width", "100%").css("height", "100%"); - if (this.geo_painter) + if (this.geo_painter){ this.geo_painter.CheckResize(); + this.effectFXAA.uniforms[ 'resolution' ].value.set( 1 / this.geo_painter._scene_width, 1 / this.geo_painter._scene_height ); + } } }); diff --git a/ui5/eve7/lib/EveScene.js b/ui5/eve7/lib/EveScene.js index f7964fa010814..05fd2999cdb69 100644 --- a/ui5/eve7/lib/EveScene.js +++ b/ui5/eve7/lib/EveScene.js @@ -408,6 +408,7 @@ sap.ui.define([ if (ctrl.separateDraw) { var p2 = "s", p1 = "h"; + // swap h1-h2 if (!prefer_highlight) { var h = h1; h1 = h2; h2 = h; p2 = "h"; p1 = "s"; } if (ctrl.drawSpecial(h2 ? h2.col : null, h2 ? h2.indx : undefined, p2)) did_change = true; if (ctrl.drawSpecial(h1 ? h1.col : null, h1 ? h1.indx : undefined, p1)) did_change = true; @@ -418,8 +419,37 @@ sap.ui.define([ did_change = ctrl.drawSpecial(h ? h.col : null, h ? h.indx : undefined); } - if (did_change && this.viewer) + if (did_change && this.viewer){ this.viewer.render(); + if(!prefer_highlight){ + if(!this.selected[mstrid]){ + // delete if its not selected anymore? + delete this.viewer.outlinePass.id2obj_map[mstrid]; + } else { + // is secondary selection + let sec_sel = this.selected[mstrid].indx; + + // if its not secondary selection pass the object + if(!sec_sel) + this.viewer.outlinePass.id2obj_map[mstrid] = obj3d; + // if its secondary selection pass all the new objects returned by 'drawSpecial' + else { + this.viewer.outlinePass.id2obj_map[mstrid] = []; // reset + if(false){ + if(obj3d.sl_special) this.viewer.outlinePass.id2obj_map[mstrid].push(obj3d.sl_special); + if(obj3d.sm_special) this.viewer.outlinePass.id2obj_map[mstrid].push(obj3d.sm_special); + } else { + for(const child of obj3d.children){ + if(child.jsroot_special) + this.viewer.outlinePass.id2obj_map[mstrid].push(child); + } + } + // print the new elements + console.log(this.viewer.outlinePass.id2obj_map[mstrid]); + } + } + } + } return did_change; } diff --git a/ui5/eve7/lib/FXAAShader.js b/ui5/eve7/lib/FXAAShader.js new file mode 100644 index 0000000000000..57f593871dff9 --- /dev/null +++ b/ui5/eve7/lib/FXAAShader.js @@ -0,0 +1,1115 @@ +/** + * @author alteredq / http://alteredqualia.com/ + * @author davidedc / http://www.sketchpatch.net/ + * + * NVIDIA FXAA by Timothy Lottes + * http://timothylottes.blogspot.com/2011/06/fxaa3-source-released.html + * - WebGL port by @supereggbert + * http://www.glge.org/demos/fxaa/ + */ + +THREE.FXAAShader = { + + uniforms: { + + "tDiffuse": { value: null }, + "resolution": { value: new THREE.Vector2( 1 / 1024, 1 / 512 ) } + + }, + + vertexShader: [ + + "varying vec2 vUv;", + + "void main() {", + + "vUv = uv;", + "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", + + "}" + + ].join( "\n" ), + + fragmentShader: [ + "precision highp float;", + "", + "uniform sampler2D tDiffuse;", + "", + "uniform vec2 resolution;", + "", + "varying vec2 vUv;", + "", + "// FXAA 3.11 implementation by NVIDIA, ported to WebGL by Agost Biro (biro@archilogic.com)", + "", + "//----------------------------------------------------------------------------------", + "// File: es3-kepler\FXAA\assets\shaders/FXAA_DefaultES.frag", + "// SDK Version: v3.00", + "// Email: gameworks@nvidia.com", + "// Site: http://developer.nvidia.com/", + "//", + "// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.", + "//", + "// Redistribution and use in source and binary forms, with or without", + "// modification, are permitted provided that the following conditions", + "// are met:", + "// * Redistributions of source code must retain the above copyright", + "// notice, this list of conditions and the following disclaimer.", + "// * Redistributions in binary form must reproduce the above copyright", + "// notice, this list of conditions and the following disclaimer in the", + "// documentation and/or other materials provided with the distribution.", + "// * Neither the name of NVIDIA CORPORATION nor the names of its", + "// contributors may be used to endorse or promote products derived", + "// from this software without specific prior written permission.", + "//", + "// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY", + "// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE", + "// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR", + "// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR", + "// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,", + "// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,", + "// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR", + "// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY", + "// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT", + "// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE", + "// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "//", + "//----------------------------------------------------------------------------------", + "", + "#define FXAA_PC 1", + "#define FXAA_GLSL_100 1", + "#define FXAA_QUALITY_PRESET 12", + "", + "#define FXAA_GREEN_AS_LUMA 1", + "", + "/*--------------------------------------------------------------------------*/", + "#ifndef FXAA_PC_CONSOLE", + " //", + " // The console algorithm for PC is included", + " // for developers targeting really low spec machines.", + " // Likely better to just run FXAA_PC, and use a really low preset.", + " //", + " #define FXAA_PC_CONSOLE 0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#ifndef FXAA_GLSL_120", + " #define FXAA_GLSL_120 0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#ifndef FXAA_GLSL_130", + " #define FXAA_GLSL_130 0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#ifndef FXAA_HLSL_3", + " #define FXAA_HLSL_3 0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#ifndef FXAA_HLSL_4", + " #define FXAA_HLSL_4 0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#ifndef FXAA_HLSL_5", + " #define FXAA_HLSL_5 0", + "#endif", + "/*==========================================================================*/", + "#ifndef FXAA_GREEN_AS_LUMA", + " //", + " // For those using non-linear color,", + " // and either not able to get luma in alpha, or not wanting to,", + " // this enables FXAA to run using green as a proxy for luma.", + " // So with this enabled, no need to pack luma in alpha.", + " //", + " // This will turn off AA on anything which lacks some amount of green.", + " // Pure red and blue or combination of only R and B, will get no AA.", + " //", + " // Might want to lower the settings for both,", + " // fxaaConsoleEdgeThresholdMin", + " // fxaaQualityEdgeThresholdMin", + " // In order to insure AA does not get turned off on colors", + " // which contain a minor amount of green.", + " //", + " // 1 = On.", + " // 0 = Off.", + " //", + " #define FXAA_GREEN_AS_LUMA 0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#ifndef FXAA_EARLY_EXIT", + " //", + " // Controls algorithm's early exit path.", + " // On PS3 turning this ON adds 2 cycles to the shader.", + " // On 360 turning this OFF adds 10ths of a millisecond to the shader.", + " // Turning this off on console will result in a more blurry image.", + " // So this defaults to on.", + " //", + " // 1 = On.", + " // 0 = Off.", + " //", + " #define FXAA_EARLY_EXIT 1", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#ifndef FXAA_DISCARD", + " //", + " // Only valid for PC OpenGL currently.", + " // Probably will not work when FXAA_GREEN_AS_LUMA = 1.", + " //", + " // 1 = Use discard on pixels which don't need AA.", + " // For APIs which enable concurrent TEX+ROP from same surface.", + " // 0 = Return unchanged color on pixels which don't need AA.", + " //", + " #define FXAA_DISCARD 0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#ifndef FXAA_FAST_PIXEL_OFFSET", + " //", + " // Used for GLSL 120 only.", + " //", + " // 1 = GL API supports fast pixel offsets", + " // 0 = do not use fast pixel offsets", + " //", + " #ifdef GL_EXT_gpu_shader4", + " #define FXAA_FAST_PIXEL_OFFSET 1", + " #endif", + " #ifdef GL_NV_gpu_shader5", + " #define FXAA_FAST_PIXEL_OFFSET 1", + " #endif", + " #ifdef GL_ARB_gpu_shader5", + " #define FXAA_FAST_PIXEL_OFFSET 1", + " #endif", + " #ifndef FXAA_FAST_PIXEL_OFFSET", + " #define FXAA_FAST_PIXEL_OFFSET 0", + " #endif", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#ifndef FXAA_GATHER4_ALPHA", + " //", + " // 1 = API supports gather4 on alpha channel.", + " // 0 = API does not support gather4 on alpha channel.", + " //", + " #if (FXAA_HLSL_5 == 1)", + " #define FXAA_GATHER4_ALPHA 1", + " #endif", + " #ifdef GL_ARB_gpu_shader5", + " #define FXAA_GATHER4_ALPHA 1", + " #endif", + " #ifdef GL_NV_gpu_shader5", + " #define FXAA_GATHER4_ALPHA 1", + " #endif", + " #ifndef FXAA_GATHER4_ALPHA", + " #define FXAA_GATHER4_ALPHA 0", + " #endif", + "#endif", + "", + "", + "/*============================================================================", + " FXAA QUALITY - TUNING KNOBS", + "------------------------------------------------------------------------------", + "NOTE the other tuning knobs are now in the shader function inputs!", + "============================================================================*/", + "#ifndef FXAA_QUALITY_PRESET", + " //", + " // Choose the quality preset.", + " // This needs to be compiled into the shader as it effects code.", + " // Best option to include multiple presets is to", + " // in each shader define the preset, then include this file.", + " //", + " // OPTIONS", + " // -----------------------------------------------------------------------", + " // 10 to 15 - default medium dither (10=fastest, 15=highest quality)", + " // 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality)", + " // 39 - no dither, very expensive", + " //", + " // NOTES", + " // -----------------------------------------------------------------------", + " // 12 = slightly faster then FXAA 3.9 and higher edge quality (default)", + " // 13 = about same speed as FXAA 3.9 and better than 12", + " // 23 = closest to FXAA 3.9 visually and performance wise", + " // _ = the lowest digit is directly related to performance", + " // _ = the highest digit is directly related to style", + " //", + " #define FXAA_QUALITY_PRESET 12", + "#endif", + "", + "", + "/*============================================================================", + "", + " FXAA QUALITY - PRESETS", + "", + "============================================================================*/", + "", + "/*============================================================================", + " FXAA QUALITY - MEDIUM DITHER PRESETS", + "============================================================================*/", + "#if (FXAA_QUALITY_PRESET == 10)", + " #define FXAA_QUALITY_PS 3", + " #define FXAA_QUALITY_P0 1.5", + " #define FXAA_QUALITY_P1 3.0", + " #define FXAA_QUALITY_P2 12.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 11)", + " #define FXAA_QUALITY_PS 4", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 3.0", + " #define FXAA_QUALITY_P3 12.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 12)", + " #define FXAA_QUALITY_PS 5", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 4.0", + " #define FXAA_QUALITY_P4 12.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 13)", + " #define FXAA_QUALITY_PS 6", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 2.0", + " #define FXAA_QUALITY_P4 4.0", + " #define FXAA_QUALITY_P5 12.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 14)", + " #define FXAA_QUALITY_PS 7", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 2.0", + " #define FXAA_QUALITY_P4 2.0", + " #define FXAA_QUALITY_P5 4.0", + " #define FXAA_QUALITY_P6 12.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 15)", + " #define FXAA_QUALITY_PS 8", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 2.0", + " #define FXAA_QUALITY_P4 2.0", + " #define FXAA_QUALITY_P5 2.0", + " #define FXAA_QUALITY_P6 4.0", + " #define FXAA_QUALITY_P7 12.0", + "#endif", + "", + "/*============================================================================", + " FXAA QUALITY - LOW DITHER PRESETS", + "============================================================================*/", + "#if (FXAA_QUALITY_PRESET == 20)", + " #define FXAA_QUALITY_PS 3", + " #define FXAA_QUALITY_P0 1.5", + " #define FXAA_QUALITY_P1 2.0", + " #define FXAA_QUALITY_P2 8.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 21)", + " #define FXAA_QUALITY_PS 4", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 8.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 22)", + " #define FXAA_QUALITY_PS 5", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 2.0", + " #define FXAA_QUALITY_P4 8.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 23)", + " #define FXAA_QUALITY_PS 6", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 2.0", + " #define FXAA_QUALITY_P4 2.0", + " #define FXAA_QUALITY_P5 8.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 24)", + " #define FXAA_QUALITY_PS 7", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 2.0", + " #define FXAA_QUALITY_P4 2.0", + " #define FXAA_QUALITY_P5 3.0", + " #define FXAA_QUALITY_P6 8.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 25)", + " #define FXAA_QUALITY_PS 8", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 2.0", + " #define FXAA_QUALITY_P4 2.0", + " #define FXAA_QUALITY_P5 2.0", + " #define FXAA_QUALITY_P6 4.0", + " #define FXAA_QUALITY_P7 8.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 26)", + " #define FXAA_QUALITY_PS 9", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 2.0", + " #define FXAA_QUALITY_P4 2.0", + " #define FXAA_QUALITY_P5 2.0", + " #define FXAA_QUALITY_P6 2.0", + " #define FXAA_QUALITY_P7 4.0", + " #define FXAA_QUALITY_P8 8.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 27)", + " #define FXAA_QUALITY_PS 10", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 2.0", + " #define FXAA_QUALITY_P4 2.0", + " #define FXAA_QUALITY_P5 2.0", + " #define FXAA_QUALITY_P6 2.0", + " #define FXAA_QUALITY_P7 2.0", + " #define FXAA_QUALITY_P8 4.0", + " #define FXAA_QUALITY_P9 8.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 28)", + " #define FXAA_QUALITY_PS 11", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 2.0", + " #define FXAA_QUALITY_P4 2.0", + " #define FXAA_QUALITY_P5 2.0", + " #define FXAA_QUALITY_P6 2.0", + " #define FXAA_QUALITY_P7 2.0", + " #define FXAA_QUALITY_P8 2.0", + " #define FXAA_QUALITY_P9 4.0", + " #define FXAA_QUALITY_P10 8.0", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_QUALITY_PRESET == 29)", + " #define FXAA_QUALITY_PS 12", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.5", + " #define FXAA_QUALITY_P2 2.0", + " #define FXAA_QUALITY_P3 2.0", + " #define FXAA_QUALITY_P4 2.0", + " #define FXAA_QUALITY_P5 2.0", + " #define FXAA_QUALITY_P6 2.0", + " #define FXAA_QUALITY_P7 2.0", + " #define FXAA_QUALITY_P8 2.0", + " #define FXAA_QUALITY_P9 2.0", + " #define FXAA_QUALITY_P10 4.0", + " #define FXAA_QUALITY_P11 8.0", + "#endif", + "", + "/*============================================================================", + " FXAA QUALITY - EXTREME QUALITY", + "============================================================================*/", + "#if (FXAA_QUALITY_PRESET == 39)", + " #define FXAA_QUALITY_PS 12", + " #define FXAA_QUALITY_P0 1.0", + " #define FXAA_QUALITY_P1 1.0", + " #define FXAA_QUALITY_P2 1.0", + " #define FXAA_QUALITY_P3 1.0", + " #define FXAA_QUALITY_P4 1.0", + " #define FXAA_QUALITY_P5 1.5", + " #define FXAA_QUALITY_P6 2.0", + " #define FXAA_QUALITY_P7 2.0", + " #define FXAA_QUALITY_P8 2.0", + " #define FXAA_QUALITY_P9 2.0", + " #define FXAA_QUALITY_P10 4.0", + " #define FXAA_QUALITY_P11 8.0", + "#endif", + "", + "", + "", + "/*============================================================================", + "", + " API PORTING", + "", + "============================================================================*/", + "#if (FXAA_GLSL_100 == 1) || (FXAA_GLSL_120 == 1) || (FXAA_GLSL_130 == 1)", + " #define FxaaBool bool", + " #define FxaaDiscard discard", + " #define FxaaFloat float", + " #define FxaaFloat2 vec2", + " #define FxaaFloat3 vec3", + " #define FxaaFloat4 vec4", + " #define FxaaHalf float", + " #define FxaaHalf2 vec2", + " #define FxaaHalf3 vec3", + " #define FxaaHalf4 vec4", + " #define FxaaInt2 ivec2", + " #define FxaaSat(x) clamp(x, 0.0, 1.0)", + " #define FxaaTex sampler2D", + "#else", + " #define FxaaBool bool", + " #define FxaaDiscard clip(-1)", + " #define FxaaFloat float", + " #define FxaaFloat2 float2", + " #define FxaaFloat3 float3", + " #define FxaaFloat4 float4", + " #define FxaaHalf half", + " #define FxaaHalf2 half2", + " #define FxaaHalf3 half3", + " #define FxaaHalf4 half4", + " #define FxaaSat(x) saturate(x)", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_GLSL_100 == 1)", + " #define FxaaTexTop(t, p) texture2D(t, p, 0.0)", + " #define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), 0.0)", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_GLSL_120 == 1)", + " // Requires,", + " // #version 120", + " // And at least,", + " // #extension GL_EXT_gpu_shader4 : enable", + " // (or set FXAA_FAST_PIXEL_OFFSET 1 to work like DX9)", + " #define FxaaTexTop(t, p) texture2DLod(t, p, 0.0)", + " #if (FXAA_FAST_PIXEL_OFFSET == 1)", + " #define FxaaTexOff(t, p, o, r) texture2DLodOffset(t, p, 0.0, o)", + " #else", + " #define FxaaTexOff(t, p, o, r) texture2DLod(t, p + (o * r), 0.0)", + " #endif", + " #if (FXAA_GATHER4_ALPHA == 1)", + " // use #extension GL_ARB_gpu_shader5 : enable", + " #define FxaaTexAlpha4(t, p) textureGather(t, p, 3)", + " #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3)", + " #define FxaaTexGreen4(t, p) textureGather(t, p, 1)", + " #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1)", + " #endif", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_GLSL_130 == 1)", + " // Requires \"#version 130\" or better", + " #define FxaaTexTop(t, p) textureLod(t, p, 0.0)", + " #define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o)", + " #if (FXAA_GATHER4_ALPHA == 1)", + " // use #extension GL_ARB_gpu_shader5 : enable", + " #define FxaaTexAlpha4(t, p) textureGather(t, p, 3)", + " #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3)", + " #define FxaaTexGreen4(t, p) textureGather(t, p, 1)", + " #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1)", + " #endif", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_HLSL_3 == 1)", + " #define FxaaInt2 float2", + " #define FxaaTex sampler2D", + " #define FxaaTexTop(t, p) tex2Dlod(t, float4(p, 0.0, 0.0))", + " #define FxaaTexOff(t, p, o, r) tex2Dlod(t, float4(p + (o * r), 0, 0))", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_HLSL_4 == 1)", + " #define FxaaInt2 int2", + " struct FxaaTex { SamplerState smpl; Texture2D tex; };", + " #define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0)", + " #define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o)", + "#endif", + "/*--------------------------------------------------------------------------*/", + "#if (FXAA_HLSL_5 == 1)", + " #define FxaaInt2 int2", + " struct FxaaTex { SamplerState smpl; Texture2D tex; };", + " #define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0)", + " #define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o)", + " #define FxaaTexAlpha4(t, p) t.tex.GatherAlpha(t.smpl, p)", + " #define FxaaTexOffAlpha4(t, p, o) t.tex.GatherAlpha(t.smpl, p, o)", + " #define FxaaTexGreen4(t, p) t.tex.GatherGreen(t.smpl, p)", + " #define FxaaTexOffGreen4(t, p, o) t.tex.GatherGreen(t.smpl, p, o)", + "#endif", + "", + "", + "/*============================================================================", + " GREEN AS LUMA OPTION SUPPORT FUNCTION", + "============================================================================*/", + "#if (FXAA_GREEN_AS_LUMA == 0)", + " FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.w; }", + "#else", + " FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.y; }", + "#endif", + "", + "", + "", + "", + "/*============================================================================", + "", + " FXAA3 QUALITY - PC", + "", + "============================================================================*/", + "#if (FXAA_PC == 1)", + "/*--------------------------------------------------------------------------*/", + "FxaaFloat4 FxaaPixelShader(", + " //", + " // Use noperspective interpolation here (turn off perspective interpolation).", + " // {xy} = center of pixel", + " FxaaFloat2 pos,", + " //", + " // Used only for FXAA Console, and not used on the 360 version.", + " // Use noperspective interpolation here (turn off perspective interpolation).", + " // {xy_} = upper left of pixel", + " // {_zw} = lower right of pixel", + " FxaaFloat4 fxaaConsolePosPos,", + " //", + " // Input color texture.", + " // {rgb_} = color in linear or perceptual color space", + " // if (FXAA_GREEN_AS_LUMA == 0)", + " // {__a} = luma in perceptual color space (not linear)", + " FxaaTex tex,", + " //", + " // Only used on the optimized 360 version of FXAA Console.", + " // For everything but 360, just use the same input here as for \"tex\".", + " // For 360, same texture, just alias with a 2nd sampler.", + " // This sampler needs to have an exponent bias of -1.", + " FxaaTex fxaaConsole360TexExpBiasNegOne,", + " //", + " // Only used on the optimized 360 version of FXAA Console.", + " // For everything but 360, just use the same input here as for \"tex\".", + " // For 360, same texture, just alias with a 3nd sampler.", + " // This sampler needs to have an exponent bias of -2.", + " FxaaTex fxaaConsole360TexExpBiasNegTwo,", + " //", + " // Only used on FXAA Quality.", + " // This must be from a constant/uniform.", + " // {x_} = 1.0/screenWidthInPixels", + " // {_y} = 1.0/screenHeightInPixels", + " FxaaFloat2 fxaaQualityRcpFrame,", + " //", + " // Only used on FXAA Console.", + " // This must be from a constant/uniform.", + " // This effects sub-pixel AA quality and inversely sharpness.", + " // Where N ranges between,", + " // N = 0.50 (default)", + " // N = 0.33 (sharper)", + " // {x__} = -N/screenWidthInPixels", + " // {_y_} = -N/screenHeightInPixels", + " // {_z_} = N/screenWidthInPixels", + " // {__w} = N/screenHeightInPixels", + " FxaaFloat4 fxaaConsoleRcpFrameOpt,", + " //", + " // Only used on FXAA Console.", + " // Not used on 360, but used on PS3 and PC.", + " // This must be from a constant/uniform.", + " // {x__} = -2.0/screenWidthInPixels", + " // {_y_} = -2.0/screenHeightInPixels", + " // {_z_} = 2.0/screenWidthInPixels", + " // {__w} = 2.0/screenHeightInPixels", + " FxaaFloat4 fxaaConsoleRcpFrameOpt2,", + " //", + " // Only used on FXAA Console.", + " // Only used on 360 in place of fxaaConsoleRcpFrameOpt2.", + " // This must be from a constant/uniform.", + " // {x__} = 8.0/screenWidthInPixels", + " // {_y_} = 8.0/screenHeightInPixels", + " // {_z_} = -4.0/screenWidthInPixels", + " // {__w} = -4.0/screenHeightInPixels", + " FxaaFloat4 fxaaConsole360RcpFrameOpt2,", + " //", + " // Only used on FXAA Quality.", + " // This used to be the FXAA_QUALITY_SUBPIX define.", + " // It is here now to allow easier tuning.", + " // Choose the amount of sub-pixel aliasing removal.", + " // This can effect sharpness.", + " // 1.00 - upper limit (softer)", + " // 0.75 - default amount of filtering", + " // 0.50 - lower limit (sharper, less sub-pixel aliasing removal)", + " // 0.25 - almost off", + " // 0.00 - completely off", + " FxaaFloat fxaaQualitySubpix,", + " //", + " // Only used on FXAA Quality.", + " // This used to be the FXAA_QUALITY_EDGE_THRESHOLD define.", + " // It is here now to allow easier tuning.", + " // The minimum amount of local contrast required to apply algorithm.", + " // 0.333 - too little (faster)", + " // 0.250 - low quality", + " // 0.166 - default", + " // 0.125 - high quality", + " // 0.063 - overkill (slower)", + " FxaaFloat fxaaQualityEdgeThreshold,", + " //", + " // Only used on FXAA Quality.", + " // This used to be the FXAA_QUALITY_EDGE_THRESHOLD_MIN define.", + " // It is here now to allow easier tuning.", + " // Trims the algorithm from processing darks.", + " // 0.0833 - upper limit (default, the start of visible unfiltered edges)", + " // 0.0625 - high quality (faster)", + " // 0.0312 - visible limit (slower)", + " // Special notes when using FXAA_GREEN_AS_LUMA,", + " // Likely want to set this to zero.", + " // As colors that are mostly not-green", + " // will appear very dark in the green channel!", + " // Tune by looking at mostly non-green content,", + " // then start at zero and increase until aliasing is a problem.", + " FxaaFloat fxaaQualityEdgeThresholdMin,", + " //", + " // Only used on FXAA Console.", + " // This used to be the FXAA_CONSOLE_EDGE_SHARPNESS define.", + " // It is here now to allow easier tuning.", + " // This does not effect PS3, as this needs to be compiled in.", + " // Use FXAA_CONSOLE_PS3_EDGE_SHARPNESS for PS3.", + " // Due to the PS3 being ALU bound,", + " // there are only three safe values here: 2 and 4 and 8.", + " // These options use the shaders ability to a free *|/ by 2|4|8.", + " // For all other platforms can be a non-power of two.", + " // 8.0 is sharper (default!!!)", + " // 4.0 is softer", + " // 2.0 is really soft (good only for vector graphics inputs)", + " FxaaFloat fxaaConsoleEdgeSharpness,", + " //", + " // Only used on FXAA Console.", + " // This used to be the FXAA_CONSOLE_EDGE_THRESHOLD define.", + " // It is here now to allow easier tuning.", + " // This does not effect PS3, as this needs to be compiled in.", + " // Use FXAA_CONSOLE_PS3_EDGE_THRESHOLD for PS3.", + " // Due to the PS3 being ALU bound,", + " // there are only two safe values here: 1/4 and 1/8.", + " // These options use the shaders ability to a free *|/ by 2|4|8.", + " // The console setting has a different mapping than the quality setting.", + " // Other platforms can use other values.", + " // 0.125 leaves less aliasing, but is softer (default!!!)", + " // 0.25 leaves more aliasing, and is sharper", + " FxaaFloat fxaaConsoleEdgeThreshold,", + " //", + " // Only used on FXAA Console.", + " // This used to be the FXAA_CONSOLE_EDGE_THRESHOLD_MIN define.", + " // It is here now to allow easier tuning.", + " // Trims the algorithm from processing darks.", + " // The console setting has a different mapping than the quality setting.", + " // This only applies when FXAA_EARLY_EXIT is 1.", + " // This does not apply to PS3,", + " // PS3 was simplified to avoid more shader instructions.", + " // 0.06 - faster but more aliasing in darks", + " // 0.05 - default", + " // 0.04 - slower and less aliasing in darks", + " // Special notes when using FXAA_GREEN_AS_LUMA,", + " // Likely want to set this to zero.", + " // As colors that are mostly not-green", + " // will appear very dark in the green channel!", + " // Tune by looking at mostly non-green content,", + " // then start at zero and increase until aliasing is a problem.", + " FxaaFloat fxaaConsoleEdgeThresholdMin,", + " //", + " // Extra constants for 360 FXAA Console only.", + " // Use zeros or anything else for other platforms.", + " // These must be in physical constant registers and NOT immediates.", + " // Immediates will result in compiler un-optimizing.", + " // {xyzw} = float4(1.0, -1.0, 0.25, -0.25)", + " FxaaFloat4 fxaaConsole360ConstDir", + ") {", + "/*--------------------------------------------------------------------------*/", + " FxaaFloat2 posM;", + " posM.x = pos.x;", + " posM.y = pos.y;", + " #if (FXAA_GATHER4_ALPHA == 1)", + " #if (FXAA_DISCARD == 0)", + " FxaaFloat4 rgbyM = FxaaTexTop(tex, posM);", + " #if (FXAA_GREEN_AS_LUMA == 0)", + " #define lumaM rgbyM.w", + " #else", + " #define lumaM rgbyM.y", + " #endif", + " #endif", + " #if (FXAA_GREEN_AS_LUMA == 0)", + " FxaaFloat4 luma4A = FxaaTexAlpha4(tex, posM);", + " FxaaFloat4 luma4B = FxaaTexOffAlpha4(tex, posM, FxaaInt2(-1, -1));", + " #else", + " FxaaFloat4 luma4A = FxaaTexGreen4(tex, posM);", + " FxaaFloat4 luma4B = FxaaTexOffGreen4(tex, posM, FxaaInt2(-1, -1));", + " #endif", + " #if (FXAA_DISCARD == 1)", + " #define lumaM luma4A.w", + " #endif", + " #define lumaE luma4A.z", + " #define lumaS luma4A.x", + " #define lumaSE luma4A.y", + " #define lumaNW luma4B.w", + " #define lumaN luma4B.z", + " #define lumaW luma4B.x", + " #else", + " FxaaFloat4 rgbyM = FxaaTexTop(tex, posM);", + " #if (FXAA_GREEN_AS_LUMA == 0)", + " #define lumaM rgbyM.w", + " #else", + " #define lumaM rgbyM.y", + " #endif", + " #if (FXAA_GLSL_100 == 1)", + " FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2( 0.0, 1.0), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2( 1.0, 0.0), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2( 0.0,-1.0), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2(-1.0, 0.0), fxaaQualityRcpFrame.xy));", + " #else", + " FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0, 1), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 0), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0,-1), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 0), fxaaQualityRcpFrame.xy));", + " #endif", + " #endif", + "/*--------------------------------------------------------------------------*/", + " FxaaFloat maxSM = max(lumaS, lumaM);", + " FxaaFloat minSM = min(lumaS, lumaM);", + " FxaaFloat maxESM = max(lumaE, maxSM);", + " FxaaFloat minESM = min(lumaE, minSM);", + " FxaaFloat maxWN = max(lumaN, lumaW);", + " FxaaFloat minWN = min(lumaN, lumaW);", + " FxaaFloat rangeMax = max(maxWN, maxESM);", + " FxaaFloat rangeMin = min(minWN, minESM);", + " FxaaFloat rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold;", + " FxaaFloat range = rangeMax - rangeMin;", + " FxaaFloat rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled);", + " FxaaBool earlyExit = range < rangeMaxClamped;", + "/*--------------------------------------------------------------------------*/", + " if(earlyExit)", + " #if (FXAA_DISCARD == 1)", + " FxaaDiscard;", + " #else", + " return rgbyM;", + " #endif", + "/*--------------------------------------------------------------------------*/", + " #if (FXAA_GATHER4_ALPHA == 0)", + " #if (FXAA_GLSL_100 == 1)", + " FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2(-1.0,-1.0), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2( 1.0, 1.0), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2( 1.0,-1.0), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2(-1.0, 1.0), fxaaQualityRcpFrame.xy));", + " #else", + " FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1,-1), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 1), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1,-1), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy));", + " #endif", + " #else", + " FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(1, -1), fxaaQualityRcpFrame.xy));", + " FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy));", + " #endif", + "/*--------------------------------------------------------------------------*/", + " FxaaFloat lumaNS = lumaN + lumaS;", + " FxaaFloat lumaWE = lumaW + lumaE;", + " FxaaFloat subpixRcpRange = 1.0/range;", + " FxaaFloat subpixNSWE = lumaNS + lumaWE;", + " FxaaFloat edgeHorz1 = (-2.0 * lumaM) + lumaNS;", + " FxaaFloat edgeVert1 = (-2.0 * lumaM) + lumaWE;", + "/*--------------------------------------------------------------------------*/", + " FxaaFloat lumaNESE = lumaNE + lumaSE;", + " FxaaFloat lumaNWNE = lumaNW + lumaNE;", + " FxaaFloat edgeHorz2 = (-2.0 * lumaE) + lumaNESE;", + " FxaaFloat edgeVert2 = (-2.0 * lumaN) + lumaNWNE;", + "/*--------------------------------------------------------------------------*/", + " FxaaFloat lumaNWSW = lumaNW + lumaSW;", + " FxaaFloat lumaSWSE = lumaSW + lumaSE;", + " FxaaFloat edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2);", + " FxaaFloat edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2);", + " FxaaFloat edgeHorz3 = (-2.0 * lumaW) + lumaNWSW;", + " FxaaFloat edgeVert3 = (-2.0 * lumaS) + lumaSWSE;", + " FxaaFloat edgeHorz = abs(edgeHorz3) + edgeHorz4;", + " FxaaFloat edgeVert = abs(edgeVert3) + edgeVert4;", + "/*--------------------------------------------------------------------------*/", + " FxaaFloat subpixNWSWNESE = lumaNWSW + lumaNESE;", + " FxaaFloat lengthSign = fxaaQualityRcpFrame.x;", + " FxaaBool horzSpan = edgeHorz >= edgeVert;", + " FxaaFloat subpixA = subpixNSWE * 2.0 + subpixNWSWNESE;", + "/*--------------------------------------------------------------------------*/", + " if(!horzSpan) lumaN = lumaW;", + " if(!horzSpan) lumaS = lumaE;", + " if(horzSpan) lengthSign = fxaaQualityRcpFrame.y;", + " FxaaFloat subpixB = (subpixA * (1.0/12.0)) - lumaM;", + "/*--------------------------------------------------------------------------*/", + " FxaaFloat gradientN = lumaN - lumaM;", + " FxaaFloat gradientS = lumaS - lumaM;", + " FxaaFloat lumaNN = lumaN + lumaM;", + " FxaaFloat lumaSS = lumaS + lumaM;", + " FxaaBool pairN = abs(gradientN) >= abs(gradientS);", + " FxaaFloat gradient = max(abs(gradientN), abs(gradientS));", + " if(pairN) lengthSign = -lengthSign;", + " FxaaFloat subpixC = FxaaSat(abs(subpixB) * subpixRcpRange);", + "/*--------------------------------------------------------------------------*/", + " FxaaFloat2 posB;", + " posB.x = posM.x;", + " posB.y = posM.y;", + " FxaaFloat2 offNP;", + " offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;", + " offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;", + " if(!horzSpan) posB.x += lengthSign * 0.5;", + " if( horzSpan) posB.y += lengthSign * 0.5;", + "/*--------------------------------------------------------------------------*/", + " FxaaFloat2 posN;", + " posN.x = posB.x - offNP.x * FXAA_QUALITY_P0;", + " posN.y = posB.y - offNP.y * FXAA_QUALITY_P0;", + " FxaaFloat2 posP;", + " posP.x = posB.x + offNP.x * FXAA_QUALITY_P0;", + " posP.y = posB.y + offNP.y * FXAA_QUALITY_P0;", + " FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0;", + " FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN));", + " FxaaFloat subpixE = subpixC * subpixC;", + " FxaaFloat lumaEndP = FxaaLuma(FxaaTexTop(tex, posP));", + "/*--------------------------------------------------------------------------*/", + " if(!pairN) lumaNN = lumaSS;", + " FxaaFloat gradientScaled = gradient * 1.0/4.0;", + " FxaaFloat lumaMM = lumaM - lumaNN * 0.5;", + " FxaaFloat subpixF = subpixD * subpixE;", + " FxaaBool lumaMLTZero = lumaMM < 0.0;", + "/*--------------------------------------------------------------------------*/", + " lumaEndN -= lumaNN * 0.5;", + " lumaEndP -= lumaNN * 0.5;", + " FxaaBool doneN = abs(lumaEndN) >= gradientScaled;", + " FxaaBool doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P1;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P1;", + " FxaaBool doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P1;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P1;", + "/*--------------------------------------------------------------------------*/", + " if(doneNP) {", + " if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));", + " if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));", + " if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;", + " if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;", + " doneN = abs(lumaEndN) >= gradientScaled;", + " doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P2;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P2;", + " doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P2;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P2;", + "/*--------------------------------------------------------------------------*/", + " #if (FXAA_QUALITY_PS > 3)", + " if(doneNP) {", + " if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));", + " if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));", + " if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;", + " if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;", + " doneN = abs(lumaEndN) >= gradientScaled;", + " doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P3;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P3;", + " doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P3;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P3;", + "/*--------------------------------------------------------------------------*/", + " #if (FXAA_QUALITY_PS > 4)", + " if(doneNP) {", + " if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));", + " if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));", + " if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;", + " if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;", + " doneN = abs(lumaEndN) >= gradientScaled;", + " doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P4;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P4;", + " doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P4;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P4;", + "/*--------------------------------------------------------------------------*/", + " #if (FXAA_QUALITY_PS > 5)", + " if(doneNP) {", + " if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));", + " if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));", + " if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;", + " if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;", + " doneN = abs(lumaEndN) >= gradientScaled;", + " doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P5;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P5;", + " doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P5;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P5;", + "/*--------------------------------------------------------------------------*/", + " #if (FXAA_QUALITY_PS > 6)", + " if(doneNP) {", + " if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));", + " if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));", + " if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;", + " if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;", + " doneN = abs(lumaEndN) >= gradientScaled;", + " doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P6;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P6;", + " doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P6;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P6;", + "/*--------------------------------------------------------------------------*/", + " #if (FXAA_QUALITY_PS > 7)", + " if(doneNP) {", + " if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));", + " if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));", + " if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;", + " if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;", + " doneN = abs(lumaEndN) >= gradientScaled;", + " doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P7;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P7;", + " doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P7;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P7;", + "/*--------------------------------------------------------------------------*/", + " #if (FXAA_QUALITY_PS > 8)", + " if(doneNP) {", + " if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));", + " if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));", + " if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;", + " if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;", + " doneN = abs(lumaEndN) >= gradientScaled;", + " doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P8;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P8;", + " doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P8;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P8;", + "/*--------------------------------------------------------------------------*/", + " #if (FXAA_QUALITY_PS > 9)", + " if(doneNP) {", + " if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));", + " if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));", + " if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;", + " if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;", + " doneN = abs(lumaEndN) >= gradientScaled;", + " doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P9;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P9;", + " doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P9;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P9;", + "/*--------------------------------------------------------------------------*/", + " #if (FXAA_QUALITY_PS > 10)", + " if(doneNP) {", + " if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));", + " if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));", + " if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;", + " if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;", + " doneN = abs(lumaEndN) >= gradientScaled;", + " doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P10;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P10;", + " doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P10;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P10;", + "/*--------------------------------------------------------------------------*/", + " #if (FXAA_QUALITY_PS > 11)", + " if(doneNP) {", + " if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));", + " if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));", + " if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;", + " if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;", + " doneN = abs(lumaEndN) >= gradientScaled;", + " doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P11;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P11;", + " doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P11;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P11;", + "/*--------------------------------------------------------------------------*/", + " #if (FXAA_QUALITY_PS > 12)", + " if(doneNP) {", + " if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));", + " if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));", + " if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;", + " if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;", + " doneN = abs(lumaEndN) >= gradientScaled;", + " doneP = abs(lumaEndP) >= gradientScaled;", + " if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P12;", + " if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P12;", + " doneNP = (!doneN) || (!doneP);", + " if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P12;", + " if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P12;", + "/*--------------------------------------------------------------------------*/", + " }", + " #endif", + "/*--------------------------------------------------------------------------*/", + " }", + " #endif", + "/*--------------------------------------------------------------------------*/", + " }", + " #endif", + "/*--------------------------------------------------------------------------*/", + " }", + " #endif", + "/*--------------------------------------------------------------------------*/", + " }", + " #endif", + "/*--------------------------------------------------------------------------*/", + " }", + " #endif", + "/*--------------------------------------------------------------------------*/", + " }", + " #endif", + "/*--------------------------------------------------------------------------*/", + " }", + " #endif", + "/*--------------------------------------------------------------------------*/", + " }", + " #endif", + "/*--------------------------------------------------------------------------*/", + " }", + " #endif", + "/*--------------------------------------------------------------------------*/", + " }", + "/*--------------------------------------------------------------------------*/", + " FxaaFloat dstN = posM.x - posN.x;", + " FxaaFloat dstP = posP.x - posM.x;", + " if(!horzSpan) dstN = posM.y - posN.y;", + " if(!horzSpan) dstP = posP.y - posM.y;", + "/*--------------------------------------------------------------------------*/", + " FxaaBool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero;", + " FxaaFloat spanLength = (dstP + dstN);", + " FxaaBool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero;", + " FxaaFloat spanLengthRcp = 1.0/spanLength;", + "/*--------------------------------------------------------------------------*/", + " FxaaBool directionN = dstN < dstP;", + " FxaaFloat dst = min(dstN, dstP);", + " FxaaBool goodSpan = directionN ? goodSpanN : goodSpanP;", + " FxaaFloat subpixG = subpixF * subpixF;", + " FxaaFloat pixelOffset = (dst * (-spanLengthRcp)) + 0.5;", + " FxaaFloat subpixH = subpixG * fxaaQualitySubpix;", + "/*--------------------------------------------------------------------------*/", + " FxaaFloat pixelOffsetGood = goodSpan ? pixelOffset : 0.0;", + " FxaaFloat pixelOffsetSubpix = max(pixelOffsetGood, subpixH);", + " if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign;", + " if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign;", + " #if (FXAA_DISCARD == 1)", + " return FxaaTexTop(tex, posM);", + " #else", + " return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM);", + " #endif", + "}", + "/*==========================================================================*/", + "#endif", + "", + "void main() {", + " gl_FragColor = FxaaPixelShader(", + " vUv,", + " vec4(0.0),", + " tDiffuse,", + " tDiffuse,", + " tDiffuse,", + " resolution,", + " vec4(0.0),", + " vec4(0.0),", + " vec4(0.0),", + " 0.75,", + " 0.166,", + " 0.0833,", + " 0.0,", + " 0.0,", + " 0.0,", + " vec4(0.0)", + " );", + "", + " // TODO avoid querying texture twice for same texel", + " gl_FragColor.a = texture2D(tDiffuse, vUv).a;", + "}" + ].join("\n") + +}; diff --git a/ui5/eve7/lib/OutlinePass.js b/ui5/eve7/lib/OutlinePass.js new file mode 100644 index 0000000000000..c1bf691c5b615 --- /dev/null +++ b/ui5/eve7/lib/OutlinePass.js @@ -0,0 +1,720 @@ +/** + * @author spidersharma / http://eduperiment.com/ + */ + +THREE.OutlinePass = function ( resolution, scene, camera ) { + + // [{ "index": number, "isPoints": boolean, "pointSize": number, "vertShader": string, "fragShader":string },......] + this.renderScene = scene; + this.renderCamera = camera; + this.selectedObjects = []; + this.id2obj_map = {}; + this.visibleEdgeColor = new THREE.Color( 1, 1, 1 ); + this.hiddenEdgeColor = new THREE.Color( 0.1, 0.04, 0.02 ); + this.edgeGlow = 0.0; + this.usePatternTexture = false; + this.edgeThickness = 1.0; + this.edgeStrength = 3.0; + this.downSampleRatio = 2; + this.pulsePeriod = 0; + + THREE.Pass.call( this ); + + this.resolution = ( resolution !== undefined ) ? new THREE.Vector2( resolution.x, resolution.y ) : new THREE.Vector2( 256, 256 ); + + var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat }; + + var resx = Math.round( this.resolution.x / this.downSampleRatio ); + var resy = Math.round( this.resolution.y / this.downSampleRatio ); + + this.maskBufferMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff } ); + this.maskBufferMaterial.side = THREE.DoubleSide; + this.renderTargetMaskBuffer = new THREE.WebGLRenderTarget( this.resolution.x, this.resolution.y, pars ); + this.renderTargetMaskBuffer.texture.name = "OutlinePass.mask"; + this.renderTargetMaskBuffer.texture.generateMipmaps = false; + + this.depthMaterial = new THREE.MeshDepthMaterial(); + this.depthMaterial.side = THREE.DoubleSide; + this.depthMaterial.depthPacking = THREE.RGBADepthPacking; + this.depthMaterial.blending = THREE.NoBlending; + + this.prepareMaskMaterial = this.getPrepareMaskMaterial(); + this.prepareMaskMaterial.side = THREE.DoubleSide; + this.prepareMaskMaterial.fragmentShader = replaceDepthToViewZ( this.prepareMaskMaterial.fragmentShader, this.renderCamera ); + + this.renderTargetDepthBuffer = new THREE.WebGLRenderTarget( this.resolution.x, this.resolution.y, pars ); + this.renderTargetDepthBuffer.texture.name = "OutlinePass.depth"; + this.renderTargetDepthBuffer.texture.generateMipmaps = false; + + this.renderTargetMaskDownSampleBuffer = new THREE.WebGLRenderTarget( resx, resy, pars ); + this.renderTargetMaskDownSampleBuffer.texture.name = "OutlinePass.depthDownSample"; + this.renderTargetMaskDownSampleBuffer.texture.generateMipmaps = false; + + this.renderTargetBlurBuffer1 = new THREE.WebGLRenderTarget( resx, resy, pars ); + this.renderTargetBlurBuffer1.texture.name = "OutlinePass.blur1"; + this.renderTargetBlurBuffer1.texture.generateMipmaps = false; + this.renderTargetBlurBuffer2 = new THREE.WebGLRenderTarget( Math.round( resx / 2 ), Math.round( resy / 2 ), pars ); + this.renderTargetBlurBuffer2.texture.name = "OutlinePass.blur2"; + this.renderTargetBlurBuffer2.texture.generateMipmaps = false; + + this.edgeDetectionMaterial = this.getEdgeDetectionMaterial(); + this.renderTargetEdgeBuffer1 = new THREE.WebGLRenderTarget( resx, resy, pars ); + this.renderTargetEdgeBuffer1.texture.name = "OutlinePass.edge1"; + this.renderTargetEdgeBuffer1.texture.generateMipmaps = false; + this.renderTargetEdgeBuffer2 = new THREE.WebGLRenderTarget( Math.round( resx / 2 ), Math.round( resy / 2 ), pars ); + this.renderTargetEdgeBuffer2.texture.name = "OutlinePass.edge2"; + this.renderTargetEdgeBuffer2.texture.generateMipmaps = false; + + var MAX_EDGE_THICKNESS = 4; + var MAX_EDGE_GLOW = 4; + + this.separableBlurMaterial1 = this.getSeperableBlurMaterial( MAX_EDGE_THICKNESS ); + this.separableBlurMaterial1.uniforms[ "texSize" ].value = new THREE.Vector2( resx, resy ); + this.separableBlurMaterial1.uniforms[ "kernelRadius" ].value = 1; + this.separableBlurMaterial2 = this.getSeperableBlurMaterial( MAX_EDGE_GLOW ); + this.separableBlurMaterial2.uniforms[ "texSize" ].value = new THREE.Vector2( Math.round( resx / 2 ), Math.round( resy / 2 ) ); + this.separableBlurMaterial2.uniforms[ "kernelRadius" ].value = MAX_EDGE_GLOW; + + // Overlay material + this.overlayMaterial = this.getOverlayMaterial(); + + // copy material + if ( THREE.CopyShader === undefined ) + console.error( "THREE.OutlinePass relies on THREE.CopyShader" ); + + var copyShader = THREE.CopyShader; + + this.copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms ); + this.copyUniforms[ "opacity" ].value = 1.0; + + this.materialCopy = new THREE.ShaderMaterial( { + uniforms: this.copyUniforms, + vertexShader: copyShader.vertexShader, + fragmentShader: copyShader.fragmentShader, + blending: THREE.NoBlending, + depthTest: false, + depthWrite: false, + transparent: true + } ); + + this.enabled = true; + this.needsSwap = true; + + this.oldClearColor = new THREE.Color(); + this.oldClearAlpha = 1; + + this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); + this.scene = new THREE.Scene(); + + this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null ); + this.quad.frustumCulled = false; // Avoid getting clipped + this.scene.add( this.quad ); + + this.tempPulseColor1 = new THREE.Color(); + this.tempPulseColor2 = new THREE.Color(); + this.textureMatrix = new THREE.Matrix4(); + + function replaceDepthToViewZ( string, camera ) { + + var type = camera.isPerspectiveCamera ? 'perspective' : 'orthographic'; + + return string.replace( /DEPTH_TO_VIEW_Z/g, type + 'DepthToViewZ' ); + + } + +}; + +THREE.OutlinePass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), { + + constructor: THREE.OutlinePass, + + checkForCustomAtts: function(){ + /* + this.atts = { + "index": [], + "pointSize": [], + "vertShader": [], + "fragShader": [], + "total": 0 + }; // reset + for (let i = 0; i < this.selectedObjects.length; ++i){ + const object = this.selectedObjects[i]; + + if(object.type === "Points"){ + this.atts["index"].push(i); + this.atts["pointSize"].push(object.material.size || 20.0); + this.atts["vertShader"].push(object["vertShader"]); + this.atts["fragShader"].push(object["fragShader"]); + ++this.atts.total; + } + } + */ + + let groups = []; + for (let i = 0; i < this.selectedObjects.length; ++i){ + const object = this.selectedObjects[i]; + + // treat Mesh and LineSegments as the same + if(object.type === "Mesh" || object.type === "LineSegments" ) + { + groups[0] = groups[0] || []; + groups[0].push(object); + } + else if(object.type === "Points") + { + let found = false; + // loop over groups + for (let z = 1; z < groups.length; ++z){ + // loop over all the elements of a group + for (let w = 0; w < z.length; ++w){ + // if the objects have the same attributes + if( + this.selectedObjects[z][w].type === object.type && + this.selectedObjects[z][w].material.size === object.material.size && + this.selectedObjects[z][w]["vertShader"] === object["vertShader"] && + this.selectedObjects[z][w]["fragShader"] === object["fragShader"] + ){ + groups[z] = groups[z] || []; + groups[z].push(object); + found = true; + break; + } + } + if(found) + break; + } + + if(!found){ + groups[i+1] = groups[i+1] || []; + groups[i+1].push(object); + } + } + else + { + console.error("unknown type of geometry! fallback to 0"); + groups[0] = groups[0] || []; + groups[0].push(object); + } + } + this.groups = groups/*.filter(Array)*/; + // console.log(groups); + }, + + dispose: function () { + + this.renderTargetMaskBuffer.dispose(); + this.renderTargetDepthBuffer.dispose(); + this.renderTargetMaskDownSampleBuffer.dispose(); + this.renderTargetBlurBuffer1.dispose(); + this.renderTargetBlurBuffer2.dispose(); + this.renderTargetEdgeBuffer1.dispose(); + this.renderTargetEdgeBuffer2.dispose(); + + }, + + setSize: function ( width, height ) { + + this.renderTargetMaskBuffer.setSize( width, height ); + + var resx = Math.round( width / this.downSampleRatio ); + var resy = Math.round( height / this.downSampleRatio ); + this.renderTargetMaskDownSampleBuffer.setSize( resx, resy ); + this.renderTargetBlurBuffer1.setSize( resx, resy ); + this.renderTargetEdgeBuffer1.setSize( resx, resy ); + this.separableBlurMaterial1.uniforms[ "texSize" ].value = new THREE.Vector2( resx, resy ); + + resx = Math.round( resx / 2 ); + resy = Math.round( resy / 2 ); + + this.renderTargetBlurBuffer2.setSize( resx, resy ); + this.renderTargetEdgeBuffer2.setSize( resx, resy ); + + this.separableBlurMaterial2.uniforms[ "texSize" ].value = new THREE.Vector2( resx, resy ); + + }, + + changeVisibilityOfSelectedObjects: function ( bVisible, object ) { + + function gatherSelectedMeshesCallBack( object ) { + + if ( object.isMesh || object.isLine || object.isPoints ) { + + if ( bVisible ) { + + object.visible = object.userData.oldVisible; + delete object.userData.oldVisible; + + } else { + + object.userData.oldVisible = object.visible; + object.visible = bVisible; + + } + + } + + } + + for(const obj of ((Array.isArray(object) ? object : (object && [object])) || this.selectedObjects)){ + obj.traverse( gatherSelectedMeshesCallBack ); + } + + }, + + changeVisibilityOfNonSelectedObjects: function ( bVisible ) { + + var selectedMeshes = []; + + function gatherSelectedMeshesCallBack( object ) { + + if ( object.isMesh || object.isLine || object.isPoints ) selectedMeshes.push( object ); + + } + + for ( var i = 0; i < this.selectedObjects.length; i ++ ) { + + var selectedObject = this.selectedObjects[ i ]; + selectedObject.traverse( gatherSelectedMeshesCallBack ); + + } + + function VisibilityChangeCallBack( object ) { + + if ( object.isMesh || object.isLine || object.isSprite || object.isPoints ) { + + var bFound = false; + + for ( var i = 0; i < selectedMeshes.length; i ++ ) { + + var selectedObjectId = selectedMeshes[ i ].id; + + if ( selectedObjectId === object.id ) { + + bFound = true; + break; + + } + + } + + if ( ! bFound ) { + + var visibility = object.visible; + + if ( ! bVisible || object.bVisible ) object.visible = bVisible; + + object.bVisible = visibility; + + } + + } + + } + + this.renderScene.traverse( VisibilityChangeCallBack ); + + }, + + updateTextureMatrix: function () { + + this.textureMatrix.set( 0.5, 0.0, 0.0, 0.5, + 0.0, 0.5, 0.0, 0.5, + 0.0, 0.0, 0.5, 0.5, + 0.0, 0.0, 0.0, 1.0 ); + this.textureMatrix.multiply( this.renderCamera.projectionMatrix ); + this.textureMatrix.multiply( this.renderCamera.matrixWorldInverse ); + + }, + + draw: function(renderer, writeBuffer, readBuffer, maskActive, group, index){ + this.changeVisibilityOfSelectedObjects(true, group); + + if(group[0].type === "Points"){ + this.prepareMaskMaterial.uniforms[ "pointSize" ].value = group[0].material.size || 20.0; + if(group[0]["vertShader"]) this.prepareMaskMaterial.vertexShader = group[0]["vertShader"]; + if(group[0]["fragShader"]) this.prepareMaskMaterial.fragmentShader = group[0]["fragShader"]; + } + renderer.render( this.renderScene, this.renderCamera ); + + this.changeVisibilityOfSelectedObjects(false, group); + }, + + render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) { + this.selectedObjects = Object.values(this.id2obj_map).flat(); + // console.log(this.selectedObjects); + // debugger; + + if ( this.selectedObjects.length > 0 ) { + this.oldClearColor.copy( renderer.getClearColor() ); + this.oldClearAlpha = renderer.getClearAlpha(); + var oldAutoClear = renderer.autoClear; + + renderer.autoClear = false; + + if ( maskActive ) renderer.context.disable( renderer.context.STENCIL_TEST ); + + renderer.setClearColor( 0xffffff, 1 ); + + // Make selected objects invisible + this.changeVisibilityOfSelectedObjects( false ); + + var currentBackground = this.renderScene.background; + this.renderScene.background = null; + + // 1. Draw Non Selected objects in the depth buffer + this.renderScene.overrideMaterial = this.depthMaterial; + renderer.setRenderTarget( this.renderTargetDepthBuffer ); + renderer.clear(); + renderer.render( this.renderScene, this.renderCamera ); + + // Update Texture Matrix for Depth compare + this.updateTextureMatrix(); + + // Make non selected objects invisible, and draw only the selected objects, by comparing the depth buffer of non selected objects + this.changeVisibilityOfNonSelectedObjects( false ); + + this.renderScene.overrideMaterial = this.prepareMaskMaterial; + this.prepareMaskMaterial.uniforms[ "cameraNearFar" ].value = new THREE.Vector2( this.renderCamera.near, this.renderCamera.far ); + this.prepareMaskMaterial.uniforms[ "depthTexture" ].value = this.renderTargetDepthBuffer.texture; + this.prepareMaskMaterial.uniforms[ "textureMatrix" ].value = this.textureMatrix; + + renderer.setRenderTarget( this.renderTargetMaskBuffer ); + renderer.clear(); + + this.checkForCustomAtts(); + + for(const group of this.groups){ + if(group.length > 0) + this.draw(renderer, writeBuffer, readBuffer, maskActive, group); + } + + // if(this.atts.total > 0){ + // let group = []; + + // for(let i = 0; i < this.selectedObjects.length; ++i){ + // let p = this.atts["index"].indexOf(i); + // if(p !== -1){ + // this.draw(renderer, writeBuffer, readBuffer, maskActive, this.selectedObjects[i], p); + // } else { + // group.push(this.selectedObjects[i]); + // } + // } + + // if(group.length > 0){ + + // } + // } else { + // this.draw(renderer, writeBuffer, readBuffer, maskActive, this.selectedObjects, -1); + // } + + // enable back all selected elements + this.changeVisibilityOfSelectedObjects(true); + + this.renderScene.overrideMaterial = null; + this.changeVisibilityOfNonSelectedObjects( true ); + + this.renderScene.background = currentBackground; + + // 2. Downsample to Half resolution + this.quad.material = this.materialCopy; + this.copyUniforms[ "tDiffuse" ].value = this.renderTargetMaskBuffer.texture; + renderer.setRenderTarget( this.renderTargetMaskDownSampleBuffer ); + renderer.clear(); + renderer.render( this.scene, this.camera ); + + this.tempPulseColor1.copy( this.visibleEdgeColor ); + this.tempPulseColor2.copy( this.hiddenEdgeColor ); + + if ( this.pulsePeriod > 0 ) { + + var scalar = ( 1 + 0.25 ) / 2 + Math.cos( performance.now() * 0.01 / this.pulsePeriod ) * ( 1.0 - 0.25 ) / 2; + this.tempPulseColor1.multiplyScalar( scalar ); + this.tempPulseColor2.multiplyScalar( scalar ); + + } + + // 3. Apply Edge Detection Pass + this.quad.material = this.edgeDetectionMaterial; + this.edgeDetectionMaterial.uniforms[ "maskTexture" ].value = this.renderTargetMaskDownSampleBuffer.texture; + this.edgeDetectionMaterial.uniforms[ "texSize" ].value = new THREE.Vector2( this.renderTargetMaskDownSampleBuffer.width, this.renderTargetMaskDownSampleBuffer.height ); + this.edgeDetectionMaterial.uniforms[ "visibleEdgeColor" ].value = this.tempPulseColor1; + this.edgeDetectionMaterial.uniforms[ "hiddenEdgeColor" ].value = this.tempPulseColor2; + renderer.setRenderTarget( this.renderTargetEdgeBuffer1 ); + renderer.clear(); + renderer.render( this.scene, this.camera ); + + // 4. Apply Blur on Half res + this.quad.material = this.separableBlurMaterial1; + this.separableBlurMaterial1.uniforms[ "colorTexture" ].value = this.renderTargetEdgeBuffer1.texture; + this.separableBlurMaterial1.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionX; + this.separableBlurMaterial1.uniforms[ "kernelRadius" ].value = this.edgeThickness; + renderer.setRenderTarget( this.renderTargetBlurBuffer1 ); + renderer.clear(); + renderer.render( this.scene, this.camera ); + this.separableBlurMaterial1.uniforms[ "colorTexture" ].value = this.renderTargetBlurBuffer1.texture; + this.separableBlurMaterial1.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionY; + renderer.setRenderTarget( this.renderTargetEdgeBuffer1 ); + renderer.clear(); + renderer.render( this.scene, this.camera ); + + // Apply Blur on quarter res + this.quad.material = this.separableBlurMaterial2; + this.separableBlurMaterial2.uniforms[ "colorTexture" ].value = this.renderTargetEdgeBuffer1.texture; + this.separableBlurMaterial2.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionX; + renderer.setRenderTarget( this.renderTargetBlurBuffer2 ); + renderer.clear(); + renderer.render( this.scene, this.camera ); + this.separableBlurMaterial2.uniforms[ "colorTexture" ].value = this.renderTargetBlurBuffer2.texture; + this.separableBlurMaterial2.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionY; + renderer.setRenderTarget( this.renderTargetEdgeBuffer2 ); + renderer.clear(); + renderer.render( this.scene, this.camera ); + + // Blend it additively over the input texture + this.quad.material = this.overlayMaterial; + this.overlayMaterial.uniforms[ "maskTexture" ].value = this.renderTargetMaskBuffer.texture; + this.overlayMaterial.uniforms[ "edgeTexture1" ].value = this.renderTargetEdgeBuffer1.texture; + this.overlayMaterial.uniforms[ "edgeTexture2" ].value = this.renderTargetEdgeBuffer2.texture; + this.overlayMaterial.uniforms[ "patternTexture" ].value = this.patternTexture; + this.overlayMaterial.uniforms[ "backbuffer" ].value = readBuffer.texture; + this.overlayMaterial.uniforms[ "edgeStrength" ].value = this.edgeStrength; + this.overlayMaterial.uniforms[ "edgeGlow" ].value = this.edgeGlow; + this.overlayMaterial.uniforms[ "usePatternTexture" ].value = this.usePatternTexture; + + if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST ); + + renderer.setRenderTarget( writeBuffer ); + renderer.clear(); + renderer.render( this.scene, this.camera ); + + renderer.setClearColor( this.oldClearColor, this.oldClearAlpha ); + renderer.autoClear = oldAutoClear; + } else { + this.quad.material = this.materialCopy; + this.copyUniforms[ "tDiffuse" ].value = readBuffer.texture; + renderer.setRenderTarget( writeBuffer ); + renderer.clear(); + renderer.render( this.scene, this.camera ); + } + }, + + getPrepareMaskMaterial: function () { + + return new THREE.ShaderMaterial( { + + uniforms: { + "depthTexture": { value: null }, + "cameraNearFar": { value: new THREE.Vector2( 0.5, 0.5 ) }, + "textureMatrix": { value: new THREE.Matrix4() }, + "pointSize": { value: 10.0 } + }, + + vertexShader: + `varying vec4 projTexCoord; + varying vec4 vPosition; + uniform mat4 textureMatrix; + uniform float pointSize; + void main() { + vPosition = modelViewMatrix * vec4( position, 1.0 ); + vec4 worldPosition = modelMatrix * vec4( position, 1.0 ); + projTexCoord = textureMatrix * worldPosition; + gl_PointSize = pointSize; + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); + }`, + + fragmentShader: + `#include + varying vec4 vPosition; + varying vec4 projTexCoord; + uniform sampler2D depthTexture; + uniform vec2 cameraNearFar; + void main() { + float depth = unpackRGBAToDepth(texture2DProj( depthTexture, projTexCoord )); + float viewZ = - DEPTH_TO_VIEW_Z( depth, cameraNearFar.x, cameraNearFar.y ); + float depthTest = (-vPosition.z > viewZ) ? 1.0 : 0.0; + gl_FragColor = vec4(0.0, depthTest, 1.0, 1.0); + }` + } ); + }, + + getEdgeDetectionMaterial: function () { + + return new THREE.ShaderMaterial( { + + uniforms: { + "maskTexture": { value: null }, + "texSize": { value: new THREE.Vector2( 0.5, 0.5 ) }, + "visibleEdgeColor": { value: new THREE.Vector3( 1.0, 1.0, 1.0 ) }, + "hiddenEdgeColor": { value: new THREE.Vector3( 1.0, 1.0, 1.0 ) }, + "pointSize": { value: 10.0 } + }, + + vertexShader: + "varying vec2 vUv;\n\ + uniform float pointSize;\n\ + void main() {\n\ + vUv = uv;\n\ + // gl_PointSize = pointSize;\n\ + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\ + }", + + fragmentShader: + `varying vec2 vUv;\ + uniform sampler2D maskTexture;\ + uniform vec2 texSize;\ + uniform vec3 visibleEdgeColor;\ + uniform vec3 hiddenEdgeColor;\ + \ + void main() { + vec4 edge = texture2D( maskTexture, vUv); + vec3 edgeColor = (1.0 - edge.g) > 0.001 ? visibleEdgeColor : hiddenEdgeColor; + gl_FragColor = vec4( edgeColor, 1.0) * (1.0-edge.r); + }` + } ); + + }, + + getSeperableBlurMaterial: function ( maxRadius ) { + + return new THREE.ShaderMaterial( { + + defines: { + "MAX_RADIUS": maxRadius, + }, + + uniforms: { + "colorTexture": { value: null }, + "texSize": { value: new THREE.Vector2( 0.5, 0.5 ) }, + "direction": { value: new THREE.Vector2( 0.5, 0.5 ) }, + "kernelRadius": { value: 1.0 }, + "pointSize": { value: 10.0 } + }, + + vertexShader: + "varying vec2 vUv;\n\ + uniform float pointSize;\n\ + void main() {\n\ + vUv = uv;\n\ + // gl_PointSize = pointSize;\n\ + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\ + }", + + fragmentShader: + "#include \ + varying vec2 vUv;\ + uniform sampler2D colorTexture;\ + uniform vec2 texSize;\ + uniform vec2 direction;\ + uniform float kernelRadius;\ + \ + float gaussianPdf(in float x, in float sigma) {\ + return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;\ + }\ + void main() {\ + vec2 invSize = 1.0 / texSize;\ + float weightSum = gaussianPdf(0.0, kernelRadius);\ + vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;\ + vec2 delta = direction * invSize * kernelRadius/float(MAX_RADIUS);\ + vec2 uvOffset = delta;\ + for( int i = 1; i <= MAX_RADIUS; i ++ ) {\ + float w = gaussianPdf(uvOffset.x, kernelRadius);\ + vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;\ + vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;\ + diffuseSum += ((sample1 + sample2) * w);\ + weightSum += (2.0 * w);\ + uvOffset += delta;\ + }\ + gl_FragColor = vec4(diffuseSum/weightSum, 1.0);\ + }" + } ); + + }, + + getOverlayMaterial: function () { + + return new THREE.ShaderMaterial( { + + uniforms: { + "maskTexture": { value: null }, + "edgeTexture1": { value: null }, + "edgeTexture2": { value: null }, + "patternTexture": { value: null }, + "backbuffer": { value: null }, + "edgeStrength": { value: 1.0 }, + "edgeGlow": { value: 1.0 }, + "usePatternTexture": { value: 0.0 }, + "pointSize": { value: 10.0 } + }, + + vertexShader: + `varying vec2 vUv; + uniform float pointSize; + void main() { + vUv = uv; + // gl_PointSize = pointSize; + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); + }`, + + fragmentShader: + `varying vec2 vUv; + precision highp float; + uniform sampler2D maskTexture; + uniform sampler2D edgeTexture1; + uniform sampler2D edgeTexture2; + uniform sampler2D patternTexture; + uniform sampler2D backbuffer; + uniform float edgeStrength; + uniform float edgeGlow; + uniform bool usePatternTexture; + + void main() { + vec4 backbuffer = texture2D(backbuffer, vUv); + vec4 edgeValue1 = texture2D(edgeTexture1, vUv); + vec4 edgeValue2 = texture2D(edgeTexture2, vUv); + vec4 maskColor = texture2D(maskTexture, vUv); + vec4 patternColor = texture2D(patternTexture, 6.0 * vUv); + float visibilityFactor = 1.0 - maskColor.g > 0.0 ? 1.0 : 0.5; + vec4 edgeValue = edgeValue1 + edgeValue2 * edgeGlow; + vec4 finalColor = edgeStrength * edgeValue; + if(usePatternTexture) + finalColor += + visibilityFactor * (1.0 - maskColor.r) * (1.0 - patternColor.r); + + #define col finalColor.rgb + + // col = edgeValue1.rgb; + col = mix(backbuffer.rgb, col, maskColor.r * dot(col, vec3(0.33333))); + + gl_FragColor = vec4(col, 1.0); + #undef col + }`, + depthTest: false, + depthWrite: false, + transparent: false + } ); + + } + +} ); + +if(false){ + THREE.OutlinePass.customAtt = function(mesh, opts){ + opts = opts || {}; + + if(opts.index === undefined) + throw "you gotta pass a valid index"; + this.index = opts.index; + + this.isPoint = mesh.isPoints || opts.isPoints || false; + if(this.isPoint) + this.pointSize = opts.pointSize || 20; + + this.hasCustomVertShader = (opts.vertShader !== undefined); + if(this.hasCustomVertShader) this.vertShader = opts.vertShader; + + this.hasCustomFragShader = (opts.fragShader !== undefined); + if(this.hasCustomFragShader) this.fragShader = opts.fragShader; + }; +} + +THREE.OutlinePass.BlurDirectionX = new THREE.Vector2( 1.0, 0.0 ); +THREE.OutlinePass.BlurDirectionY = new THREE.Vector2( 0.0, 1.0 ); \ No newline at end of file