序文みなさんこんにちは。CSS ウィザードの alphardex です。 この記事では、three.js を使用して、落ちる露滴というクールな光学効果を実装します。物体の表面から露が落ちると、粘着性が生じることはよく知られています。 2D 平面では、この接着効果は CSS フィルターを使用して実際に簡単に実現できます。しかし、3D の世界では、それはそれほど単純ではありません。これを実現するには、レイ マーチングという重要なアルゴリズムを伴う照明に頼る必要があります。以下は最終的な効果図です 撃て、拝島ルート! 準備私の three.js テンプレート: 右下のフォークをクリックしてコピーします ポジティブフルスクリーンカメラ まず、カメラを正投影カメラに変更し、平面の長さを 2 に調整して画面いっぱいに表示します。 クラスRayMarchingはBaseを拡張します{ コンストラクタ(sel: 文字列、debug: ブール値) { スーパー(sel、デバッグ); this.clock = 新しい THREE.Clock(); this.cameraPosition = 新しい THREE.Vector3(0, 0, 0); this.orthographicCameraParams = { 左: -1、 右: 1、 トップ: 1, 下: -1、 近く: 0, 遠い: 1, ズーム: 1 }; } // 初期化 init() { シーンを作成します。 this.createOrthographicCamera(); レンダラーを作成します。 this.createRayMarchingMaterial(); this.createPlane(); this.createLight(); this.trackMousePos(); リスナーを追加します。 ループを設定します。 } // 平面を作成する createPlane() { const ジオメトリ = 新しい THREE.PlaneBufferGeometry(2, 2, 100, 100); const マテリアル = this.rayMarchingMaterial; this.createMesh({ 幾何学、 材料 }); } } マテリアルの作成シェーダに渡されるすべてのパラメータを定義するシェーダマテリアルを作成します。 const matcapTextureUrl = "https://i.loli.net/2021/02/27/7zhBySIYxEqUFW3.png"; クラスRayMarchingはBaseを拡張します{ // レイトレーシングマテリアルを作成する createRayMarchingMaterial() { const ローダー = 新しい THREE.TextureLoader(); const テクスチャ = loader.load(matcapTextureUrl); const rayMarchingMaterial = 新しい THREE.ShaderMaterial({ 頂点シェーダー: rayMarchingVertexShader、 フラグメントシェーダー: rayMarchingFragmentShader、 サイド: THREE.DoubleSide、 制服: u時間: { 値: 0 }, uマウス: { 値: 新しい THREE.Vector2(0, 0) }, u解像度: 値: 新しい THREE.Vector2(window.innerWidth, window.innerHeight) }, uテクスチャ: { 値: テクスチャ }, 進捗状況: 値: 1 }, uVelocityBox: { 値: 0.25 }, uVelocitySphere: { 値: 0.5 }, u角度: 値: 1.5 }, u距離: 値: 1.2 } } }); this.rayMarchingMaterial = rayMarchingMaterial; } } 頂点シェーダ 焦点はフラグメントシェーダ フラグメントシェーダー背景 ウォーミングアップとして、光り輝く背景を作成しましょう。 変化するvec2 vUv; vec3背景(vec2 uv){ 浮動小数点数 = 長さ(uv-vec2(.5)); vec3 bg = mix(vec3(.3),vec3(.0),dist); bg を返します。 } void main(){ vec3 bg = 背景(vUv); vec3 色=bg; gl_FragColor = vec4(色,1.); } 自衛隊 照明モデルでオブジェクトを作成するにはどうすればいいですか?自衛隊が必要だ。 SDF は符号付き距離関数を意味します。関数空間内の座標が渡されると、その点とある平面との間の最短距離を返します。戻り値の符号は、点が平面の内側にあるか外側にあるかを示すため、符号付き距離関数と呼ばれます。 ボールを作成したい場合は、ボールの SDF を使用して作成する必要があります。球面方程式は次のGLSLコードで表現できる。 フロート sdSphere(vec3 p,フロート r) { 長さ(p)-rを返します。 } ブロックのコードは次のとおりです 浮動小数点ボックス(vec3 p,vec3 b) { vec3 q=abs(p)-b; 長さ(max(q,0.))+最小(max(qx,max(qy,qz)),0.)を返します。 } わからない場合はどうすればいいですか?問題ではない、海外ではすでに、一般的に使用されている自衛隊の公式を整理した専門家がいる。 まずSDFにブロックを作成する 浮動小数点数sdf(vec3 p){ フロートボックス=sdBox(p,vec3(.3)); 返品ボックス; } ゲストのライトさんがまだ入室していないため、画面はまだ空白です。 軽い足取り次は、この記事の目玉であるレイ ステッパーです。彼女を紹介する前に、彼女の良き友人であるレイ トレーシングについて見てみましょう。 まず、レイ トレーシングの仕組みを理解する必要があります。カメラに位置の レイマーチングでは、シーン全体が一連の SDF 角度によって定義されます。シーンと視線の境界を見つけるために、カメラの位置から始めて、光線に沿って各ポイントを少しずつ移動します。各ステップで、ポイントがシーンの表面内にあるかどうかを判断します。そうであれば、光線が何かに当たったことを示し、これで完了です。そうでない場合、光線は前進し続けます。 上図では、p0 はカメラの位置であり、青い線は光線を表しています。光の最初のステップ p0p1 が非常に大きく、これがこの時点で光から表面までの最短距離になっていることがわかります。表面上の点は最短距離ですが、視線に沿っていないため、点 p4 の検出を継続する必要があります。 shadertoyにインタラクティブな例があります 以下はレイマーチングのGLSLコード実装です。 定数フロートEPSILON=.0001; float rayMarch(vec3 eye,vec3 ray,float end,int maxIter){ 浮動小数点の深さ=0。; for(int i=0;i<maxIter;i++){ vec3 pos=目+深さ*光線; 浮動小数点数=sdf(pos); 深さ+=距離; if(dist<EPSILON||dist>=end){ 壊す; } } 深さを返します。 } メイン関数で光線を作成し、それを光線ステッピング アルゴリズムに渡して、光線から表面までの最短距離を取得します。 void main(){ ... vec3目 = vec3(0.,0.,2.5); vec3 ray = normalize(vec3(vUv,-eye.z)); フロート終了=5。; 整数最大反復回数 = 256; float depth=rayMarch(eye,ray,end,maxIter); if(深さ<終了){ vec3 pos=目+深さ*光線; 色=位置; } ... } 軽快なステップに誘われて、ワイルドブロックが登場! センター素材現在のブロックには2つの問題があります。1. 中央に配置されていない 2. x軸方向に伸びている センタリング+ストレッチ品質2段階 vec2 中心紫外線(vec2 紫外線){ uv=2.*uv-1.; フロートアスペクト=uResolution.x/uResolution.y; uv.x*=アスペクト; uv を返します。 } void main(){ ... vec2 cUv = centerUv (vUv); vec3 ray = normalize(vec3(cUv,-eye.z)); ... } 立方体は瞬時に画面の中央に浮かび上がったが、この時点では彼女には色はなかった。 表面法線の計算照明モデルでは、マテリアルの色を与えるために表面法線を計算する必要があります。 vec3 calcNormal(vec3 p 内) { 定数float eps = .0001; 定数vec2 h = vec2(eps,0); 正規化を返す(vec3(sdf(p+h.xyy)-sdf(ph.xyy), sdf(p+h.yxy)-sdf(ph.yxy)、 sdf(p+h.yyx)-sdf(ph.yyx))); } void main(){ ... if(深さ<終了){ vec3 pos=目+深さ*光線; vec3 正規分布 = calcNormal(pos); 色=通常; } ... } この時点では、立方体に青色が与えられていますが、まだ立体的な図形であることは分かりません。 動き出そう ブロックを360度回転させてみましょう。3D回転機能はgistで検索すると見つかります。 均一な float uVelocityBox; mat4回転行列(vec3軸、float角度){ 軸を正規化します。 s = sin(角度)を浮動小数点数化します。 フロート c=cos(角度); フロート oc=1.-c; mat4(oc*axis.x*axis.x+c,oc*axis.x*axis.y-axis.z*s,oc*axis.z*axis.x+axis.y*s,0., を返します。 oc*axis.x*axis.y+axis.z*s、oc*axis.y*axis.y+c、oc*axis.y*axis.z-axis.x*s、0.、 oc*axis.z*axis.x-axis.y*s、oc*axis.y*axis.z+axis.x*s、oc*axis.z*axis.z+c、0.、 0.,0.,0.,1.); } vec3 回転(vec3 v,vec3 軸,float 角度){ mat4 m=回転行列(軸、角度); 戻り値: m*vec4(v,1.)).xyz; } 浮動小数点数sdf(vec3 p){ vec3 p1 = rotate(p、vec3(1.)、uTime*uVelocityBox); フロートボックス=sdBox(p1,vec3(.3)); 返品ボックス; } 融合効果キューブ1つだけでは寂しすぎるので、一緒にいられるボールを作りましょう ボールとブロックをくっつけるにはどうすればいいでしょうか?smin関数が必要です ユニフォームフロート uProgress; フロートsmin(フロートa、フロートb、フロートk) { フロートh=クランプ(.5+.5*(ba)/k,0.,1.); mix(b,a,h)-k*h*(1.-h) を返します。 } 浮動小数点数sdf(vec3 p){ vec3 p1 = rotate(p、vec3(1.)、uTime*uVelocityBox); フロートボックス=sdBox(p1,vec3(.3)); 浮動小数点球=sdSphere(p,.3); float sBox=smin(ボックス、球、.3); float mixedBox=mix(sBox,box,uProgress); 混合ボックスを返します。 } ダイナミックフュージョン次に、結露が落ちるアニメーションを実現します。これは、実際には融合された形状に変位変換を適用します。 均一な float uAngle; 均一な float uDistance; 均一な float uVelocitySphere; 定数浮動小数点数 PI=3.14159265359; float movingSphere(vec3 p, float shape){ 浮動小数点rad=uAngle*PI; vec3 pos=vec3(cos(rad),sin(rad),0.)*u距離; vec3 変位 = pos*fract(uTime*uVelocitySphere); フロート gotoCenter=sdSphere(p-変位,.1); smin(shape,gotoCenter,.3) を返します。 } 浮動小数点数sdf(vec3 p){ vec3 p1 = rotate(p、vec3(1.)、uTime*uVelocityBox); フロートボックス=sdBox(p1,vec3(.3)); 浮動小数点球=sdSphere(p,.3); float sBox=smin(ボックス、球、.3); float mixedBox=mix(sBox,box,uProgress); 混合ボックス = movingSphere(p, 混合ボックス); 混合ボックスを返します。 } マットキャップマップ デフォルトのテクスチャは土っぽすぎますか?役に立つクールなマットキャップマップがあります 均一サンプラー2D uTexture; vec2 matcap(vec3 eye,vec3 normal){ vec3 反射 = reflect(eye,normal); 浮動小数点数 m=2.8284271247461903*sqrt(reflected.z+1.); reflected.xy/m+.5 を返します。 } float fresnel(float バイアス、float スケール、float パワー、vec3 I、vec3 N) { バイアス+スケール*pow(1.+dot(I,N),power)を返します。 } void main(){ ... if(深さ<終了){ vec3 pos=目+深さ*光線; vec3 正規分布 = calcNormal(pos); vec2 matcapUv = matcap(ray,normal); 色=texture2D(uTexture,matcapUv).rgb; float F=fresnel(0.,.4,3.2,ray,normal); 色=ミックス(色、背景、F); } ... } マットキャップとフレネル数式を並べると一気にかっこよくなりますよね? ! プロジェクトギャラリー レイ・マーチング・グーイ・エフェクト three.js で露滴アニメーション効果を実装するためのサンプルコードに関するこの記事はこれで終わりです。three.js で露滴アニメーションを実装するための関連コンテンツの詳細については、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後も 123WORDPRESS.COM を応援してください。 以下もご興味があるかもしれません:
|
>>: Windows プラットフォームでの MySQL のインストールと設定方法と注意事項
Tencent Cloud上に構築されたMySQLは、開発用コンピュータでNavicatを使用して...
この記事の例では、衝突検出を実装するためのjsの具体的なコードを参考までに共有しています。具体的な内...
目次序文SSHとは何かssh は何に使用されますか? sshの使い方ssh 再修正要約する序文ssh...
長期間稼働しているデータベースの場合、テーブルがストレージ領域を占有しすぎるという問題がよく発生しま...
実験環境最小限にインストールされた CentOS 7.3 仮想マシン基本環境を構成する1. ngin...
目次概要ハッシュプロパティホストプロパティホスト名属性Href属性起源のプロパティユーザー名とパスワ...
目次1minioはシンプル2 Dockerビルド minio 2.1 単一ノード2.2 マルチノード...
同僚から、停電のため MySQL インスタンスを起動できないという報告がありました。 innodb_...
Yahoo チームが書いた、ウェブサイトのパフォーマンス最適化に関する記事を読みました。この記事は...
これは新しいバージョンではもう不可能なようで、推奨されません。そうでない場合は、ソフト リンクを直接...
この記事では、Ubuntu 18.04 に Redis と phpredis 拡張機能をインストール...
昨日、VMware に CentOS7 をインストールしました。Tomcat パッケージを転送するた...
テクノロジーファンHTMLウェブページ、知っておくべきYouyou が開発した vue フロントエン...
1. 仮想環境はプロジェクトに従い、単一のプロジェクト用の仮想環境を作成します(Python 3.4...
この記事では、Linux yumを使用してmysql5.6をインストールする簡単な手順を参考までに紹...