| |
|
|
- 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 8 - |
|
|
HofK | Wer die Wahl hat, hat die Qual!
Es gibt so einige Möglichkeiten an der Grundform Kugel herumzuwerkeln.
Was soll man da nehmen
Nach Boden und Deckel habe ich probiert die Kugelkeile zu schließen.
Das funktioniert ohne großen Aufwand, wenn man die faces mit den vorhandenen vertices bildet. Da ich vorerst mit indexed BufferGeometry arbeite, wird aber sofort das Problem mit dem uv-Mapping deutlich. Die vertices haben bereits uv's und so ergibt sich die Verzerrung der Textur.
Beim Boden / Deckel am Pol ist das ja korrekt, wie man bei den Bildern der letzten Beiträge erkennt. Aber Boden / Deckel als Gegenstück zum Pol ergeben auf diese Art eine spiegelbildliche Textur - im Bild zu erkennen. Bei der "abgewählten" Geometry hat man das Problem nicht, da die uv's bei den faces gespeichert werden.
Bei BufferGeometry gibt es nur vertex uv's. Man muss also alle betroffenen vertices bei selber Lage - zeitabhängig in morphVertices() - doppeln und damit die neuen faces bilden. Dann kann man sogar eine eigene Textur aufbringen. Will man das? Ein erheblicher Mehraufwand!
Dabei: Warum die Geometry trotz aller Theorie und Absicht flotter ist, weiß ich immer noch nicht. [...] [...]
Ehe ich mich entscheide, werde ich erst einmal schauen, wie ich die Kugel breitquetschen kann. Wie bei THREEf unrollCover wird der Radius auf dem die verices liegen immer größer, bis fast unendlich. Dann gibt es hier wenn gleichmäßig gequetscht wird schließlich zwei Kreise (Süd / Nord) mit dem Radius r * PI/2.
squeeze,// function ( v, t )// 0 sphere to 1 flat circle
Das funktioniert anders als stretchSouth / stretchNorth Da wird nur die y Koordinate per verändertem Radius manipuliert.
function xyzCalculation( south_north, phi, theta, thetaY ) { r = g.radius * g.rPhiTheta( nji, ni, t ); x = r * Math.cos( theta ) * Math.cos( phi ) + g.radius * g.moveX( nji, ni, t ); z = - r * Math.cos( theta ) * Math.sin( phi ) + g.radius * g.moveZ( nji, ni, t ); r *= ( south_north === SOUTH ? g.stretchSouth( nji, ni, t ) : g.stretchNorth( nji, ni, t ) ) ; y = r * Math.sin( thetaY ) + south_north * gap + g.radius * g.moveY( nji, ni, t ); } |
|
|
| |
|
|
|
p.specht
| Wahnsinn, was da alles geht! |
|
|
| XProfan 11Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'... | 25.08.2017 ▲ |
|
|
|
|
HofK | |
|
| |
|
|
|
HofK | Nach einigen Fehlversuchen und auch Änderungen am vorhandenen Code ist nun THREEp.js ( rev 87.1 alpha ) auf GitHub [...] und auch schon bei [...] gepostet.
Übrigens nutze ich neuerdings deepl [...] als Übersetzungshilfe. Macht sich besser als Google Translator.
Das habe ich ( mit nachträglichen eigenen Anpassungen - die Fachtermini sind immer ein Problem) übersetzt:
THREEp.js. - eine erweiterte Alpha Version ist nun auf GitHub verfügbar.
- Es funktioniert mit three.js r87. - Die Kugelkeile können an der Seite geschlossen werden (default). - Die Äquator Lücke ist nun als Funktion verfügbar.
Mit der Äquator Lücke - nun als Funktion - öffnet und schließt ein kleines Monster sein Maul. Mit Parameter t - Zeit.
screenshots exampleA2.html
Die Bilder mal nur da: [...]
var parameters = {
equator: 4,
equatorGap: function( u, t ) { return 0.5 *( 1 + Math.cos( 6.28 * u)) *( 0.5 - u )*( 0.5 - u ) * ( 1 + Math.sin( t ) ) }, stretchSouth: function ( u, v, t ) { return ( 1 + Math.cos( 6.28 * u)) *( 0.5 - u )*( 0.5 - u ) * ( 1 + Math.sin( t ) ) },
wedges: 11, usedWedges: 8,
topCircle: 7, withTop: true,
bottomCircle: 3, withBottom: true,
}
|
|
|
| |
|
|
|
HofK |
Die Quetschung ist doch komplizierter, als ich mir das so vorgestellt hatte: Einfach draufdrücken und fertig.
Deshalb habe ich nach einigen Bleistift- Kritzeleien ganz gegen meine Art doch mal eine halbwegs saubere Skizze fabriziert:
Beispielsweise unter [...] findet man ausreichend viele Formeln zur Berechnung.
Der Bogen des Viertelkreises mit dem Radius 1 muss auf den Bogen des halben Kreissegments abgebildet werden. Die Bogenlänge ist stets Pi/2.
Dabei ist die Teilung der Schnittpunkte auf der x und y Achse nicht proportional! Hat man die Höhe auf 0,5 gedrückt, ist die halbe Sehne bereits auf deutlich mehr als die Hälfte von 1 zu Pi/2 vorgerückt.
Beim Versuch, eine Funktion für die Abhängigkeit zu ermitteln habe ich sehr schnell aufgegeben. Trigonometrische Gleichungen sind nicht immer geschlossen lösbar. Der ermittelte Zusammenhang
cos( Pi / (2*r) ) = 1 - h/r, (r squeeze) um das Zentrum und den Winkel des großen Kreises zu bestimmen, machte wenig Mut.
Vielleicht ist unter den Lesern ein Trigonometrieexperte der das löst oder zeigt: nicht lösbar?
Deshalb verfolge ich folgenden Ansatz:
Ich gebe eine fiktive Quetschrate vor und ermittele daraus dann die zugehörigen benötigten Werte:
Aus h = r * ( 1 - cos (alpha / 2 ) ) mit r = (Pi/2) / alpha kann man die Höhe und dann die anderen Werte ermitteln. Dabei zeigt sich, dass Quetschrate (squeeze) und Höhe etwa "zueinander passen". qSq = 1 - squeeze
Etwas schwieriger als bei den Zylinderkoordinaten in THREEf gestaltet sich auch die Mischung der Funktionen. Der Winkel Theta wird durch die Quetschung verändert, ist aber Argument der Funktionen.
Der noch nicht optimierte aber funktionierende Code:
// ////// only squeeze //////////// /////////////////////////////////////////////////// qSq = 1 - g.squeeze( t ); alphaSq = qSq * pi2; // squeeze angle rSq = 1 / qSq; // radius squeeze circle hSq = pi2 / alphaSq * ( 1 - Math.cos( alphaSq ) ); // height (squeezed) cSq = rSq - hSq; // center(y)squeeze circle /////////////////////////////////////////////////////////////////////////////////////////////
function xyzCalculation( south_north ) {
r0 = g.radius; x0 = r0 * Math.cos( theta ) * Math.cos( phi ); y0 = r0 * Math.sin( thetaY ); z0 = -r0 * Math.cos( theta ) * Math.sin( phi ); r1 = g.radius * g.rPhiTheta( nji, ni, t ); r1y = r1 * ( south_north === SOUTH ? g.stretchSouth( nji, ni, t ) : g.stretchNorth( nji, ni, t ) ); x1 = r1 * Math.cos( theta ) * Math.cos( phi ) + g.radius * g.moveX( nji, ni, t ); y1 = r1y * Math.sin( thetaY ) + g.radius * ( south_north * g.equatorGap( nji, t ) / 2 + g.moveY( nji, ni, t ) ); z1 = - r1 * Math.cos( theta ) * Math.sin( phi ) + g.radius * g.moveZ( nji, ni, t ); dx = x1 - x0; dy = y1 - y0; dz = z1 - z0; //------------ r2 = r0 * rSq;
thetaSq = south_north * ( pi2 - alphaSq ) + alphaSq * theta / pi2 ; thetaSqY = south_north * ( pi2 - alphaSq ) + alphaSq * thetaY / pi2 ;
x2 = r2 * Math.cos( thetaSq ) * Math.cos( phi ); y2 = r2 * Math.sin( thetaSqY ) - south_north * r0 * cSq; z2 = - r2 * Math.cos( thetaSq ) * Math.sin( phi ); // ------------ x = x2 + dx; y = y2 + dy; z = z2 + dz; }
Schnappschüsse (Funktion mit t - Zeit):
var parameters = {
equator: 5, //squeeze: function( t ) { return 0.99}, // bei 1 noch FEHLER 1/0 - Radius UNENDLICH squeeze: function( t ) { return 0.45 * ( 1 + Math.sin( 0.5 * t ) ) }, rPhiTheta: function ( u, v, t ) { return 0.75 + 2 * (0.5-v)*(0.5-v) + 0.2 * Math.sin( 6.28 * u) },
stretchNorth: function ( u, v, t ) { return 1 + 0.4 * u },
wedges: 5, usedWedges: 4,
} |
|
|
| |
|
|
|
HofK | Im obigen Beispiel ist squeeze noch auf den Parameter t beschränkt. Natürlich kommt hier noch der azimutale Winkel hinzu und die Quetschung kann rundherum dosiert werden. Zwei Schnappschüsse mit einer Dahlie von der IGA in Berlin:
var parameters = {
squeeze: function ( u, t ) { return 0.45 * ( 1 + Math.sin( 6.28 * u ) * Math.sin( t ) ) },
equator: 8, wedges: 6, usedWedges: 5, wedgeOpen: false, // default is true now
}
Da es durch die verschiedenen Funktionen auch Sinn macht bei wedges === usedWedges wedgeOpen zu nutzen, habe ich das inhaltlich geändert. |
|
|
| |
|
|
|
HofK | Um die Neuerungen in THREEp.js einfacher testen zu können und um auch diese Sandbox immer halbwegs aktuell zu haben, startet die Box jetzt in der alpha Phase.
Dazu habe ich auf sandbox.threejs.hofk.de/ [...] eine Auswahlseite hochgeladen.
Von dort kommt man zur "alten" Sandbox THREEf und zur in der Entwicklung befindlichen Box für THREEp.
Der direckte Weg ist
sandboxthreef.threejs.hofk.de/ [...]
bzw.
sandboxthreep.threejs.hofk.de/ [...]
Beide Seiten funktionieren nur mit Firefox.
|
|
|
| |
|
|
|
HofK | Nun funktioniert teilweise schon Multimaterial.
var materials = [
// material index:
new THREE.MeshBasicMaterial( { transparent: true, opacity: 0.15, 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: dahliaTex, side: side } ),// 8 photo dahlia (free)
new THREE.MeshPhongMaterial( { color: 0xee55ff, emissive: 0x7733dd, side: side } ),// 9 color
new THREE.MeshPhongMaterial( { color: 0x444444, emissive: 0x333333, side: side } )// 10 grey
];
var parameters = {
materialSouth: function ( u, v, t ) { return u },
materialNorth: function ( u, v, t ) { return v },
equator: 10,
wedges: 10,
}
Da Material 0 transparent ist, kann man in die Kugel, durch die Kugel hindurch schauen.
Bei 10 Kugelkeilen bzw. Ringen bis zum Äquator werden die Materialien 0 bis 9 genutzt.
In der Sandbox [...] kann man das selber ausprobieren (Firefox).
Die Materialspielerei erreicht man wieder durch "passende" Indexrechnungen.
Dabei fallen die Differenzen der Quadrat wie i * i - g.bottomCircle * g.bottomCircle ins Auge. Die Quadrate sind die Summe der faces in einem Keil vom Pol beginnend, 1 + 3 + 5 + 7 ..., also Summe der ungeraden Zahlen. Das Ergebnis ist das Quadrat der Anzahl der Summanden, hier also 4*4 = 16.
|
|
|
| |
|
|
|
ByteAttack | Ist echt der Hammer den Du da machst! Wenn es so weiter geht, bekommst Du hier noch deine eigene Wiki... |
|
|
| |
|
|
|
HofK | Ein fieser Bug hat mich genervt und Zeit gekostet. Er war schon länger drin. Aber nur bei bestimmten Parameterkonstellationen wurde er sichtbar. So konnte er längere Zeit durchschlüpfen.
Es fehlten plötzlich faces! Bei genauerer Betrachtung waren dafür an identischer Position faces doppelt vorhanden.
Da der Code doch schon etwas komplexer ist und die Struktur komplizierter als beim Zylinder, konnte ich den Fehler nicht finden und habe einige mit ähnlichen Fehlern behaftete Varianten produziert .
Der positive Nebeneffekt ist, dass die Funktion vertexNumbersHelper nun auf vertexFaceNumbersHelper erweitert ist. Wahlweise vertices oder faces oder beide Dinge.
Mit dieser Hilfe hatte die Wanze dann keine Chance mehr.
Im Endeffekt war es eine fehlerhafte Zählung in der Schleife für die wedges. Nur wenn Nord- und Südhalbkugel mit geschlossenem Kugelkeil gebildet wurden und der Bodenkreis nicht 0 war, trat der Fehler im südlichen wedge auf und die letzten faces der Nordhalbkugel fehlten. Das Material war dann falsch zugeordnet. Hier eine der produzierten Fehlleistungen: falsch
... aber richtig
Sicher noch nicht fehlerfrei - ALPHA - aber zum experimentieren geeignet die aktuelle Version dort: [...] (firefox) |
|
|
| |
|
|
|
HofK | Wer keine Zeit oder Lust hat in der sandbox selber etwas auszuprobieren, kann jetzt da [...] schnell Video schauen. Kein abendfüllendes Programm, aber immer auf dem aktuellen Stand. Immer die neuesten Kreationen! ...........................................................................
Jetzt stehe ich vor einer Designentscheidung. Und die ist schwieriger als vorhin beim Hecke schneiden - rund kurz oder mehr dranlassen. Die Natur wird es sowieso wieder wachsen lasssen. Das Softwaredesign ist da statischer!
Das Problem: Die Skalierung des Azimuts (phi) bezieht sich ganz natürlich auf beide Halbkugeln:
endAzimuth,//function ( v, t )// end azimuth angle phi (per theta) startAzimuth,//function ( v, t )// starting azimuth angle phi (per theta) scaleAzimuth,//function ( u, t )// scaling between start and end of azimuth angle ( phi 0 .. 2*PI)
Beim Polwinkel ist das nicht so klar. Intern wird jede Halbkugel gesondert vom Pol zum Äquator berechnet. Möchte man jetzt vom Südpol zum Nordpol skalieren, gibt es eine umfangreiche Unterscheidung wie bei der Erstellung der vertices und faces. Dort ist das kein Problem, da die Sache nur einmal ausgeführt wird. Die Skalierung muss aber ständig in der Funktion xyzCalculation( south_north ) zeitabhängig berechnet werden.
Bei stretch... habe ich mich schon für zwei gesonderte Funktionen für die Halbkugeln entschieden. Der weiter oben abgebildete "Zahn" zeigt, dass es durchaus Sinn macht.
Momentan ist es so, dass die Funktionen identisch auf beide Halbkugeln wirken.
(Zählung für Halbkugeln nih, - für Kugel ni, - Vertices im Kreis i: nji; Äquator ist eqt )
Gut am Netzwerk erkennbar die Skalierung nach der Wurzelfunktion. Die Berechnung für Nord -und Südpol und das Zentrum in der Mitte fehlt noch, deshalb nicht korrekt!
Nimmt man zwei getrennte Funktionssätze, muss der Nutzer bei Bedarf diese so "auswählen", dass eine gewünschte einheitliche Skalierung von Süd nach Nord entsteht. Das ist wiederum nachteilig weil etwas schwieriger als mit einem Funktionssatz zu arbeiten.
Ich nehme gern sachdienliche Hinweise entgegen!
........----- |
|
|
| |
|
|
|
HofK | Die Skalierung ist fast geschafft.
scalePole: function( v, t ) { return Math.sqrt( v ) },
scalePoleH: function( v, t ) { return Math.sqrt( v ) },
Da ich mich nicht entscheiden konnte, ist ein Kompromiss die beste Lösung.
Man kann eine Funktion scalePoleHemisphere oder scalePole angeben. Intern wird mit zwei Funktionen für Süd und Nord gearbeitet. Dabei bedurfte es nicht der befürchteten Unterscheidung wie bei der Erstellung der Geometrie. Eine sinnvolle Umrechnung genügt!
Die Angabe von Funktion scalePole überschreibt eine vorhandene Funktion scalePoleH. |
|
|
| |
|
|