three 镜面反射

镜面反射插件

import {
  Color,
  LinearFilter,
  MathUtils,
  Matrix4,
  Mesh,
  PerspectiveCamera,
  Plane,
  RGBFormat,
  ShaderMaterial,
  RepeatWrapping,
  UniformsUtils,
  Vector3,
  Vector4,
  WebGLRenderTarget
} from 'three';

class Reflector extends Mesh {

  constructor(geometry, options = {}) {

    super(geometry);

    this.type = 'Reflector';

    const self = this;

    const color = options.color !== undefined ? new Color(options.color) : new Color(0x7F7F7F);
    const textureWidth = options.textureWidth || 512;
    const textureHeight = options.textureHeight || 512;
    const strength = options.strength;
    const Ttexture = options.Ttexture;
    const clipBias = options.clipBias || 0;
    const shader = options.shader || Reflector.ReflectorShader;

    const reflectorPlane = new Plane();
    const normal = new Vector3();
    const reflectorWorldPosition = new Vector3();
    const cameraWorldPosition = new Vector3();
    const rotationMatrix = new Matrix4();
    const lookAtPosition = new Vector3(0, 0, - 1);
    const clipPlane = new Vector4();

    const view = new Vector3();
    const target = new Vector3();
    const q = new Vector4();

    const textureMatrix = new Matrix4();
    const virtualCamera = new PerspectiveCamera();

    const parameters = {
      minFilter: LinearFilter,
      magFilter: LinearFilter,
      format: RGBFormat
    };

    const renderTarget = new WebGLRenderTarget(textureWidth, textureHeight, parameters);

    if (!MathUtils.isPowerOfTwo(textureWidth) || !MathUtils.isPowerOfTwo(textureHeight)) {

      renderTarget.texture.generateMipmaps = false;

    }
    const material = new ShaderMaterial({
      uniforms: UniformsUtils.clone(shader.uniforms),
      fragmentShader: shader.fragmentShader,
      vertexShader: shader.vertexShader
    });


    Ttexture.wrapS = RepeatWrapping;
    Ttexture.wrapT = RepeatWrapping;

    material.uniforms['tDiffuse'].value = renderTarget.texture;
    material.uniforms['color'].value = color;
    material.uniforms['textureMatrix'].value = textureMatrix;
    material.uniforms['strength'].value = strength;
    material.uniforms['Ttexture'].value = Ttexture;

    this.material = material;

    this.onBeforeRender = function (renderer, scene, camera) {

      reflectorWorldPosition.setFromMatrixPosition(self.matrixWorld);
      cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);

      rotationMatrix.extractRotation(self.matrixWorld);

      normal.set(0, 0, 1);
      normal.applyMatrix4(rotationMatrix);

      view.subVectors(reflectorWorldPosition, cameraWorldPosition);

      // Avoid rendering when reflector is facing away

      if (view.dot(normal) > 0) return;

      view.reflect(normal).negate();
      view.add(reflectorWorldPosition);

      rotationMatrix.extractRotation(camera.matrixWorld);

      lookAtPosition.set(0, 0, - 1);
      lookAtPosition.applyMatrix4(rotationMatrix);
      lookAtPosition.add(cameraWorldPosition);

      target.subVectors(reflectorWorldPosition, lookAtPosition);
      target.reflect(normal).negate();
      target.add(reflectorWorldPosition);

      virtualCamera.position.copy(view);
      virtualCamera.up.set(0, 1, 0);
      virtualCamera.up.applyMatrix4(rotationMatrix);
      virtualCamera.up.reflect(normal);
      virtualCamera.lookAt(target);

      virtualCamera.far = camera.far; // Used in WebGLBackground

      virtualCamera.updateMatrixWorld();
      virtualCamera.projectionMatrix.copy(camera.projectionMatrix);

      // Update the texture matrix
      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
      );
      textureMatrix.multiply(virtualCamera.projectionMatrix);
      textureMatrix.multiply(virtualCamera.matrixWorldInverse);
      textureMatrix.multiply(self.matrixWorld);

      // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
      // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
      reflectorPlane.setFromNormalAndCoplanarPoint(normal, reflectorWorldPosition);
      reflectorPlane.applyMatrix4(virtualCamera.matrixWorldInverse);

      clipPlane.set(reflectorPlane.normal.x, reflectorPlane.normal.y, reflectorPlane.normal.z, reflectorPlane.constant);

      const projectionMatrix = virtualCamera.projectionMatrix;

