Instructables Universe in Three.js (3 / 13 stap)

Stap 3: Kinetic.js: suggestieve sterrenbeelden


Wanneer je scheel, een constellatie ziet eruit als iets.

Mijn aanpak hier was, wederom, om te kijken door de sterrenbeelden. De sterrenbeelden zag ik zelden zag eruit als specifieke dingen (het leek mij dat één persoon de Leeuw zou muis van een andere persoon, of zelfs alleen maar een vierkant met enkele lijnen die uit het), maar ze leek te delen een suggestieve kwaliteit afgeleid van enkele eenvoudige en consistente

Geometrische regels:

-Er zijn geen kruising lijnen
-Punten (sterren) sluit meestal met aangrenzende of in de buurt van de aangrenzende sterren. Het is ongebruikelijk dat merkbaar meer lijnen.
-Er zijn neiging om een (soms nul, soms twee) gesloten veelhoek... een "lichaam" van een soort
-Punten hebben één, twee, drie of vier verbindingen. Er zijn bijna nooit vijf verbindingen met één aanspreekpunt.
-Sterrenbeelden bestaat uit ongeveer 3-20 sterren

In pseudo-code is het zoiets als dit:

First-pass:
-Start met een willekeurige ster
-Voorstellen de lijn naar de dichtstbijzijnde un-bijgevoegde ster
-Test dat deze lijn geen bestaande regels overschrijden
-Deze lijn trekken als dit wordt doorgegeven, niet als het niet
-Verplaatsen naar de volgende dichtstbijzijnde ster
-Repeat

Tweede Pass:
-Het vinden van sterren zonder verbindingen
-Vinden van ten minste één niet-overschrijding lijn te trekken uit deze sterren om ze te verbinden

Derde Pass:
-Voeg een handvol niet-aansluitende lijnen

