Deutsch
PHP, HTML & JavaScript- Forum

3D Grafik - WebGL mit three.js

 
- Seite 1 -



HofK
Auf einen heißen Tipp von IF hin, habe ich mir mal
three.js  [...]  angeschaut
und unter download die three.js-master.zip heruntergeladen.

Einen leichten Einstieg findet man z.B. über die
Links:  [...]  [...]  [...]  [...]  [...]  [...] 

Damit habe ich zuerst eine "Grundübung" gebastelt und dann einen Androiden mit gps Bandarole  [...]  (Bildschirm nach Ende der Datenaufnahme) gebaut.

Da  [...]  kann man es anschauen und z.B. den Androiden selbst mit der Maus (oder per touch) steuern.

Mit der web Konsole z.B. in Firefox kann man die minimale html Seite und auch das JavaScript ansehen.

Die grundlegenden Skripte three.min.js und für die Steuerung OrbitControl.js findet man nach entpacken von three.js-master.zip dann im Ordner three.js-master\build und three.js-master\examples\js\controls .
 
31.01.2016  
 



 
- Seite 14 -



HofK
Die interne Struktur der Generierung der Wände musste noch einmal geändert werden, da sie nur für dünne Wände (Innenseite der Außenwände) konzipiert war. Da ich aber auch dicke Wände als Trennwände haben möchte und mit dieser Verfahrensweise auch andere Bauteile wie Konsolen, Podeste, Ausstellungstische usw. realisiert werden sollten, war eine Neuprogrammierung unumgänglich.

Mal abgesehen von den noch unmöglichen Texturen, kann man aber schon erkennen, wo es hin geht.





Es sind auch runde Formen möglich.

Die Böden, Decken und Wände und eckigen Bauteile habe ich mit selbst erstellter non-indexed BufferGeometry erzeugt.

Für die runden Formen bot sich THREE.CylinderBufferGeometry an.
Diese wird in three.js als indexed BufferGeometry realisiert.

Mit den uv's hatte ich dann ein Problem. Standardmäßig ist die Textur nach außen richtig herum und innen gespiegelt. Im obigen Bild ist aber der Zylinderteil (runde Raum"ecke") von innen zu sehen.

Nach Recherche habe ich gleich zwei einfache Lösungen gefunden. Wer die Wahl hat, hat die Qual. Ich habe mich noch nicht entschieden.

Einmal kann man die Textur spiegeln

var uvMirroredGrid= new THREE.TextureLoader().load( "uvgrid01.png" );
uvMirroredGrid.wrapS = THREE.RepeatWrapping;
uvMirroredGrid.repeat.x = - 1;


oder man spiegelt die uv's im Attribut der Geometrie

for ( var i = 0; i < roundWallGeometrys[ r ].getAttribute('uv').array.length; i += 2 ) {

roundWallGeometrys[ r ].getAttribute('uv').array[ i ] =
1 - roundWallGeometrys[ r ].getAttribute('uv').array[ i ];

}


Um einige passende Texturen zu bekommen, muss ich mich noch intensiver mit Grafik befassen. Mit Gimp 2.8 bin ich nicht so richtig "warm" geworden.

Habe etwas gesucht und Krita gefunden. Ist auch größtenteils Deutsch.
Bei heise  [...]  .
Mal schauen, ob ich da besser klarkomme. Die getupfte Rückwand ist ein erster Versuch!
 
vor 30 Tagen  
 




HofK
oder man spiegelt die uv's im Attribut der Geometrie

... erscheint mir sinnvoller, da sie die Geometrie selbst betrifft und die Textur nicht verändert wird. So kann man die Textur auch unverändert mehrfach benutzen.

.....................................................................................................................................

In den obigen Bildern klafft ein Loch. Da muss eine Tür rein. Zuerst aber mal die Zarge.

