VorwortHallo zusammen, hier ist der CSS-Assistent – alphardex. In diesem Artikel verwenden wir three.js, um einen coolen optischen Effekt zu implementieren – fallende Tautropfen. Wir wissen, dass ein klebriger Effekt entsteht, wenn Tautropfen von der Oberfläche eines Objekts fallen. In einer 2D-Ebene kann dieser Adhäsionseffekt tatsächlich leicht durch die Verwendung von CSS-Filtern erzielt werden. In der 3D-Welt ist es jedoch nicht so einfach. Um dies zu erreichen, müssen wir uns auf die Beleuchtung verlassen, die einen wichtigen Algorithmus beinhaltet - Ray Marching. Nachfolgend sehen Sie das endgültige Effektdiagramm Verdammt, Hajima-Route! VorbereitungMeine three.js-Vorlage: Klicken Sie unten rechts auf „Fork“, um eine Kopie zu erstellen. positivVollbildkamera Ändern Sie zunächst die Kamera in eine orthographische Kamera und passen Sie dann die Länge der Ebene auf 2 an, sodass sie den Bildschirm ausfüllt. Klasse RayMarching erweitert Base { Konstruktor(sel: string, debug: boolean) { super(sel, debug); diese.Uhr = neue DREI.Uhr(); diese.Kameraposition = neuer THREE.Vector3(0, 0, 0); diese.orthographicCameraParams = { links: -1, rechts: 1, oben: 1, unten: -1, in der Nähe von: 0, weit: 1, Zoom: 1 }; } // Initialisierung init() { dies.createScene(); dies.createOrthographicCamera(); dies.createRenderer(); dies.createRayMarchingMaterial(); dies.createPlane(); dies.createLight(); dies.trackMousePos(); dies.addListeners(); dies.setLoop(); } // Erstelle ein Flugzeug createPlane() { const Geometrie = neue THREE.PlaneBufferGeometry(2, 2, 100, 100); const material = this.rayMarchingMaterial; dies.createMesh({ Geometrie, Material }); } } Materialien erstellenErstellen Sie ein Shadermaterial, das alle Parameter definiert, die an den Shader übergeben werden sollen const matcapTextureUrl = "https://i.loli.net/2021/02/27/7zhBySIYxEqUFW3.png"; Klasse RayMarching erweitert Base { // Erstelle ein Raytracing-Material createRayMarchingMaterial() { const loader = neues THREE.TextureLoader(); const texture = loader.load(matcapTextureUrl); const rayMarchingMaterial = neues THREE.ShaderMaterial({ vertexShader: rayMarchingVertexShader, fragmentShader: rayMarchingFragmentShader, Seite: DREI.Doppelseite, Uniformen: uZeit: { Wert: 0 }, uMaus: { Wert: neuer THREE.Vector2(0, 0) }, uAuflösung: Wert: neuer THREE.Vector2(window.innerWidth, window.innerHeight) }, uTextur: { Wert: Textur }, uFortschritt: Wert: 1 }, uVelocityBox: { Wert: 0,25 }, uVelocitySphere: { Wert: 0,5 }, uWinkel: Wert: 1,5 }, uEntfernung: Wert: 1,2 } } }); dies.rayMarchingMaterial = rayMarchingMaterial; } } Vertex-Shader Der Fokus liegt auf dem Fragment-Shader Fragment-ShaderHintergrund Lassen Sie uns als Aufwärmübung einen strahlenden Hintergrund erstellen. variierender Veränderlicher Vektor 2 vUv; vec3 Hintergrund(vec2 uv){ float dist = Länge(uv-vec2(.5)); vec3 bg = mix(vec3(.3),vec3(.0),verteilt); Rückkehr bg; } void main(){ vec3 bg = Hintergrund(vUv); vec3 Farbe=Hintergrund; gl_FragColor = vec4(Farbe,1.); } sdf Wie erstelle ich Objekte im Beleuchtungsmodell? Wir brauchen SDF. SDF steht für vorzeichenbehaftete Distanzfunktion: Wenn eine Koordinate im Funktionsraum übergeben wird, gibt sie die kürzeste Distanz zwischen diesem Punkt und einer Ebene zurück. Das Vorzeichen des Rückgabewerts gibt an, ob der Punkt innerhalb oder außerhalb der Ebene liegt, daher wird sie als vorzeichenbehaftete Distanzfunktion bezeichnet. Wenn wir einen Ball erstellen möchten, müssen wir zur Erstellung die SDF des Balls verwenden. Die Kugelgleichung kann mit dem folgenden GLSl-Code ausgedrückt werden float sdSphere(vec3 p,float r) { Rückgabelänge (p)-r; } Der Code des Blocks lautet wie folgt Float sdBox(vec3 p, vec3 b) { vec3 q=abs(p)-b; Rückgabelänge (max(q,0.))+min(max(qx,max(qy,qz)),0.); } Was soll ich tun, wenn ich etwas nicht verstehe? Es spielt keine Rolle, es gibt bereits Experten im Ausland, die die gängigen SDF-Formeln aussortiert haben Erstellen Sie zuerst einen Block in SDF Gleitkommazahl sdf(vec3 p){ float-box=sdBox(p,vec3(.3)); Rücksendekarton; } Der Bildschirm ist noch leer, da unser Gast – Licht – noch nicht hereingekommen ist. Leichtes TretenAls nächstes kommt die Schlagzeile dieses Artikels – der Ray Stepper. Bevor wir sie vorstellen, werfen wir einen Blick auf ihren guten Freund, das Raytracing. Zunächst müssen wir wissen, wie Raytracing funktioniert: Man gibt der Kamera ein Beim Ray Marching wird die gesamte Szene durch eine Reihe von SDF-Winkeln definiert. Um die Grenze zwischen der Szene und der Sichtlinie zu finden, beginnen wir bei der Position der Kamera und bewegen jeden Punkt Stück für Stück entlang des Strahls. Bei jedem Schritt bestimmen wir, ob der Punkt innerhalb einer Oberfläche der Szene liegt. Wenn dies der Fall ist, sind wir fertig, was bedeutet, dass der Strahl auf etwas trifft. Wenn nicht, bewegt sich der Strahl weiter vorwärts. In der obigen Abbildung ist p0 die Kameraposition und die blaue Linie stellt den Strahl dar. Es ist ersichtlich, dass der erste Schritt p0p1 des Lichts sehr groß ist. Dies ist zufällig die kürzeste Entfernung vom Licht zur Oberfläche zu diesem Zeitpunkt. Obwohl der Punkt auf der Oberfläche die kürzeste Entfernung aufweist, liegt er nicht entlang der Sichtlinie. Daher müssen wir mit der Erkennung von Punkt p4 fortfahren. Es gibt ein interaktives Beispiel auf Shadertoy Nachfolgend sehen Sie die GLS-Codeimplementierung von Ray Marching Konstante Float EPSILON = .0001; float rayMarch(vec3 Auge,vec3 Strahl,float Ende,int maxIter){ Schwimmertiefe=0.; für(int i=0;i<maxIter;i++){ vec3 pos=Auge+Tiefe*Strahl; Float dist = sdf (pos); Tiefe+=Abstand; wenn(dist<EPSILON||dist>=Ende){ brechen; } } Rücklauftiefe; } Erstellen Sie in der Hauptfunktion einen Strahl und geben Sie ihn in den Strahlschrittalgorithmus ein, um die kürzeste Entfernung vom Strahl zur Oberfläche zu erhalten. void main(){ ... vec3 Auge = vec3(0.,0.,2.5); vec3 Strahl = normalisieren(vec3(vUv,-eye.z)); Gleitkommazahl Ende=5.; int maxIter=256; Float-Tiefe = RayMarch (Auge, Strahl, Ende, MaxIter); wenn(Tiefe<Ende){ vec3 pos=Auge+Tiefe*Strahl; Farbe=pos; } ... } Angelockt durch die leichten Schritte, erscheinen wilde Blöcke! MittelmaterialDer aktuelle Block hat zwei Probleme: 1. Er ist nicht zentriert. 2. Er ist in der x-Achsenrichtung gestreckt. Zentrierung + Dehnungsqualität 2 Schritte vec2 centerUv(vec2 uv){ uv=2.*uv-1.; Float-Aspekt = uResolution.x/uResolution.y; uv.x*=Aspekt; UV zurückgeben; } void main(){ ... vec2 cUv=centerUv(vUv); vec3 Strahl = normalisieren(vec3(cUv,-eye.z)); ... } Der Würfel schwebte sofort in die Mitte des Bildschirms, aber zu diesem Zeitpunkt hatte sie keine Farbe Berechnen von OberflächennormalenIm Beleuchtungsmodell müssen wir die Oberflächennormale berechnen, um dem Material Farbe zu geben vec3 calcNormal(in vec3 p) { Konstanten-Float eps = .0001; const vec2 h = vec2(eps,0); returniere normalisieren(vec3(sdf(p+h.xyy)-sdf(ph.xyy), sdf(p+h.yxy)-sdf(ph.yxy), sdf(p+h.yyx)-sdf(ph.yyx))); } void main(){ ... wenn(Tiefe<Ende){ vec3 pos=Auge+Tiefe*Strahl; vec3 normal = calcNormal(pos); Farbe=normal; } ... } Zu diesem Zeitpunkt erhält der Würfel eine blaue Farbe, wir können jedoch noch nicht erkennen, dass es sich um eine dreidimensionale Figur handelt. Bewegen Sie sich Lassen Sie uns den Block um 360 Grad drehen. Sie finden die 3D-Rotationsfunktion, indem Sie nach Gist suchen. einheitlicher Float uVelocityBox; mat4 rotationMatrix(vec3 Achse,Float Winkel){ Achse=normalisieren(Achse); float s=sin(Winkel); float c=cos(Winkel); Gleitkommazahl oc=1.-c; returniere mat4(oc*Achse.x*Achse.x+c,oc*Achse.x*Achse.y-Achse.z*s,oc*Achse.z*Achse.x+Achse.y*s,0., oc*Achse.x*Achse.y+Achse.z*s,oc*Achse.y*Achse.y+c,oc*Achse.y*Achse.z-Achse.x*s,0., oc*Achse.z*Achse.x-Achse.y*s,oc*Achse.y*Achse.z+Achse.x*s,oc*Achse.z*Achse.z+c,0., 0.,0.,0.,1.); } vec3 drehen(vec3 v,vec3 Achse,Float-Winkel){ mat4 m=RotationsMatrix(Achse,Winkel); Rückgabewert(m*vec4(v,1.)).xyz; } Gleitkommazahl sdf(vec3 p){ vec3 p1=rotieren(p,vec3(1.),uTime*uVelocityBox); float-Box=sdBox(p1,vec3(.3)); Rücksendebox; } Fusion-EffektEin einzelner Würfel ist zu einsam. Erstelle einen Ball, der ihr Gesellschaft leistet. Wie kann man den Ball und den Block zusammenkleben? Dazu braucht man die Smin-Funktion einheitlicher Float uProgress; Gleitkommazahl smin(Gleitkommazahl a,Gleitkommazahl b,Gleitkommazahl k) { Gleitkommazahl h=Klemme(.5+.5*(ba)/k,0.,1.); Rückgabemix(b,a,h)-k*h*(1.-h); } Gleitkommazahl sdf(vec3 p){ vec3 p1=rotieren(p,vec3(1.),uTime*uVelocityBox); float-Box=sdBox(p1,vec3(.3)); Gleitkomma-Kugel = sdKugel (p,.3); Gleitkomma sBox = smin (Box, Kugel, .3); float mixedBox=mix(sBox,box,uProgress); gebe gemischteBox zurück; } Setzen Sie den Wert von Setzen Sie den Wert von Dynamische FusionAls nächstes wird die Animation der fallenden Tautropfen realisiert, wobei eigentlich eine Verschiebungstransformation auf die verschmolzene Form angewendet wird. gleichmäßiger Gleitkommawert uWinkel; gleichmäßiger Gleitkommawert uDistance; gleichmäßiger Gleitkommawert uVelocitySphere; Konstante Gleitkommazahl PI = 3,14159265359; float movingSphere(vec3 p, float Form){ float rad=uWinkel*PI; vec3 pos=vec3(cos(rad),sin(rad),0.)*uAbstand; vec3 Verschiebung = Position * Bruch (uZeit * uVelocitySphere); float gotoCenter=sdSphere(p-Verschiebung,.1); gibt smin zurück (Form, gehe zu Mittelpunkt, .3); } Gleitkommazahl sdf(vec3 p){ vec3 p1=rotieren(p,vec3(1.),uTime*uVelocityBox); float-Box=sdBox(p1,vec3(.3)); Gleitkomma-Kugel = sdKugel (p,.3); Gleitkomma sBox = smin (Box, Kugel, .3); float mixedBox=mix(sBox,box,uProgress); gemischteBox = beweglicheKugel(p, gemischteBox); gebe mixedBox zurück; } Matcap-Karte Die Standardtextur ist zu erdig? Wir haben coole Matcap-Karten, die Ihnen helfen einheitlicher Sampler2D uTexture; vec2 matcap(vec3 Auge,vec3 normal){ vec3 reflektiert = reflektieren (Auge, normal); float m=2.8284271247461903*sqrt(reflektiert.z+1.); gebe reflektiertes xy/m+.5 zurück; } Float Fresnel (Float-Bias, Float-Skala, Float-Leistung, vec3 I, vec3 N) { Rendite-Bias + Maßstab * pow (1. + Punkt (I, N), Leistung); } void main(){ ... wenn(Tiefe<Ende){ vec3 pos=Auge+Tiefe*Strahl; vec3 normal = calcNormal(pos); vec2 matcapUv=matcap(Strahl,normal); Farbe=Textur2D(uTexture,matcapUv).rgb; Gleitkomma F=fresnel(0.,.4,3.2,Strahl,normal); Farbe=Mix(Farbe,Hintergrund,F); } ... } Nach dem Anordnen von Matcap und Fresnel-Formel wird es sofort cool, oder? ! Projektgalerie Ray Marching Gooey-Effekt Dies ist das Ende dieses Artikels über den Beispielcode zur Implementierung des Tautropfen-Animationseffekts mit three.js. Weitere relevante Inhalte zur Implementierung der Tautropfen-Animation mit three.js finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den verwandten Artikeln weiter unten. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen! Das könnte Sie auch interessieren:
|
<<: Einführung in die Linux-Dateikomprimierung und -Verpackung
Vorwort Um bei Datenbankoperationen die Richtigke...
1. Gründe Wenn das System Centos7.3 ist, ist die ...
Es ist ganz einfach, gehen Sie einfach zum Tutori...
So schreiben Sie DROP TABLE in verschiedene Daten...
Die Verwendung von H-Tags, insbesondere h1, war sc...
1. Anwendungsszenarien Es gibt eine solche Anford...
Dies ist eine Sammlung häufig verwendeter, aber l...
1. Voraussetzungen: Die Datenbanksicherung ist be...
Inhaltsverzeichnis Hbase-Installation und -Konfig...
Hiermit werden die Grundkenntnisse des Interviewt...
Die Methoden und Konzepte privater und globaler F...
1. Was ist ein virtueller Host? Virtuelle Hosts v...
In diesem Artikel erfahren Sie mehr über die Opti...
JavaScript-Skripte können überall in HTML eingebe...
Inhaltsverzeichnis Warum brauchen wir Partitionen...