| |
|
|
- Seite 1 - |
|
HofK | Auf einen heißen Tipp von IF hin, habe ich mir mal three.js [...] angeschaut. Da [...] (ganz unten) die ersten Resultate. |
|
|
| |
|
|
| |
|
- Seite 10 - |
|
|
HofK | Die Funktion explode gibt es nun auch bei THREEf.
Die neuesten Versionen befinden sich auf meiner Seite und auf GitHub.
--------------------------------------------------------------------------------------
Dann ein wenig Abwechselung und eventuell konnte ich helfen.
Dort [...] war mal wieder eine einfache Frage - zu einer " slot machine" Spielautomat ? .
Im Ergebnis habe ich ein weiteres kleines Anfängerbeispiel.
Man kann es unter [...] bzw. [...] ausprobieren.
<!DOCTYPE html>
<!-- *** wheel ***
/**
* @author hofk
*/
-->
<html lang="de">
<head>
<title> numberwheel </title>
<meta charset="utf-8" />
</head>
<body>
</body>
<script src="three.min.88.js"></script>
<script src="OrbitControls.js"></script>
<script src="THREEx.WindowResize.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 20000 );
camera.position.set( 250, 100, 60 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xdddddd, 1 );
var container = document.createElement('div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
THREEx.WindowResize( renderer, camera );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.enableZoom = true;
var clock = new THREE.Clock( true );
var time;
// material
var uvTex = new THREE.TextureLoader().load( "uvgrid_w_0_9 .jpg" );
var material = new THREE.MeshBasicMaterial( { map: uvTex, side: THREE.DoubleSide } );
var geometry = new THREE.CylinderGeometry(80, 80, 80, 10, 1, true);
// mesh
var mesh1 = new THREE.Mesh( geometry, material );
scene.add( mesh1 );
mesh1.rotation.x = 1.57;
animate();
function animate() {
requestAnimationFrame( animate );
time = clock.getElapsedTime();
mesh1.rotation.y = 0.4 * time;
renderer.render( scene, camera );
controls.update();
}
</script>
</html>
Man benötigt nur passende Grafiken - da gibt es andere Experten als mich!
Mein Versuch:
|
|
|
| |
|
|
|
HofK | |
|
| |
|
|
|
HofK | Habe die Nähte erst einmal beiseite gelegt und die Festlegung des Materialindex je face per String-Datenfeld ergänzt. Bei THREEp geht es ganz einfach nach der Reihenfolge der faces per Halbkugel, die Strings sind für bottom bzw. top (Süd/ Nord, wenn vorhanden) für jede Kugelschicht und für die Deckebene und den Keil (wenn vorhanden).
Damit ist der Umfang nun ähnlich wie bei THREEf und die Betaphase erreicht.
Ausprobieren unter [...] oder Code bei GitHub betrachten/ downloaden unter [...] |
|
|
| |
|
|
|
HofK | Mal wieder etwas Abwechslung - eine interessante 3D Sache. -----
In einem Beitrag bei discourse.threejs.org [...] fand ich eine Spur zu einer Bibliothek zur "Mischung" von geometrischen Objekten. [...]
Darunter kann man auf der Seite einen Beispielcode editieren und so seine selbst erstellten Resultate in 3D begutachten.
Ein Versuch.
Mit a.setColor(1, 1, 0); oder a.setColor(255, 255, 255); sieht es gleich ganz anders aus.
Einfach mal probieren! |
|
|
| |
|
|
|
HofK | Weil bei der Variante mit den Kugelkoordinaten alle Dreiecke (faces) mit einerm fixierten Material versehen werden können, habe ich für die Zylindervariante THREEf nun noch den bisher dort fehlenden Boden und Deckel ergänzt.
Anders als bei der Kugel sind Boden und Deckel aber hier in der Konstruktion sehr eigenständig. Deshalb gibt es dafür zusätzlich zum Datenfeld fixedMaterial zwei extra Eigenschaften fixedMatTop und fixedMatBottom. Sie können eine Zeichenkette aus Ziffern 0 bis 9 enthalten. Platzhalter ist auch hier der Punkt. Damit werden die Materialien der Dreiecke / faces fixiert. Auch hier ist die Eingabe fehlertolerant. Also eine Zeichenkette .5.5 fixiert das zweite und vierte face auf Material 5. Überschreibt also ein Ergebnis der Funktionen materialBottom bzw. materialTop. Dabei kann Boden/ Deckel durchaus mehr als vier faces umfassen.
Bereits dort integriert: [...]
Noch nicht auf GitHub. |
|
|
| |
|
|
|
HofK | Rotationen im Raum
sind eine für den Menschen nicht ganz so einfach zu überschauende Sache.
Gäbe es Vögel mit meschlicher Intelligenz, die sich three.js verschrieben hätten, wäre das für die primitiv. Sie leben im Raum und durch die Augenstellung haben sie Rundumblick. Wenn ein Mensch einen Salto mit Schraube macht, ist das schon Medaillen verdächtig!
Wenn ich also behaupte, mein räumliches Denken ist nicht schlecht, ist das sehr relativ.
In three.js werden für Rotationen sogenannte Quaternionen benutzt. Wer das Wort noch nie gehört hat, dem geht es wie mir bis vor einiger Zeit, obwohl ich mich sehr wohl seit langer Zeit mit Mathematik beschäftige. Die Mathematik ist aber so umfangreich, dass manche Teilbereiche nur in bestimmten Anwendungsbereichen eine Rolle spielen.
Robotik [...]
Autobranche DIN 70000 [...]
Flugregler Seite 125 [...]
Und weil es für mich neu war, habe ich nach einer guten Visualisierung gesucht. Viel war nicht zu finden und entsprach dann nicht meinen Bedürfnissen.
Aber einige Grundlagen habe ich so zusammengetragen.
Umrechnung [...]
Grafikprogrammierung (Folie 24) [...]
Quaternionen und Drehungen [...]
Understanding Quaternions [...]
Freie Rotation im Raum - Kamerasteuerung [...]
Ein schöner Umrechner - aber ohne Visualisierung. [...]
______________________________________________
Dann also wieder mal selber gemacht.
Designed für Firefox.
Und dort ausprobieren / Code betrachten. [...] bzw. [...]
-----------
NACHTRAG 06.12.:
Tipp! Gibt man nicht normalisierte Werte in die Eingabefelder ein und wechselt zum Schieber, werden die Vektoren normalisiert (Länge 1). |
|
|
| |
|
|
|
p.specht
| Tolle Zusammenstellung, gute Umsetzung! Da sucht man normalerweise einen Monat im Net - Danke! |
|
|
| XProfan 11Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'... | 06.12.2017 ▲ |
|
|
|
|
HofK | Die "Rotations-Testperson" ist ja schick gemustert, was für den Zweck recht hilfreich ist, aber doch sehr einfach.
Sie besteht eben nur aus elementaren Körpern.
Kompliziertere Körper mit Funktionen zu erzeugen finde ich selbst sehr interessant - siehe oben. Aber es ist sicher nicht jedermanns Sache und nicht alle Körper lassen sich so herstellen.
Es gibt einige Tools um 3D Objekte zu erzeugen, so ist Blender sehr verbreitet. [...] Als Anfänger wird man von der Oberfläche aber erst einmal glatt "erschlagen".
Einfacher aber natürlich weniger umfangreich sind z.B. [...] (sehr einfach) [...] (Seite auch Deutsch, Software Englisch - etwas umfangreicher)
Allerdings bekam ich beim Export der benötigten .obj Dateien keine .mtl Datei für die Materialien. Diese "Bastelei" ist mir entweder zu langweilig oder zu anstrengend - nicht mein Ding.
Aber man kann auch fertige Objekte benutzen. Leider gibt es eine Vielfalt an Dateitypen. Bei three.js auf der Startseite [...] sind featured projects zu finden. So auch poly [...]
Dort kann man Objekte hoch- und einige auch runterladen. Nur habe ich wenige herunterladbare (Lizenz!) .obj Dateien ( plus .mtl Datei für das Material) gefunden.
Zur Lizenz:
Diesen Inhalt remixen Dieser Inhalt wird unter einer CC-BY-Lizenz veröffentlicht. Wenn du den Autor namentlich nennst, kannst du diesen Inhalt kostenlos verwenden.
Nun fehlt noch ein kleines Script, um den Spinner beliebig in three.js zu verwenden. Das Problem sind wie immer sich schnell ändernde Statements in three.js. Ein gutes Beispiel [...] [...] ist nach ca. 11 Monaten schon nicht mehr ganz aktuell. Es gibt Warnungen, läuft aber noch unter der aktuellen Revision 88. Ganz so einfach ist das Beispiel aber auch nicht.
Das offizielle Beispiel in threejs.org ist für Anfänger wie meist zu komplex. Erst einmal Wichtiges ist schwer herauszufiltern.
Also habe ich radikal zusammengestrichen.
Dann bleibt nur der überschaubare Kern übrig.
Etwas gewöhnungsbedürftig: Es wird in einer Funktion das Material geladen und in dieser Funktion dann das Objekt.
Wenn das Objekt erstellt wird, muss das zugehörige Material bekannt sein. Also verschachtelt man es.
var exampleObject = new THREE.Object3D();
var mtlLoaderExample = new THREE.MTLLoader( );
mtlLoaderExample.load(
'spiner.mtl', // Lizenz function (materials) {
materials.preload();
var objLoaderExample = new THREE.OBJLoader( ); objLoaderExample.setMaterials( materials ); objLoaderExample.load( 'spiner.obj', // Lizenz function (object) {
exampleObject.add(object); } ); } );
scene.add( exampleObject );
Das komplette Beispiel: [...] bzw. [...]
_________________________________
Nachträge: Da [...] gibt es einige obj Dateien mit Vorschaubild. Aber ohne Material! --- Weitere siehe Beitrag vom 16.01.2018 weiter unten. |
|
|
| |
|
|
|
HofK | Wenn man eine Geometrie "von Hand" erzeugt, siehe Quelltext (Strg+U) von [...] trägt man Werte für Positionen usw. in JavaScript Datenfelder ein. Man hat die Geometrie sozusagen voll im Griff und kann mal schnell einen Wert ändern.
Benutzt man nun aber mein Addon THREEf.js, so gibt man nur ein paar Funktionen als Parameter an und fertig ist die Geometrie.
Wie sieht die nun aber intern aus? Wie die Datenfelder?
Weil ich neugierig bin, wollte ich mir das natürlich jetzt mal ansehen. Ausserdem dazu die Idee, per Funktionen erzeugte Geometrie nachträglich zu modifizieren. Das macht Sinn, wenn die Grundform klar ist und schnell durch Funktionen erzeugt werden kann, aber einige Kleinigkeiten sehr individuell gestaltet werden sollen. Und wenn man dazu nicht ein Modellierungstool wie Blender benutzen möchte - ich möchte nicht!
Deshalb habe ich ein kleines Script geschrieben. Es gibt die Datenfelder aus. Um zu sehen, ob die auch korrekt sind und als Vorbereitung zu Umsetzung der Idee zur Modifizierung der Geometrie, habe ich aber nicht die Zahlenwerte aneinandergereiht, sondern um sie herum auch den JavaScript Code zur Erzeugung der Geometrie per three.js mit generiert. Kopiert man nun diesen Code per Strg+A, Strg+C, Strg+V in eine leere Datei geo.js und bindet diese per <script src="geo.js"></script> in das Script mit der Ausgabe ein, erhält man nach Aktualisierung den Vergleich, wenn im Script noch
// skript geo.js definiert Geometrie geo var me = new THREE.Mesh( geo, materials ); scene.add( me ); me.add( geo.quadLine ); me.position.x = 50;
zur Erzeugung der gedoppelten Geometrie 50 rechts ergänzt wird. Unten dran das zu kopierende JavaScript.
Der Quellcode:
<!DOCTYPE html>
<!-- *** modify THREEf geometries ***
/**
* @author hofk / https://sandbox.threejs.hofk.de/
*/
-->
<html lang="de">
<head>
<title> modify </title>
<meta charset="utf-8" />
</head>
<body>
<div id="webGL"> </div>
<div id="output"> output </div>
</body>
<script src="three.min.88.js"></script>
<script src="OrbitControls.js"></script>
<script src="THREEx.WindowResize.js"></script>
<script src="THREEf.js"></script>
<script src="geo.js"></script>
<script>
'use strict'
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 200000 );
camera.position.set( 0, 80, 200 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xeeeeee, 1 );
var container = document.getElementById('webGL' );
container.appendChild( renderer.domElement );
THREEx.WindowResize( renderer, camera );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.enableZoom = true;
// material
var uvTex = new THREE.TextureLoader().load( "uvgrid01.png" );
var waterlilyTex = new THREE.TextureLoader().load( "waterlily.png" );
var side = THREE.DoubleSide;
var materials = [// material index:
new THREE.MeshBasicMaterial( { transparent: true, color: 0x00ff00, opacity: 0.7, side: side } ),// 0 transparent
new THREE.MeshBasicMaterial( { map: uvTex, side: side } ),// 1 uv grid
new THREE.MeshPhongMaterial( { color: 0xff0000, emissive: 0xff0000, side: side, } ),// 2 red
new THREE.MeshPhongMaterial( { color: 0x00ff00, emissive: 0x00ff00, side: side, } ),// 3 green
new THREE.MeshPhongMaterial( { color: 0x0000ff, emissive: 0x0000ff, side: side, } ),// 4 blue
new THREE.MeshPhongMaterial( { color: 0xffff00, emissive: 0xffff00, side: side, } ),// 5 yellow
new THREE.MeshPhongMaterial( { color: 0xff00ff, emissive: 0xff00ff, side: side, } ),// 6 mgenta
new THREE.MeshPhongMaterial( { color: 0x00ffff, emissive: 0x00ffff, side: side, } ),// 7 cyan
new THREE.MeshBasicMaterial( { map: waterlilyTex, side: side } ),// 8 photo waterlily (free)
new THREE.MeshPhongMaterial( { color: 0x7755ff, emissive: 0x4433dd, side: side } ),// 9 color
new THREE.MeshPhongMaterial( { color: 0x444444, emissive: 0x333333, side: side } )// 10 grey
];
var sun1 = new THREE.DirectionalLight();
sun1.intensity = 0.6;
sun1.position.set(50, 200, 300);
scene.add(sun1);
var sun2 = new THREE.DirectionalLight();
sun2.intensity = 0.5;
//sun2.position.set(-50, -200, 300);
sun2.position.set(0, 0, 0);
scene.add(sun2);
// geometry
var parameters = {
height: 20,
quadLine: true,
quadColor: 0xff00ff,
circOpen: true,
unrollCover: function ( v, t ) { return 0.2 },
radiusSegments: 2,
heightSegments: 1,
rCircHeight: function ( u, v, t ) { return u + v },
materialCover: function ( u, v, t ) { return 0 },
}
var geometry = new THREE.BufferGeometry();
geometry.createMorphGeometry = THREEf.createMorphGeometry;
geometry.createMorphGeometry( parameters );
// ........... start output JavaScript Code ....................................................
var vc3 = geometry.vertices.length;
var uvc2 = geometry.uvs.length;
var fc = geometry.faceIndices.length / 3;
output.innerHTML = "var geo = new THREE.BufferGeometry(); <br />";
output.innerHTML += "geo.faceIndices = new Uint32Array( [ " + geometry.faceIndices + " ] ); <br /> ";
output.innerHTML += "geo.vertices = new Float32Array( [ ";
for ( var v = 0; v < vc3 ; v ++ ) {
output.innerHTML += geometry.vertices[ v ];
output.innerHTML += v < vc3 - 1 ? ", " : "";
}
output.innerHTML += " ] ); <br /> ";
output.innerHTML += "geo.normals = new Float32Array( [ ";
for ( var v = 0; v < vc3 ; v ++ ) {
output.innerHTML += geometry.normals[ v ];
output.innerHTML += v < vc3 - 1 ? ", " : "";
}
output.innerHTML += " ] ); <br /> "
output.innerHTML += "geo.uvs = new Float32Array( [ ";
for ( var v = 0; v < uvc2 ; v ++ ) {
output.innerHTML += geometry.uvs[ v ];
output.innerHTML += v < uvc2 - 1 ? ", " : "";
}
output.innerHTML += " ] ); <br /> "
output.innerHTML += "geo.setIndex( new THREE.BufferAttribute( geo.faceIndices, 1 ) ); <br /> geo.addAttribute( 'position', new THREE.BufferAttribute( geo.vertices, 3 )); <br />geo.addAttribute( 'normal', new THREE.BufferAttribute( geo.normals, 3 )); <br /> geo.addAttribute( 'uv', new THREE.BufferAttribute( geo.uvs, 2 ) );<br /> ";
output.innerHTML += "var geoG = [ ";
for ( var f = 0, p = 0; f < fc ; f ++, p += 3 ) {
output.innerHTML += geometry.groups[ f ].start + ", " + geometry.groups[ f ].count + ", " + geometry.groups[ f ].materialIndex ;
output.innerHTML += f < fc - 1 ? ", " : "";
}
output.innerHTML += " ]; <br /> ";
output.innerHTML += " for ( var f = 0, p = 0; f < " + fc + "; f ++, p += 3 ) { geo.addGroup( geoG[ p ], geoG[ p + 1 ], geoG[ p + 2 ] ); } <br /> ";
if ( geometry.quadLine ) {
output.innerHTML += "geo.lineGeometry = new THREE.BufferGeometry(); <br />";
output.innerHTML += "geo.quadLine = new THREE.Line( geo.lineGeometry, new THREE.LineBasicMaterial( { color: " + geometry.quadColor + "} ) ); <br />";
output.innerHTML += "geo.linePositions = new Float32Array( [ ";
for ( var v = 0; v < 2 * vc3 ; v ++ ) {
output.innerHTML += geometry.linePositions[ v ];
output.innerHTML += v < 2 * vc3 - 1 ? ", " : "";
}
output.innerHTML += " ] ); <br /> ";
output.innerHTML += "geo.lineGeometry.addAttribute( 'position', new THREE.BufferAttribute( geo.linePositions, 3 ) ); <br />";
}
// .............. end output JavaScript Code .......................................................
// mesh
var mesh = new THREE.Mesh( geometry, materials );
scene.add( mesh );
mesh.add( geometry.quadLine );
mesh.colorsNeedUpdate = true;
//... skript geo.js def. Geometry geo ............ ......
var me = new THREE.Mesh( geo, materials );
scene.add( me );
me.add( geo.quadLine );
me.position.x = 50;
//..........................................................
animate();
//-----------------
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
controls.update();
}
</script>
</html>
|
|
|
| |
|
|
|
HofK | Wenn man die Geometrie modifizieren möchte, benötigt man den 3D Zugriff per Maus und einige Informationen. Dazu konnte ich mein Raycaster Beispiel [...] als Grundlage verwenden.
Raycaster ermittelt so manche Werte.
Wie bei der Vorstellung des Beispiels (erste Version 29.10.2016 , deutsch) besprochen, werden Positionen im lokalen Speicher des Browsers abgelegt. Neuere Browserversionen ermöglichen nun den Zugriff! Da kann man nach den gespeicherten Werten sehen und sie bei Bedarf auch löschen. Mit Firefox sieht das beim Beispiel so aus.
Also mal schauen, was andere Seiten da so abladen!
Kein Geheimnis: Laufende Projekte bearbeite ich aus einer RAM-Disk heraus. Kein Festplattenlärm, SSD schonen und superschnell.
Wie man im oberen Bild erkennt, trat bei indices ein Fehler auf.
undefined
Nach Recherche fand ich ein Problem und das für mich erstaunlicherweise bei BufferGeometry faceIndex funktioniert.
Das habe ich mal als Frage bei discourse.threejs.org gestellt: [...]
Soeben kam schon eine Antwort herein! |
|
|
| |
|
|
|
HofK | Mittlerweile habe ich ein wenig an der Manipulation der Positionen der Geometrie herumgewerkelt. Das Prinzip ist eigentlich ganz einfach, aber wie so oft steckt der im Detail und hat mir manchmal dazwischengefunkt.
Man berechnet die Richtung und den Abstand (Vektor) des Schnittpunktes des Strahls von der Kamera mit der Hilfsebene (raycaster.intersectObjects( ... ) zu den Ecken a, b, c des Dreiecks. Bewegt man dann die Maus, werden die Eckpunkte entsprechend mitbewegt, indem man den Vektor addiert.
Der noch unfertige Arbeitsstand ist aktuell als Video dort [...] (Mittlerweile dort neuere Videos!) zu sehen.Die Reaktion der Hilfsebene auf die Mausbewegung macht mir noch Probleme, da ist Feinarbeit angesagt, oder es muss etwas am Grundkonzept geändert werden.
Ich hatte mit gridHelperXY = new THREE.GridHelper( ... noch insgesamt drei Hilfsgitter eingeblendet, aber dann war die Mausreaktion "Glückssache".
Die eigentliche Manipulation der Werte im Datenfeld ist sehr überschaubar:
Dabei ist handle... der Schnittpunkt auf der Hilfsebene senkrecht zur Kamera und paV, pbV und pcV die Vektoren von dort zu den Eckpunkten.
|
|
|
| |
|
|
|
ByteAttack | Ob sich das wirklich hier im Forum wirklich anschaut? Wage ich zu bezweifeln... ich persönlich finde deine Arbeit toll! |
|
|
| |
|
|