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 13 -



HofK
da geht es weiter ...

Eine Kugel ist überall schön rund, ein Oktaeder nur eckig und kantig.

Aber was liegt dazwischen?

Man kann ein Oktaeder stetig zu einer Kugel transformieren. Dazu benötigt man passende Zick Zack Funktionen.

Eine schöne Herleitung findet man da:  [...] 

Mit dieser Hilfe ist die Transformation dann kein Problem. Im momentanen Testcode ist die Transformation noch als Konstante 0.5 eingetragen. Da muss noch ein Parameter mit Werten 0 bis 1 ersetzt werden.

In der xyz Berechnug wurde dann einfach sin durch sinlike und cos durch coslike ersetzt - fertig.
function sinlike( x ) {

    var y1 = 2 / pi * Math.asin( Math.sin( x ) );
    var y2 = Math.sin( x );
    return y1 + 0.5 * ( y2 - y1 );

}

function coslike( x ) {

    var y1 = -2 / pi * Math.asin( -Math.cos( x ) );
    var y2 = Math.cos( x );
    return y1 + 0.5 * ( y2 - y1 );

}

function xyzCalculation( ) {

    x = g.radius( t ) * coslike( theta ) * coslike( phi );
    y = g.radius( t ) * sinlike( theta );
    z = -g.radius( t ) * coslike( theta ) * sinlike( phi );

    if ( !g.driftDefault ) {

        x += signX * g.driftX( t );
        y += signY * g.driftY( t );
        z += signZ * g.driftZ( t );

    }

}




Die Konstruktion besteht aus 8 unabhängigen Teilen. Diese können mit einem Parameter drift auseinander geschoben werden - abhängig von der Zeit. Das habe ich im Bild gemacht. Dadurch ist auch die leichte Rundung gut zu erkennen.

Ohne Drift und mit passendem Parameter erhält man ein Oktaeder.

 
04.02.2018  
 




HofK
Auch andere 2Pi periodische Funktionen ergeben interessante Formen.

Um das schnell zu testen, habe ich mal XProfan benutzt. Damit geht das ohne großen Aufwand so nebenbei. Da ich in letzter Zeit fast nur mit JavaScript gearbeitet habe, ist es ebenfalls ganz gut, auch abweichende Syntax zu verwenden. Es wird ein Punkt mit x zwischen 0 und Pi/2 und y zwischen 0 und 1 - hier (0.5, 0.75) - angegeben. Daraus werden zwei Geradenabschnitte bestimmt. Nun wird durch entsprechende Zuordnung aus diesem Teilstück die periodische Funktion gebastelt.



Daraus wird



Es ist ein Fehler im 4. (letzten) Oktanten zu erkennen. Offenbar ein nummerisches Problem, muss ich noch näher beleuchten.

Der Code:
XProfan 11
// Periodische Funktion erzeugen
Var px! = 0.5
Var py! = 0.75
//-------------
Window 0,0 - 1800,1000
Var x! = 0
Var y! = 0
Var m! = 0
Var pi2! = Pi() / 2
UsePen 0, 2, RGB(200,0,0)
x! = -1.57
MoveTo 400 + x! * 200 , 500 + 200

WhileLoop 0, 784

    x! = x! + 0.01
    y! = sinlike(x!)
    LineTo 400 + x! * 200 , 500 - y! * 200

EndWhile

UsePen 0, 2, RGB(0,200,0)
x! = -1.57
MoveTo 400 + x! * 200 , 500

WhileLoop 0, 784

    x! = x! + 0.01
    y! = coslike(x!)
    LineTo 400 + x! * 200 , 500 - y! * 200

EndWhile

UsePen 0, 1, RGB(0,0,0)
x! = -1.57
MoveTo 400 + x! * 200 , 500 + 200

WhileLoop 0, 784

    x! = x! + 0.01
    y! = sin(x!)
    LineTo 400 + x! * 200 , 500 - y! * 200

EndWhile

UsePen 0, 1, RGB(0,200,200)
x! = -1.57
MoveTo 400 + x! * 200 , 500

WhileLoop 0, 784

    x! = x! + 0.01
    y! = cos(x!)
    LineTo 400 + x! * 200 , 500 - y! * 200

