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 discourse.threejs.org gab es eine interessante Frage.  [...] 

Es sah für mich wie eine Straße aus. Sie sollte dynamisch verändert werden und die Konstruktion war nicht vollständig. Die Form wurde durch viele einzelne Linien verdeutlicht.

Die Konstruktion der faces konnte ich sehr einfach aus meinem Addon THREEf ableiten. Auch die Berechnung der vertices geschieht mit Tangente, Binormale und Normale ganz ähnlich.

Ich werde das Beispiel verallgemeinert meinem Addon THREEg hinzufügen.


<!DOCTYPE html>
<!-- @author hofk -->
<head>
<title> FourLaneRoad </title>
<meta charset="utf-8" />
</head>
<body>
</body>
<script src="../js/three.min.101.js"></script>
<script src="../js/OrbitControls.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 100 );
camera.position.set( -1, 14, 24 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x000000, 1 );
var container = document.createElement('div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var gridHelper = new THREE.GridHelper( 100, 100 );
scene.add( gridHelper );
var ls = 200;// length segments
var ws = 4;// width segments, tracks
var lss = ls + 1;
var wss = ws + 1;
var faceCount = ls * ws * 2;
var vertexCount = lss * wss;
var g = new THREE.BufferGeometry( );
g.faceIndices = new Uint32Array( faceCount * 3 );
g.vertices = new Float32Array( vertexCount * 3 );
//g.normals = 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 ).setDynamic( true ) );
//g.addAttribute( 'normal', new THREE.BufferAttribute( g.normals, 3 ).setDynamic( true ) );
//g.addAttribute( 'uv', new THREE.BufferAttribute( g.uvs, 2 ) );
var idxCount = 0;

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

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

        // 2 faces / segment,  3 vertex indices
        a =  wss * j + i;
        b1 = wss * ( j + 1 ) + i;// right-bottom
        c1 = wss * ( j + 1 ) + 1 + i;
        b2 = wss * ( j + 1 ) + 1 + i;// left-top
        c2 = wss * j + 1 + i;
        g.faceIndices[ idxCount     ] = a;// right-bottom
        g.faceIndices[ idxCount + 1 ] = b1;
        g.faceIndices[ idxCount + 2 ] = c1;
        g.faceIndices[ idxCount + 3 ] = a;// left-top
        g.faceIndices[ idxCount + 4 ] = b2,
        g.faceIndices[ idxCount + 5 ] = c2;
        g.addGroup( idxCount, 6, i );// write groups for multi material
        idxCount += 6;

    }

}

var curve = new THREE.CatmullRomCurve3( [
new THREE.Vector3( -25, 0, -25 ),
new THREE.Vector3( -4, 2, -9 ),
new THREE.Vector3( 4, 1, -6 ),
new THREE.Vector3( 6, 0, 0 ),
new THREE.Vector3( -3, 1, 1 ),
new THREE.Vector3( -11, 0, 6 ),
new THREE.Vector3( -12, 1, 1 ),
new THREE.Vector3( -7, 1, -3 ),
new THREE.Vector3( 7, 8, -9 ),
new THREE.Vector3( 13, 2, -12 ),
] );
var points = curve.getPoints( ls );
var curveGeometry = new THREE.BufferGeometry().setFromPoints( points );
var tangent;
var normal = new THREE.Vector3( 0, 0, 0 );
var binormal = new THREE.Vector3( 0, 1, 0 );
var x, y, z;
var vIdx = 0;// vertex index
var posIdx;// position  index

for ( var j = 0; j < lss; j ++ ) {// length

    for ( var i = 0; i < wss; i ++ ) {// width

        // calculate here the coordinates according to your wishes
        tangent = curve.getTangent( j / ls );//  .. / length segments
        normal.cross( tangent, binormal );
        binormal.cross( normal, tangent );// new binormal
        normal.normalize().multiplyScalar( 0.25 );
        x = points[ j ].x + ( i - ws / 2 ) * normal.x;
        y = points[ j ].y;
        z = points[ j ].z + ( i - ws / 2 ) * normal.z;
        xyzSet();
        vIdx ++;

    }

}

g.attributes.position.needsUpdate = true;
//g.attributes.normal.needsUpdate = true;
var material = [
new THREE.MeshBasicMaterial( { color: 0x00ff00, side: THREE.DoubleSide, wireframe: true } ),
new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide, wireframe: true } ),
new THREE.MeshBasicMaterial( { color: 0x0000ff, side: THREE.DoubleSide, wireframe: true } ),
new THREE.MeshBasicMaterial( { color: 0xff00ff, side: THREE.DoubleSide, wireframe: true } ),
];
var mesh = new THREE.Mesh( g, material );
scene.add( mesh );
var curveMaterial = new THREE.LineBasicMaterial( { color : 0xffffff } );
var curveLine = new THREE.Line( curveGeometry, curveMaterial );
scene.add( curveLine );
animate();
//............................
// set vertex position

function xyzSet() {

    posIdx = vIdx * 3;
    g.vertices[ posIdx ]  = x;
    g.vertices[ posIdx + 1 ]  = y;
    g.vertices[ posIdx + 2 ]  = z;

}

