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. Da  [...]  (ganz unten) die ersten Resultate.
 
31.01.2016  
 



 
- Seite 20 -



HofK
Bei Experimenten zu geometrischen Figuren bin ich darauf gestoßen, dass man Kreise und Kugeln auch ohne trigonometrische Funktionen wie allgemein üblich, sehr einfach generieren kann.

Der Aufbau ist generell wie bei der Magischen Kugel in meinem Addon passend zum Logo von discourse. Allerdings habe ich diesmal indexed BufferGeometry benutzt.



Dort anzuschauen:  [...] 

Korrektur 15.April

Da ich meist nur THREE.DoubleSide und wireframe: true benutzt habe, blieb mir der Fehler verborgen. Die Hälfte der Oktanten hatte die Frontseite innen!

Dort muss man die Reihenfolge der Indizes umkehren. Also ist die Funktion
indicesPartSphere( p ) zu korrigieren.
Ich benutze
spin = ( p === 0 || p === 2 || p === 5 || p === 7 ) ? true : false;

Der komplette (korrigierte) Code:
<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/sphere-without-use-of-trigonometric-functions/6856  -->
<!-- http://discourse.threejs.hofk.de/2019/SphereWithoutTrigonometry/SphereWithoutTrigonometry.html -->
<head>
<title> SphereWithoutTrigonometry </title>
<meta charset="utf-8" />
</head>
<body> 	</body>
<script src="../js/three.min.103.js"></script>
<script src="../js/OrbitControls.js"></script>
<script>
// @author hofk
'use strict';
const sumNN = ( n ) => ( n * ( n + 1 ) / 2 );// Sum natural numbers
const sumON = ( n ) => ( n * n );// Sum odd numbers
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 100 );
camera.position.set( 0, 1, 8 );
const renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xdddddd, 1 );
const container = document.createElement('div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
const controls = new THREE.OrbitControls( camera, renderer.domElement );
const tex1 = new THREE.TextureLoader().load('uvgrid01.png' );
//const material = new THREE.MeshBasicMaterial( { map: tex1, side: THREE.DoubleSide } );
const tex2 = new THREE.TextureLoader().load('dahlia.png' );
const material = [
new THREE.MeshBasicMaterial( { map: tex1, side: THREE.DoubleSide } ),
new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide, wireframe: true } ),
new THREE.MeshBasicMaterial( { color: 0xff00ff, side: THREE.DoubleSide } ),
new THREE.MeshBasicMaterial( { color: 0x00ffff, side: THREE.DoubleSide, wireframe: true } ),
new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } ),
new THREE.MeshBasicMaterial( { map: tex2, side: THREE.DoubleSide, wireframe: false } ),
new THREE.MeshBasicMaterial( { color: 0x33ff55, side: THREE.DoubleSide } ),
new THREE.MeshBasicMaterial( { map: tex1, side: THREE.DoubleSide } )
];
const g = new THREE.BufferGeometry( );
//SphereWithoutTrigonometry( g, 2.5, 10, [ 1,1,0,0, 1,0,1,0 ] );  //  ( BufferGeometry, radius, equator, parts )
//equator = half of height segments = quarter of equatorial segments
SphereWithoutTrigonometry( g, 3,18 );
const mesh = new THREE.Mesh( g, material );
scene.add( mesh );
animate();

function animate() {

    requestAnimationFrame( animate );
    renderer.render( scene, camera );
    controls.update();

}