EndWhile

UsePen 0, 1, RGB(0,0,200)
Line 100, 500, 1700, 500
Line 400,  50,  400, 900
waitinput

Proc k1

    Parameters x!
    m! = ( 1 - py! ) / ( pi2! - px! )

    if x! <= px!

        return  py! / px! * x!;

    endif

    if x! > px!

        return   m! * x! + 1 - pi2! * m!

    endif

EndProc

Proc sinlike

    Parameters x!

    if ( x! < 0 )

        return -k1( -x! )

    endif

    if ( x! >= 0 ) AND ( x! <= pi2!)

        return k1( x! );

    endif

    if ( x! > pi2! ) AND ( x! <= Pi() )

        return k1( Pi()  - x! );

    endif

    if ( x! > Pi() ) AND ( x! <= 3 * pi2! )

        return -k1( x! - Pi() );

    endif

    if ( x! > 3 * pi2! ) AND ( x! <= 2 * Pi() )

        return -k1( 2 * Pi() - x! );

    endif

    if ( x! > 2 * Pi() ) AND ( x! <= 5 * pi2!)

        return  k1( x! - 2 * Pi()  );

    endif

EndProc

Proc coslike

    Parameters x!
    return sinlike( x! + pi2! );

EndProc


nur die Funktionen in JavaScript

var px = 0.5;
var py = 0.75;

function k1( x ) {

var m = ( 1 - py ) / ( pi2 - px );
return x > px ? m * x + 1 - pi2 * m : py / px * x;

}

function sinlike( x ) {

if ( x < 0 ) return -k1( -x );
if ( x >= 0 && x <= pi2 ) return k1( x );
if ( x > pi2 && x <= pi ) return k1( pi - x );
if ( x > pi && x <= 3 * pi2 ) return -k1( x - pi );
if ( x > 3 * pi2 && x <= 2 * pi ) return -k1( 2 * pi - x );
if ( x > 2 * pi && x <= 5 * pi2) return k1( x - 2 * pi );

}

function coslike( x ) {

return sinlike( x + pi2 );

}
 
07.02.2018  
 




p.specht

Unermüdlich! Toll ...
 
XProfan 11
Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'...
07.02.2018  
 




HofK
Offenbar ein nummerisches Problem, muss ich noch näher beleuchten.

Schuld sind die unvermeidlichen Rundungsfehler. So kommt es vor, dass 5 mal Pi-Halbe leicht überschritten wird. Abhilfe schafft eine kleine Zugabe oder weglassen der oberen Schranke. Letztere Methode hat den Nachteil, dass dann irgendwelche Folgefehler schwerer zu ermitteln sind.

if ( x > 2 * pi && x <= 5 * pi2 + 0.001 ) return k1( x - 2 * pi, t );
//if ( x > 2 * pi ) return k1( x - 2 * pi, t ); // ???


Neu: Parameter t in der Funktion k1. 

Es gibt mittlerweile drei Modi um die Form festzulegen.
g.contourmode mit den möglichen Werten

'rounding'
'profile'
'point'


Bei der Parameterangabe sieht das dann so aus.

var parameters = {

contourmode: 'profile',

// rounding: function( t ){ return -0.7 + 1.2 * ( 1 + Math.sin( 0.4 * t ) ) },

profile: function( x, t ){ return 0.90 * Math.sin( x ) + 0.10 * Math.sin( 9 * x ) * Math.sin( t ) },

// pointX: function( t ){ return 0.6 * ( 1 + Math.sin( 0.4 * t) ) },
// pointY: function( t ){ return 0.4 * ( 1 + Math.sin( 0.3 * t) ) },

}


Bei 'profile' ist eine beliebige Funktion mit f(0,t) = 0 und f(Pi/2,t) = 1 anzugeben.
Diese wird dann wieder periodisch auf 0 bis 2*Pi erweitert.

Ein Schnappschuss des obigen Beispiels

 
08.02.2018  
 




HofK
Der Konturmodus 'point' ist ganz schön eckig.

Da gibt es doch noch die Bézierkurven  [...]  um die Ecke auszubügeln. Hier benötigt man die quadratische Form der Kurve.

