最新要闻
- 天天视点!国际货币基金组织敦促黎巴嫩加快改革以启动一揽子救助计划
- 谷歌回应Bard内容“抄袭”:插入链接会打断对话
- 快资讯丨浙江2人遭雷击不幸身亡 急救中心发布雷雨天出行提示
- 0糖0脂肪 丘里福建大红袍、铁观音茶饮闭眼囤:券后6瓶15.8元
- 天天新动态:最远能跑333km 五菱缤果官宣3月29日上市:7万交个朋友?
- 认真做优化 Intel显卡驱动容量减少一半:从1.3GB降至0.6GB
- 天天速递!全国跳水冠军赛:昌雅妮成为女子3米板“双冠王 ”
- 焦点信息:DNF远古地下城怎么开
- 天天观点:抵制汽车行业网络水军!比亚迪、长城、蔚小理等发起联合倡议
- 萤石TV Studio发布:接管电视“大脑” 让一屏秒变三屏!
- 【世界快播报】灯座安装即插即用:萤石发布4G款灯座云台摄像机C8b
- 环球新动态:比亚迪宋Pro DM-i 2023款实车曝光:前脸大变 加长加高
- 【全球新视野】2023第三届大湾区数字峰会在广州召开
- 关于工作态度和责任心的句子有哪些?工作态度自我评价模板
- 燃野少年的天空老狗最后和谁在一起了?燃野少年的天空演员表
- 春联横批是从左到右还是从右到左?通用的春联横批大全
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
焦点!记录--用three.js渲染真实的下雨效果
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
建模
首先我们需要一些贴图素材
贴图素材一般可以在3dtextures网站上找到,这里我找了2份,包含了墙的法线贴图和潮湿地面的法线、透明度、粗糙度贴图
通过kokomi.AssetManager将贴图素材一次性全部加载出来,将它们应用到Mesh
上,加上基本的环境光照,即可完成最基本的建模
【资料图】
// 光照const pointLight1 = new THREE.PointLight(config.color, 0.5, 17, 0.8);pointLight1.position.set(0, 2, 0);this.scene.add(pointLight1);...// 网格const aspTex = am.items["asphalt-normal"];aspTex.rotation = THREE.MathUtils.degToRad(90);aspTex.wrapS = aspTex.wrapT = THREE.RepeatWrapping;aspTex.repeat.set(5, 8);const wallMat = new THREE.MeshPhongMaterial({ color: new THREE.Color("#111111"), normalMap: aspTex, normalScale: new THREE.Vector2(0.5, 0.5), shininess: 200,});const wall = new THREE.Mesh(new THREE.BoxGeometry(25, 20, 0.5), wallMat);this.scene.add(wall);wall.position.y = 10;wall.position.z = -10.3;...// 文字const t3d = new kokomi.Text3D(this, config.text, font, { size: 3, height: 0.2, curveSegments: 120, bevelEnabled: false,});t3d.mesh.geometry.center();const tm = new THREE.Mesh( t3d.mesh.geometry, new THREE.MeshBasicMaterial({ color: config.color, }));this.scene.add(tm);tm.position.y = 1.54;
积水地面
地面上的积水能反射出周围的景色,因此我们将选用kokomi.Reflector来实现反射效果
const mirror = new kokomi.Reflector(new THREE.PlaneGeometry(25, 100));mirror.position.z = -25;mirror.rotation.x = -Math.PI / 2;
普通的反射器仅仅是一面镜子,因此我们要自定义反射器的Shader
涟漪效果
之前逛shadertoy时看到了一个很棒的涟漪特效,就直接拿来用了
// https://www.shadertoy.com/view/4djSRWfloat hash12(vec2 p){ vec3 p3=fract(vec3(p.xyx)*.1031); p3+=dot(p3,p3.yzx+19.19); return fract((p3.x+p3.y)*p3.z);}vec2 hash22(vec2 p){ vec3 p3=fract(vec3(p.xyx)*vec3(.1031,.1030,.0973)); p3+=dot(p3,p3.yzx+19.19); return fract((p3.xx+p3.yz)*p3.zy);}// https://gist.github.com/companje/29408948f1e8be54dd5733a74ca49bb9float map(float value,float min1,float max1,float min2,float max2){ return min2+(value-min1)*(max2-min2)/(max1-min1);}vec2 rippleUv=75.*p*uTexScale;vec2 p0=floor(rippleUv);float rainStrength=map(uRainCount,0.,10000.,3.,.5);if(rainStrength==3.){ rainStrength=50.;}vec2 circles=vec2(0.);for(int j=-MAX_RADIUS;j<=MAX_RADIUS;++j){ for(int i=-MAX_RADIUS;i<=MAX_RADIUS;++i) { vec2 pi=p0+vec2(i,j); #if DOUBLE_HASH vec2 hsh=hash22(pi); #else vec2 hsh=pi; #endif vec2 p=pi+hash22(hsh); float t=fract(.8*iTime+hash12(hsh)); vec2 v=p-rippleUv; float d=length(v)-(float(MAX_RADIUS)+1.)*t+(rainStrength*.1*t); float h=1e-3; float d1=d-h; float d2=d+h; float p1=sin(31.*d1)*smoothstep(-.6,-.3,d1)*smoothstep(0.,-.3,d1); float p2=sin(31.*d2)*smoothstep(-.6,-.3,d2)*smoothstep(0.,-.3,d2); circles+=.5*normalize(v)*((p2-p1)/(2.*h)*(1.-t)*(1.-t)); }}circles/=float((MAX_RADIUS*2+1)*(MAX_RADIUS*2+1));float intensity=.05*floorOpacity;vec3 n=vec3(circles,sqrt(1.-dot(circles,circles)));vec2 rainUv=intensity*n.xy;
与地面结合
光有涟漪效果也不够,要将它与地面的贴图相结合起来
这里采用了自定义mipmap
技术,利用kokomi.PackedMipMapGenerator生成了多个贴图的mipmap
自定义mipmap除了能捆绑贴图外,还有个好处就是可以动态控制贴图的模糊程度
const mipmapper = new kokomi.PackedMipMapGenerator();const mirrorFBO = mirror.getRenderTarget();const mipmapFBO = new kokomi.FBO(this);mirror.material.uniforms.tDiffuse.value = mipmapFBO.rt.texture;this.update(() => { mipmapper.update(mirrorFBO.texture, mipmapFBO.rt, this.renderer);});
vec2 p=vUv;vec2 texUv=p*uTexScale;texUv+=uTexOffset;float floorOpacity=texture(uOpacityTexture,texUv).r;vec3 floorNormal=texture(uNormalTexture,texUv).rgb*2.-1.;floorNormal=normalize(floorNormal);float roughness=texture(uRoughnessTexture,texUv).r;vec2 finalUv=reflectionUv+floorNormal.xy*uDistortionAmount-rainUv;float level=roughness*uBlurStrength;vec3 col=packedTexture2DLOD(tDiffuse,finalUv,level,uMipmapTextureSize).rgb;
下雨动画
生成雨滴
雨滴数量会很多,因此要用到THREE.InstancedMesh来生成实例化网格对象
const rain = new THREE.InstancedMesh(new THREE.PlaneGeometry(), rainMat, count);rain.instanceMatrix.needsUpdate = true;const dummy = new THREE.Object3D();for (let i = 0; i < rain.count; i++) { dummy.position.set( THREE.MathUtils.randFloat(-10, 10), 0, THREE.MathUtils.randFloat(-20, 10) ); dummy.scale.set(0.03, THREE.MathUtils.randFloat(0.3, 0.5), 0.03); dummy.updateMatrix(); rain.setMatrixAt(i, dummy.matrix);}rain.rotation.set(-0.1, 0, 0.1);rain.position.set(0, 4, 4);
这里要注意一点:雨滴的方向是始终朝向用户的,为了达成这点就要用billboard方案来实现
vec3 billboard(vec3 v,mat4 view){ vec3 up=vec3(view[0][1],view[1][1],view[2][1]); vec3 right=vec3(view[0][0],view[1][0],view[2][0]); vec3 pos=right*v.x+up*v.y; return pos;}vec3 billboardPos=billboard(transformed,modelViewMatrix);transformed=billboardPos;
下落动画
我们可以给雨滴赋予随机的高度和速度attribute,并在顶点着色器中让它动起来
const progressArr = [];const speedArr = [];for (let i = 0; i < rain.count; i++) { ... progressArr.push(Math.random()); speedArr.push(dummy.scale.y * 10);}rain.geometry.setAttribute( "aProgress", new THREE.InstancedBufferAttribute(new Float32Array(progressArr), 1));rain.geometry.setAttribute( "aSpeed", new THREE.InstancedBufferAttribute(new Float32Array(speedArr), 1));
attribute float aProgress;attribute float aSpeed;uniform float uSpeed;uniform float uHeightRange;vec3 distort(vec3 p){ float y=mod(aProgress-iTime*aSpeed*.25*uSpeed,1.)*uHeightRange-(uHeightRange*.5); p.y+=y; return p;}transformed=distort(transformed);
反射效果
创建背景的离屏渲染FBO,将其作为反射的主要材质
const bgFBO = new kokomi.FBO(this, { width: window.innerWidth * 0.1, height: window.innerHeight * 0.1,});rainMat.uniforms.uBgRt.value = bgFBO.rt.texture;const fboCamera = this.camera.clone();this.update(() => { rain.visible = false; this.renderer.setRenderTarget(bgFBO.rt); this.renderer.render(this.scene, fboCamera); this.renderer.setRenderTarget(null); rain.visible = true;});
在顶点着色器中获取屏幕空间vScreenspace
// https://github.com/Samsy/glsl-screenspacevec2 screenspace(mat4 projectionmatrix,mat4 modelviewmatrix,vec3 position){ vec4 temp=projectionmatrix*modelviewmatrix*vec4(position,1.); temp.xyz/=temp.w; temp.xy=(.5)+(temp.xy)*.5; return temp.xy;}vScreenspace=screenspace(projectionMatrix,modelViewMatrix,transformed);
在片元着色器中采样反射材质
uniform sampler2D uNormalTexture;uniform sampler2D uBgRt;uniform float uRefraction;uniform float uBaseBrightness;varying vec2 vScreenspace;void main(){ vec2 p=vUv; vec4 normalColor=texture(uNormalTexture,p); if(normalColor.a<.5){ discard; } vec3 normal=normalize(normalColor.rgb); vec2 bgUv=vScreenspace+normal.xy*uRefraction; vec4 bgColor=texture(uBgRt,bgUv); float brightness=uBaseBrightness*pow(normal.b,10.); vec3 col=bgColor.rgb+vec3(brightness); col=vec3(p,0.); gl_FragColor=vec4(col,1.);}
这里有一点要注意:积水地面中要把雨滴的反射去掉,不然会看着很乱
rainFloor.mirror.ignoreObjects.push(rain);
灯光闪烁
用setInterval
来间歇地设置文字和灯光材质的颜色即可
// flickerconst turnOffLight = () => { tm.material.color.copy(new THREE.Color("black")); pointLight1.color.copy(new THREE.Color("black"));};const turnOnLight = () => { tm.material.color.copy(new THREE.Color(config.color)); pointLight1.color.copy(new THREE.Color(config.color));};let flickerTimer = null;const flicker = () => { flickerTimer = setInterval(async () => { const rate = Math.random(); if (rate < 0.5) { turnOffLight(); await kokomi.sleep(200 * Math.random()); turnOnLight(); await kokomi.sleep(200 * Math.random()); turnOffLight(); await kokomi.sleep(200 * Math.random()); turnOnLight(); } }, 3000);};flicker();
后期处理
为了让文字灯光看上去更加明亮,可以用Bloom
滤镜来照亮文字
由于后期处理中原先renderer的抗锯齿会失效,故用SMAA
滤镜来实现抗锯齿
// postprocessingconst composer = new POSTPROCESSING.EffectComposer(this.renderer);this.composer = composer;composer.addPass(new POSTPROCESSING.RenderPass(this.scene, this.camera));// bloomconst bloom = new POSTPROCESSING.BloomEffect({ luminanceThreshold: 0.4, luminanceSmoothing: 0, mipmapBlur: true, intensity: 2, radius: 0.4,});composer.addPass(new POSTPROCESSING.EffectPass(this.camera, bloom));// antialiasingconst smaa = new POSTPROCESSING.SMAAEffect();composer.addPass(new POSTPROCESSING.EffectPass(this.camera, smaa));
待优化
效果算是基本实现了,但也有很多待优化的点
- 添加现实中的雨声
- 实现更棒的相机交互
- 添加更多的物体
本文转载于:
https://juejin.cn/post/7200443454567137336
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
关键词:
世界微速讯:记一次若依后台管理系统渗透
焦点!记录--用three.js渲染真实的下雨效果
傲软录屏工具使用教程(附工具亲测有效!!!)
天天视点!国际货币基金组织敦促黎巴嫩加快改革以启动一揽子救助计划
全球简讯:论文阅读笔记(五):Hire-MLP Vision MLP via Hierarchical Rearrangement
【焦点热闻】73.迭代器
环球观察:[vue] 脚手架笔记
世界动态:别让疲劳成为你的最后一程路:如何避免驾驶疲劳?丨曼孚科技
前沿资讯!L2-040 哲哲打游戏
每日快看:【新华500】新华500指数(989001)24日跌0.29%
谷歌回应Bard内容“抄袭”:插入链接会打断对话
快资讯丨浙江2人遭雷击不幸身亡 急救中心发布雷雨天出行提示
0糖0脂肪 丘里福建大红袍、铁观音茶饮闭眼囤:券后6瓶15.8元
天天新动态:最远能跑333km 五菱缤果官宣3月29日上市:7万交个朋友?
认真做优化 Intel显卡驱动容量减少一半:从1.3GB降至0.6GB
天天速递!全国跳水冠军赛:昌雅妮成为女子3米板“双冠王 ”
环球快讯:MySQL错误ERROR 2003 (HY000) Can't connect to MySQL server .' (111)
CSP20230319-4 星际网络II 题解
焦点信息:DNF远古地下城怎么开
天天观点:抵制汽车行业网络水军!比亚迪、长城、蔚小理等发起联合倡议
萤石TV Studio发布:接管电视“大脑” 让一屏秒变三屏!
【世界快播报】灯座安装即插即用:萤石发布4G款灯座云台摄像机C8b
环球新动态:比亚迪宋Pro DM-i 2023款实车曝光:前脸大变 加长加高
【全球新视野】2023第三届大湾区数字峰会在广州召开
环球快看点丨开心档之Go 语言数据类型
C#中?.、??、?:、及?等符号用途
看热讯:泛型的学习
关于工作态度和责任心的句子有哪些?工作态度自我评价模板
燃野少年的天空老狗最后和谁在一起了?燃野少年的天空演员表
春联横批是从左到右还是从右到左?通用的春联横批大全
大玉儿是不是孝庄太后?大玉儿爱多尔衮还是皇太极?
郭晓婷和袁弘是什么关系?郭晓婷演过的电视剧有哪些?
比亚迪新专利获授权 通过手背静脉识别控制车辆
当前滚动:玩家搜集信息拼凑《GTA6》地图:比洛圣都要大3倍
腾讯把《和平精英》里的技术引入输入法和地图 1700万人受益
HTTP请求方法
每日聚焦:RTX 4080 Ti运行《暗黑破坏神4》变砖:暴雪与NVIIDIA进行联合调查
广州突降冰雹 车主晒特斯拉玻璃车顶快被砸烂
中国电竞酒店突破2万家:西安郑州最多 玩家不止玩游戏
13代标压i5还有军工级品质!华硕a豆14 2023笔记本评测:智能远控 直击痛点
被曝垃圾桶捞回食材上桌!网红店半天妖发布致歉声明
全球快讯:2023年八字运势查询 乙酉日柱事业好
环球快资讯:SaaS 营销,如何利用 RPA 实现自动化获客?
全球视点!保姆级教程!玩转 ChunJun 详细指南
python入门语法
灵感来自中国:俄罗斯电视台首次推出AI女主播
全球关注:“大嫂”高叶代言!《原始征途》手游公测:史玉柱亲自研发
每日快看:碳酸锂价格暴跌一半!特斯拉还会再降价?
环球要闻:支付宝首页能直接刷短视频了 新增“看一看”入口
票房全球第三 《阿凡达2》4K高清资源偷跑:容量13GB
2023江苏连云港市考试录用公安机关特殊专技职位公务员(人民警察)入围技能测试人选公告
热头条丨Lunabot让你在任何网站都能使用ChatGPT(亲测有效!!!)
世界微头条丨高铁餐食又上新了:星级酒店烹饪 30分钟极速送达 还是热的
世界观天下!半价大促:五芳斋豆沙青团6枚9.9元到手 清甜绵软
快消息!特斯拉Model 3标准续航版或失7500美元税收优惠:只因用了中国电池
全球观天下!本田大法还香吗?全新紧凑型SUV车型HR-V量产下线:或16万起售
当前短讯!索赔近2万维修费!老人故意推倒摩托车案今日开庭:车主起诉继承人
浙江铁塔为结对帮扶村送医送药暖民心
数据库系统原理之数据库设计
世界时讯:安全高效 | AIRIOT智慧工地管理解决方案
世界今头条!ChatGPT王炸更新!能联网获取新知识、可与5000+个应用交互:太疯狂了
国产科幻FPS大作来了!《边境》官宣4月14日正式发售
全球热资讯!深圳一兰博基尼车头被教练车撞瘪 驾校:车上有一学员
国光电器:计划年内推出搭载类GPT硬件产品
【报资讯】读C#代码整洁之道笔记05_使用工具改善代码和单元测试
SaaS 营销怎么做?几点思考
Bitmap、RoaringBitmap原理分析
焦点快播:【金融街发布】人民银行上海总部:2月长三角地区人民币贷款增加6039亿元
大V实测百度AI画图:输入“刘慈欣” 打死也想不出画的是啥
每日时讯!海底捞回应孕妇可以插队:目前仅黑海会员有排队优先权益
当前滚动:中国移动:2023年营收将突破1万亿 利润或有史以来最高
当前观点:【新华财经调查】大全能源“逆势”扩产近两倍 坦陈今年终端需求不确定性较大
全球实时:德媒:纳格尔斯曼昨天还在与女友一起度假,今天就面临下课
ChatGPT又一个重磅功能插件系统上线 胡说八道的毛病治好了
焦点短讯!电影《铃芽之旅》预售票房破亿:3月24日上映
不速之约电视剧剧情
当前要闻:读Java性能权威指南(第2版)笔记26_性能测试方法下
前沿资讯!美国智库:25%美成年人吃不饱饭 很多人应急储蓄不足500美元
快播:crackme002-abexcm5
理想MPV预告图泄露 李想微博回应 还有5款纯电车型
微星发布第二款不用风扇的PCIe 5.0 SSD:又是尴尬的残血
贾跃亭真成了 法拉第未来宣布:FF 91将于3月30日开始生产
《CS》终于迎来一波超级大更新:有倒爷一晚上赚了几十万!
【天天聚看点】又吵上了热搜:网友称海底捞水果仅限打包一份
今年又有多少让人扶额的青团?
世界最资讯丨商务部:美方应尽早取消对华加征的301关税
每日时讯!5 Why 分析法,一种用于归纳抽象出解决方案的好方法
环球视点!day11-2-内置Tomcat的配置和切换
微服务实用篇--学习笔记
全球今日报丨C++ 标准库 sort() / stable_sort() / partial_sort() 对比
天天快讯:Docker 开始清退开源组织,不付费就删除所有私镜像怎么看
《暗黑破坏神4》B测神优化!N多RTX 3080 Ti惨遭黑屏变砖 暴雪:概不负责
天天新消息丨737 Max客机空难致346人丧生 波音最新表态:速度过快 乘客毫无痛苦地死去
海外爆发迄今最严峻禽流感疫情:专家详解
世界热点评!AMD终于能享受192GB内存了!连跑2小时0错误
当前热文:72.标准库类型vector
React的生命周期
关于使用AWS的CDN-CloudFront的费用计算及说明
全球即时:【财经分析】美联储连续第九次加息 抗通胀仍是主旋律
特斯拉一“咳嗽”:国内汽车行业加速洗牌了