因此,我正在尝试使用 EffectComposer 动态屏蔽 UnrealBloomPass,并且得到了意想不到的结果。我不确定我是否在这里遗漏了一个关键概念,或者我是否应该尝试以不同的方式实现这一点。任何输入将不胜感激。

Composer 被设置为这些层:

  • hexgradientPass (主要内容)
  • maskingPass(我试图用鼠标动态移动它)
  • bloomPass(我试图用 ^ 掩盖)
  • clearMaskPass(清除掩码)
  • effectCopyPass(应用效果)

  • 我一直在尽可能密切地关注教程和示例,但仍然没有骰子。提前致谢。
     <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>BloomShader Mask</title>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
            <style>
                body {
                    color: #fff;
                    font-family:Monospace;
                    font-size:13px;
                    text-align:center;
                    background-color: #fff;
                    margin: 0px;
                    overflow: hidden;
                }
                #info {
                    position: absolute;
                    top: 0px;
                    width: 100%;
                    padding: 5px;
                }
                #info p {
                    max-width: 600px;
                    margin-left: auto;
                    margin-right: auto;
                    padding: 0 2em;
                }
                a {
                    color: #2983ff;
                }
            </style>
        </head>
        <body>
            <div id="container"></div>
            <script src="./build/three.js"></script>
            <script src="js/libs/stats.min.js"></script>
            <script src="js/libs/dat.gui.min.js"></script>
            <script src="js/controls/OrbitControls.js"></script>
            <script src="js/loaders/GLTFLoader.js"></script>
            <script src="js/postprocessing/EffectComposer.js"></script>
            <script src="js/postprocessing/RenderPass.js"></script>
            <script src="js/postprocessing/ShaderPass.js"></script>
            <script src="js/postprocessing/MaskPass.js  "></script>
            <script src="js/shaders/CopyShader.js"></script>
            <script src="js/shaders/LuminosityHighPassShader.js"></script>
            <script src="js/postprocessing/UnrealBloomPass.js"></script>
        <script id="gradientShader" type="shader-code">
          uniform vec2 resolution;
          uniform vec2 mousePosition;
          void main() {
            vec2 pos = (gl_FragCoord.xy - mousePosition.xy * 1.2) / resolution.xy;
            gl_FragColor = vec4(1.0, pos.x, pos.y, 1.0);
          }
        </script>
        <script>
          var clock = new THREE.Clock();
          var stats;
          var gui;
          var sceneHexGradient;
          var sceneMask;
          var camera;
          var orbitControls;
          var pointLight;
          var composer;
          var mixer;
          var maskerMesh;
          var bloomPass;
          var width = 0;
          var height = 0;
          var cameraZoom = 120;
          var mousePositionY = 0;
    
          var params = {
              exposure: 2,
              bloomStrength: .81,
              bloomThreshold: 0,
              bloomRadius: .05,
              cameraZoom: cameraZoom
          };
    
          function init() {
            // Init vars (DOM needed)
            gui = initGui();
            stats = initStats();
            width = window.innerWidth;
            height = window.innerHeight;
            pixelRatio = window.devicePixelRatio;
    
            // Renderer
            var webGLRenderer = new THREE.WebGLRenderer({ antialias: true });
            webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0));
            webGLRenderer.setPixelRatio(pixelRatio);
            webGLRenderer.setSize(width , height);
            webGLRenderer.toneMapping = THREE.ReinhardToneMapping;
            webGLRenderer.shadowMap.enabled = true;
            appendChild(webGLRenderer.domElement);
    
            // Scene
            sceneHexGradient = new THREE.Scene();
            sceneMasker = new THREE.Scene();
    
            // Camera
            camera = new THREE.OrthographicCamera(-width, width, height, -height, -1000, 1000);
            camera.zoom = cameraZoom;
            camera.lookAt(new THREE.Vector3(0, 0, 0));
            camera.updateProjectionMatrix();
    
            sceneHexGradient.add(camera);
            sceneMasker.add(camera);
    
            // Orbit
            orbitControls = new THREE.OrbitControls(camera, webGLRenderer.domElement);
            orbitControls.maxPolarAngle = Math.PI * 0.5;
            orbitControls.minDistance = 1;
            orbitControls.maxDistance = 10;
    
            // Draw onto Scenes
            drawGradientToScene(sceneHexGradient);
            drawHexToScene(sceneHexGradient);
            drawMaskerToScene(sceneMasker);
    
            // ShaderPass
            var hexgradientPass = new THREE.RenderPass(sceneHexGradient, camera);
            hexgradientPass.clear = false;
    
            var effectCopyPass = new THREE.ShaderPass(THREE.CopyShader);
            effectCopyPass.renderToScreen = true;
    
            var maskingPass = new THREE.MaskPass(sceneMasker, camera);
            maskingPass.clear = true;
            // var maskingPass = new THREE.RenderPass(sceneMasker, camera);
            // maskingPass.renderToScreen = true;
    
            bloomPass = new THREE.UnrealBloomPass(new THREE.Vector2(width, height), 1.5, 0.4, 0.85);
            bloomPass.renderToScreen = true;
            bloomPass.threshold = params.bloomThreshold;
            bloomPass.strength = params.bloomStrength;
            bloomPass.radius = params.bloomRadius;
    
            var clearMaskPass = new THREE.ClearMaskPass();
    
            composer = new THREE.EffectComposer(webGLRenderer);
            composer.renderTarget1.stencilBuffer = true;
            composer.renderTarget2.stencilBuffer = true;
            composer.setSize(width, height);
            composer.addPass(hexgradientPass);
            composer.addPass(maskingPass);
            // composer.addPass(maskingVerticalBlurPass);
            composer.addPass(bloomPass);
            composer.addPass(clearMaskPass);
            composer.addPass(effectCopyPass);
    
            render();
    
            function initStats() { // Debug only
              var stats = new Stats();
              stats.setMode(0);
              stats.domElement.style.position = 'absolute';
              stats.domElement.style.left = '0px';
              stats.domElement.style.top = '0px';
              appendChild(stats.dom);
              return stats;
            }
    
            function initGui() { // Debug only
                    gui = new dat.GUI();
    
              gui.add(params, 'exposure', 0.1, 2 ).onChange((value) => {
                webGLRenderer.toneMappingExposure = Math.pow(value, 4.0);
              });
    
              gui.add(params, 'bloomThreshold', 0.0, 1.0).onChange((value) => {
                bloomPass.threshold = Number(value);
              });
    
              gui.add(params, 'bloomStrength', 0.0, 3.0).onChange((value) => {
                bloomPass.strength = Number(value);
              });
    
              gui.add(params, 'bloomRadius', 0.0, 1.0).step(0.01).onChange((value) => {
                bloomPass.radius = Number(value);
              });
    
              gui.add(params, 'cameraZoom', 100, 150).onChange((value) => {
                camera.zoom = Number(value);
                camera.updateProjectionMatrix();
              });
    
              return gui;
            }
    
            function appendChild(domElement) {
              var container = document.getElementById('container');
              if (container) {
                return container.appendChild(domElement);
              }
              return false;
            }
    
            function drawGradientToScene(scene) {
              var gradientUniforms = {};
              gradientUniforms["resolution"] = { type:'v2', value:new THREE.Vector2(width, height)};
              gradientUniforms['mousePosition'] = { type:'v2', value:new THREE.Vector2(0, 0) };
              var shaderCode = document.getElementById('gradientShader').innerHTML;
              var material = new THREE.ShaderMaterial({ uniforms:gradientUniforms, fragmentShader:shaderCode });
              var geometry = new THREE.PlaneBufferGeometry(width, height);
              var mesh = new THREE.Mesh(geometry, material);
              scene.add(mesh);
            }
    
            function drawHexToScene(scene) {
              var hexes = [];
              var colCount = 100;
              var rowCount = 100;
              var hexDiameter = 1;
              var xStart = -(colCount) * hexDiameter * 0.5;
              var rowSpace = Math.sqrt(3) * (hexDiameter * 0.5);
              var yStart = (rowCount - 1) * (rowSpace * 0.5);
    
              var hexGeom = new THREE.CylinderGeometry(hexDiameter * .55, hexDiameter * .55, 0.0625, 6, 1);
              hexGeom.rotateX(Math.PI * 0.5);
              for (let j = 0; j < rowCount; j++) {
                for (let i = 0; i < colCount + (j % 2 === 0 ? 0 : 1); i++) {
                  let hex = new THREE.Mesh(hexGeom, new THREE.MeshBasicMaterial({
                    color: 0x000000,
                    wireframe: false,
                  }));
                  var x = (xStart + i * hexDiameter + (j % 2 === 0 ? 0.5 * hexDiameter : 0));
                  var y = (yStart - j * rowSpace);
                  hex.position.set(x, y, 0);
                  hexes.push(hex);
                  scene.add(hex);
                }
              }
            }
    
            function drawMaskerToScene(scene) {
              var boxGeometry = new THREE.BoxGeometry(width, height, 10);
              var basicMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
              maskerMesh = new THREE.Mesh(boxGeometry, basicMaterial);
              maskerMesh.position.y = -height;
              scene.add(maskerMesh);
            }
    
            function onResze() {
              camera.position.set(0, 0, -15);
              camera.zoom = cameraZoom;
              camera.updateProjectionMatrix();
                      composer.setSize(width, height);
            }
    
            function onMouseMove(event) {
              mousePositionY = event.clientY;
            }
    
            function render() {
              webGLRenderer.autoClear = false;
              stats.update();
    
              var delta = clock.getDelta();
              // orbitControls.update(delta);
    
              requestAnimationFrame(render);
    
              maskerMesh.position.y = mousePositionY;
              // composer.setSize(window.innerWidth, window.innerHeight);
              composer.render();
            }
    
            window.addEventListener('mousemove', onMouseMove);
        } // End - init
        // Listeners
        window.onload = init;
        window.onresize = init.onResze;
            </script>
        </body>
    </html>
    

    最佳答案

    这实际上是一系列问题的组合。主要问题是在通行证上设置标志,清除或渲染到屏幕。这不是一件容易调试的事情:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>BloomShader Mask</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no,
        minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                color: #fff;
                font-family:Monospace;
                font-size:13px;
                text-align:center;
                background-color: #fff;
                margin: 0px;
                overflow: hidden;
            }
            #info {
                position: absolute;
                top: 0px;
                width: 100%;
                padding: 5px;
            }
            #info p {
                max-width: 600px;
                margin-left: auto;
                margin-right: auto;
                padding: 0 2em;
            }
            a {
                color: #2983ff;
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
        <script src="./build/three.js"></script>
        <script src="js/libs/stats.min.js"></script>
        <script src="js/libs/dat.gui.min.js"></script>
    <script src="js/controls/OrbitControls.js"></script>
        <script src="js/loaders/GLTFLoader.js"></script>
        <script src="js/postprocessing/EffectComposer.js"></script>
    <script src="js/postprocessing/ClearPass.js"></script>
        <script src="js/postprocessing/RenderPass.js"></script>
    <script src="js/postprocessing/ShaderPass.js"></script>
    <script src="js/postprocessing/MaskPass.js  "></script>
        <script src="js/shaders/CopyShader.js"></script>
        <script src="js/shaders/LuminosityHighPassShader.js"></script>
    <script src="js/postprocessing/UnrealBloomPass.js"></script>
    <script id="gradientShader" type="shader-code">
      uniform vec2 resolution;
      uniform vec2 mousePosition;
      void main() {
        vec2 pos = ((gl_FragCoord.xy - mousePosition.xy * 1.3) / resolution.xy);
        gl_FragColor = vec4(1.0, pos.x, pos.y, 1.0);
      }
    </script>
        <script>
      var clock = new THREE.Clock();
      var stats;
      var gui;
      var sceneHexGradient;
      var sceneBloomMasker;
      var sceneMasker;
      var camera;
      var orbitControls;
      var pointLight;
      var composer;
      var mixer;
      var maskerMesh;
      var bloomPass;
      var width = 0;
      var height = 0;
      var cameraZoom = 120;
      var mousePositionY = 0;
    
            var params = {
                exposure: 2, //1.1
                bloomStrength: 1.75,
                bloomThreshold: 0,
        bloomRadius: .16,
        cameraZoom: cameraZoom
            };
    
      function init() {
        // Init vars (DOM needed)
        gui = initGui();
        stats = initStats();
        width = window.innerWidth;
        height = window.innerHeight;
        pixelRatio = window.devicePixelRatio;
    
        // Camera
        camera = new THREE.OrthographicCamera(-width, width, height, -height, -1000, 1000);
        camera.zoom = cameraZoom;
        camera.lookAt(new THREE.Vector3(0, 0, 0));
        camera.updateProjectionMatrix();
    
        // Renderer
        var webGLRenderer = new THREE.WebGLRenderer({ antialias: true });
        webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0));
        webGLRenderer.setPixelRatio(pixelRatio);
        webGLRenderer.setSize(width , height);
        webGLRenderer.toneMapping = THREE.ReinhardToneMapping;
        webGLRenderer.shadowMap.enabled = true;
        webGLRenderer.autoClear = false;
        appendChild(webGLRenderer.domElement);
    
        // Scene
        sceneHexGradient = new THREE.Scene();
        sceneBloom = new THREE.Scene();
        sceneMasker = new THREE.Scene();
    
        sceneHexGradient.add(camera);
        sceneBloom.add(camera);
        sceneMasker.add(camera);
    
        // Lights (are they needed ? )
        sceneBloom.add(new THREE.AmbientLight(0xffffff));
    
        // Orbit
        orbitControls = new THREE.OrbitControls(camera, webGLRenderer.domElement);
        orbitControls.maxPolarAngle = Math.PI * 0.5;
        orbitControls.minDistance = 1;
        orbitControls.maxDistance = 10;
    
        // Draw onto Scenes
        drawGradientToScene(sceneHexGradient);
        drawHexToScene(sceneHexGradient);
        drawMaskerToScene(sceneMasker);
    
        bloomPass = new THREE.UnrealBloomPass(new THREE.Vector2(width, height), 1.5, 0.4, 0.85);
        bloomPass.threshold = params.bloomThreshold;
        bloomPass.strength = params.bloomStrength;
        bloomPass.radius = params.bloomRadius;
    
        // ShaderPasses
        var clearPass       = new THREE.ClearPass();
        var clearMaskPass   = new THREE.ClearMaskPass();
        var hexgradientPass = new THREE.RenderPass(sceneHexGradient, camera);
        var maskingPass     = new THREE.MaskPass(sceneMasker, camera);
        var outputPass      = new THREE.ShaderPass(THREE.CopyShader);
    
                outputPass.renderToScreen = true;
    
        var parameters = {
                    minFilter: THREE.LinearFilter,
                    magFilter: THREE.LinearFilter,
                    format: THREE.RGBFormat,
                    stencilBuffer: true
                };
    
                var renderTarget = new THREE.WebGLRenderTarget(width, height, parameters);
    
        composer = new THREE.EffectComposer(webGLRenderer, renderTarget);
    
        composer.addPass(clearPass);
        composer.addPass(hexgradientPass);
        composer.addPass(maskingPass);
        composer.addPass(bloomPass);
        composer.addPass(clearMaskPass);
        composer.addPass(outputPass);
    
        function initStats() { // Debug only
          var stats = new Stats();
          stats.setMode(0);
          stats.domElement.style.position = 'absolute';
          stats.domElement.style.left = '0px';
          stats.domElement.style.top = '0px';
          appendChild(stats.dom);
          return stats;
        }
    
        function initGui() { // Debug only
                gui = new dat.GUI();
    
          gui.add(params, 'exposure', 0.1, 2 ).onChange((value) => {
            webGLRenderer.toneMappingExposure = Math.pow(value, 4.0);
          });
    
          gui.add(params, 'bloomThreshold', 0.0, 1.0).onChange((value) => {
            bloomPass.threshold = Number(value);
          });
    
          gui.add(params, 'bloomStrength', 0.0, 3.0).onChange((value) => {
            bloomPass.strength = Number(value);
          });
    
          gui.add(params, 'bloomRadius', 0.0, 1.0).step(0.01).onChange((value) => {
            bloomPass.radius = Number(value);
          });
    
          gui.add(params, 'cameraZoom', 100, 150).onChange((value) => {
            camera.zoom = Number(value);
            camera.updateProjectionMatrix();
          });
    
          return gui;
        }
    
        function appendChild(domElement) {
          var container = document.getElementById('container');
          if (container) {
            return container.appendChild(domElement);
          }
          return false;
        }
    
        function getRandomNumber(min = 1, max = 100) {
          return Math.floor(Math.random() * (+max - +min)) + +min;
        }
    
        function getArrayOfRandomNumbers(count = 1, min = 1, max = 100) {
          const outArr = [];
          for( i = 0; i < count; ++i) {
            outArr.push(getRandomNumber(min, max));
          }
          return outArr.sort();
        }
    
        function drawBlackoutMask(scene) {
          // var x = 0, y = 0;
          // var hexDiameter = 2;
          // var shapeWidth = 10;
    
          // var facets = getRandomNumber(1, shapeWidth);
          // var xValuesArr = getArrayOfRandomNumbers(facets, 0, shapeWidth);
          // var yValuesArr = getArrayOfRandomNumbers(facets, 0, shapeWidth);
    
          // var hexGeom = new THREE.CylinderGeometry(hexDiameter * .55, hexDiameter * .55, 0.0625, 6, 1);
          // hexGeom.rotateX(Math.PI * 0.5);
          // var boxGeometry = new THREE.BoxGeometry(10, 10, 10);
          // var mesh = new THREE.Mesh(boxGeometry, new THREE.MeshBasicMaterial({ color: 0xff0000 }));
          // mesh.position.x = 0;
          // mesh.position.y = 0;
          // scene.add(mesh);
    
          // for(var i = 0; i < facets; i++) {
          //   var hexGeom = new THREE.CylinderGeometry(hexDiameter * .55, hexDiameter * .55, 0.0625, 6, 1);
          //   var mesh = new THREE.Mesh(hexGeom, new THREE.MeshBasicMaterial({
          //     color: 0xff0000,
          //     wireframe: false,
          //   }));
          //   mesh.position.x = xValuesArr[i];
          //   mesh.position.y = yValuesArr[i];
          //   scene.add(mesh);
          // }
        }
    
        function drawMaskerToScene(scene) {
          var boxGeometry = new THREE.CylinderBufferGeometry(width, height, 10);
          // var basicMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
          boxGeometry.computeBoundingBox();
          var material = new THREE.ShaderMaterial({
            uniforms: {
              color1: {
                value: new THREE.Color(0xffffff)
              },
              color2: {
                value: new THREE.Color(0x000000)
              },
              bboxMin: {
                value: boxGeometry.boundingBox.min
              },
              bboxMax: {
                value: boxGeometry.boundingBox.max
              }
            },
            vertexShader: `
              uniform vec3 bboxMin;
              uniform vec3 bboxMax;
    
              varying vec2 vUv;
    
              void main() {
                vUv.y = (position.y - bboxMin.y) / (bboxMax.y - bboxMin.y);
                gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
              }
            `,
            fragmentShader: `
              uniform vec3 color1;
              uniform vec3 color2;
    
              varying vec2 vUv;
    
              void main() {
                gl_FragColor = vec4(mix(color1, color2, vUv.y), 1.0);
              }
            `,
            wireframe: false
          });
          maskerMesh = new THREE.Mesh(boxGeometry, material); //basicMaterial);
          // maskerMesh.scale.set(1,1,1);
          // maskerMesh.position.y = -height;
          scene.add(maskerMesh);
        }
    
        function drawGradientToScene(scene) {
          var gradientUniforms = {};
          gradientUniforms["resolution"] = { type:'v2', value:new THREE.Vector2(width, height)};
          gradientUniforms['mousePosition'] = { type:'v2', value:new THREE.Vector2(0, 0) };
          var shaderCode = document.getElementById('gradientShader').innerHTML;
          var material = new THREE.ShaderMaterial({ uniforms:gradientUniforms, fragmentShader:shaderCode });
          var geometry = new THREE.PlaneBufferGeometry(width, height);
          var mesh = new THREE.Mesh(geometry, material);
          scene.add(mesh);
        }
    
        function drawHexToScene(scene) {
          var hexes = [];
          var colCount = 100;
          var rowCount = 100;
          var hexDiameter = 1;
          var xStart = -(colCount) * hexDiameter * 0.5;
          var rowSpace = Math.sqrt(3) * (hexDiameter * 0.5);
          var yStart = (rowCount - 1) * (rowSpace * 0.5);
    
          var hexGeom = new THREE.CylinderGeometry(hexDiameter * .55, hexDiameter * .55, 0.0625, 6, 1);
          hexGeom.rotateX(Math.PI * 0.5);
          for (let j = 0; j < rowCount; j++) {
            for (let i = 0; i < colCount + (j % 2 === 0 ? 0 : 1); i++) {
              let hex = new THREE.Mesh(hexGeom, new THREE.MeshBasicMaterial({
                color: 0x000000,
                wireframe: false,
              }));
              var x = (xStart + i * hexDiameter + (j % 2 === 0 ? 0.5 * hexDiameter : 0));
              var y = (yStart - j * rowSpace);
              hex.position.set(x, y, 0);
              hexes.push(hex);
              scene.add(hex);
            }
          }
        }
    
        function onResze() {
          camera.position.set(0, 0, -15);
          camera.zoom = cameraZoom;
          camera.updateProjectionMatrix();
                  composer.setSize(width, height);
        }
    
        function onMouseMove(event) {
          mousePositionY = event.clientY;
        }
    
        function render() {
          webGLRenderer.autoClear = false;
          stats.update();
    
          var delta = clock.getDelta();
    
          // orbitControls.update(delta);
    
          requestAnimationFrame(render);
    
          maskerMesh.position.y = mousePositionY;
          webGLRenderer.clear();
          composer.render(delta);
        }
    
        window.addEventListener('mousemove', onMouseMove);
        render();
    } // End - init
    // Listeners
    window.onload = init;
    window.onresize = init.onResze;
        </script>
    </body>
    

    关于javascript - Threejs/EffectComposer - 交互屏蔽 UnrealBloomPass,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54581356/

    10-11 13:23