Allerdings sind die Kurven abhängig von einem Parameter definiert. Ich benötige aber eine Funktion y = f(x). Also muss der Parameter raus. Die äußeren Punkte sind fest: P0(0,0) und P2(Pi/2, 1). Der mittlere Punkt sei P1(px, py)

Durch ( 0, 0 ) vereinfacht sich die Rechnung. Man kann durch lösen einer quadratischen oder linearen Gleichung den Parameter in Abhängigkeit von x ermitteln und dann in die Parametergleichung y einsetzen. Der Parameter t ist hier nicht die Zeit! Da muss man aufpassen, sonst gibt es Chaos. Also mal wieder ein Blatt Papier verbraucht.



Mit XProfan sieht das dann so aus:
// Bezierfunktion 0 .. Pi/2
Var pi2! = Pi() / 2
Var px! = 1.2
Var py! = 0.4
//-------------
Window 0,0 - 1800,1000
Var x! = 0
Var y! = 0
UsePen 0, 1, RGB(0,0,200)
Line 500, 600, 1000, 600
Line 600, 400,  914, 400
Line 600, 300,  600, 700
Line 914, 400,  914, 600
UsePen 0, 3, RGB(200,0,0)
MoveTo 600 , 600

WhileLoop 0, 156

    x! = x! + 0.01
    y! = bezier( x!, px!, py! )
    LineTo 600 + x! * 200 , 600 - y! * 200

EndWhile

waitinput

Proc bezier

    Parameters x!// , px!, py!
    var tm! = 0
    var a! = pi2! - 2 * px!

    If a! = 0

        tm! = x! / (  2 * px!)

    Else

        var tp! = px! / a!
        var tr! = tp! * tp! + x! / a!

        If ( px! < pi2! / 2)

            tm! = -tp! + Sqrt( tr! )

        Else

            tm! = -tp! - Sqrt( tr! )

        Endif

    Endif

    return ( 1 - 2 * py!) * tm! * tm! + 2 * py! * tm!

EndProc


Mit Strichstärke 3:



In JavaScript:
function bezier( x ) {

    var tm;
    var a = pi2 - 2 * pX;

    if( a === 0 ) {

        tm = x / ( 2 * pX );

    } else {

        var tp = pX / a;
        var tr = tp * tp  + x / a;
        tm =  - tp + ( pX < pi2 / 2 ? 1 : -1 ) * Math.sqrt( tr );

    }

    return ( 1 - 2 * pY ) * tm * tm + 2 * pY * tm;

}


Da auch hier ein Punkt anzugeben ist, habe ich contourmode nochmal geändert. Jetzt gibt es 'rounding' 'profile' 'bezier' 'linear'
(linear war vorher point)

Noch zwei Schnappschüsse bei zeitabhängigen Punkten (t Zeit)

contourmode: 'bezier',
pointX: function( t ){ return 0.6 * ( 1 + Math.sin( 0.4 * t) ) },
pointY: function( t ){ return 0.4 * ( 1 + Math.sin( 0.3 * t) ) },





 
11.02.2018  
 




HofK
geschafft

Die erste spezielle Geometrie ist soweit fertig. Möglich, dass mir noch eine Ergänzung einfällt, dann wird halt erweitert.

Bei threejs.hofk.de habe ich es eingebunden. Unmittelbarer unter  [...]  bzw.  [...]  erreichbar.



Bei den speziellen Geometrien ist es kein echter Buddelkasten. Es gibt eine beliebig erweiterbare Anzahl von Beispielen mit den zugehörigen Parametern. Das macht Sinn, da die Anzahl der Parameter deutlich geringer ist als bei THREEf und THREEp.

Man kopiert die Parameter einfach in sein eigenes Programm oder ergänzt die Beispielsammlung für sich.

Benutzt man Firefox, bekommt man auch lokal ohne irgendwelche Manipulationen die Texturen. 

...
parameterExamples[ 12 ] = {
equator: 30,
uvmode: 1,
contourmode: 'profile',
parts: [ 1, 0, 1, 0, 1, 0, 1, 0 ],
profile: function( x, t ){ return 1 - 0.97* Math.cos( x ) - 0.03 * Math.cos( 21 * x ) },
}


