PHP, HTML & JavaScript- Forum | | | | - 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 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>
|
| | | | |
| | 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
|
| | | | |
| | 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.
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>
|
| | | | |
| | 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>
|
| | | | |
| | 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>
|
| | | | |
| | 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>
|
| | | | |
| | 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: [...] |
| | | | |
| | 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>
|
| | | | |
| | 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>
|
| | | | |
| | 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>
|
| | | | |
| | p.specht
| Toll! Aber du dürftest auch einen sehr schnellen Rechner haben, oder? |
| | | XProfan 11Computer: 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. |
| | | | |
|
AntwortenThemenoptionen | 332.774 Betrachtungen |
ThemeninformationenDieses Thema hat 10 Teilnehmer: |