function animate() {

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

}

</script>
</html>
 
18.02.2019  
 




HofK
Es gab noch Probleme bzw. Wünsche.

"Ich habe jetzt eine Straße, aber ich kämpfe mit der Erstellung einer Linie (volle Linie und gestrichelt) dazwischen, die eine gewisse Breite hat. " 

Zwei Varianten:

1. mit schwarzem und weißem Material:
var ls = 200;// length segments
var ws = 5;// width segments, tracks, streaks, stripes
var d = [ -0.6, -0.58, -0.01, 0.01, 0.58, 0.6 ];

for ( var j = 0; j < lss; j ++ ) {// length

    for ( var i = 0; i < wss; i ++ ) {// width

        // calculate here the coordinates according to your wishes
        tangent = curve.getTangent( j / ls );//  .. / length segments
        normal.cross( tangent, binormal );
        binormal.cross( normal, tangent );// new binormal
        normal.normalize();
        x = points[ j ].x + d[ i ] * normal.x;
        y = points[ j ].y;
        z = points[ j ].z + d[ i ] * normal.z;
        xyzSet();
        vIdx ++;

    }

}




2. mit Textur
// nehme
var ls = 200;// length segments
var ws = 3;// width segments
// aktiviere
g.uvs = new Float32Array( vertexCount * 2 );
g.addAttribute('uv', new THREE.BufferAttribute( g.uvs, 2 ) );
//berechne
var uvIdxCount = 0;

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

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

        g.uvs[ uvIdxCount     ] = j / ls;
        g.uvs[ uvIdxCount + 1 ] = i / ws;
        uvIdxCount += 2;

    }

}

// nehme
var d = [ -0.52, -0.5, 0.5, 0.52 ];
// nehme
normal.normalize();
x = points[ j ].x + d[ i ] * normal.x;
y = points[ j ].y;
z = points[ j ].z + d[ i ] * normal.z;
//Material
tex = new THREE.TextureLoader().load('RoadMarking.png' );
tex.wrapS = THREE.RepeatWrapping;
tex.wrapT = THREE.RepeatWrapping;
tex.repeat.set( 100, 1 );
var material = [
new THREE.MeshBasicMaterial( { color: 0xffffff, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { map: tex, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { color: 0xffffff, side: THREE.DoubleSide} ),
];

RoadMarking.png schnell gemalt, ich bin kein Künstler 



 
19.02.2019  
 




HofK
Eine weitere Variante mit gesonderten Segmenten für die Markierung. Damit kann man die Markierungen flexibel in der Breite gestalten, ohne jeweils eine spezielle Textur zu benötigen.

Die Textur wird sehr einfach.
CentralMarking.png





Bei ungleichmäßigen Abständen der Punkte entstehen unterschiedlich lange Segmente. Deshalb sind bei der vorherigen Variante die weißen Abschnitte unterschiedlich lang. Das kann man beheben, indem man die uv's anders berechnet.
var uvIdxCount = 0;

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

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

        //g.uvs[ uvIdxCount     ] = j / ls;
        //g.uvs[ uvIdxCount + 1 ] = i / ws;
        g.uvs[ uvIdxCount     ] = lenList[ j ] / len;
        g.uvs[ uvIdxCount + 1 ] = i / ws;
        uvIdxCount += 2;

    }

}


Das vollständige Programm:
<!DOCTYPE html>
<!-- @author hofk -->
<head>
<title> RoadMarking </title>
<meta charset="utf-8" />
</head>
<body>
</body>
<script src="../js/three.min.101.js"></script>
<script src="../js/OrbitControls.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 100 );
camera.position.set( -1, 14, 24 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x11ff33, 1 );
var container = document.createElement('div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var light = new THREE.AmbientLight( 0xffffff );
scene.add( light );
var gridHelper = new THREE.GridHelper( 100, 100 );
scene.add( gridHelper );
var ls = 200;// length segments
var ws = 5;// width segments
var lss = ls + 1;
var wss = ws + 1;
var faceCount = ls * ws * 2;
var vertexCount = lss * wss;
var g = new THREE.BufferGeometry( );
g.faceIndices = new Uint32Array( faceCount * 3 );
g.vertices = new Float32Array( vertexCount * 3 );
//g.normals = 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 ).setDynamic( true ) );
//g.addAttribute( 'normal', new THREE.BufferAttribute( g.normals, 3 ).setDynamic( true ) );
g.addAttribute('uv', new THREE.BufferAttribute( g.uvs, 2 ) );
var posIdxCount = 0;

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

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

        // 2 faces / segment,  3 vertex indices
        a =  wss * j + i;
        b1 = wss * ( j + 1 ) + i;// right-bottom
        c1 = wss * ( j + 1 ) + 1 + i;
        b2 = wss * ( j + 1 ) + 1 + i;// left-top
        c2 = wss * j + 1 + i;
        g.faceIndices[ posIdxCount     ] = a;// right-bottom
        g.faceIndices[ posIdxCount + 1 ] = b1;
        g.faceIndices[ posIdxCount + 2 ] = c1;
        g.faceIndices[ posIdxCount + 3 ] = a;// left-top
        g.faceIndices[ posIdxCount + 4 ] = b2,
        g.faceIndices[ posIdxCount + 5 ] = c2;
        g.addGroup( posIdxCount, 6, i );// write groups for multi material
        posIdxCount += 6;

    }

}

