three.jsアニメーション効果を実現するための例コード
前言
こんにちは、ここはCSS魔法使いのalphardexです。
本論文ではthree.jsを用いて,非常にクールな光学効果を実現する。私たちは、露が一つの物体の表面から滴り落ちると、粘着効果があることを知っています。2 D平面では,この接着効果はcssフィルタを用いると簡単に実現できる。しかし、3 D世界になると、そんなに簡単ではありません。この時は光照射によって実現しなければなりません。その中には重要なアルゴリズムがあります。光のステップ(Ray Marching)があります。以下は最終実現の効果図です。
撒き、ハジマルート!
準備工作
著者のthree.jsテンプレート:右下のforkをクリックしてコピーできます。
正面の映画
フルスクリーンカメラ
まずカメラを直交カメラに変えて、平面の長さを2に調整して、スクリーンを埋めます。
材質を作成
発色器の材質を作成しました。中には発色器に渡すすべてのパラメータが定義されています。
重点はパッチ測色器
パッチ
背景
ウォーミングアップとして、まず放射状の背景を作りましょう。
sdf
光照射モデルで物体を作るにはどうすればいいですか?私たちはsdfが必要です。
sdfとは、シンボル距離関数を意味します。関数空間の中のある座標に伝達すると、その点といくつかの平面との間の最短距離を返します。戻り値の記号表示点は平面の内部ですか?それとも外部ですか?だから、シンボル距離関数と呼びます。
ボールを作るなら、ボールのsdfで作らなければなりません。球方程式は以下のglslコードで表現できます。
sdfで先に正方形を作成します。
光のステップ
続いて本文の一番上の人物です。光の歩みです。彼女を紹介する前に、私達は先に彼女の良い姫の友達の光線の追跡を見にきましょう。
まず、光線追跡がどのように行われているかを知る必要がある。カメラの位置
光のステップでは、シーン全体が一連のsdfの角度で定義されます。シーンと視線の境界を見つけるために、カメラの位置から放射線に沿って少しずつ移動します。この点はシーンのある面の中にないと判断します。もし完成すれば、光が何かに当たるということを表します。
上の図のp 0はカメラの位置で、青い線は放射線を表しています。光の最初のステップp 0 p 1は非常に大きいことが分かります。これもちょうどこの時光が表面までの最短距離です。表面の点は最短距離であっても、視線の方向に沿っていないので、p 4という点を引き続き検出します。
sharadtoyにインタラクティブな例があります。
以下は光のステップのglslコードの実現です。
光の歩みに誘われて、野生の方形が現れた。
中央揃え
現在の正方形には2つの問題があります。1.中央にない2.x軸方向に引っ張られています。
中央に立つ+ストレッチの素質の2は続けて歩きます。
ボックスは画面の真ん中に一瞬で飛んできたが、まだ色がない。
表面法線の計算
光照射モデルでは、表面法線を計算して、材質に色を与える必要があります。
この時、四角は青色を与えられましたが、彼女は立体図形とは見えません。
動き始める
正方形360°を回転させましょう。3 D回転関数は直接gistの上で検索すればいいです。
融合効果
ただの四角形は寂しすぎます。ボールを作って彼女のお供をしましょう。
どのようにボールとブロックをくっつけますか?smainの関数が必要です。
動的融合
次は露が滴り落ちるアニメが実現しました。実は融合パターンにシフト変換を適用しました。
matcapスタンプ
デフォルトの材質はダサいですか?かっこいいマップがあります。応援します。
matcapとフレネルの公式を手配した後、瞬間coolはありますか?
プロジェクトのアドレス
Ray Marching Gooey Effect
以上で、three.jsが露の滴り落ちるアニメーション効果を実現するためのコード例についての記事を紹介しました。これに関連して、three.jsが露の滴り落ちるアニメーションの内容を実現します。以前の記事を検索してください。または、下記の関連記事を引き続きご覧ください。これからもよろしくお願いします。
こんにちは、ここはCSS魔法使いのalphardexです。
本論文ではthree.jsを用いて,非常にクールな光学効果を実現する。私たちは、露が一つの物体の表面から滴り落ちると、粘着効果があることを知っています。2 D平面では,この接着効果はcssフィルタを用いると簡単に実現できる。しかし、3 D世界になると、そんなに簡単ではありません。この時は光照射によって実現しなければなりません。その中には重要なアルゴリズムがあります。光のステップ(Ray Marching)があります。以下は最終実現の効果図です。
撒き、ハジマルート!
準備工作
著者のthree.jsテンプレート:右下のforkをクリックしてコピーできます。
正面の映画
フルスクリーンカメラ
まずカメラを直交カメラに変えて、平面の長さを2に調整して、スクリーンを埋めます。
class RayMarching extends Base {
constructor(sel: string, debug: boolean) {
super(sel, debug);
this.clock = new THREE.Clock();
this.cameraPosition = new THREE.Vector3(0, 0, 0);
this.orthographicCameraParams = {
left: -1,
right: 1,
top: 1,
bottom: -1,
near: 0,
far: 1,
zoom: 1
};
}
//
init() {
this.createScene();
this.createOrthographicCamera();
this.createRenderer();
this.createRayMarchingMaterial();
this.createPlane();
this.createLight();
this.trackMousePos();
this.addListeners();
this.setLoop();
}
//
createPlane() {
const geometry = new THREE.PlaneBufferGeometry(2, 2, 100, 100);
const material = this.rayMarchingMaterial;
this.createMesh({
geometry,
material
});
}
}
材質を作成
発色器の材質を作成しました。中には発色器に渡すすべてのパラメータが定義されています。
const matcapTextureUrl = "https://i.loli.net/2021/02/27/7zhBySIYxEqUFW3.png";
class RayMarching extends Base {
//
createRayMarchingMaterial() {
const loader = new THREE.TextureLoader();
const texture = loader.load(matcapTextureUrl);
const rayMarchingMaterial = new THREE.ShaderMaterial({
vertexShader: rayMarchingVertexShader,
fragmentShader: rayMarchingFragmentShader,
side: THREE.DoubleSide,
uniforms: {
uTime: {
value: 0
},
uMouse: {
value: new THREE.Vector2(0, 0)
},
uResolution: {
value: new THREE.Vector2(window.innerWidth, window.innerHeight)
},
uTexture: {
value: texture
},
uProgress: {
value: 1
},
uVelocityBox: {
value: 0.25
},
uVelocitySphere: {
value: 0.5
},
uAngle: {
value: 1.5
},
uDistance: {
value: 1.2
}
}
});
this.rayMarchingMaterial = rayMarchingMaterial;
}
}
頂点着色器rayMarchingVertexShader
、これはテンプレートで既製のものであれば大丈夫です。重点はパッチ測色器
rayMarchingFragmentShader
です。パッチ
背景
ウォーミングアップとして、まず放射状の背景を作りましょう。
varying vec2 vUv;
vec3 background(vec2 uv){
float dist=length(uv-vec2(.5));
vec3 bg=mix(vec3(.3),vec3(.0),dist);
return bg;
}
void main(){
vec3 bg=background(vUv);
vec3 color=bg;
gl_FragColor=vec4(color,1.);
}
sdf
光照射モデルで物体を作るにはどうすればいいですか?私たちはsdfが必要です。
sdfとは、シンボル距離関数を意味します。関数空間の中のある座標に伝達すると、その点といくつかの平面との間の最短距離を返します。戻り値の記号表示点は平面の内部ですか?それとも外部ですか?だから、シンボル距離関数と呼びます。
ボールを作るなら、ボールのsdfで作らなければなりません。球方程式は以下のglslコードで表現できます。
float sdSphere(vec3 p,float r)
{
return length(p)-r;
}
ブロックのコードは以下の通りです。
float sdBox(vec3 p,vec3 b)
{
vec3 q=abs(p)-b;
return length(max(q,0.))+min(max(q.x,max(q.y,q.z)),0.);
}
分かりませんが、どうすればいいですか?大丈夫です。海外にはすでに大牛がいます。一般的なsdf公式を全部まとめました。sdfで先に正方形を作成します。
float sdf(vec3 p){
float box=sdBox(p,vec3(.3));
return box;
}
画面はまだ真っ白です。ゲストの光はまだ入場していません。光のステップ
続いて本文の一番上の人物です。光の歩みです。彼女を紹介する前に、私達は先に彼女の良い姫の友達の光線の追跡を見にきましょう。
まず、光線追跡がどのように行われているかを知る必要がある。カメラの位置
eye
に、前に目盛線を置き、カメラの位置からビームray
を放射し、物体にグリッドを通して、像の各ピクセルはグリッド上の各点に対応している。光のステップでは、シーン全体が一連のsdfの角度で定義されます。シーンと視線の境界を見つけるために、カメラの位置から放射線に沿って少しずつ移動します。この点はシーンのある面の中にないと判断します。もし完成すれば、光が何かに当たるということを表します。
上の図のp 0はカメラの位置で、青い線は放射線を表しています。光の最初のステップp 0 p 1は非常に大きいことが分かります。これもちょうどこの時光が表面までの最短距離です。表面の点は最短距離であっても、視線の方向に沿っていないので、p 4という点を引き続き検出します。
sharadtoyにインタラクティブな例があります。
以下は光のステップのglslコードの実現です。
const float EPSILON=.0001;
float rayMarch(vec3 eye,vec3 ray,float end,int maxIter){
float depth=0.;
for(int i=0;i<maxIter;i++){
vec3 pos=eye+depth*ray;
float dist=sdf(pos);
depth+=dist;
if(dist<EPSILON||dist>=end){
break;
}
}
return depth;
}
主関数で放射線を作成し、それを光のステップアルゴリズムに供給すると、光から表面までの最短距離が得られます。
void main(){
...
vec3 eye=vec3(0.,0.,2.5);
vec3 ray=normalize(vec3(vUv,-eye.z));
float end=5.;
int maxIter=256;
float depth=rayMarch(eye,ray,end,maxIter);
if(depth<end){
vec3 pos=eye+depth*ray;
color=pos;
}
...
}
光の歩みに誘われて、野生の方形が現れた。
中央揃え
現在の正方形には2つの問題があります。1.中央にない2.x軸方向に引っ張られています。
中央に立つ+ストレッチの素質の2は続けて歩きます。
vec2 centerUv(vec2 uv){
uv=2.*uv-1.;
float aspect=uResolution.x/uResolution.y;
uv.x*=aspect;
return uv;
}
void main(){
...
vec2 cUv=centerUv(vUv);
vec3 ray=normalize(vec3(cUv,-eye.z));
...
}
ボックスは画面の真ん中に一瞬で飛んできたが、まだ色がない。
表面法線の計算
光照射モデルでは、表面法線を計算して、材質に色を与える必要があります。
vec3 calcNormal(in vec3 p)
{
const float eps=.0001;
const vec2 h=vec2(eps,0);
return normalize(vec3(sdf(p+h.xyy)-sdf(p-h.xyy),
sdf(p+h.yxy)-sdf(p-h.yxy),
sdf(p+h.yyx)-sdf(p-h.yyx)));
}
void main(){
...
if(depth<end){
vec3 pos=eye+depth*ray;
vec3 normal=calcNormal(pos);
color=normal;
}
...
}
この時、四角は青色を与えられましたが、彼女は立体図形とは見えません。
動き始める
正方形360°を回転させましょう。3 D回転関数は直接gistの上で検索すればいいです。
uniform float uVelocityBox;
mat4 rotationMatrix(vec3 axis,float angle){
axis=normalize(axis);
float s=sin(angle);
float c=cos(angle);
float oc=1.-c;
return 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 rotate(vec3 v,vec3 axis,float angle){
mat4 m=rotationMatrix(axis,angle);
return(m*vec4(v,1.)).xyz;
}
float sdf(vec3 p){
vec3 p1=rotate(p,vec3(1.),uTime*uVelocityBox);
float box=sdBox(p1,vec3(.3));
return box;
}
融合効果
ただの四角形は寂しすぎます。ボールを作って彼女のお供をしましょう。
どのようにボールとブロックをくっつけますか?smainの関数が必要です。
uniform float uProgress;
float smin(float a,float b,float k)
{
float h=clamp(.5+.5*(b-a)/k,0.,1.);
return mix(b,a,h)-k*h*(1.-h);
}
float sdf(vec3 p){
vec3 p1=rotate(p,vec3(1.),uTime*uVelocityBox);
float box=sdBox(p1,vec3(.3));
float sphere=sdSphere(p,.3);
float sBox=smin(box,sphere,.3);
float mixedBox=mix(sBox,box,uProgress);
return mixedBox;
}
uProgress
の値を0に設定して、彼女たちは成功的にくっつきました。uProgress
の値を1に戻して、彼女たちはまた別れました。動的融合
次は露が滴り落ちるアニメが実現しました。実は融合パターンにシフト変換を適用しました。
uniform float uAngle;
uniform float uDistance;
uniform float uVelocitySphere;
const float PI=3.14159265359;
float movingSphere(vec3 p,float shape){
float rad=uAngle*PI;
vec3 pos=vec3(cos(rad),sin(rad),0.)*uDistance;
vec3 displacement=pos*fract(uTime*uVelocitySphere);
float gotoCenter=sdSphere(p-displacement,.1);
return smin(shape,gotoCenter,.3);
}
float sdf(vec3 p){
vec3 p1=rotate(p,vec3(1.),uTime*uVelocityBox);
float box=sdBox(p1,vec3(.3));
float sphere=sdSphere(p,.3);
float sBox=smin(box,sphere,.3);
float mixedBox=mix(sBox,box,uProgress);
mixedBox=movingSphere(p,mixedBox);
return mixedBox;
}
matcapスタンプ
デフォルトの材質はダサいですか?かっこいいマップがあります。応援します。
uniform sampler2D uTexture;
vec2 matcap(vec3 eye,vec3 normal){
vec3 reflected=reflect(eye,normal);
float m=2.8284271247461903*sqrt(reflected.z+1.);
return reflected.xy/m+.5;
}
float fresnel(float bias,float scale,float power,vec3 I,vec3 N)
{
return bias+scale*pow(1.+dot(I,N),power);
}
void main(){
...
if(depth<end){
vec3 pos=eye+depth*ray;
vec3 normal=calcNormal(pos);
vec2 matcapUv=matcap(ray,normal);
color=texture2D(uTexture,matcapUv).rgb;
float F=fresnel(0.,.4,3.2,ray,normal);
color=mix(color,bg,F);
}
...
}
matcapとフレネルの公式を手配した後、瞬間coolはありますか?
プロジェクトのアドレス
Ray Marching Gooey Effect
以上で、three.jsが露の滴り落ちるアニメーション効果を実現するためのコード例についての記事を紹介しました。これに関連して、three.jsが露の滴り落ちるアニメーションの内容を実現します。以前の記事を検索してください。または、下記の関連記事を引き続きご覧ください。これからもよろしくお願いします。