function SphereWithoutTrigonometry( g, r, eqt, parts ) {//  ( BufferGeometry, optional: radius, equator, parts )

    r = r !== undefined ? r : 1;
    eqt = eqt !== undefined ? eqt : 8;
    // parts array, value 1 for octant, otherwise arbitrary - upper counterclockwise, lower clockwise seen from below
    parts = parts !== undefined ? parts : [ 1,1,1,1, 1,1,1,1 ];
    let pCount = 0;

    for ( let p = 0; p < 8; p ++ ) {

        pCount += parts[ p ] === 1 ? 1 : 0;

    }

    let posIdx = 0;// position index
    let uvIdx = 0;// uv index
    let fIdx = 0;// face index
    const vertexCount = sumNN( eqt + 1 ) * pCount;
    const faceCount = sumON( eqt ) * pCount;
    g.faceIndices = new Uint32Array( faceCount * 3 );
    g.vertices = new Float32Array( vertexCount * 3 );
    g.uvs = new Float32Array( vertexCount * 2 );
    g.setIndex( new THREE.BufferAttribute( g.faceIndices, 1 ) );
    g.addAttribute('position', new THREE.BufferAttribute( g.vertices, 3 ) );
    g.addAttribute('uv', new THREE.BufferAttribute( g.uvs, 2 ) );
    pCount = 0;

    for ( let p = 0; p < 8; p ++ ) {

        if (  parts[ p ] === 1 ) {

            indicesPartSphere( p );
            verticesUVsPartSphere( p );
            pCount += 1;

        }

    }

    function indicesPartSphere( p ) {

        let a0, a1, b0, b1;// indices
        let spin = ( p === 0 || p === 2 || p === 5 || p === 7 ) ? true : false;
        a0 = sumNN( eqt + 1 ) * pCount;// start vertex index per part
        g.addGroup( fIdx, sumON( eqt ) * 3, p );// write groups for multi material

        for ( let i = 0; i < eqt; i ++ ) {

            a1 = a0 + 1;
            b0 = a0 + i + 1;//  below ( i )
            b1 = b0 + 1;
            // each two faces

            for ( let j = 0; j < i; j ++ ) {

                g.faceIndices[ fIdx     ] = j + a0;// left face
                g.faceIndices[ fIdx + 1 ] = j + ( spin ? b1 : b0 );
                g.faceIndices[ fIdx + 2 ] = j + ( spin ? b0 : b1 );
                g.faceIndices[ fIdx + 3 ] = j + a0;// right face
                g.faceIndices[ fIdx + 4 ] = j + ( spin ? a1 : b1 );
                g.faceIndices[ fIdx + 5 ] = j + ( spin ? b1 : a1 );
                fIdx += 6;

            }

            g.faceIndices[ fIdx     ] = i + a0;// last face in row ( like a left face )
            g.faceIndices[ fIdx + 1 ] = i + ( spin ? b1 : b0 );
            g.faceIndices[ fIdx + 2 ] = i + ( spin ? b0 : b1 );
            fIdx += 3;
            a0 += i + 1;// next start index

        }

    }

    function verticesUVsPartSphere( p ) {

        const signX = ( p === 0 || p === 3 || p === 4 || p === 7 ) ? 1 : -1;
        const signY = p < 4 ? 1 : -1;
        const signZ = ( p === 2 || p === 3 || p === 6 || p === 7 ) ? 1 : -1;
        let xp, yp, zp, len;
        let ux = 0.5;
        let du = 1 / eqt;
        let uy = 1 + du;

        for ( let i = 0 ; i <= eqt; i ++ ) {

            yp =  1 -  i / eqt;
            ux =  0.5 + signX * signY * signZ * ( i + 2 ) * du / 2;
            uy -= du;

            for ( let j = 0; j <= i ; j ++ ) {

                xp =  ( i -  j ) / eqt;
                zp =  j / eqt;
                len = Math.sqrt( xp * xp + yp * yp + zp * zp );// to normalize
                g.vertices[ posIdx     ] = r * signX * xp / len;
                g.vertices[ posIdx + 1 ] = r * signY * yp / len;
                g.vertices[ posIdx + 2 ] = r * signZ * zp / len;
                posIdx += 3;
                ux += -signX * signY * signZ * du;
                g.uvs[ uvIdx ] = ux;
                g.uvs[ uvIdx + 1 ] = uy;
                uvIdx  += 2;

            }

        }

    }

}

</script>
</html>
 
vor 26 Tagen  
 




p.specht
Toll! Aber du dürftest auch einen sehr schnellen Rechner haben, oder?
 
XProfan 11
So Computer sind halt auch nur Menschen...
vor 25 Tagen  
 