var curve = new THREE.CatmullRomCurve3( [
new THREE.Vector3( -25, 0.2, -25 ),
new THREE.Vector3( -24, 0.2, -24 ),
new THREE.Vector3( -4, 2, -9 ),
new THREE.Vector3( 4, 1, -6 ),
new THREE.Vector3( 6, 0, 0 ),
new THREE.Vector3( -3, 1, 1 ),
new THREE.Vector3( -11, 0, 6 ),
new THREE.Vector3( -12, 1, 1 ),
new THREE.Vector3( -7, 1, -3 ),
new THREE.Vector3( 7, 8, -9 ),
new THREE.Vector3( 13, 2, -12 ),
] );
var len = curve.getLength( );
var points = curve.getPoints( ls );
var lenList = curve.getLengths ( ls );
var uvIdxCount = 0;

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

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

        //g.uvs[ uvIdxCount     ] = j / ls;
        //g.uvs[ uvIdxCount + 1 ] = i / ws;
        g.uvs[ uvIdxCount     ] = lenList[ j ] / len;
        g.uvs[ uvIdxCount + 1 ] = i / ws;
        uvIdxCount += 2;

    }

}

var tangent;
var normal = new THREE.Vector3( 0, 0, 0 );
var binormal = new THREE.Vector3( 0, 1, 0 );
var x, y, z;
var vIdx = 0;// vertex index
var posIdx;// position  index
var d = [ -0.62, -0.6, -0.02, 0.02, 0.6, 0.62];

for ( var j = 0; j < lss; j ++ ) {// length

    for ( var i = 0; i < wss; i ++ ) {// width

        // calculate here the coordinates according to your wishes
        tangent = curve.getTangent( j / ls );//  .. / length segments
        normal.crossVectors( tangent, binormal );
        binormal.crossVectors( normal, tangent );// new binormal
        normal.normalize();
        x = points[ j ].x + d[ i ] * normal.x;
        y = points[ j ].y;
        z = points[ j ].z + d[ i ] * normal.z;
        xyzSet();
        vIdx ++;

    }

}

g.attributes.position.needsUpdate = true;
//g.attributes.normal.needsUpdate = true;
tex = new THREE.TextureLoader().load('CentralMarking.png' );
tex.wrapS = THREE.RepeatWrapping;
//tex.wrapT = THREE.RepeatWrapping;
tex.repeat.set( ls / 2 );
var material = [
new THREE.MeshBasicMaterial( { color: 0xffffff, side: THREE.DoubleSide, wireframe: true} ),
new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide, wireframe: true} ),
new THREE.MeshBasicMaterial( { map: tex, side: THREE.DoubleSide, wireframe: true } ),
new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { color: 0xffffff, side: THREE.DoubleSide} ),
];
var mesh = new THREE.Mesh( g, material );
scene.add( mesh );
animate();
//............................
// set vertex position

function xyzSet() {

    posIdx = vIdx * 3;
    g.vertices[ posIdx ]  = x;
    g.vertices[ posIdx + 1 ]  = y;
    g.vertices[ posIdx + 2 ]  = z;

}

function animate() {

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

}

</script>
</html>
 
21.02.2019  
 




HofK
Ich habe die Straße in mein Addon THREEg auf GitHub integriert. [...] 

Damit wird die Definition sehr einfach.

Das Programm:
<!DOCTYPE html>
<!-- see https://discourse.threejs.org/t/create-a-curved-plane-surface-which-dynamically-changes-its-size/6161/16 -->
<head>
<title> RoadMarking </title>
<meta charset="utf-8" />
<style>	body { margin: 0;} </style>
</head>
<body>
</body>
<script src="../js/three.min.102.js"></script>
<script src="../js/OrbitControls.js"></script>
<script src="../js/THREEg.js"></script>
<script>
// @author hofk
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 200 );
camera.position.set( -1, 14, 24 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x11ff33, 1 );
var container = document.createElement('div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var light = new THREE.AmbientLight( 0xffffff );
scene.add( light );
var gridHelper = new THREE.GridHelper( 100, 100 );
scene.add( gridHelper );
var curvePoints =  [
-25, 0.2, -25,
-24, 0.2, -24,
-4, 2, -9,
4, 1, -6,
6, 0, 0,
-3, 1, 1,
-11, 0, 6,
-12, 1, 1,
-7, 1, -3,
7, 8, -9,
13, 2, -12,
];
var lengthSegments = 200;
var trackDistances = [ -0.62, -0.6, -0.02, 0.02, 0.6, 0.62 ];
var g = new THREE.BufferGeometry( );
g.createRoad = THREEg.createRoad;
g.createRoad( curvePoints, lengthSegments, trackDistances );
//g.createRoad( ); // all parameters default
tex = new THREE.TextureLoader().load('CentralMarking.png' );
tex.wrapS = THREE.RepeatWrapping;
//tex.wrapT = THREE.RepeatWrapping;
tex.repeat.set( lengthSegments / 2 );
var material = [
new THREE.MeshBasicMaterial( { color: 0xffffff, side: THREE.DoubleSide, wireframe: true} ),
new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide, wireframe: true} ),
new THREE.MeshBasicMaterial( { map: tex, side: THREE.DoubleSide, wireframe: true } ),
new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { color: 0xffffff, side: THREE.DoubleSide} ),
];
var mesh = new THREE.Mesh( g, material );
scene.add( mesh );
animate();
//............................

