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

news/2025/1/18 8:10:42/文章来源:https://www.cnblogs.com/mjwblog/p/18677208
一、背景
最近在做数字孪生项目,使用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);// 创建 Reflectorconst 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>}`
}
我是用立方体做例子,如果有实际模型,效果会更好一些。
欢迎指正。
 
 
 
 
 
 
 
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/871122.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3D-NAND 计算(下)

过去几年, 具有存算一体特性的 AI 芯片不断 涌现, 工艺节点涵盖了 14—180 nm, 计算架构包括 了近存计算、存内计算和神经形态计算, 应用场景 覆盖了边缘端到云端设备. 在各种硬件方案中, 基 于 3D-NAND 的神经形态芯片在芯片容量, CMOS 工艺兼容性和成本方面极具优势. 本文首先…

海康工业相机的应用部署不是简简单单!?

作者:SkyXZ CSDN:SkyXZ~-CSDN博客 博客园:SkyXZ - 博客园 笔者使用的设备及环境:WSL2-Ubuntu22.04+MV-CS016-10UC 不会吧?不会吧?不会还有人拿到海康工业相机还是一脸懵叭?不会还有人觉得海康相机的API使用很难叭?不用慌!这篇文章从官方文档涵盖了海康相机官方…

3D-NAND 计算(上)

3D-NAND 闪存工艺成熟并且存储密度极高, 基于 3D-NAND 的神经形态芯片受到许多研究者的关注. 然而由于该技术的专利性质, 少有基 于 3D-NAND 神经形态计算的硬件实现. 本文综述了用 3D-NAND 实现神经形态计算的工作, 介绍了其中前 向传播和反向传播的机制, 并提出了目前 3D NAN…

blender4.3.2-修改器

关于修改器的其他问题 1.在修改器执行应用前,无法与其他物体进行合并 阵列修改器 生成->阵列指定数量和间隔,生成克隆体,所有克隆体同步发生选中和修改 倒角修改器 生成->倒角使用倒角修改器而不直接使用编辑模式中的倒角,好处在于像立方体这种使用了倒角修改器而未应…

推荐书籍《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》4本,谢谢

4本书推荐《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》由清华大学出版社资深编辑赵佳霓老师策划编辑的新书《AI芯片开发核心技术详解》已经出版,京东、淘宝天猫、当当等网上,相应陆陆续续可以购买。该…

2025 最佳免费商用文本转语音模型: Kokoro TTS

在文本转语音(TTS)技术领域,一项突破性的进展引起了广泛关注——Kokoro TTS 模型凭借其卓越性能和完全免费的商用许可,成为目前最出色的 TTS 解决方案之一。基于广受欢迎的开源框架 StyleTTS,Kokoro TTS 在灵活性和功能性上都表现出色,可广泛应用于多种场景。接下来,我们…

2025春秋杯部分wpDAY1

2025春秋杯 DAY1 WEB easy_flask 直接fenjing一把梭file_copy 下载github上的脚本MISC 简单算术 题目提示了异或简单镜像提取formost提取到镜像文件然后用autopsy打开flag{E7A10C15E26AA5750070EF756AAA1F7C} CRYPTO 通往哈希的旅程 import hashlib# 目标哈希值 target_hash = …

【教育行业】2024中国网络安全产业势能榜优能企业「教育行业」典型案例展示

教育行业的数字化转型不断加速,线上教学、学籍管理、科研数据等方面的安全问题日益突出。随着教育信息化的不断推进,如何保护学生和教师的个人信息、确保教学平台的安全成为亟待解决的重要课题。我们将通过一些典型案例,展示教育行业在提升信息安全方面的最新成果和应对之策…

去攀登更高的山,渡过更长的河--软件工程个人总结

轻舟已过万重山——2024秋软工实践个人总结博客一、学期回顾 1.1 回顾你对于软件工程课程的想象 初次接触软件工程这门课程时,我内心充满了忐忑与不安 😰。作为一门实践性极强的课程,它不仅要求我们掌握各种开发技术,还需要我们具备团队协作、项目管理等综合能力。我记得第…

Avalonia系列文章之小试牛刀

最近有朋友反馈,能否分享一下Avalonia相关的文章,于是就抽空学习了一下,发现Avalonia真的是一款非常不错的UI框架,值得花时间认真学习一下,于是边学习边记录,整理成文,分享给大家,希望可以一起学习,共同进步。最近有朋友反馈,能否分享一下Avalonia相关的文章,于是就…

器件选型基础知识

器件选型基础知识器件选型基础知识 1. PCB结构与工艺 PCB主要由五部分组成,分别是介电层、孔、防焊墨油、丝印和线路组成。介电层:用来保持线路及各层之间的绝缘性,俗称为基材,最常见的材料是玻璃纤维; 孔:导通孔可以使两层次以上的线路彼此导通; 防焊墨油:对于整个电路…

【CodeForces训练记录】Codeforces Round 997 (Div. 2)

训练情况赛后反思 A题犯蠢了,题目看成面积了,C题应该可以更快的搓出来,只能说结论猜了几次不对 A题 我们把周长移动一下,补成一个长方形,左下角的坐标为 \((x_1,y_1)\),右上角坐标为 \((\sum{x_i}+m,\sum{y_i}+m)\),已知两点直接求周长 #include <bits/stdc++.h> …