HofK
p.specht (02.04.2019)
Toll! Aber du dürftest auch einen sehr schnellen Rechner haben, oder?


Keineswegs, mein Laptop ist in die Jahre gekommen, habe das Gerät 2013 erstanden. Ein 17 Zoll ASUS N76V mit i7 der damaligen Generation. Da zwei zugängliche Plattenschächte vorhanden waren, habe ich eine SSD als Systemlaufwerk eingebaut und nutze die Festplatte für Daten. Die Grafikkomponente für meinen 22 Zoll externen Monitor hat schon vor einiger Zeit den "Geist" aufgegeben. Mit einem USB to HD Adapter an USB 3 reicht das für mich aber. Ist allerdings nichts für Spielefreaks.

Die Kugel ohne trigonometrische Funktionen erfordert intern weniger Aufwand als mit!

Momentan bastele ich an einer Kugel, die man gleichzeitig mit Öffnungen parallel zu allen Koordinatenflächen versehen kann. Der erste, unvollständige Entwurf (zwei Teilflächen fehlen, Öffnung fehlt):



Er ist mir zu kompliziert, ich suche noch nach einer einfacheren Lösung.
 
vor 18 Tagen  
 



 
- Seite 21 -



HofK
Diese Lösung ist recht einfach, erzeugt aber keine kreisförmigen Öffnungen. Man kann sie aber eventuell als Ausgangspunkt nehmen und das Netz passend "verbiegen". Ich werde es probieren.

 
vor 17 Tagen  
 




HofK
Beim herumexperimentieren gibt es immer wieder interessant aussehende Fehlentwürfe.

Da sind wohl Vorzeichen nicht ganz in Ordnung und die Radiuskonstante wurde an einer Stelle vergessen. Sieht aber interessant aus.



Fehler gefunden, nun sieht es so aus.



Man erkennt schon, wie es werden soll. Das Problem ist, dass die sonst horizontalen Bögen hier schräg verlaufen müssen und sich unterschiedliche face-Reihen ergeben.

Betrachtet man die Konstruktion aus einer anderen Perspektive, sieht man besser, dass ich noch geschummelt habe.



Um das Verfahren zu testen, habe ich die linke und rechte Kante der unteren Bereiche einfach durch Geraden verbunden.

Daraus müssen nun noch "Geraden auf der Kugel" - also Kreisbögen werden.

Da kann ich wieder die Radiuskonstante vergessen!

Die Rechnerei für dieses Verfahren ist komplizierter als im ersten Entwurf, erscheint mir aber insgesamt effizienter. Allerdings hat man durch die "schrägen" Linien/Bögen keine so schöne Symmetrie-
 
vor 15 Tagen  
 




p.specht
Könnte es sein, daß Du ein Faible für Netzstrümpfe hast ?
 
XProfan 11
So Computer sind halt auch nur Menschen...
vor 13 Tagen  
 




HofK
Eher ein Faible für mathematische Netze, Netzstrümpfe sind mathematisch sehr schwer zu erfassen. Da nimmt man dann eine Modellierungs-Software.

Das Netz aus Dreiecken ist die Grundlage der 3D Grafik, also führt nichts daran vorbei.
 

Und es gibt so schöne Fehlentwürfe!





Aber wie das Sprichwort sagt "Ende gut, alles gut"



Die Lösung erfordert weniger Teilflächen als der erste Ansatz, ist aber nicht so symmetrisch, wenn man verschieden große Öffnungen hat (hier alle gleich ). Allerdings ist die Rechnung etwas "spezifisch", aber gut überschaubar.

Der Code muss noch optimiert werden, momentan noch "wirr" und nicht vorzeigbar.
 
vor 13 Tagen  
 




HofK
Die Kugel mit unterschiedlich großen Öffnungen, der Code ist noch in Überarbeitung.



Mich hat dann doch der Vergleich der Varianten interessiert. Die symmetrische Lösung macht bei der Erweiterung von einem auf acht Oktanten recht viel Aufwand und es hakt noch.

Aber wieder ein schöner Fehlentwurf. Statt wie nötig von hinten nach vorn die Indizes im Zentrum andersherum bearbeitet.