function animate() {

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

}

</script>
</html>
 
01.03.2019  
 




HofK
THREEg road wurde nochmal etwas bereinigt und die Tangenten, Normalen und Binormalen nun in der Geometrie gespeichert.
g.t = [];// tangents
g.n = [];// normals
g.b = [];// binormals

Damit habe ich eine kleine Basisanwendung für ein Straßenrennen gebaut.



Dort schauen:  [...] 

Die Sache findet man nun auch auf GitHub.  [...] 
<!DOCTYPE html>
<head>
<title> RoadRace </title>
<meta charset="utf-8" />
<style>	body { margin: 0;} </style>
</head>
<body>
</body>
<script src="../js/three.min.102.js"></script>
<script src="../js/OrbitControls.js"></script>
<script src="../js/THREEg.js"></script>
<script>
// @author hofk
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 65, window.innerWidth / window.innerHeight, 0.01, 200 );
camera.position.set( 0, 8, 16 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x11ff33, 1 );
var container = document.createElement('div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var clock = new THREE.Clock( );
var light = new THREE.AmbientLight( 0xffffff );
scene.add( light );
var gridHelper = new THREE.GridHelper( 30, 30 );
scene.add( gridHelper );
var curvePoints =  [
-6, 0, 10,
-1, 0, 10,
3, 0,  4,
6, 0,  1,
11, 0,  2,
13, 0,  6,
9, 1,  9,
4, 1,  7,
1, 1,  1,
0, 1, -5,
2, 0, -9,
8, 0,-10,
13, 0, -5,
14, 1,  2,
10, 3,  7,
2, 1,  8,
-4, 3,  7,
-8, 1,  1,
-9, 1, -4,
-6, 1, -9,
0, 1,-10,
7, 1, -7,
5, 2,  0,
0, 2,  2,
-5, 1,  0,
-7, 2, -5,
-8, 2, -9,
-11, 2, -10,
-14, 1, -7,
-13, 1, -2,
-14, 0,  3,
-11, 0, 10,
-6, 0, 10
];
var lengthSegments = 1000;
var trackDistances = [ -0.31, -0.3, -0.01, 0.01, 0.3, 0.31 ];
var gRoad = new THREE.BufferGeometry( );
gRoad.createRoad = THREEg.createRoad;
gRoad.createRoad( curvePoints, lengthSegments, trackDistances );
//gRoad.createRoad( ); // all parameters default
tex = new THREE.TextureLoader().load('CentralMarking.png' );
tex.wrapS = THREE.RepeatWrapping;
//tex.wrapT = THREE.RepeatWrapping;
tex.repeat.set( lengthSegments * 2 );
var material = [
new THREE.MeshBasicMaterial( { color: 0xffffff, side: THREE.DoubleSide  } ),
new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide  } ),
new THREE.MeshBasicMaterial( { map: tex, side: THREE.DoubleSide } ),
new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { color: 0xffffff, side: THREE.DoubleSide} ),
];
var mesh = new THREE.Mesh( gRoad, material );
scene.add( mesh );
var h = 0.08;
var redCar = new THREE.Mesh(
new THREE.BoxBufferGeometry( 0.1, h * 1.9 , 0.3 ),
new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide, wireframe: true } )
);
scene.add( redCar );
var redCarIdx = 0;
var redCarX, redCarY, redCarZ;
var blueCar = new THREE.Mesh(
new THREE.BoxBufferGeometry( 0.12, h * 1.9, 0.4 ),
new THREE.MeshBasicMaterial( { color: 0x0000ff, side: THREE.DoubleSide, wireframe: true  } )
);
scene.add( blueCar );
var blueCarIdx = gRoad.points.length - 1;
var blueCarX, blueCarY, blueCarZ;
var gTngt = new THREE.BufferGeometry( );// tangent
gTngt.positions = new Float32Array( 6 );
gTngt.addAttribute('position', new THREE.BufferAttribute( gTngt.positions, 3 ).setDynamic( true ) );
lineTngt = new THREE.Line( gTngt, new THREE.LineBasicMaterial( { color: 0x00ffff, side: THREE.DoubleSide } ) );
scene.add( lineTngt );
var gNorm = new THREE.BufferGeometry( );// normal
gNorm.positions = new Float32Array( 6 );
gNorm.addAttribute('position', new THREE.BufferAttribute( gNorm.positions, 3 ).setDynamic( true ) );
lineNorm = new THREE.Line( gNorm, new THREE.LineBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide } ) );
scene.add( lineNorm );
var gBino = new THREE.BufferGeometry( );// binormal
gBino.positions = new Float32Array( 6 );
gBino.addAttribute('position', new THREE.BufferAttribute( gBino.positions, 3 ).setDynamic( true ) );
lineBino = new THREE.Line( gBino, new THREE.LineBasicMaterial( { color: 0x0000ff, side: THREE.DoubleSide } ) );
scene.add( lineBino );
var sysIdx = 8;
var t1 = 0;
var t2;
animate();
//............................