parameterExamples[ 13 ] = {

}
...

Einfach weitere parameterExamples[ ... ] Blöcke ergänzen und ausfüllen.

Die Parameter sind in THREEg.js ersichtlich.
/*	parameter overview	--- all parameters are optional ---
p = {
// simple properties
equator,
uvmode,
contourmode,
// array, value 1 for octant, otherwise arbitrary - upper counterclockwise, lower clockwise
parts,
// functions with  parameter time   // function ( t )
radius,
rounding,
profile,		// y = f( x, t ),  0 < x < PI / 2, 0 < y < 1
pointX,			// interval 0 to PI / 2
pointY,			// interval 0 to 1
driftX,
driftY,
driftZ,
explod,			// factor for exploded view - non indexed BufferGeometry
}
*/
//............................................................set defaults
g.equator = 	p.equator !== undefined ? p.equator	: 6;
g.uvmode = 		p.uvmode !== undefined ? p.uvmode	: 0;
g.contourmode =	p.contourmode !== undefined ? p.contourmode	:'rounding'; // 'profile'  'bezier' 'linear'
g.parts = 		p.parts !== undefined ? p.parts	: [ 1, 1, 1, 1, 1, 1, 1, 1 ];
g.radius = 		p.radius !== undefined ? p.radius		: function ( t ) { return 1 };
g.rounding =	p.rounding !== undefined ? p.rounding	: function ( t ) { return 1 };
g.profile = 	p.profile !== undefined ? p.profile		: function ( x, t ) { return Math.sin( x ) };
g.pointX = 		p.pointX !== undefined ? p.pointX		: function ( t ) { return 0.001 };
g.pointY = 		p.pointY !== undefined ? p.pointY		: function ( t ) { return 0.999 };
g.driftX =		p.driftX !== undefined ? p.driftX		: function ( t ) { return 0 };
g.driftY =		p.driftY !== undefined ? p.driftY		: function ( t ) { return 0 };
g.driftZ = 		p.driftZ !== undefined ? p.driftZ		: function ( t ) { return 0 };
g.explode = 	p.explode !== undefined ? p.explode		: function ( t ) { return 0 };
 
13.02.2018  
 




p.specht

Hah! Die Pixar Studios bekommen offenbar Konkurrenz!
Faszinierend!
 
XProfan 11
Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'...
14.02.2018  
 




HofK
Bevor die magische Box dran ist, habe ich einen Abstecher zu den Gitternetzen gemacht. Hat sich so ergeben.



Das Resultat kann dort  [...]  genauer betrachtet werden. Rein und raus zoomen.

Einige Beispiele benötigen meine Addons THREEf, THREEp, THREEg.

Ein Beispiel nutzt eine Erweiterung .toGrid von prisoner849 (Paul West), siehe  [...]  und Quellcode hier.

Der Quelltext:
<!DOCTYPE html>
<!--   *** grids ***
/**
* @author hofk
*/
-->
<html lang="de">
<head>
<title> grids  </title>
<meta charset="utf-8" />
</head>
<body> </body>
<script src="three.min.89.js"></script>
<script src="OrbitControls.js"></script>
<script src="THREEx.WindowResize.js"></script>
<script src="THREEf.js"></script>
<script src="THREEp.js"></script>
<script src="THREEg.js"></script>
<script>
'use strict'
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 2000 );
camera.position.z = 120;
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x777777, 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 );
var uvTex = new THREE.TextureLoader().load( "sunflower.png" );// free
var material = new THREE.MeshBasicMaterial( {  map: uvTex, side: THREE.DoubleSide} );// not wireframe
var wireMaterial = new THREE.MeshBasicMaterial( { map: uvTex, side: THREE.DoubleSide, wireframe: true } );

