<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          three.js 實現(xiàn)火花特效

          共 5424字,需瀏覽 11分鐘

           ·

          2021-10-18 11:52

          推薦關(guān)注↓

          前言

          大家好,這里是 CSS兼WebGL 魔法使——alphardex。

          上周末剛在原神里抽到了“火花騎士”可莉,于是就心血來潮,想用three.js來實現(xiàn)一種火系的特效,不是炸彈的爆炸,而是炸彈爆炸后在草上留下的火花效果

          ![RBvmVJ.jpg](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f50a053a9eb94d2889d73e6a334b66a3~tplv-k3u1fbpfcp-zoom-1.image)[2]

          游戲里的效果相對比較卡通化,而本文的效果將更加逼近現(xiàn)實一點

          讓我們開始吧!

          準備工作

          在開始本項目之前,你首先要了解ray marching這個概念,掌握了基礎(chǔ)概念后就可以開始了

          本項目需要用到:

          筆者的three.js模板:https://codepen.io/alphardex/pen/yLaQdOq

          著色器模塊化:glslify?https://github.com/glslify/glslify

          著色器npm包:glsl-noise,glsl-sdf-primitives,glsl-sdf-ops

          正文

          場景搭建

          按之前的慣例,搭建一個場景,放一個鋪滿屏幕的平面,設(shè)定一些必要的參數(shù)(火花的速度與顏色)

          class?RayMarchingFire?extends?Base?{
          ??constructor(sel:?string,?debug:?boolean)?{
          ????super(sel,?debug);
          ????this.clock?=?new?THREE.Clock();
          ????this.cameraPosition?=?new?THREE.Vector3(0,?0,?1);
          ????this.params?=?{
          ??????velocity:?2,
          ????};
          ????this.colorParams?=?{
          ??????color1:?"#ff801a",
          ??????color2:?"#ff5718",
          ????};
          ??}
          ??//?初始化
          ??init()?{
          ????this.createScene();
          ????this.createOrthographicCamera();
          ????this.createRenderer();
          ????this.createRayMarchingFireMaterial();
          ????this.createPlane();
          ????this.createLight();
          ????this.trackMousePos();
          ????this.addListeners();
          ????this.setLoop();
          ??}
          ??//?創(chuàng)建材質(zhì)
          ??createRayMarchingFireMaterial()?{
          ????const?rayMarchingFireMaterial?=?new?THREE.ShaderMaterial({
          ??????vertexShader:?rayMarchingFireVertexShader,
          ??????fragmentShader:?rayMarchingFireFragmentShader,
          ??????side:?THREE.DoubleSide,
          ??????uniforms:?{
          ????????uTime:?{
          ??????????value:?0,
          ????????},
          ????????uMouse:?{
          ??????????value:?new?THREE.Vector2(0,?0),
          ????????},
          ????????uResolution:?{
          ??????????value:?new?THREE.Vector2(window.innerWidth,?window.innerHeight),
          ????????},
          ????????uVelocity:?{
          ??????????value:?3,
          ????????},
          ????????uColor1:?{
          ??????????value:?new?THREE.Color(this.colorParams.color1),
          ????????},
          ????????uColor2:?{
          ??????????value:?new?THREE.Color(this.colorParams.color2),
          ????????},
          ??????},
          ????});
          ????this.rayMarchingFireMaterial?=?rayMarchingFireMaterial;
          ????this.shaderMaterial?=?rayMarchingFireMaterial;
          ??}
          ??//?創(chuàng)建平面
          ??createPlane()?{
          ????const?geometry?=?new?THREE.PlaneBufferGeometry(2,?2,?100,?100);
          ????const?material?=?this.rayMarchingFireMaterial;
          ????this.createMesh({
          ??????geometry,
          ??????material,
          ????});
          ??}
          ??//?動畫
          ??update()?{
          ????const?elapsedTime?=?this.clock.getElapsedTime();
          ????const?mousePos?=?this.mousePos;
          ????if?(this.rayMarchingFireMaterial)?{
          ??????this.rayMarchingFireMaterial.uniforms.uTime.value?=?elapsedTime;
          ??????this.rayMarchingFireMaterial.uniforms.uMouse.value?=?mousePos;
          ????}
          ??}
          }

          接下來開始編寫片元著色器

          創(chuàng)建發(fā)光漸變橢圓

          仔細觀察火花的形狀你會發(fā)現(xiàn)其實它的大致形狀像一個橢圓,而且還是發(fā)光的漸變橢圓,于是我們就要想辦法來創(chuàng)建這種形狀。簡要說下思路:ray marching獲取的值改成光線位置pos和光線移動的進度strength,光線位置的y軸將用于設(shè)定火花的顏色;光線移動的進度strength用于設(shè)定火花的形狀(這里就是橢圓)

          #pragma glslify:centerUv=require(../modules/centerUv)
          #pragma glslify:getRayDirection=require(../modules/getRayDirection)
          #pragma glslify:sdSphere=require(glsl-sdf-primitives/sdSphere)
          #pragma glslify:opU=require(glsl-sdf-ops/union)
          #pragma glslify:cnoise=require(glsl-noise/classic/3d)

          uniform float uTime;
          uniform vec2 uMouse;
          uniform vec2 uResolution;
          uniform float uVelocity;
          uniform vec3 uColor1;
          uniform vec3 uColor2;

          varying vec2 vUv;
          varying vec3 vPosition;

          float fire(vec3 p){
          vec3 p2=p*vec3(1.,.5,1.)+vec3(0.,1.,0.);
          float geo=sdSphere(p2,1.);
          float result=geo;
          return result;
          }

          vec2 sdf(vec3 p){
          float result=opU(abs(fire(p)),-(length(p)-100.));
          float objType=1.;
          return vec2(result,objType);
          }

          vec4 rayMarch(vec3 eye,vec3 ray){
          float depth=0.;
          float strength=0.;
          float eps=.02;
          vec3 pos=eye;
          for(int i=0;i<64;i++){
          pos+=depth*ray;
          float dist=sdf(pos).x;
          depth=dist+eps;
          if(dist>0.){
          strength=float(i)/64.;
          }
          }
          return vec4(pos,strength);
          }

          void main(){
          vec2 p=centerUv(vUv,uResolution);
          p=p*vec2(1.6,-1);

          vec3 ro=vec3(0.,-2.,4.);
          vec3 ta=vec3(0.,-2.5,-1.5);
          float fl=1.25;
          vec3 rd=getRayDirection(p,ro,ta,fl);

          vec3 color=vec3(0.);

          vec4 result=rayMarch(ro,rd);

          float strength=pow(result.w*2.,4.);
          vec3 ellipse=vec3(strength);
          color=ellipse;

          gl_FragColor=vec4(color,1.);
          }

          centerUv.glsl

          vec2 centerUv(vec2 uv,vec2 resolution){
          uv=2.*uv-1.;
          float aspect=resolution.x/resolution.y;
          uv.x*=aspect;
          return uv;
          }

          #pragma glslify:export(centerUv);

          getRayDirection.glsl

          #pragma glslify:setCamera=require(./setCamera)

          vec3 getRayDirection(vec2 p,vec3 ro,vec3 ta,float fl){
          mat3 ca=setCamera(ro,ta,0.);
          vec3 rd=ca*normalize(vec3(p,fl));
          return rd;
          }

          #pragma glslify:export(getRayDirection)

          setCamera.glsl

          mat3 setCamera(in vec3 ro,in vec3 ta,float cr)
          {
          vec3 cw=normalize(ta-ro);
          vec3 cp=vec3(sin(cr),cos(cr),0.);
          vec3 cu=normalize(cross(cw,cp));
          vec3 cv=(cross(cu,cw));
          return mat3(cu,cv,cw);
          }

          #pragma glslify:export(setCamera)

          用噪聲生成火花

          接下來就對這個橢圓應(yīng)用上噪聲(這里選了傳統(tǒng)噪聲,為了更好看的外觀,也可以選擇其他的噪聲)

          float fire(vec3 p){
          vec3 p2=p*vec3(1.,.5,1.)+vec3(0.,1.,0.);
          float geo=sdSphere(p2,1.);
          // float result=geo;
          float displacement=uTime*uVelocity;
          vec3 displacementY=vec3(.0,displacement,.0);
          float noise=(cnoise(p+displacementY))*p.y*.4;
          float result=geo+noise;
          return result;
          }

          莫名感覺像黑魂3里的芙莉德修女的黑焰,盡管這樣也很cool,我們還是給它加上顏色,讓它更像現(xiàn)實中的火花

          給火花加上顏色

          將顏色通過mix函數(shù)混合起來(強度是光線位置的y軸),和之前的顏色相乘即可

          void main(){
          ...

          float fireBody=result.y/64.;
          vec3 mixColor=mix(uColor1,uColor2,fireBody);
          color*=mixColor;

          gl_FragColor=vec4(color,1.);
          }

          項目地址

          Ray Marching Fire:https://codepen.io/alphardex/pen/OJmPpeJ


          作者:alphardex

          https://juejin.cn/post/6979744391074316319

          瀏覽 45
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美X X888做受 | 肏网| 天天好逼亚洲综合 | 日本无码中文字幕 | 北京老太HD大全 |