function animate( ) {

    t2 = clock.getElapsedTime ( );
    requestAnimationFrame( animate );
    renderer.render( scene, camera );

    if ( t2 - t1 > 0.04 ) {

        redCarX = gRoad.points[ redCarIdx ].x + gRoad.n[ redCarIdx ].x * trackDistances[ 4 ] * 0.6;
        redCarY = gRoad.points[ redCarIdx ].y + h;
        redCarZ = gRoad.points[ redCarIdx ].z + gRoad.n[ redCarIdx ].z * trackDistances[ 4 ] * 0.6;
        redCar.position.set( redCarX, redCarY, redCarZ );
        redCar.rotation.y = 1.57 + Math.atan2( -gRoad.t[ redCarIdx ].z, gRoad.t[ redCarIdx ].x );
        // other: take tangent, binormal for calculation
        redCarIdx ++;

        if ( redCarIdx === gRoad.points.length  ) redCarIdx = 0;

            blueCarX = gRoad.points[ blueCarIdx ].x + gRoad.n[ blueCarIdx ].x * trackDistances[ 1 ] * 0.6;
            blueCarY = gRoad.points[ blueCarIdx ].y + h;
            blueCarZ = gRoad.points[ blueCarIdx ].z + gRoad.n[ blueCarIdx ].z * trackDistances[ 1 ] * 0.6;
            blueCar.position.set( blueCarX, blueCarY, blueCarZ );
            blueCar.rotation.y = 1.57 + Math.atan2( -gRoad.t[ blueCarIdx ].z, gRoad.t[ blueCarIdx ].x );
            // other: take tangent, binormal for calculation
            blueCarIdx --;

            if ( blueCarIdx === -1  ) blueCarIdx = gRoad.points.length - 1;

                gTngt.positions[ 0 ] = gRoad.points[ sysIdx ].x;// tangent
                gTngt.positions[ 1 ] = gRoad.points[ sysIdx ].y;
                gTngt.positions[ 2 ] = gRoad.points[ sysIdx ].z;
                gTngt.positions[ 3 ] = gRoad.points[ sysIdx ].x + gRoad.t[ sysIdx ].x;
                gTngt.positions[ 4 ] = gRoad.points[ sysIdx ].y + gRoad.t[ sysIdx ].y;
                gTngt.positions[ 5 ] = gRoad.points[ sysIdx ].z + gRoad.t[ sysIdx ].z;
                gTngt.attributes.position.needsUpdate = true;
                gNorm.positions[ 0 ] = gRoad.points[ sysIdx ].x;// normal
                gNorm.positions[ 1 ] = gRoad.points[ sysIdx ].y;
                gNorm.positions[ 2 ] = gRoad.points[ sysIdx ].z;
                gNorm.positions[ 3 ] = gRoad.points[ sysIdx ].x + gRoad.n[ sysIdx ].x;
                gNorm.positions[ 4 ] = gRoad.points[ sysIdx ].y + gRoad.n[ sysIdx ].y;
                gNorm.positions[ 5 ] = gRoad.points[ sysIdx ].z + gRoad.n[ sysIdx ].z;
                gNorm.attributes.position.needsUpdate = true;
                gBino.positions[ 0 ] = gRoad.points[ sysIdx ].x;// binormal
                gBino.positions[ 1 ] = gRoad.points[ sysIdx ].y;
                gBino.positions[ 2 ] = gRoad.points[ sysIdx ].z;
                gBino.positions[ 3 ] = gRoad.points[ sysIdx ].x + gRoad.b[ sysIdx ].x;
                gBino.positions[ 4 ] = gRoad.points[ sysIdx ].y + gRoad.b[ sysIdx ].y;
                gBino.positions[ 5 ] = gRoad.points[ sysIdx ].z + gRoad.b[ sysIdx ].z;
                gBino.attributes.position.needsUpdate = true;
                sysIdx ++;

                if ( sysIdx === gRoad.points.length  ) sysIdx = 0

                    t1 = t2;

                }

                controls.update();

            }

            </script>
            </html>
 
04.03.2019  
 




HofK
Wieder mal ein Problem auf discourse.threejs.org.

Wie findet man einen Schnittpunkt zwischen zwei Strahlen?  [...] 

Dazu eine Reihe von Erläuterungen und Beispielen. Da mich das interessiert hat, habe ich nachträglich ein kleines Programm mit verschiedenen Varianten der Berechnung erstellt.



Zur Vereinfachung lässt sich nur die x Komponente eines Richtungsvektors ändern. Den Schnittpunkt kann man mit einer Genauigkeitsschranke festlegen.

Sind die Geraden Bahnen von Objekten, kann man mit den Objektgrößen eine Kollision ermitteln.

