Instructables universum i Three.js (9 / 13 steg)
Steg 9: Three.js: Hit-prestanda med 20.000 poäng i 3D
ThreeJS har fått oss en lång väg. I stället för 20 000 plan, orörlig punkter, vi nu har 20.000 poäng i tre-space, snurrar runt ojämna centra och med ultimate löfte att vi kan animera kameran, alltför, och verkligen utforska inne i galaxen.
Men när du trycker på en stjärna, hur snabbt kan ThreeJS hitta den? Ganska fort det visar sig. När detta skrivs stöder ThreeJS inte raycaster korsningar för ParticleSystems (womp womp) men lyckligtvis någon annanstans räknat ut. Det finns massor av gafflar kan du använda, eller bara lägga koden i biblioteket själv och bygga en egen kopia. Detta är vad du vill lägga till Raycaster.js (anpassad från liknande kod jag hittade över, som här):
...
} else om (objekt instanceof tre. ParticleSystem) {
Se: < en href = "https://github.com/mrdoob/three.js/issues/3492" >< en href = "https://github.com/mrdoob/three.js/issues/3492" > https://github.com/mrdoob/three.js/issues/3492
< /a >
< /a >
var hörn = object.geometry.vertices;
var punkt, avstånd, skär, tröskel = 3;
var localMatrix = nya tre. Matrix4();
var localtempRay = raycaster.ray.clone();
var localOrigin = localtempRay.origin;
var localDirection = localtempRay.direction;
localMatrix.getInverse(object.matrixWorld);
localOrigin.applyMatrix4(localMatrix);
localDirection.transformDirection(localMatrix);
för (var jag = 0; jag <.length; i ++) {
Peka = hörn [i];
avståndet = localtempRay.distanceToPoint(point);
om (avstånd > tröskel) {
fortsätta;
}
skär = {
avstånd: avstånd,
punkt: peka,
ansikte: null,
objekt: objekt,
vertex: Jag
};
intersects.push(Intersect);
}
} else om...
När biblioteket är byggt på lämpligt sätt (jag lämnar det som en övning för läsaren), få korsningen från en användares kran eller musklick är ganska enkelt: det är en raycaster med aktuella kamerans position, scenen, och (x, y) koordinaterna för användarens klick. Psuedo koden:
-Get (x, y) av användarens klicka
-Göra detta till en tre. Vector3()
-FN-projekt vektorn baserat på kameraposition
-Ställ in en raycaster med kameraposition och unprojected vektor
-kör ray.intersectObjects()
-göra något med resultaten
Verkligheten i koden för detta projekt, med dess flera particlesystems och önskan att hitta närmaste skärningspunkten bland korsningar från alla i particlesystems är något mer komplex. Plus, också förklaras av Jens Arps, finns det några mystery kött när du slår en skärm punkt i en 3d vektor (du ser detta i min kod för: nya tre. Vector3 ((e.clientX / Galaxy.Settings.width) * 2-1,-(e.clientY / Galaxy.Settings.height) * 2 + 1, 0,5)):
canvasClickEvent: function(e) {
e.preventDefault();
e.stopPropagation();
this.resetInteractionTimer(); stoppar "auto-läget" från återuppta för 90-talet
var vektor = nya tre. Vector3 ((e.clientX / Galaxy.Settings.width) * 2-1,-(e.clientY / Galaxy.Settings.height) * 2 + 1, 0,5);
var projektor = nya tre. Projector();
projector.unprojectVector (vektor, this.camera);
var ray = nya tre. Raycaster (this.camera.position, vector.sub (this.camera.position) .normalize());
Om det redan valda stjärnor ute i fältet, dvs från en författare stjärnbilden eller relaterad grupp,
Vi förutsätter att användaren försöker att välja ett av dessa. Dock om de olika systemen innehåller
endast en enstaka brytpunkt, som anger att användaren kan bara vara att klicka runt individuellt. Så Använd inte pre-valde
stjärnor för korsningen i så fall.
var intersectSystems = this.particleSystemsArray,
som = detta.
om (! _.isUndefined(this.__glowingParticleSystems)) {
_.each(this.__glowingParticleSystems,function(system) {
om (system.geometry.vertices.length! == 1) {
skär med glödande system istället
intersectSystems = den .__glowingParticleSystems;
}
});
}
När kameran är mycket nära den stjärna som väljs, är avståndet bedrar. Vi i grunden behöver justera hit tolerans beroende på avståndet till kamera
Beräkna avstånd kameran--> star genom att konvertera stjärnans position till världen coords och sedan mäta
Intersection.Point = Vector3
Intersection.Object = ParticleSystem det är en del av
var getCameraDistanceForHit = function(intersection) {
var intersectionVect = intersection.point.clone();
intersectionVect = intersection.object.localToWorld(intersectionVect);
återvända intersectionVect.distanceTo(that.camera.position.clone());
};
skär sorterade efter avstånd så det första objektet är "bästa passform"
var skär = _.sortBy (ray.intersectObjects (intersectSystems, sann), function(intersection) {
återgå getCameraDistanceForHit(intersection) / intersection.distance;
});
När en hit är alltför nära kameran för sin hit tolerans, det räknas inte. Ta bort dessa värden.
skär = _.filter (skär, function(intersection) {
återgå getCameraDistanceForHit(intersection) / intersection.distance > 100.
});
om (intersects.length > 0) {
this.selectVertex(intersects[0])
} annat {
inga korsningar är inom toleransen.
This.Reset ({projectTagsAddAfterCameraReset: true});
}
},
Och det visar sig vara ganska snärtiga!