function createObliqueGrid( width, height, widthSegments, heightSegments, stretch, flat ) {

    width = width !== undefined ? width : 100;

        height = height !== undefined ? height : 100;
        widthSegments = widthSegments !== undefined ? widthSegments : 20;
        heightSegments = heightSegments !== undefined ? heightSegments : 20;
        stretch = stretch !== undefined ? stretch : 0;// normally -1 to +1
        flat = flat !== undefined ? flat : false;
        var split = flat ? 3 : 2;
        var halfWidth = width / 2;
        var halfHeight = height / 2;
        var wp = split * widthSegments + 1;
        var dwp = width / widthSegments / split;
        var dhp = height / heightSegments / 2;
        var st = 1 + stretch;
        var obliqueGrid = new THREE.Object3D( );
        var zigzags = [ ];
        var geometryZigzag = [ ];
        var positions = [ ];
        var uvs = [ ];
        var sign, i1;

        for ( var i = 0; i < heightSegments * 2; i ++ ) {

            geometryZigzag[ i ] = new THREE.BufferGeometry();
            positions[ i ] = new Float32Array( wp * 3 );
            uvs[ i ] = new Float32Array( wp * 2 );
            geometryZigzag[ i ].addAttribute('position', new THREE.BufferAttribute( positions[ i ], 3 ) );
            geometryZigzag[ i ].addAttribute('uv', new THREE.BufferAttribute( uvs[ i ], 2 ) );
            sign = i % 2 === 0 ? -1 : 1;
            i1 = i % 2 === 0 ?  i + 1 : i;

            for ( var j = 0; j < wp ; j ++ ) {

                positions[ i ][ j * 3 ] = j * dwp;
                positions[ i ][ j * 3 + 1 ] = j % split === 0 ? 0 : sign * st * dhp;
                positions[ i ][ j * 3 + 2 ] = 0;

            }

            zigzags[ i ] = new THREE.Line( geometryZigzag[ i ], material );// material is not wireframe - still a grid

            for ( var j = 0; j < wp ; j ++ ) {

                zigzags[ i ].geometry.getAttribute('uv' ).array[ j * 2 ] = j * dwp / width;
                zigzags[ i ].geometry.getAttribute('uv' ).array[ j * 2 + 1 ] = ( i1 * dhp + ( j % split === 0 ? 0 : sign * st * dhp ) ) / height;

            }

            zigzags[ i ].position.set( -halfWidth, i1 * dhp - halfHeight, 0 );
            obliqueGrid.add( zigzags[ i ] );

        }

        return obliqueGrid;

    }

    function createHexagonGrid( radius, rings ) {

        // outer grid radius, rings of hexagons around the central hexagon
        radius = radius !== undefined ? radius : 50;
        rings = rings !== undefined ? rings : 20;
        var x, y;
        var r = 2 * radius / ( 2 * rings + 1 ) / Math.sqrt( 3 );// radius of corner points, size of a single hexagon
        var ri = r * Math.sqrt( 3 ) / 2;// inner radius of a single hexagon
        var pi6 = Math.PI / 6;
        var hexagonGrid = new THREE.Object3D( );
        var hexagons = [ ];
        //var hexagonCount = 3 * rings * rings + 3 * rings + 1;
        var geometryHexagon	 = [ ];
        var positions = [ ];
        var uvs = [ ];
        var h = 0;

        for ( var sg = -1; sg < 2; sg ++ ) {

            var rg0 = sg === 0 ? rings : 0;

            for( var i = 1, k = 2 * rings + 1 - Math.abs( sg ); k > rings + rg0; i ++, k -- ) {

                x = ri * ( 1 - k );
                y = sg * 1.5 * r * i;

                for( var j = 0 ; j < k; j ++ ) {

                    geometryHexagon[ h ] = new THREE.BufferGeometry();
                    positions[ h ] = new Float32Array( 18 );
                    uvs[ h ] = new Float32Array( 12 );
                    geometryHexagon[ h ].addAttribute('position', new THREE.BufferAttribute( positions[ h ], 3 ) );
                    geometryHexagon[ h ].addAttribute('uv', new THREE.BufferAttribute( uvs[ h ], 2 ) );

                    for( var ip = 0; ip < 6; ip ++ ) {

                        positions[ h ][ ip * 3 ] = r * Math.cos( ( 2 * ip + 1 ) * pi6 );
                        positions[ h ][ ip * 3 + 1 ] = r * Math.sin( ( 2 * ip + 1 ) * pi6 );
                        positions[ h ][ ip * 3 + 2 ] = 0;

                    }

                    hexagons[ h ] = new THREE.LineLoop( geometryHexagon[ h ], material );// material is not wireframe - still a grid

                    for( var iuv = 0; iuv < 6; iuv ++ ) {

                        hexagons[ h ].geometry.getAttribute('uv' ).array[ iuv * 2 ] =  0.5 * ( 1 + ( x + r * Math.cos( ( 2 * iuv + 1 ) * pi6 ) ) / radius );
                        hexagons[ h ].geometry.getAttribute('uv' ).array[ iuv * 2 + 1 ] =  0.5  * ( 1 + ( y + r * Math.cos( ( 2 * iuv + 1 ) * pi6 ) ) / radius );

                    }

                    x += ri * 2;
                    hexagons[ h ].position.set( x, y, 0 );
                    hexagonGrid.add( hexagons[ h ] );
                    h ++;

                }

            }

        }

        return hexagonGrid;

    }

    /* .toGrid: function() from prisoner849 (Paul West)
    https://discourse.threejs.org/t/gridboxgeometry/1420
    https://discourse.threejs.org/t/grids-of-waves-shaders/1168
    https://jsfiddle.net/prisoner849/mcdtatpv/
    */

    Object.assign(THREE.PlaneBufferGeometry.prototype, {

        toGrid: function() {

            let segmentsX = this.parameters.widthSegments || 1;
            let segmentsY = this.parameters.heightSegments || 1;
            let indices = [];

            for (let i = 0; i < segmentsY + 1; i++) {

                let index11 = 0;
                let index12 = 0;

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

                    index11 = (segmentsX + 1) * i + j;
                    index12 = index11 + 1;
                    let index21 = index11;
                    let index22 = index11 + (segmentsX + 1);
                    indices.push(index11, index12);

                    if (index22 < ((segmentsX + 1) * (segmentsY + 1) - 1)) {

                        indices.push(index21, index22);

                    }

                }

                if ((index12 + segmentsX + 1) <= ((segmentsX + 1) * (segmentsY + 1) - 1)) {

                    indices.push(index12, index12 + segmentsX + 1);

                }

            }

            this.setIndex(indices);
            return this;

        }

    });

    var geometry = new THREE.PlaneBufferGeometry( 40, 40, 40, 40 );
    var geometryTHREEf =  new THREE.BufferGeometry();
    geometryTHREEf.createMorphGeometry = THREEf.createMorphGeometry;

    geometryTHREEf.createMorphGeometry({

        style:'map',
        radius: 6.5,
        height: 40,
        radiusSegments: 20,
        heightSegments: 20,
        waffled: true,

    });

    var rhombGeometry = new THREE.PlaneBufferGeometry( 40, 40, 40, 40 );
    var toGridGeometry = new THREE.PlaneBufferGeometry( 40, 40, 40, 40 ).toGrid();// .toGrid() from prisoner849 (Paul West)
    var geometryTHREEp3 = new THREE.BufferGeometry();
    geometryTHREEp3.createMorphGeometry = THREEp.createMorphGeometry;

    geometryTHREEp3.createMorphGeometry({

        style:'map',
        radius: 12,
        wedges: 3,
        usedWedges: 3,
        equator: 20,
        bottom: 20,
        top: 40,

    });

    var geometryTHREEg =  new THREE.BufferGeometry();
    geometryTHREEg.createMagicSphere = THREEg.createMagicSphere;

    geometryTHREEg.createMagicSphere({

        rounding: function ( t ) { return 0 },
        radius: function ( t ) { return 30 },
        equator: 40,
        parts: [ 1 ],

    });

    var geometryTHREEp =  new THREE.BufferGeometry();
    geometryTHREEp.createMorphGeometry = THREEp.createMorphGeometry;

    geometryTHREEp.createMorphGeometry({

        style:'map',
        radius: 12,
        equator: 20,
        bottom: 20,
        top: 40,

    });

    // ...........................................................
    var mesh0 = new THREE.Mesh( geometry, material );// material is not wireframe  - no grid
    scene.add( mesh0 );
    mesh0.position.set( -100, 50, 0 );
    var obliqueGrid = new createObliqueGrid( 40, 40, 40, 40, 0.4, true );
    scene.add( obliqueGrid );
    obliqueGrid.position.set( -50, 50, 0 );
    var hexagonGrid = createHexagonGrid( 20, 25 );// grid radius and rings of hexagons around the central hexagon
    scene.add( hexagonGrid );
    hexagonGrid.position.y = 50;
    var meshTHREEf = new THREE.Mesh( geometryTHREEf, wireMaterial );
    scene.add( meshTHREEf );
    meshTHREEf.position.set( 30, 50, 0 );
    var mesh1 = new THREE.Mesh( geometry, wireMaterial );
    scene.add( mesh1 );
    mesh1.position.x = -50;
    var rhombMesh = new THREE.LineSegments( rhombGeometry, material );// material is not wireframe - still a grid
    scene.add( rhombMesh );
    var gridMesh = new THREE.LineSegments( toGridGeometry, material );// material is not wireframe - still a grid
    scene.add( gridMesh );
    gridMesh.position.x = 50;
    var meshTHREEp3 = new THREE.Mesh( geometryTHREEp3, wireMaterial );
    scene.add( meshTHREEp3 );
    meshTHREEp3.position.set( -70, -50, 0 );
    meshTHREEp3.rotation.set( 1.57, 1.57, 0 );
    var meshTHREEg = new THREE.Mesh( geometryTHREEg, wireMaterial );
    scene.add( meshTHREEg );
    meshTHREEg.position.set( 0, -57, -20 );
    meshTHREEg .rotation.set( 0.62, -2.35, 0 );
    var meshTHREEp = new THREE.Mesh( geometryTHREEp, wireMaterial );
    scene.add( meshTHREEp );
    meshTHREEp.position.set( 30, -50, 0 );
    meshTHREEp.rotation.set( 1.57, 1.57, 0 );
    var gridHelper = new THREE.GridHelper( 150, 3, 0x00ff00, 0x00ff00 );
    scene.add( gridHelper );
    gridHelper.rotation.x = 1.57
    animate();

    function animate() {

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

    }

    </script>
    </html>
 