Dort testen:  [...] 
<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/solved-how-to-find-intersection-between-two-rays/6464/6 -->
<!-- http://threejs.hofk.de/LinesDistance/LinesDistance.html -->
<head>
<title> LinesDistance </title>
<meta charset="utf-8" />
</head>
<body>
mp.x <input type="range" id="mpx" min="0" max="1" value="0.725" step="0.0001" style="width: 90%;">
<div id="distance"> </div>
<div id="Pn"> </div>
<div id="Qn"> </div>
</body>
<script src="../js/three.min.102.js"></script>
<script src="../js/OrbitControls.js"></script>
<script>
// @author hofk
var mpx = document.getElementById('mpx' );
mpx.onchange = refresh;
var dpnqnDet, pnDet, qnDet;// uses determinant
var dpnqnCr, pnCr, qnCr;// uses cross vectors
var dist;// uses formula distance
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 0, 10, 40 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xaaaaaa, 1 );
var container = document.createElement('div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var axesHelper = new THREE.AxesHelper( 28 );
scene.add( axesHelper );
var grid = new THREE.GridHelper( 50, 50 );
scene.add( grid );
var gLineP = new THREE.BufferGeometry( );
gLineP.positions = new Float32Array( 6 );
gLineP.addAttribute('position', new THREE.BufferAttribute( gLineP.positions, 3 ).setDynamic( true )   );
lineP  = new THREE.Line( gLineP, new THREE.LineBasicMaterial( { color: 0x00ffff, side: THREE.DoubleSide } ) );
var p = new THREE.Vector3( -15, 12, -5 );
var mp = new THREE.Vector3( 35, -8 , 15 );// mp.x can be changed with slider
gLineP.positions[ 0 ] = p.x;
gLineP.positions[ 1 ] = p.y;
gLineP.positions[ 2 ] = p.z;
gLineP.positions[ 3 ] = p.x + mp.x;
gLineP.positions[ 4 ] = p.y + mp.y;
gLineP.positions[ 5 ] = p.z + mp.z;
scene.add( lineP );
var gLineQ = new THREE.BufferGeometry( );
gLineQ.positions = new Float32Array( 6 );
gLineQ.addAttribute('position', new THREE.BufferAttribute( gLineQ.positions, 3 )  );
lineQ  = new THREE.Line( gLineQ, new THREE.LineBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } ) );
var q = new THREE.Vector3( -12, 14, -15 );
var mq = new THREE.Vector3( 34, -12, 33 );
gLineQ.positions[ 0 ] = q.x;
gLineQ.positions[ 1 ] = q.y;
gLineQ.positions[ 2 ] = q.z;
gLineQ.positions[ 3 ] = q.x + mq.x;
gLineQ.positions[ 4 ] = q.y + mq.y;
gLineQ.positions[ 5 ] = q.z + mq.z;
scene.add( lineQ );
refresh( );
animate();

function animate() {

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

}

function linesDistance( ) {// mp and mq  non-collinear

    var pq = new THREE.Vector3( ).subVectors( q, p );
    var n = new THREE.Vector3( ).crossVectors( mp, mq ).normalize( );
    var d = pq.dot( n );
    return Math.abs( d );

}

function closestPointsDet( ) {// mp and mq  non-collinear

    // using determinant
    var qp = new THREE.Vector3( ).subVectors( p, q );
    var qpDotmp = qp.dot( mp );
    var qpDotmq = qp.dot( mq );
    var mpDotmp = mp.dot( mp );
    var mqDotmq = mq.dot( mq );
    var mpDotmq = mp.dot( mq );
    var detp = qpDotmp * mqDotmq - qpDotmq * mpDotmq;
    var detq = qpDotmp * mpDotmq - qpDotmq * mpDotmp;
    var detm = mpDotmq * mpDotmq - mqDotmq * mpDotmp;
    pnDet = p.clone( ).add( mp.clone( ).multiplyScalar( detp / detm ) );
    qnDet = q.clone( ).add( mq.clone( ).multiplyScalar( detq / detm ) );
    dpnqnDet = pnDet.clone( ).sub( qnDet ).length( );

}

function closestPointsCross( ) {// mp and mq  non-collinear

    // using cross vectors
    var qp = new THREE.Vector3( ).subVectors( p, q );
    var pq = qp.clone( ).multiplyScalar( -1 );
    var npq = new THREE.Vector3( ).crossVectors( mp, mq ).normalize( );
    var nqp = new THREE.Vector3( ).crossVectors( mq, mp ).normalize( );
    var n1 = new THREE.Vector3( ).crossVectors( mp, nqp ).normalize( );
    var n2 = new THREE.Vector3( ).crossVectors( mq, npq ).normalize( );
    var qpDotn1 = qp.dot( n1 );
    var pqDotn2 = pq.dot( n2 );
    var mpDotn2 = mp.dot( n2 );
    var mqDotn1 = mq.dot( n1 );
    pnCr = p.clone( ).add( mp.clone( ).multiplyScalar( pqDotn2 / mpDotn2 ) );
    qnCr = q.clone( ).add( mq.clone( ).multiplyScalar( qpDotn1 / mqDotn1 ) );
    dpnqnCr = pnCr.clone( ).sub( qnCr ).length( );

}