Da gab es bei Discourse mal eine Frage [...] 
und eine tolle Lösung von prisoner849[...] 
function ProfiledContourGeometry(profileShape, contour, contourClosed) { ...

Mit dieser Funktion ist es dann schnell getan. Hier die Türzarge kurz vor dem Einbau.



Aus den beiden Werten 0.5 einfach 0 gemacht und schon sitzt die Zarge passend.

Wenn das mal praktisch auch so schnell ginge, ich habe da schon mal Stunden verbracht! 
 
vor 29 Tagen  
 




HofK
Der Ausstellungsraum ist zwar noch im Rohbau, aber schon wurden die ersten Exponate angeliefert.

Und gleich zwei Königinnen!

Also müssen sie testweise platziert werden.



Das Foto der "Königin der Nacht" hat mit der Methode wie für die Zarge ganz schnell einen passenden Rahmen bekommen.
[ 4.91,0.25, 1.21,2.89, 7.09,0.25, 1.21,2.89, 1 ]

Die letzte 1 schließt den Rahmen. Das Bild selbst wird wie eine dünne Wand generiert. Das Foto dient als Textur.
<!-- Bilder -->
[ 7,0.26, 1.3,2.8, 5,0.26, 1.3,2.8 ],


Unsere Königin blüht immer Ende Juni. Nach dem Abendbrot geht sie langsam auf und wenn man nicht ganz früh aufsteht, ist sie schon wieder verwelkt. So gegen 5:00-6:00 Sommerzeit kann man nochmal schauen.

Die Nofretete wird von @author bhouston / http ://clara.io [...]  kostenlos zur Verfügung gestellt. Ben Houston ist auch einer der Mitentwickler von three.js.



Das Modell liegt im JSON Format (JavaScript Object Notation) vor.
var objectLoader = new THREE.ObjectLoader();
objectLoader.load( "nefertiti.json", loadNefertiti );

function loadNefertiti( obj ) {
obj.scale.set( 0.1, 0.1, 0.1 );
obj.position.set( 7, 1, 2 );
obj.rotation.y = 2.1;
room.add( obj );
}

In meiner Ausstellung sieht die altägyptische Königin im Gegensatz zum Original bei clara.io etwas blass aus. Es fehlt noch die passende Farbzuordnung/Beleuchtung - Rohbau!

Übrigens kann man die JSON Datei mit Firefox laden. Etwas warten, die Datei ist recht groß. Das verzögert auch den Seitenaufbau bei meinem Schauraum.

Beim Bilderrahmen kann man erkennen, dass die linke untere Ecke sich farblich etwas abhebt. Hier leuchtet ein Farbspot.

var spotLight = new THREE.SpotLight( 0xccffcc,1.0,16,0.2,0.5,1.2 );
spotLight.position.set( 5, 3.4, 4 );
scene.add( spotLight );

spotLight.target = frameMeshes[ 1 ];
 
vor 28 Tagen  
 




HofK
Einige (Kunst)blumen machen den Raum gleich freundlicher.

Zum Test habe ich eine Blume von Hitesh Sahu (free)  [...]  in zwei Formaten (JSON und OBJ/MTL) heruntergeladen.

Die Einbindung der JSON Datei:

new THREE.ObjectLoader().load( "flower.json", loadFlower );
function loadFlower( obj ) {
obj.scale.set( 0.01, 0.01, 0.01 ); // Original hat anderen Maßstab!
obj.position.set( 7, 0.0001, 3 );
room.add( obj );
}


brachte eine Überraschung für mich.

Nicht nur das reine Modell, sondern auch die Beleuchtung steckt in der .json Datei.



Diese kommt zu meiner bereits vorhandenen Beleuchtung hinzu und der Raum ist stark überbeleuchtet. Man erkennt am Blumentopf, dass Licht aus verschiedenen Richtungen kommt.

Bringt nun jedes Modell sein eigenes Licht mit, gibt das die totale Lichtverschmutzung.

JSON Dateien sind lesbar und so findet man fast am Anfang die Lichtvoreinstellung (light preset).



Hier einfach für alle Lichter (gesamter Block) "visible" auf false gesetzt und das Extralicht geht aus. Natürlich kann man auch den Block an lassen und einzelne Lichtquellen, z.B. das Sonnenlicht ausschalten.



Nun die identische Blume als OBJ/MTL Dateien importiert. Dazu muss man im Gegensatz zu JSON zusätzlich zu three.js noch die (sehr kleinen) Scripte

<script src="OBJLoader.js"></script>
<script src="MTLLoader.js"></script>


einbinden.

new THREE.MTLLoader( ).load("flower.mtl", loadMtlObjFlower );
function loadMtlObjFlower( materials ) {
materials.preload( );
var objLoader = new THREE.OBJLoader( ).setMaterials( materials );
objLoader.load( "flower.obj", function ( obj ) {
obj.scale.set( 0.01, 0.01, 0.01 ); // Original hat anderen Maßstab!
obj.position.set( 6.6, 0.0001, 3 );
room.add( obj );
} );
}


Durch die Trennung von Geometrie (.obj) und Material (.mtl) ist die Sache aufwändiger.



Hier kam kein Licht mit.

Die Blumen werden nicht identisch dargestellt. Da spielt das Beleuchtungsmodell, die Beziehung von Licht/Material/Geometrie mit.

Wenn ich für meinen Bilderrahmen statt THREE.MeshLambertMaterial (flatShading ändert nichts)



THREE.MeshPhongMaterial mit flatShading: true nehme, sieht es auch deutlich anders aus.



Es gibt sooooooooooooo viele Möglichkeiten und damit kann man eben tolle Effekte erzielen, es braucht etwas Zeit, das halbwegs zu überschauen.
 
vor 27 Tagen  
 



 
- Seite 15 -



HofK
Hat man einen Spiegel, kann man Exponate auch von hinten betrachten. Und man kann sich selbst sehen.

Also musste einer her!

Die Vorlage liefert  [...]  . Das Beispiel benutzt das zusätzliche Script Reflector.js  [...]  .

Dieses Script eingebunden und mit

genutzt. Ein rahmenloser Spiegel schräg in der Ecke. Er reicht bis zum Boden.



Reflector.js benutzt eine virtuelle Kamera am Standort des Spiegels. Sie nimmt die Scene von dort auf.
var virtualCamera = new THREE.PerspectiveCamera();

Es wird ein Shader benutzt um das Spiegelbild darzustellen.
var shader = options.shader || THREE.Reflector.ReflectorShader;
...
var material = new THREE.ShaderMaterial( {
uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,

} );



--------------------------------------------------------------------------------------------

Damit man sich im Raum ordentlich bewegen kann, um Dinge auch näher zu betrachten, benötigt man eine Möglichkeit die Augen des virtuellen Besuchers ( Kamera, die 3D Scene in 2D abbildet) leicht zu steuern. Der Besucher muss in alle Richtungen gehen können, sich drehen, bücken und strecken und die Augen nach oben und unten richten können.

Dazu habe ich einen virtuellen Controler gebastelt. Er ist unaufdringlich transparent, kann frei im Browserfenster bewegt werden und wenn die Maus über eine der aktiven kreisförmigen Bereiche kommt, wird das Symbol kräftig und es startet die jeweilige Bewegung. Sie hört auf, wenn die Maus den Bereich verlässt. Ein Klick ist nicht nötig.



Wie man sieht ( extra zum Teil über die graue Wand geschoben!) , sind noch nicht alle Kreise mit Symbolen und Funktionen belegt.

Der Controler ist modular aufgebaut, man kann Kreise auch vollständig ausblenden. Es werden Icons 32x32 und 16x16 oder in der Maxivariante 64x64 und 32x32 benötigt. Diese müssen so gestaltet sein, dass sie in den Kreis passen, dürfen also nicht die Ecken benutzen.

Die Lücken zwischen den Kreisen sind ausreichend groß, um mit der Maus ohne eine Funktion auszulösen stressfrei zu navigieren.
 
vor 24 Tagen  
 




HofK
Ostern

ist ja auch die Zeit der Suche.

Allerdings habe ich nur etwas sortiert und nicht gesucht.
Aber trotzdem etwas gefunden!



Nein, das ist nicht meine neueste three.js - Kreation die ich verlegt habe.

Dieses Blatt habe ich vor ziemlich genau 30 Jahren auf meinem seinerzeit hochmodernem 8 Nadel Drucker LX 800 ausgedruckt.

Es lag in diesem Bestseller,



den ich einige Monate zuvor mit Staunen ob der ungeahnten Möglichkeiten in kürzester Zeit förmlich "verschlungen" hatte.

Die 3D Grafik ist programmiert auf dem ATARI 520ST mit GFA Basic 3.0 mit integriertem Editor, was weit mehr als ein BASIC war. Einige Features vermisse ich heute bei JavaScript und anderen Sprachen! Auch hatte das grafische Betriebssystem einige Vorzüge gegenüber Windows, das da noch nicht aktuell war.

Eine Sache werde ich nicht vergessen. Um Daten zu übertragen habe ich ein serielles Verbindungskabel ATARI zu PC (DOS) gebastelt.

Die Schnittstelle auf dem ATARI zu programmieren ging mit wenigen gut dokumentierten Befehlen recht zügig, unter DOS hat das Nerven gekostet und mit Fehlversuchen gedauert. Aber ich war (bin) hartnäckig und konnte so jahrelang Textdateien (WLAN war noch nicht!) schnell übertragen.

Nicht das technisch bessere setzt sich immer durch, oft auch Schrott!



FROHE OSTERN!


 
vor 23 Tagen  
 




p.specht
Frohe Ostern auch Dir !
 
XProfan 11
So Computer sind halt auch nur Menschen...
vor 23 Tagen  
 




HofK
... einen virtuellen Controler gebastelt ...

Der Controler war wirklich nur gebastelt. Es ging mir erst einmal lediglich um die Funktionsweise im Schauraum.

Eigentlich wollte ich mich ja mit three.js befassen, aber man kommt nicht umhin auch etwas Javascript für DOM/HTML/CSS zu machen.

Und das ist ein historisch gewachsener Syntax-Sumpf.
Als ich seinerzeit erstmals HTML begegnet bin, gefiel mir das als Programmierer überhaupt nicht. Aber mit Hypertexten hatte ich nichts zu tun und dachte, das berührt mich nicht. Auf Dauer falsch gedacht. Mit der Integration von JavaScript bin ich mittendrin.

Warum ich gerade "jammere"?
 


Mein Controler ist mit Bildern bestückt, also img -tags. Diese sind an span -tags gebunden, um mit einen passenden Randradius den Kreis zu erzeugen.

Nun muss man einen Ereignislauscher benutzen.

navigationControl.addEventListener('mouseover', mouseover );


Was liegt näher, als nun in der Funktion function mouseover( event ) die Identifikationsnummer zu ermitteln und auf das Ereignis bezogen auf das auslösende Element zu reagieren. img -tags haben standardmäßig kein id Attribut.

Wenn man die span und img -tags mit JavaScript erzeugt, muss man die id sowieso selbst generieren. Erlauscht wird dann die "oben" liegende. Ist ein Bild auf dem span gibt es nur die Bild id. Ist logisch, aber man muss es erst mal finden, wenn man nicht so tief in HTML/CSS drinsteckt.


imgs[ i ].setAttribute('id', i.toString( ) + ' imgId' );

function mouseover( event ) {

console.log( 'event.target.id ' + event.target.id );
var idx = parseInt( event.target.getAttribute( 'id' ) );

if ( idx > 0 ) { ... irgendetwas zur id von span oder Bild ...


Als Wegweiser durch den HTML/CSS/DOM/JavaScript Dschungel ist mir immer mehr  [...]  mit recht guter interner Suche sehr hilfreich. Hier z.B. unter anderem  [...] 

So einfach konfiguriert man den Controler:







Das kommt heraus (andere Farben für Center):



Die äußeren drei span's haben kein Bild.
 
vor 20 Tagen  
 




HofK


Mit dem Controler bewegt sich der virtuelle Besucher zügig durch den Ausstellungsraum.


Die unsichtbare Kamera sind seine Augen. Damit der Besucher sich selbst im Spiegel erblicken kann, braucht er einen sichtbaren Körper. Zum Test reicht erst einmal ein einfaches Gitter. Da die Augen mitten im Körper sitzen, sieht er nicht nur sein Spiegelbild, sondern auch noch einige originale Körperlinien.



Wenn der Besucher nun flott im Raum umher geht, knallt er ganz schnell mal gegen einen Einrichtungsgegenstand oder eine Wand. Er geht sogar durch Wände! Das muss verhindert werden.

Der erste Gedanke war Kollisionserkennung. Dazu habe ich ein einfaches Beispiel auf threejs.hofk.de  [...] 

Also den Code angepasst.
Vorbereitet für mehrere Besucher. Hier erst einmal Besucher 0 - visitor...[ 0 ]

function detectCollision( cIdx ) {

var ray;
var originPoint = visitorMeshes[ 0 ].position.clone();
var localVertex = new THREE.Vector3( );
var globalVertex;
var directionVector;
var distance = Infinity;

for ( var j = 0; j < visitorGeometries[ 0 ].getAttribute('position').array.length; j += 3 ) {

localVertex.x = visitorGeometries[ 0 ].getAttribute('position').array[ j ];
localVertex.y = visitorGeometries[ 0 ].getAttribute('position').array[ j + 1 ];
localVertex.z = visitorGeometries[ 0 ].getAttribute('position').array[ j + 2 ];
globalVertex = localVertex.applyMatrix4( visitorMeshes[ 0 ].matrix );
directionVector = globalVertex.sub( visitorMeshes[ 0 ].position );
ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
collisionResults = ray.intersectObjects( collidableMeshes );

if ( collisionResults.length > 0 ) distance = collisionResults[0].distance;

return distance;

}

}

Die Sache hat aber einen entscheidenden Haken. Es sind anders als in der kleinen Vorlage mit zwei Wänden sehr viele Objekte zu überprüfen. Um kleinere Gegenstände zu erfassen, muss das Hilfsgitter des Besuchers auch ausreichend engmaschig sein. Befindet sich die Maus über einem Kreis des Controlers, muss unablässig die Kollisionserkennung durchgeführt werden. Aus dem flotten Besucher wird eine Ruckelschnecke.

Da ich keine brauchbare Idee habe den Aufwand drastisch zu reduzieren, nun ein neuer Ansatz.

Wie im realen Leben wird auch der virtuelle Besucher in seiner Bewegungsfreiheit eingegrenzt. Für Menschen nimmt man Seile oder Absperrgitter, für Mähroboter einen eingegrabenen Begrenzungsdraht und für virtuelle Besucher eine Anzahl von Rechtecken, definiert durch zwei Ecken.
<textarea id="visitorAreas"  style="width: 620px; height: 100px " > [
<!-- Besucher, Rechtecke x0,z0, < x1,z1 -->
[ 1, 1, 8, 6 ],
[ 8, 2, 9, 5 ],
[ 9, 2.5, 10, 4.5 ]
] </textarea>

Ein Späher schaut vorab, ob die nächste Bewegung über die Begrenzung hinausgeht. Wenn nicht, geht es nun wieder zügig weiter. Der Prüfaufwand ist gering.
 
vor 15 Tagen  
 




HofK
Schaut man sich die Navigationskommandos im vorletzten Beitrag genauer an, wird deutlich, dass die Richtungen auf den Raum bezogen sind. Dreht sich nun der Besucher, ist das für die Navigation ungeeignet. Aus vorwärts im Raum (Richtung negative z Achse) wird dann z.B. auch mal schräg zurück für den Besucher.

Die Anpassung lässt sich leicht mit sin() und cos() bewerkstelligen. Dabei habe ich gleich noch neu strukturiert und einen Geschwindigkeitsfaktor eingefügt.





Der Parameter obj gestattet nun verschiedene Objekte zu navigieren. So braucht es auch keine kopierten Kommandos für den Scout mehr.

Aus eval( navActionCommands[ i ] ); wird einfach
navActionCommands[ i ]( camera ); oder navActionCommands[ i ]( scout );
 
vor 10 Tagen  
 




HofK
Der Raum hat Öffnungen nach draußen. Bisher war da nur die Hintergrundfarbe. Wenn man hinaus schaut, möchte man aber auch die Umgebung sehen.

Das lässt sich ganz einfach nach dem Beispiel  [...]  auf meiner Seite erreichen.

Diesmal ist es keine Linse, sondern der Schauraum, der sich in der Box befindet. Die Cubemap ist erst einmal wieder von der Seite humus.name [...] 

Solche Cubemaps kann ich nicht erzeugen. Für mein Beispiel reicht aber eine einfachere Variante. Die Schwierigkeit besteht ja darin, dass die sechs Teilfotos an den Rändern nahtlos zueinander passen müssen. Aber nur, wenn der Blick auf die Ränder fallen kann. Da der Raum aber nur wenige Öffnungen hat, lässt es sich so einrichten, dass der Blick immer komplett auf einer der sechs Seiten bleibt. Wenn man keine Pfahlhütte mit Bodenloch baut, benötigt man auch kein sinnvolles Bild für negatives y. Hat man ein Dachfenster, ist ein Wolkenbild für positives y unabdingbar. Aber solche Einzelbilder sind ja kein Problem.

Der Blick in die Natur:




Im vergrößerten Spiegel wird auch der Wald mit gespiegelt.



Näher herangetreten ist mehr Wiese zu sehen.



Hier könnte nan meinen, rechts eine Kante der Box zu haben. Ist aber nicht!

Das komplette Bild der Seite:



---
Einfach ein Bild wie die "Königin der Nacht" in den Raumöffnungen zu platzieren hat keinen 3D Effekt. Der Besucher sieht nur mit dieser Methode wie auch real verschiedene Ausschnitte der Umgebung.
 
vor 9 Tagen  
 




HofK
Der Frühling kommt, die (Computer)Zeit wird knapper.

Habe einige Varianten des Ladens von Objekten ausprobiert, - das dauert.

Dann die Spiegel näher untersucht.

Es geht auch eine Doppelspiegelung. Dazu setzt man in new THREE.Reflector ...

recursion: 1



Bei 0 bleibt der Spiegel im Spiegel Dunkel.



Allerdings konnte ich keine Mehrfachspiegelung erreichen. Geht eventuell nicht, der Rechenaufwand wäre auch enorm.
 
vor 3 Tagen  
 




Antworten


Thementitel, max. 100 Zeichen.
 

Systemprofile:

Kein Systemprofil angelegt. [anlegen]

XProfan:

 Beitrag  Schrift  Smilies  ▼ 

Bitte anmelden um einen Beitrag zu verfassen.
 

Themenoptionen

28.056 Betrachtungen

Unbenanntvor 0 min.
WalterGestern (20:20)
Thomas FreierVorgestern (20:43)
Manfred BareiVorgestern (20:37)
Georg TelesVorgestern (14:09)
Mehr...

Themeninformationen



AGB  |  Chat  |  Datenschutz  |  Download  |  Eingangshalle  |  Hilfe  |  Impressum  |  Shop  |  Support  |  Schnittstellen  |  Suche  |  XProfan.De

Ein Projekt aller XProfaner, die es gibt!


Mein XProfan
Private Nachrichten
Eigenes Ablageforum
Themen-Merkliste
Eigene Beiträge
Eigene Themen
Zwischenablage
Abmelden
 Deutsch English Français Español Italia
Übersetzungen

Cookie-Richtlinie


Information über die Nutzung von Cookies, und darüber, dass Sie mit Nutzung der Seiten unseren AGB zustimmen.

OKDatenschutzbestimmungen
Ich möchte keinen Cookie