So soll es sein.



Es gibt dann insgesamt 8 mal 7 = 56 Teilflächen!
 
vor 8 Tagen  
 




HofK
Da sind die 56 Teilflächen:



Alle Öffnungen sind verschieden groß-

Nimmt man überall die maximale Öffnung, sind tatsächlich nur 32 Teilflächen zu erzeugen. Die maximale Öffnung ist bei dieser Variante auf den halben Äquator begrenzt. Bei der anderen Variante kann eine Öffnung maximal sogar bis zum Äquator gehen (Halbkugel). Allerdings dürfen sich benachbarte Öffnungen dort nicht überschneiden.



Füllt man die Öffnungen mit THREE.CircleBufferGeometry erhält man einen sehr speziellen Spielwürfel.

Aber dazu muss ich erst noch die uv-Werte berechnen.
 
vor 5 Tagen  
 




HofK

Die Berechnung der uv-Werte konnte ich nach kleinen Anpassungen des Codes dieser symmetrischen Kugelvariante von der anderen Variante übernehmen. Diese Berechnung hatte ich vorher dort schon getestet.
function setUVs( x, y, z ) {

    let uvu;
    x += 0.4 * x * ( 1 - Math.cos( pi2 * y ) );
    z += 0.4 * z * ( 1 - Math.cos( pi2 * y ) );
    uvu = ( Math.asin( x ) + Math.acos( z ) ) / 2 / pi2;
    g.uvs[ uvIdx ] = spin ? 1 - uvu : uvu ;
    g.uvs[ uvIdx + 1 ] = Math.asin( y ) / pi2;
    uvIdx += 2;

}


Es ist wie gewohnt eine kleine Rechnerei mit trigonometrischen Funktionen.





Nun muss der Code noch ein wenig aufgeräumt und in die Form für mein Addon THREEg gebracht werden.
 
vor 4 Tagen  
 




p.specht
Würde eine Globus-Karte unverzerrt dargestellt? Oder wie müsste deren Textur aussehen?
 
So Computer sind halt auch nur Menschen...
vor 4 Tagen  
 




HofK
Da ich die Kugel in acht einzelne Teile zerlege um jede Teilfläche mit einer anderen Textur versehen zu können (Multimaterial) ist eine Globuskarte hier nicht sinnvoll möglich.

Dazu benutzt man die einfache Kugeldefinition von THREE.js mit Längen - und Breitengraden.

Man kann eine Globuskarte natürlich auf alle möglichen Formen aufbringen. Siehe mein Beispielbild rechts oben auf sandbox .threejs.hofk  [...] 

Mir geht es hier um die 6 möglichen gleichzeitigen Öffnungen in der Kugel .
 
vor 4 Tagen  
 




Antworten


Thementitel, max. 100 Zeichen.
 

Systemprofile:

Kein Systemprofil angelegt. [anlegen]

XProfan:

 Beitrag  Schrift  Smilies  ▼ 

Bitte anmelden um einen Beitrag zu verfassen.
 

Themenoptionen

55.768 Betrachtungen

Unbenanntvor 0 min.
Uwe Langvor 12 min.
RudiB.Gestern (11:31)
WalterVorgestern (17:31)
Peter Max MüllerVorgestern (17:18)
Mehr...

Themeninformationen



AGB  |  Chat  |  Datenschutz  |  Download  |  Eingangshalle  |  Hilfe  |  Impressum  |  Mart  |  Support  |  Suche

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

Datenschutz


Wir verwenden Cookies nur als Session-Cookies wegen der technischen Notwendigkeit und bei uns gibt es keine Cookies von Drittanbietern.

Wenn du hier auf unsere Webseite klickst oder navigierst, stimmst du unserer Erfassung von Informationen in unseren Cookies auf XProfan.Net zu.

Weitere Informationen zu unseren Cookies und dazu, wie du die Kontrolle darüber behältst, findest du in unserer nachfolgenden Datenschutzerklärung.


einverstandenDatenschutzerklärung
Ich möchte keinen Cookie