20.02.2018  
 




HofK
Eigentlich muss man für die magische Box nur die Grundkonstruktion von THREEf nehmen. Der Style 'map' liefert ein Rechteck. Davon benötigt man sechs für die Seiten und dann noch 12 für die abgerundeten Kanten. Die Abrundung ist ähnlich wie bei der magischen Kugel aus THREEg zu bewerkstelligen, da diese Konstruktion die 8 Ecken liefert und die insgesamt 26 Teile der Box zusammenpassen sollen.

Also habe ich fleißig zusammen kopiert. Das Problem sind sich eventuell überschneidende Bezeichnungen und die Gesamtstruktur. Da kann man nicht immer nur kopieren sondern muss abwandeln und anpassen.

Mittlerweile funktioniert das Grundgerüst. Die Ecken habe ich zum Test etwas heraus gesetzt. Die 12 Kantenteile müssen noch positioniert und gebogen werden, auf dem Bild ist nur eine ebene Testkante.



Man kann wählen, welche Teile dargestellt werden sollen. Default für das seitenbezogene Datenfeld ist [ 1, 1, 1, 1, 1, 1 ]
// array, sides order +x, -x, +y, -y, +z, -z
sides,// values: no side = 0, complete = 1, in addition: no plane = 2, edgeless = 3, no corners = 4

