当前位置: 首页 > news >正文

【three.js】实现玻璃材质时,出现黑色/白色像素噪点

three.js小白的学习之路。

最近在使用blender绘制一些厂房模型,不可避免的要开几个窗户,增加几个玻璃。

其实在几个月之前也遇到过类似的问题,就是在blender中将玻璃材质的折射、投射、金属度和粗糙度等参数调整好之后,在blender中看没有任何问题,但是导出glb,加载到three.js中渲染就会出现一些白色或者黑色的噪点,就类似于下面的这种情况:

在没有遮挡的时候是正常的玻璃材质,在后面有遮挡的时候就会出现黑色噪点。

{const geo = new Three.PlaneGeometry(500, 500);const mat = new Three.MeshBasicMaterial({color: "gray",});const mesh = new Three.Mesh(geo, mat);mesh.position.set(0, -100, 0);mesh.rotation.x = -Math.PI / 2;scene.add(mesh);
}{const geometry = new Three.BoxGeometry(100, 100, 100);const material = new Three.MeshPhysicalMaterial({color: "white",metalness: 0,roughness: 0,transmission: 0.9, // 透光率ior: 1.8, // 折射});const mesh = new Three.Mesh(geometry, material);mesh.position.set(0, 0, 0);scene.add(mesh);const gui = new GUI();gui.add(material, "metalness", 0, 1, 0.01);gui.add(material, "roughness", 0, 1, 0.01);gui.add(material, "transmission", 0, 1, 0.01);gui.add(material, "ior", 0, 2.333, 0.01);
}

可以通过GUI调试查看更改各个参数时,玻璃材质会体现出什么样的效果。

原因分析

在three.js的官网,关于ior折射以及transmission透光的解释是这样的:

ior: number,表示非金属材料的折射率,默认1.5,范围1.0-2.333。

transmission: number,表示投射程度,当其非0时,不透明度应该设置为1,默认0,范围0-1。

可以看出,上述两个属性是用来反射某个环境的,高度依赖于环境的反射和折射来模拟真实的效果。

blender中导出的模型是没有设置玻璃所要反射的环境的(blender中在渲染模式下,是有世界环境的),或者如上述的例子中,也是没有设置材质的环境的。这就导致玻璃材质不知道要反射什么东西,无法正确计算环境反射,导致渲染异常。

解决方法

既然需要反射的环境,就给他一个环境就可以了。这个参数是 envMap。

envmap: Texture,确保物理渲染正确的环境贴图,默认 null。

envMapIntensity: number,通过乘以对应的颜色值来计算最终的环境贴图,默认1。

我们加载一个环境贴图,并赋值给对应材质的envMap:

const textureCube = new Three.CubeTextureLoader().load([px, mx, py, my, pz, mz]);// ………………
const material = new Three.MeshPhysicalMaterial({color: "white",metalness: 0,roughness: 0,transmission: 0.9, // 透光率ior: 1.8, // 折射envMap: textureCube,});

效果如下:

可以看到,增加了envMap属性之后,就没有之前看到的黑色噪点了。问题解决。

这样会引入一个新的问题,我找不到贴切的纹理贴图怎么办?或者,本意只是说弄几个玻璃意思意思,拥有玻璃的特质,透过玻璃可以看到内部即可,不是真的要渲染周围的环境。

这就需要用到第二个参数,envMapIntensity,我们添加一个gui测一下:

const material = new Three.MeshPhysicalMaterial({color: "white",metalness: 0,roughness: 0,transmission: 0.9, // 透光率ior: 1.8, // 折射envMap: textureCube,envMapIntensity: 1,});const gui = new GUI();gui.add(material, "metalness", 0, 1, 0.01);gui.add(material, "roughness", 0, 1, 0.01);gui.add(material, "transmission", 0, 1, 0.01);gui.add(material, "ior", 0, 2.333, 0.01);gui.add(material, "envMapIntensity", 0, 1, 0.01);

效果如下:

可以看到,在envMapIntensity设置成0时,依然保留了玻璃的特性,但是不会再反应周围的环境了,有点类似于透明度opacity设置成0,但是又能清晰地看到有这么一块东西。

其他的实现玻璃效果的方法

除了修改物理材质这一个方法,还有其他的方法生成玻璃效果,也是three.js提供的API。

1.cubeCamera

cubeCamera用于实拍当前场景,并将渲染结果生成在一个离屏渲染目标上,用于提供对应的纹理。这种就可以应用到监控视频等场景中。

使用方法:

const cubeRenderTarget = new Three.WebGLCubeRenderTarget(512); // 参数是分辨率
const cubeCamera = new Three.CubeCamera(1, 1000, cubeRenderTarget);const group = new Three.Group();const geo1 = new Three.PlaneGeometry(1000, 1000);const mat1 = new Three.MeshStandardMaterial({metalness: 1,roughness: 0,envMap: cubeRenderTarget.texture,});const plane= new Three.Mesh(geo1, mat1);group.add(plane);const geo2 = new Three.SphereGeometry(100);const mat2 = new Three.MeshStandardMaterial({ color: "blue" });const ball= new Three.Mesh(geo2, mat2);ball.position.set(0, 0, 500);group.add(ball);scene.add(group);const render = () => {requestAnimationFrame(render);renderer.render(scene, camera);cubeCamera.position.copy(plane.position);cubeCamera.update(renderer, scene);
};

这里我们生成一个小球,和一个平面,并处理好相应位置。使用cubeCamera,并与plane的位置相同,这样cubeCamera拍摄出来的场景就是从平面的角度所能看到的场景目标。

注意,要在render里面循环更新cubeCamera,因为移动控制器的时候,不更新的话,就无法正常渲染。

2.Reflector

如果你运行了cubeCamera的例子,你会发现一切都没啥问题。于是你想:我再整一个镜子,让这两个镜子面对面,是不是就会出现现实世界中的那种“你中有我,我中有你”的效果。

如果你试了,你会发现,完全不行。

为什么?因为从一个镜子的方向看,他可以看到另一个镜子,但是另一个镜子就是一个平面而已,只是我们后加了材质和环境贴图罢了,反之亦然。

有没有更好的方法?有的,就是Reflector。

const group = new Three.Group();const geo1 = new Three.PlaneGeometry(1000, 1000);const mesh1 = new Reflector(geo1, {color: "blue",textureWidth: window.innerWidth * window.devicePixelRatio,textureHeight: window.innerHeight * window.devicePixelRatio,});mesh1.name = "mirror1";mesh1.position.z = -500;group.add(mesh1);const geo2 = new Three.PlaneGeometry(1000, 1000);const mesh2 = new Reflector(geo2, {color: "red",textureWidth: window.innerWidth * window.devicePixelRatio,textureHeight: window.innerHeight * window.devicePixelRatio,});mesh2.name = "mirror2";mesh2.position.z = 500;mesh2.rotateY(Math.PI);group.add(mesh2);scene.add(group);

对比之前的创建方式,可以发现,Reflector替代了PBR物理渲染材质,而是直接通过geometry生成模型。

这样就可以实现上述的效果。

只不过这个方法更耗性能,并且也不是无限的透射出另一面镜子,一般就两三回。

http://www.dtcms.com/a/593402.html

相关文章:

  • 低功耗蓝牙芯片CH9141蓝牙串口透传方案
  • 保山网站建设报价黄金网站下载免费
  • 【如何通过LoadRunner在Visual Studio中开发单元测试?】
  • MySQL + Java 常规八股(2 w字 + 不定期更新)
  • 黄石网站建设哪家好北京网站改版有哪些好处
  • 深入解析QSettings:Qt应用程序的配置管理利器
  • uvx安装
  • 物理服务器都有哪些作用?
  • AI场景开放:打造人机共生新图景
  • 广西 南宁 微信微网站开发上海专业网站建设机构
  • S16 排序算法--堆排序
  • KUKA机械臂使用EthernetKRL配置与C#上位机实现TCP通讯
  • IU5516:3μ低功耗,直通跟随模式,2.0A降压DCDC,适用于摄像头、智能门锁、机器人
  • 20251110易灵思的FPGA打开debugger模式
  • SQLAlchemy 插入数据报错:Data too long for column ‘password_hash’
  • 政务内网网站群建设方案网页设计模板 中文
  • 互联网大厂Java求职面试实战:Spring Boot到Kubernetes的技术问答
  • 合规安全的整形医院系统服务商排名
  • 贵州贵州省住房和城乡建设厅网站做游戏音频下载网站
  • 块状数组超级兵器:区间动态排名问题
  • 在网站开发中如何设置用户登录网站查看
  • SAP FICO资产主数据创建接口
  • 『 QT 』显示类控件 (一)
  • 网站建设彳金手指排名wordpress电子书插件
  • 石狮网站建设科技vmware做网站步骤
  • 全国网站建设公司排名泰安市人才交流服务中心
  • C++双向链表删除操作:由浅入深完全指南
  • 云手机轻松玩转网络手游
  • 手机拍照明晰度评估:传感器尺寸像素数量与处理器算法解析
  • Web VIVO手机商城网站项目4页面