      q.x = (Math.sign(clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0];
      q.y = (Math.sign(clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5];
      q.z = - 1.0;
      q.w = (1.0 + projectionMatrix.elements[10]) / projectionMatrix.elements[14];

      // Calculate the scaled plane vector
      clipPlane.multiplyScalar(2.0 / clipPlane.dot(q));

      // Replacing the third row of the projection matrix
      projectionMatrix.elements[2] = clipPlane.x;
      projectionMatrix.elements[6] = clipPlane.y;
      projectionMatrix.elements[10] = clipPlane.z + 1.0 - clipBias;
      projectionMatrix.elements[14] = clipPlane.w;

      // Render

      renderTarget.texture.encoding = renderer.outputEncoding;

      self.visible = false;

      const currentRenderTarget = renderer.getRenderTarget();

      const currentXrEnabled = renderer.xr.enabled;
      const currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;

      renderer.xr.enabled = false; // Avoid camera modification
      renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows

      renderer.setRenderTarget(renderTarget);

      renderer.state.buffers.depth.setMask(true); // make sure the depth buffer is writable so it can be properly cleared, see #18897

      if (renderer.autoClear === false) renderer.clear();
      renderer.render(scene, virtualCamera);

      renderer.xr.enabled = currentXrEnabled;
      renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;

      renderer.setRenderTarget(currentRenderTarget);

      // Restore viewport

      const viewport = camera.viewport;

      if (viewport !== undefined) {

        renderer.state.viewport(viewport);

      }

      self.visible = true;

    };

    this.getRenderTarget = function () {

      return renderTarget;

    };

    this.dispose = function () {

      renderTarget.dispose();
      self.material.dispose();

    };

  }

}

Reflector.prototype.isReflector = true;

Reflector.ReflectorShader = {

  uniforms: {

    color: {
      value: null
    },

    tDiffuse: {
      value: null
    },

    textureMatrix: {
      value: null
    },

    strength: {
      value: null
    },

    Ttexture: {
      value: null
    }

  },

  vertexShader: /* glsl */`
		uniform mat4 textureMatrix;
		varying vec4 vUv;
    varying vec2 uv2;

		#include <common>
		#include <logdepthbuf_pars_vertex>

		void main() {
      uv2 = uv;
			vUv = textureMatrix * vec4( position, 1.0 );

			gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

			#include <logdepthbuf_vertex>

		}`,
  fragmentShader: /* glsl */`
    uniform vec3 color;
    uniform sampler2D tDiffuse;
    uniform float strength;
    varying vec4 vUv;
    varying vec2 uv2;
		uniform sampler2D Ttexture;
    
    #include <logdepthbuf_pars_fragment>
    
    float blendOverlay( float base, float blend ) {
      return( base < 1.0 ? ( 0.3 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );
    }
    
    vec3 blendOverlay( vec3 base, vec3 blend ) {
      return vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ));
    }
    

/// ==============
// 模糊半径
  // for 循环的次数必须为常量
  const float RADIUS = 20.0;

  // 获取模糊颜色
  // vec4 getBlurColor (vec2 pos) {
  //   vec4 color = vec4(0); // 初始颜色
  //   float sum = 0.0; // 总权重
  //   // 卷积过程
  //   for (float r = -RADIUS; r <= RADIUS; r++) { // 水平方向
  //     for (float c = -RADIUS; c <= RADIUS; c++) { // 垂直方向
  //       vec2 target = pos + vec2(r / size.x, c / size.y); // 目标像素位置
  //       float weight = (RADIUS - abs(r)) * (RADIUS - abs(c)); // 计算权重
  //       color += texture2D(Ttexture, target) * weight; // 累加颜色
  //       sum += weight; // 累加权重
  //     }
  //   }
  //   color /= sum; // 求出平均值
  //   return color;
  // }
//========
    
    void main() {
    
      #include <logdepthbuf_fragment>
    
     vec4 textureColor = texture2D( Ttexture, uv2);
      vec4 base = texture2DProj( tDiffuse, vUv );
      vec4 base2 = vec4( blendOverlay( base.rgb*strength, color ), .1 );

//  ====
// vec4 color = getBlurColor(uv2); // 获取模糊后的颜色
//===

      gl_FragColor = mix(base,textureColor, 0.01);
      #include <encodings_fragment>
    }`

};

export {Reflector};

使用方式


const planeLine = textureLoader.load(require('../../assets/img/opacity.png'), texture => {
  texture.wrapS = THREE.RepeatWrapping;
  texture.wrapT = THREE.RepeatWrapping;
  texture.needsUpdate = true;
  texture.repeat.set(1, 1);
  texture.anisotropy = 1;
  texture.encoding = THREE.sRGBEncoding;
});
loadGroundMirror() {
      const geometry = new THREE.PlaneGeometry(50000, 50000);
      const verticalMirror = new Reflector(geometry, {
        clipBias: 0.1,
        textureWidth: window.innerWidth * window.devicePixelRatio,
        textureHeight: window.innerHeight * window.devicePixelRatio,
        color: '#fff',
        strength: 0.001,
        Ttexture: planeLine
      });
      verticalMirror.position.y = -10;
      verticalMirror.position.z = 0;
      verticalMirror.position.x = 0;
      verticalMirror.rotateX(-Math.PI / 2);
      scene.add(verticalMirror);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LBY_XK

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值