function refresh( ) {

    mp.x = mpx.value * 50;
    gLineP.positions[ 3 ] = p.x + mp.x;
    gLineP.attributes.position.needsUpdate = true;
    closestPointsDet( );
    closestPointsCross( );
    Pn.innerHTML =' Pn Det ( ' + pnDet.x + ', '+ pnDet.y + ', '+ pnDet.z + ' ) <==> Pn Cr ( ' + pnCr.x + ', '+ pnCr.y + ', '+ pnCr.z + ' ) ';
    Qn.innerHTML =' Qn Det ( ' + qnDet.x + ', '+ qnDet.y + ', '+ qnDet.z + ' ) <==> Qn Cr ( ' + qnCr.x + ', '+ qnCr.y + ', '+ qnCr.z + ' ) ';
    dist = linesDistance( );
    distance.innerHTML ='distance: dPQ Determinant: ' + dpnqnDet +  '  <==>   function linesDistance( ) :' + dist + '   <==> dPQ Cross: ' + dpnqnCr;

}</script>

</html>
 
11.03.2019  
 




HofK
Eine Straße ist horizontal. Bringt man die Sache in die Vertikale, gibt es eine Wand oder Mauer.

Allerdings sollte diese in 3D dann auch eine Dicke haben und auch die obige Straße kann einen Unterbau gut vertragen.

Also habe ich die Konstruktion erweitert. Es gibt zwei unterschiedliche Funktionen

createRoad( curvePoints, lengthSegments, trackDistances )
createWall( curvePoints, lengthSegments, sidesDistances, widthDistance, hightDistance )


die intern aber auf eine identische Funktion buildRoadWall( ) zugreifen.



Alle Parameter sind optional. Ohne Parameter gibt es nur eine einfache Basisvariante.

Dort ausprobieren: Straße  [...]  Wand  [...] 
GitHub:  [...] 
 
19.03.2019  
 




HofK
Der Fragensteller zur Straße hat noch ein weiteres Anliegen.  [...] 

Daraus noch ein Beispiel in der Sammlung: [...] 



Die Farben wechseln ständig zufällig.
<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/assign-different-colors-to-different-parts-of-buffergeometry/6604/12 -->
<head>
<title> ColorStripeChanging </title>
<meta charset="utf-8" />
<style>
body { margin: 0; }
</style>
</head>
<body> </body>
<script src="../js/three.min.102.js"></script>
<script src="../js/OrbitControls.js"></script>
<script>
// @author hofk
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 100 );
camera.position.set( 0, 5, 4 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x555555, 1 );
var container = document.createElement('div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var ls = 24;// length segments
var ws = 1;// width segments
var lss = ls + 1;
var wss = ws + 1;
var faceCount = ls * ws * 2;
var vertexCount = lss * wss;
var g = new THREE.BufferGeometry( );
g.faceIndices = new Uint32Array( faceCount * 3 );
g.vertices = new Float32Array( vertexCount * 3 );
g.setIndex( new THREE.BufferAttribute( g.faceIndices, 1 ) );
g.addAttribute('position', new THREE.BufferAttribute( g.vertices, 3 ) );
var idxCount = 0;

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

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

        // 2 faces / segment,  3 vertex indices
        a =  wss * j + i;
        b1 = wss * ( j + 1 ) + i;// right-bottom
        c1 = wss * ( j + 1 ) + 1 + i;
        b2 = wss * ( j + 1 ) + 1 + i;// left-top
        c2 = wss * j + 1 + i;
        g.faceIndices[ idxCount     ] = a;// right-bottom
        g.faceIndices[ idxCount + 1 ] = b1;
        g.faceIndices[ idxCount + 2 ] = c1;
        g.faceIndices[ idxCount + 3 ] = a;// left-top
        g.faceIndices[ idxCount + 4 ] = b2,
        g.faceIndices[ idxCount + 5 ] = c2;
        idxCount += 6;

    }

}

// write groups for multi material

for ( var f = 0, p = 0; f < faceCount; f ++, p += 6) {

    g.addGroup( p, 6, f % 8 );

}

var x, y, z;
var vIdx = 0;// vertex index
var posIdx;// position  index

for ( var j = 0; j < lss; j ++ ) {// length

    for ( var i = 0; i < wss; i ++ ) {// width

        // calculate here the coordinates according to your wishes
        x = j / 10 - 2;
        y = Math.sin(  Math.PI * j / 25 );
        z = i  ;
        xyzSet();
        vIdx ++;

    }

}