Dabei gilt die Eigenschaft "nicht darstellen" für die der Seite zugeordneten Teile. Wählt man also 4 für die ersten beiden Elemente das Feldes, wird bereits keine Ecke dargestellt. Die Seiten liegen gegenüber und betreffen damit alle 8 Ecken.

Mit den vorbereitenden Funktionen werden bis zu 26 Teile erzeugt.
// up to 26 parts:
//  planes

for ( var i = 0; i < 6; i ++ ) {

    if ( g.vPlanesIdx[ i ] > -1 ) {

        facesPlaneEdge('plane', i );

    }

}

// edges

for ( var i = 0; i < 12; i ++ ) {

    if ( g.vEdgesIdx[ i ] > -1 ) {

        facesPlaneEdge('edge', i );

    }

}

// corners

for ( var i = 0; i < 8; i ++ ) {

    if ( g.vCornersIdx[ i ] > -1 ) {

        facesPartSphere( i );

    }

}


Ähnlich dann beim Morphen. Auch die Box ist nicht nur statisch.
 
26.02.2018  
 




HofK
Die 12 Kantenteile müssen noch positioniert und gebogen werden.


Das hat geklappt, wobei ein Fehlversuch mal wieder glatt als Feature herhalten könnte.



Da hat die Box einen festen Stand und kann nicht kippeln!

