首页 > 其他分享 >threejs 实现镜面反射,只反射指定物体,背景透明

threejs 实现镜面反射,只反射指定物体,背景透明

时间:2025-01-18 08:59:33浏览次数:1  
标签:反射 threejs reflector 镜面反射 blendOverlay vec4 base include blend

一、背景 最近在做数字孪生项目,使用threejs渲染模型,UI要求地面反射建筑物,也就是模型要有倒影。 二、调研 在官网找到一个镜面反射的例子(https://threejs.org/examples/?q=refle#webgl_mirror) 如图: 0 和UI要的功能类似,但有缺陷 1、反射出了地面上所有的元素,连天空盒都反射出来了,我只想反射建筑物 2、没反射的地方,有颜色,盖住了镜面平面下的内容 如图: 0 三、如何只反射指定物体 通过阅读源码,我们发现在 Three.js 中,Reflector 类有一个 onBeforeRender 方法,我们可以称它为“渲染前回调”或“预渲染处理函数”。 如果能拿到这个钩子,在这个钩子里做过滤,问题就迎刃而解了。 但是,最怕有但是,但是这个方法没放出来,不能直接调,怎么办呢? 那就只能曲线救国,改它的方法! 如图:   0 解决方法,就是重写reflector对象的onBeforeRender方法 onBeforeRender方法传入一个 scene 对象,代表视图,也就是反射的内容,过滤scene,不需要的模型对象,隐藏掉(visible = false)   效果如下: 0 现在已经不反射天空盒了,只反射我想要的模型 但是,最怕有但是,但是不反射的地方变成黑色的了,修改镜面平面的材质透明度(opacity)不起效果,怎么办呢? 修改片元着色器。 四、修改片元着色器,使不反射的地方透明 reflector有shander属性,用于传入自定义着色器,着色器(Shader)是图形编程中的一个术语,指的是在图形处理单元(GPU)上运行的程序。这块涉及WebGL的知识,我不懂,不多言。

Reflector.ReflectorShader = {

    uniforms: {

        'color': {
            value: null
        },

        'tDiffuse': {
            value: null
        },

        'textureMatrix': {
            value: null
        }

    },

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

        #include <common>
        #include <logdepthbuf_pars_vertex>

        void main() {

            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;
        varying vec4 vUv;

        #include <logdepthbuf_pars_fragment>

        float blendOverlay( float base, float blend ) {

            return( base < 0.5 ? ( 2.0 * 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 ) );

        }

        void main() {

            #include <logdepthbuf_fragment>

            vec4 base = texture2DProj( tDiffuse, vUv );
            gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );

            #include <tonemapping_fragment>
            #include <encodings_fragment>

        }`
};

 

这是threejs源码,reflector类里定义的默认着色器,拷出来,改一下,再通过shader属性传进去。 0   加上这三行代码即可 效果如图 0 镜面平面透明了 五、如何调整镜面平面的透明度 刚才说了,调整镜面的透明度(opacity)已经不起效果了,我也不想细查为啥了 透明度也可以直接通过片元着色器修改 0 把红框内值改了就行了,数值范围是0~1 改为0.4后,效果如图: 0   注意:要想让镜面平面透明,一定要把镜面材质的是否支持透明度属性改为true,也就是支持透明 0 0 完整代码如下
import { Reflector } from 'three/examples/jsm/objects/Reflector.js';
import { transparentMirrorShader } from '../xxxx.js'

// 创建镜面反射平面
createMirrorPlane() {
    // 创建一个圆形几何体
    const radius = 640; // 圆的半径
    const segments = 256; // 圆的细分数,细分越多圆形越平滑
    const geometry = new THREE.CircleGeometry(radius, segments);

    // 创建 Reflector
    const reflector = new Reflector(geometry, {
        color: 0x000000, // 设置反射颜色
        textureWidth: window.innerWidth * window.devicePixelRatio, // 反射纹理宽度
        textureHeight: window.innerHeight * window.devicePixelRatio, // 反射纹理高度
        shader: transparentMirrorShader,
        clipBias: 0.000 // 裁剪偏移量
    });

    const subModelNameList = ['wall', '天空盒']
    reflector.originOnBeforeRender = reflector.onBeforeRender;
    reflector.onBeforeRender = function (renderer, scene, camera) {
        const scene1 = scene.clone();
        scene1.traverse(child => {
            if (!child.isScene && !child.isLight && child.name && subModelNameList.some(ele => child.name.includes(ele))) {
                if (['wall'].some(ele => child.name.includes(ele))) {
                    child.visible = true;
                } else {
                    child.visible = false;
                }
            }
        });
        
        reflector.originOnBeforeRender(renderer, scene1, camera);
    }

    // 设置位置和旋转
    reflector.position.set(0, -0.01, 0);
    reflector.rotation.x = -Math.PI / 2;

    reflector.name = '镜面反射平面';

    reflector.material.transparent = true;

    // 添加到场景
    this.scene.add(reflector);
},
export const transparentMirrorShader = {
    uniforms: {
        'color': {
            value: null
        },

        'tDiffuse': {
            value: null
        },

        'textureMatrix': {
            value: null
        }

    },

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

        #include <common>
        #include <logdepthbuf_pars_vertex>

        void main() {

            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;
        varying vec4 vUv;

        #include <logdepthbuf_pars_fragment>

        float blendOverlay( float base, float blend ) {

            return( base < 0.5 ? ( 2.0 * 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 ) );

        }

        void main() {

            #include <logdepthbuf_fragment>

            vec4 base = texture2DProj( tDiffuse, vUv );

            // 检查是否有有效的反射纹理,如果没有则透明
            if (base.a < 0.1) {
                discard;
            }

            gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1 );

            #include <tonemapping_fragment>
            #include <encodings_fragment>

        }`
}
我是用立方体做例子,如果有实际模型,效果会更好一些。 欢迎指正。                

标签:反射,threejs,reflector,镜面反射,blendOverlay,vec4,base,include,blend
From: https://www.cnblogs.com/mjwblog/p/18677208

相关文章

  • 毕设学习第四天之Java的注解和反射
    注解(Annotation)Java注解(Annotation)是一种特殊的语言构造,用于为代码元素(如类、方法、字段等)提供元数据,通常不直接影响程序的逻辑执行。它们可以被编译器、框架或工具解析,用于执行特定操作,如自动化配置、代码生成、验证等。Java提供了内置的注解(如@Override、@Deprecated)和允......
  • Java反射、静态代理、动态代理
    概述反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。Spring、mybatis、动态代理、注解都是使用了反射。优点:可以让......
  • Java中的反射机制及其应用场景
    目录什么是Java反射机制?工作原理主要应用场景注意事项总结什么是Java反射机制?Java反射机制是一种强大的工具,它允许程序在运行时访问、检查和修改其本身的类和对象的信息。通过反射,开发者可以在不知道类的具体实现细节的情况下,动态地操作类的属性和方法。这种能力使得......
  • 「C/C++」C++ 之 反射机制
    ✨博客主页何曾参静谧的博客(✅关注、......
  • unity下零GC反射实现思路
    C#反射GC怎么产生的?C#的反射API确实在某些情况下会导致频繁的垃圾回收(GC),尤其是在使用MethodInfo.Invoke等方法时。反射API的设计使得值类型在传递时需要进行装箱(boxing),这会导致额外的内存分配,从而增加GC的压力。反射导致GC的原因装箱和拆箱:当值类型(如int、......
  • 【Django】自定义中间件的注册和使用,利用反射规范代码
    在Django中创建和使用自定义中间件1.创建自定义中间件在你的Django应用目录下创建一个新的文件,通常命名为middleware.py。在这个文件中,你可以定义自己的中间件类。示例中间件#middleware.pyclassCustomMiddleware:def__init__(self,get_response):......
  • 【语法】反射机制
    【作用】通过字符串的方式进行事件驱动,例如通过字符串的方式导入模块,通过字符串的方式再通过模块寻找函数并进行执行。实现插件系统或者模块的动态加载。这意味着你可以在不修改原有代码的情况下,为程序添加新功能。深入浅出Python反射机制_python反射-CSDN博客......
  • ThreeJS入门(217):THREE.DRACOExporter 知识详解,示例代码
    作者:还是大剑师兰特,曾为美国某知名大学计算机专业研究生,现为国内GIS领域高级前端工程师,CSDN知名博主,深耕openlayers、leaflet、mapbox、cesium,webgl,ThreeJS,canvas,echarts等技术开发,欢迎加微信(gis-dajianshi),一起交流。查看本专栏目录-本文是第217篇入门文章......
  • 使用自定义注解与反射实现多sheet表、多表头复杂Excel表解析,实现导入功能
    使用自定义注解与反射实现多sheet表、多表头复杂Excel解析一、分析Excel表多sheet表表头分析(以原料水检测表为例)表头特点:表头占用1-3行A、B列为日期、时间第2行一级表头为不同类别的废水第3行二级表表头为各类别废水中各个化学元素的浓度,特点是每个类别下的化学......
  • Java注解与反射--枚举
    Java注解与反射注解注解定义使用注解反射获取Class对象使用Class对象注解与反射举例定义一个注解@SetValue,给类成员变量赋值枚举类型定义与使用枚举类方法枚举继承接口注解给类、方法、变量、参数等标注的信息注解本身不影响程序运行,但可以通过反射机制,对被标......