var material = [
new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { color: 0xffffff, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { color: 0x00ffff, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { color: 0x00ff00, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { color: 0x0000ff, side: THREE.DoubleSide} ),
new THREE.MeshBasicMaterial( { color: 0xff00ff, side: THREE.DoubleSide} )
];
var mesh = new THREE.Mesh( g, material );
scene.add( mesh );
var t = 0;
animate();
//............................
// set vertex position

function xyzSet() {

    posIdx = vIdx * 3;
    g.vertices[ posIdx ]  = x;
    g.vertices[ posIdx + 1 ]  = y;
    g.vertices[ posIdx + 2 ]  = z;

}

function getRandomInt( max ) {

    return Math.floor( Math.random( ) * Math.floor( max ) );

}

function animate( ) {

    requestAnimationFrame( animate );
    renderer.render( scene, camera );
    g.groups[ getRandomInt( faceCount - 1 ) ].materialIndex = getRandomInt( 7 );
    g.groupsNeedUpdate = true;// to change materialIndex for multi material
    controls.update();

}

</script>
</html>
 
20.03.2019  
 




HofK
Als Ergebnis der Diskussion zu vertex colors noch eine Variante mit dieser Methode.

 [...] 
<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/assign-different-colors-to-different-parts-of-buffergeometry/6604/12 -->
<head>
<title> ColorStripeChanging2 </title>
<meta charset="utf-8" />
<style>	body { margin: 0;} </style>
</head>
<body>
<button type="button" id="newcolors"> new colors </button>
</body>
<script src="../js/three.min.102.js"></script>
<script src="../js/OrbitControls.js"></script>
<script>
// @author hofk
document.getElementById( "newcolors" ).onclick = newcolors;
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 100 );
camera.position.set( 5, -18, 30 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x111111, 1 );
var container = document.createElement('div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var clock = new THREE.Clock( );
var stripCount = 24;
var stripWidth = 1;
var stripHeight = 12;
var centerX = stripCount * stripWidth / 2;
var centerY = stripHeight / 2;
var faceCount = stripCount * 2;
// use THREE.VertexColors
var material = new THREE.MeshBasicMaterial( { side: THREE.DoubleSide,  vertexColors: THREE.VertexColors, wireframe: false } );
var g = new THREE.BufferGeometry( );// non indexed BufferGeometry
g.positions = new Float32Array( faceCount * 9 );// 'triangle soup'
g.addAttribute('position', new THREE.BufferAttribute( g.positions, 3 ) );
g.colors = new Float32Array( faceCount * 9 );
g.addAttribute('color', new THREE.BufferAttribute( g.colors, 3 ) );

for ( var i = 0, j = 0; i < stripCount; i ++, j += 18 ) {

    // left face
    g.positions[ j ]     = i * stripWidth - centerX;
    g.positions[ j + 1 ] = 0 - centerY;
    g.positions[ j + 2 ] = 8 * Math.sin(  Math.PI * i / 25 );
    g.positions[ j + 3 ] = ( i + 1 ) * stripWidth - centerX;
    g.positions[ j + 4 ] = stripHeight - centerY;
    g.positions[ j + 5 ] = 8 * Math.sin(  Math.PI * ( i + 1 ) / 25 );
    g.positions[ j + 6 ] = i * stripWidth - centerX;
    g.positions[ j + 7 ] = stripHeight - centerY;
    g.positions[ j + 8 ] = 8 * Math.sin(  Math.PI * i / 25 );
    // right face
    g.positions[ j +  9 ] = i * stripWidth - centerX;
    g.positions[ j + 10 ] = 0 - centerY;
    g.positions[ j + 11 ] = 8 * Math.sin(  Math.PI * i / 25 );
    g.positions[ j + 12 ] = ( i + 1 ) * stripWidth - centerX;
    g.positions[ j + 13 ] = 0 - centerY;
    g.positions[ j + 14 ] = 8 * Math.sin(  Math.PI * ( i + 1 ) / 25 );
    g.positions[ j + 15 ] = ( i + 1 ) * stripWidth - centerX;
    g.positions[ j + 16 ] = stripHeight - centerY;
    g.positions[ j + 17 ] = 8 * Math.sin(  Math.PI * ( i + 1 ) / 25 );

}

var mesh = new THREE.Mesh( g, material );
scene.add( mesh );
var t1 = 0;
var t2;
var c8;
var c = [];
newcolors( );
animate();
//..................................

function animate() {

    t2 = clock.getElapsedTime ( );
    requestAnimationFrame( animate );
    renderer.render( scene, camera );

    if ( t2 - t1 > 0.4 ) {

        for ( var i = 0, j = 0; i < stripCount; i ++, j += 18 ) {

            c8 = getRandomInt( 7 ) * 3;

            for ( k = 0; k < 18; k ++ ) {// apply color

                g.colors[ j + k ] = c[ k % 3 + c8 ];

            }

        }

        t1 = t2;

    }

    g.attributes.color.needsUpdate = true;
    controls.update();

}

function getRandomInt( max ) {

    return Math.floor( Math.random( ) * Math.floor( max ) );

}

function newcolors( ) {

    c = [];

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

        c.push( Math.random( ), Math.random( ), Math.random( ) );

    }

}

</script>
</html>
 
21.03.2019  
 




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




p.specht

Toll! Aber du dürftest auch einen sehr schnellen Rechner haben, oder?
 
XProfan 11
Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'...
02.04.2019  
 




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.
 
09.04.2019  
 




Antworten


Thementitel, max. 100 Zeichen.
 

Systemprofile:

Kein Systemprofil angelegt. [anlegen]

XProfan:

 Beitrag  Schrift  Smilies  ▼ 

Bitte anmelden um einen Beitrag zu verfassen.
 

Themenoptionen

333.535 Betrachtungen

Unbenanntvor 0 min.
HofK vor 26 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