Korrekt ist es aber so.



Bei 12 Kanten (part) schien der Programmieraufwand groß zu werden, aber durch die Systematik ließ er sich reduzieren.

Zu jeder Achse gehört ein Block. Segmentzahl: s1, s2

pi2 ist PI/2
for ( var j = 0; j < s1 + 1; j ++ ) {

    nj = j / s1;

    for ( var i = 0; i < s2 + 1; i ++ ) {

        ni   = i / s2;

        if ( type ==='edge' ) {

            theta = pi2 * ( 1 - ni );

            if ( part < 4 ) {

                sign1 = part < 2 ? -1 : 1;
                sign2 = ( part === 1 ) || ( part === 2 ) ? -1 : 1;
                x = ( nj - 0.5 ) * g.widthP( t );
                y = sign1 * g.radius( t ) * sinuslike( theta ) + sign1 * g.heightP( t ) / 2;
                z = sign2 * g.radius( t ) * cosinuslike( theta ) + sign2 * g.depthP( t ) / 2;

            }

            if ( part > 3 && part < 8 ) {

                sign1 = ( part === 5 ) || ( part === 6 ) ? -1 : 1;
                sign2 = part < 6 ? -1 : 1;
                x = sign1 * g.radius( t ) * sinuslike( theta ) + sign1 * g.widthP( t ) / 2;
                y = ( nj - 0.5 ) * g.heightP( t );
                z = sign2 * g.radius( t ) * cosinuslike( theta ) + sign2 * g.depthP( t ) / 2;

            }

            if ( part > 7 ) {

                sign1 = part > 9 ? -1 : 1;
                sign2 = ( part === 9 ) || ( part === 10 ) ? 1 : -1;
                x = sign1 * g.radius( t ) * sinuslike( theta ) + sign1 * g.widthP( t ) / 2;
                y = sign2 * g.radius( t ) * cosinuslike( theta ) + sign2 * g.heightP( t ) / 2;
                z = ( nj - 0.5 ) * g.depthP( t );

            }

        }

    }

}


Auch das uv Mapping funktioniert bereits.



Nun sind die Normalen dran, sie müssen noch überprüft und eventuell angepasst werden.
 
28.02.2018  
 




ByteAttack
Zu kompliziert für mich Bin raus
 
XProfan X3
Website:  [...] 
Facebook:  [...] 
28.02.2018  
 




p.specht

Beim scrollen der Seite entsteht der Eindruck, dass die untere Biegung der Figur etwas nachhinkt im Bildaufbau... könnte eine optische Täuschung sein. Sonst: Toll !
 
XProfan 11
Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'...
01.03.2018  
 




Antworten


Thementitel, max. 100 Zeichen.
 

Systemprofile:

Kein Systemprofil angelegt. [anlegen]

XProfan:

 Beitrag  Schrift  Smilies  ▼ 

Bitte anmelden um einen Beitrag zu verfassen.
 

Themenoptionen

332.667 Betrachtungen

Unbenanntvor 0 min.
HofK vor 23 Tagen
Rschnett24.08.2024
Michael W.28.03.2024
Thomas Zielinski17.02.2024
Mehr...

Themeninformationen



Admins  |  AGB  |  Anwendungen  |  Autoren  |  Chat  |  Datenschutz  |  Download  |  Eingangshalle  |  Hilfe  |  Händlerportal  |  Impressum  |  Mart  |  Schnittstellen  |  SDK  |  Services  |  Spiele  |  Suche  |  Support

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