En tot slot de eigenlijke code ik eindigde met:

 function ConstellationMaker3D(options){ if (_.isUndefined(THREE) || _.isUndefined(Galaxy) || _.isUndefined(Galaxy.Utilities) || _.isUndefined(Galaxy.TopScene)) { throw new Error("Missing dependencies for ConstellationMaker3D"); } // ConstellationMaker3D is a function of a camera object because the 2-dimensional rules need a particular projection to work from this.init(options); } ConstellationMaker3D.prototype.init = function(options){ var camera = options.camera || Galaxy.Utilities.makeTemporaryCamera(); var nodes = options.nodes; _.bindAll(this, 'getConnections'); this.camera = camera; // three.js camera object this.nodes = this.projectPoints(nodes); // Vector2's (math -- flattened representation of XYZ points) this.segments = []; // Line3's (math). Note these are 2D line segments; the 3d ones are rendered, but not part of the constellation construction this.connections = []; // Array of connected instructable ids. ie, [[id1,id2],[id2,id3]] this.disconnectedNodes = [];// Vector3's not yet dealt with this.lineObject = null; // THREE.Line() object this.calculateConstellation(); if (options.hidden !== true) this.displayConstellation(); }; ConstellationMaker3D.prototype.projectPoints = function(vector3List){ var that = this; return _.map(vector3List,function(vec){ var position = Galaxy.Utilities.vectorWorldToScreenXY(vec,that.camera), vec2 = new THREE.Vector2(position.x,position.y); vec2.instructableId = vec.instructableId; return vec2; }); }; ConstellationMaker3D.prototype.spatialPointsForConnections = function(connectionList){ return _.map(connectionList,function(connectionPair){ return Galaxy.Utilities.worldPointsFromIbleIds(connectionPair); }); }; ConstellationMaker3D.prototype.displayConstellation = function(callback){ // Place THREE.JS objects corresponding to the calculated objects into the scene var connectedPoints3d = this.spatialPointsForConnections(this.connections); var that = this; if (!_.isEmpty(connectedPoints3d)) { // Initialize geometry, add first point var lineGeometry = new THREE.Geometry(); // connect subsequent dots along the chain of connected points _.each(connectedPoints3d,function(pair){ var closerPair = pair; lineGeometry.vertices.push( closerPair[0] ); lineGeometry.vertices.push( closerPair[1] ); }); // display the line var material = new THREE.LineBasicMaterial({ linecap: "round", color: 0xffffff, linewidth: 2, transparent: true, opacity: 0.5 }); this.lineObject = new THREE.Line( lineGeometry, material, THREE.LinePieces ); this.lineObject.name = "constellation"; Galaxy.TopScene.add( this.lineObject ); } if (typeof callback === "function") { callback(); } }; ConstellationMaker3D.prototype.movePointsCloser = function(pair){ // part of displaying the constellation lines is shortening the segments for graphic effect. var end1 = pair[0].clone(); var end2 = pair[1].clone(); // move each point slightly towards the other var diff = end2.clone().sub(end1.clone()); diff.multiplyScalar(0.08); return [end1.add(diff.clone()), end2.sub(diff.clone())]; }; ConstellationMaker3D.prototype.clear = function(){ if (!_.isNull(this.lineObject)) { Galaxy.TopScene.remove(this.lineObject); } }; ConstellationMaker3D.prototype.calculateConstellation = function(){ var currentNode = this.nodes.shift(), that=this; while (this.nodes.length > 0) { currentNode = this.addSegmentFromNode(currentNode); } }; ConstellationMaker3D.prototype.closestNodeToNodeFromNodeSet = function(testNode,nodesToTest){ _.each(nodesToTest,function(potentialNextNode){ potentialNextNode.distance = testNode.distanceTo(potentialNextNode); }); var sorted = _.sortBy(nodesToTest,"distance"); return sorted; } ConstellationMaker3D.prototype.findLineLineIntersection = function(line1,line2){ var eqn1, eqn2, intx, inty; // if the two lines share an end (ie, they are drawn from the same node), pass if (this.shareEndpoint(line1, line2) === true) return false; eqn1 = this.equationForLine(line1); eqn2 = this.equationForLine(line2); // same slope = no intersection if (eqn1.m == eqn2.m) return false; // x-value of intersection point intx = (eqn2.b - eqn1.b) / (eqn1.m - eqn2.m); // y-value of intersection point inty = eqn1.m * intx + eqn1.b; // if x or y are out of range for either line, there's no intersection var range = { minx: Math.min(line1.start.x,line1.end.x), maxx: Math.max(line1.start.x,line1.end.x), miny: Math.min(line1.start.y,line1.end.y), maxy: Math.max(line1.start.y,line1.end.y) }; if (intx < range.minx || intx > range.maxx) return false; if (inty < range.miny || inty > range.maxy) return false; range = { minx: Math.min(line2.start.x,line2.end.x), maxx: Math.max(line2.start.x,line2.end.x), miny: Math.min(line2.start.y,line2.end.y), maxy: Math.max(line2.start.y,line2.end.y) }; if (intx < range.minx || intx > range.maxx) return false; if (inty < range.miny || inty > range.maxy) return false; return true; } ConstellationMaker3D.prototype.equationForLine = function(line){ // eqn's store m & b from y = mx + b var m, b; // slope m = (line.end.y - line.start.y) / (line.end.x - line.start.x); // y-intercept: b = y-mx. Sub in values from a known point. b = line.end.y - m * line.end.x; return {m: m, b: b}; } ConstellationMaker3D.prototype.shareEndpoint = function(line1,line2){ if (line1.start.x == line2.end.x && line1.start.y == line2.end.y) return true; if (line1.end.x == line2.start.x && line1.end.y == line2.start.y ) return true; if (line1.end.x == line2.end.x && line1.end.y == line2.end.y) return true; if (line1.start.x == line2.start.x && line1.start.y == line2.start.y) return true; return false; } ConstellationMaker3D.prototype.addSegmentFromNode = function(node){ var nextNodeList = this.closestNodeToNodeFromNodeSet(node,this.nodes); var proposedLine = this.lineConnectingNodes2D(node,nextNodeList[0]); if (this.lineIntersectsPriorLines(proposedLine) == true) { this.disconnectedNodes.push(node); } else { this.connections.push([node.instructableId,nextNodeList[0].instructableId]); this.segments.push(proposedLine); } this.nodes = _.without(this.nodes,nextNodeList[0]); return nextNodeList[0]; } ConstellationMaker3D.prototype.connectNodeMultipleTimes = function(node,times){ var closest = this.closestNodeToNodeFromNodeSet(node,this.allNodes), lineCount = 0; for (var i = 2; i < closest.length && lineCount < times; i++) { var proposedLine = this.lineConnectingNodes2D(node,closest[i]); if (!this.lineIntersectsPriorLines(proposedLine)) { this.segments.push(proposedLine); this.constellationLayer.add(proposedLine); lineCount++; } } } ConstellationMaker3D.prototype.lineIntersectsPriorLines = function(proposedLine){ var that = this, intersectionFound = false; _.each(this.segments,function(testSegment){ var intersect = that.findLineLineIntersection.apply(that,[testSegment, proposedLine]); if (intersect === true) { intersectionFound = true; } }); return intersectionFound; } ConstellationMaker3D.prototype.lineConnectingNodes2D = function(node1,node2){ return new THREE.Line3(new THREE.Vector3(node1.x,node1.y,0),new THREE.Vector3(node2.x,node2.y,0)); } ConstellationMaker3D.prototype.getConnections = function(instructableId){ // returns an array of instructable id's to which the supplied id has connections. var flat = _.uniq(_.flatten(this.connections)); var index = _.indexOf(flat,instructableId); switch(index) { case -1: return []; case 0: return [flat[1]]; case flat.length-1: return flat[flat.length-2]; default : return [flat[index-1],flat[index+1]]; } console.log(instructableId + ' found at ' + index + ' in '+ flat); } 

De overgang van KineticJS naar ThreeJS beslist bemoeilijkt dingen. Sterrenbeelden zijn fundamenteel 2d in aard: ze zijn verbindingen tussen punten in 3 dimensies (zelfs als u vraagt Ptolemaeus), maar het sterrenbeeld zelf vooroordelen een bepaald perspectief vanaf de aarde. Lijnen die worden weergegeven voor ons niet te steken kunnen in feite kruisen wanneer u ze van de kant weergeeft, zoals ze in de interactieve demo doen.

Daar ThreeJS op 3D-objecten functioneert, een methode van het instorten van de gegevens aan een camera vlak noodzakelijk geworden. Introduceerde ik sommige hulpprogrammamethoden om het scherm XY-coördinaten van een punt van de wereld XYZ, gegeven een camerapositie:

 vectorWorldToScreenXY : function(vector,camera){ // vector assumed to be in world xyz coordinates coming in. var widthHalf = window.Galaxy.Settings.width / 2, heightHalf = window.Galaxy.Settings.height / 2, projector = new THREE.Projector(), screenPosition; projector.projectVector( vector, camera ); screenPosition = { x : ( vector.x * widthHalf ) + widthHalf, y : - ( vector.y * heightHalf ) + heightHalf }; return screenPosition; }, 

Gerelateerde Artikelen

The Instructables University Game

The Instructables University Game

Ik had niet gepland op het invoeren van de "How to play wedstrijd" want ik niet echt een gameconsole ben. Na het nadenken, kwam ik met The Instructables Universiteit Game. Ik heb geprobeerd om mijn volwassen zoon aan bij de pret hier, maar zijn
Verleden projecten/Pre Instructables...

Verleden projecten/Pre Instructables...

I wish I would have found Instructables two or three years ago. Ik kon een deurklink van een veel meer hebben bijgedragen. Met mijn recente verplaatsen onvermijdelijk dat heb ik besloten om enkele foto's van eerdere projecten in mijn huidige huis ver
Jus te gaan met een gebraden

Jus te gaan met een gebraden

hoewel dit dom eenvoudig is, ik ben voortdurend verbaasd over het aantal mensen die geïntimideerd, zijn wanneer het gaat om het maken van een simpele jus te gaan met een gebraden. Deze jus werkt ruim aardappelen, besprenkeld over het vlees of de volg
Gedetailleerde geweven Duct Tape portefeuilles Instructable

Gedetailleerde geweven Duct Tape portefeuilles Instructable

Ja, ja, het is een ander Duct Tape wallet instructable.Hoe saai, juiste?De reden dat ik dit doe is dat ik proberen zal te doen samenballen van kennis over het bouwen van allerlei soorten Duct Tape portefeuilles en ingaan op veel aspecten zodat u zal
Steven Universe jurk

Steven Universe jurk

Een goede vriend van mij houdt Steven Universe, dus ik haar deze jurk als een gift van de verjaardag maakte. Ik denk dat dit is een echt mooie jurk, en zou een geweldig cosplay of Halloween kostuum!Ik maakte haar ook een volledige set van kat vinger
TestrBot: De $300 Universal testmachine

TestrBot: De $300 Universal testmachine

UPDATE 9-2-15: ik vrijgegeven een batch van testresultaten die aantonen dat mijn beweegredenen voor terwijl "infill"-ontwerp is de beste!* Wat is TestrBot?TestrBot is een $300 Universal Test Machine (UTM) en kan worden gebruikt voor het uitvoere
Steven Universe lumi inkodye ondergoed met crystal gem Garnet

Steven Universe lumi inkodye ondergoed met crystal gem Garnet

Een van de dingen die mijn geld kan niet kopen is prima super held/favoriet karakter ondergoed (of elke merch echt) voor dames. Elke vorm van boksers schijnt beschikbaar te zijn, en soms heb ik geprobeerd kopen sommige "jongens" grootte ondergoe
SUMO&nbsp;:&nbsp;&nbsp;Slimme&nbsp;/*&nbsp;*&nbsp;Smart&nbsp;Pulse&nbsp;Monitor&nbsp;*&nbsp;Author&nbsp;:&nbsp;Geeve&nbsp;George&nbsp;*&nbsp;Instructables&nbsp;:&nbsp;*/&nbsp;#include&nbsp;const&nbsp;int&nbsp;analo

SUMO&nbsp;:&nbsp;<youtube&nbsp;id="lDKM7UKUL5A"></youtube>&nbsp;Slimme&nbsp;/*&nbsp;*&nbsp;Smart&nbsp;Pulse&nbsp;Monitor&nbsp;*&nbsp;Author&nbsp;:&nbsp;Geeve&nbsp;George&nbsp;*&nbsp;Instructables&nbsp;:&nbsp;*/&nbsp;#include&nbsp;const&nbsp;int&nbsp;analo

src = "HalloIedereen,Ik benGeeveGeorgeeen15jaaroudeMaker/elektronicaHobbyist.IliefdeComputerVisie,AndroïdeOntwikkelingenAlgoritmeDesign.Iamop dit momentin11eRangComputerWetenschapStudentbijWeinigRockIndischeSchool.:)Zoekenmeerovermebij:href = "h
DIY zelf geactiveerd PRIVATE UNIVERSE

DIY zelf geactiveerd PRIVATE UNIVERSE

dit is mijn allereerste ooit Instructables uploaden dus, wees voorzichtig met mij.Ik maakte dit voor een kleine galerie ruimte in een ARI genoemd Constance in Hobart, Tasmanië, Australië, en is speciaal ontworpen om te worden geactiveerd wanneer mens
Knex verstek zagen instructies

Knex verstek zagen instructies

het is teruggekeerd! Ja, na 3 jaar, heb ik eindelijk besloten om te posten van instructies van mijn verstek zaag. Deze zaag is net als de oude is, behalve een paar kleine kleurwijzigingen te geven een meer consistent kleurenschema. Voor degenen onder
Pimp mijn PSP hoofdstuk 1 uw one-stop Instructable voor al uw PSP behoeften!

Pimp mijn PSP hoofdstuk 1 uw one-stop Instructable voor al uw PSP behoeften!

Dit instructable leert u sommige unieke dingen die uw PSP in een Multi-Media beest transformeren zal.Dit instructable zal u tonen hoe te:1. update uw PSP (officiële Firmware, niet Custom Firmware)2. video's toevoegen aan uw PSP (hoofdstuk 2)3. foto's
Met de Switch()-instructie als Sequencing Control

Met de Switch()-instructie als Sequencing Control

In dit Instructable, zal wij gaan over de "switch()"-instructie en het gebruik in de programmering. De instructie switch is een krachtig hulpmiddel voor het organiseren van uw programma, gemakkelijk kunt u complexe stroomdiagrammen doorlopen.In
Overleven in het wild-het meest unieke instructable tot nu toe

Overleven in het wild-het meest unieke instructable tot nu toe

u hebben net wakker om jezelf te vinden op de grond in het wild.  Vóór het opstaan vanuit je liggende positie realiseert je je dat, naast het feit dat niet in uw eigen warme comfortabele bed, u hebben gewekt in het kreupelhout onder het bladerdak van
Stalen Python Knex achtbaan - instructies

Stalen Python Knex achtbaan - instructies

is terug iedereen-staal Python!Dit model is de recreatie van mijn oudere ontwerp, met een paar kleine wijzigingen, aangezien ik nooit had specifieke foto's van het origineel. Dit ontwerp heeft natuurlijk zijn gebreken, zodat u wellicht om te knoeien