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 19 - |
| | HofK | In ein Labyrinth gehören auch einige Objekte. Wie platziert man sie zufällig beim Start? Das war die Frage.
Die Lösung:
var insideLabyrinth = [];
for ( let i = 0; i < design2D.length; i ++) {
for ( let j = 0; j < design2D[ i ].length; j ++) { if ( design2D[ i ][ j ] === '+' ) insideLabyrinth.push( j , i ); // x, z positions }
}
var tetra = new THREE.TetrahedronBufferGeometry( 0.45 ); var tetraMesh = new THREE.Mesh( tetra, materialUV );
var random = new Date().getMilliseconds() / 1000 ;
console.log( random +'s' ); ///////////////////
var idx = Math.floor( random * insideLabyrinth.length / 2 );
console.log( idx + ' idx ' ); ///////////////////
var posX = insideLabyrinth[ idx * 2 ]; var posZ = insideLabyrinth[ idx * 2 + 1 ];;
console.log( posX, posZ ); /////////////
tetraMesh.position.set( posX + 0.5, 0.3, posZ + 0.5); mesh2D.add( tetraMesh );
Zwischenzeitlich habe ich die Labyrinth Geometrie in mein Addon THREEg.js eingebracht. [...] Dort befindet sich nun die finale Version. Beim Materialindex für 2D wird nun nur eine Eckige Klammer benötigt. Des 2D Design nutzt zur besseren Übersichtlichkeit und da dieses Zeichen bei 3D nicht auftritt nun + als Markierung. [...] |
| | | | |
| | HofK | Nach Lösung des Labyrinth-Problems gab es eine weitere Frage [...]
und dann nach Lösung dieses Problems bei mir eine gedankliche Verknüpfung.
Daraus ist eine neue spezielle Geometrie entstanden. [...]
Ich habe die Konstruktion von einfach zu gestaltenden Liniengittern realisiert. Damit kann man ganz einfach 2D-Linienlabyrinthe erstellen.
Die in den 3D-2D Labyrinthen verwendeten Designelemente können in einem Design kombiniert werden. Das Raster kann entweder in der xy-Ebene erstellt werden, oder an den Seiten eines Quaders.
Die Größe des Quaders wird standardmäßig durch das Design bestimmt, kann aber auch nach Bedarf angegeben werden. Die Länge der ersten Zeile des Designs jeder Seite ist entscheidend für die Zentrierung des Gitters. Man kann die Zentrierung leicht ändern, indem man Leerzeichen am Anfang und Ende verwendet.
Führt das Design zu Doppellinien an einer Stelle, wird die überschüssige Linie eliminiert. Ein wenig binäre Arithmetik genügt.
Multimaterial wird im Seiten- und Ausrichtungsmodus unterstützt.
Dort ist das Beispiel zu obigem Bild: [...]
Demnächst im Addon THREEg auch auf Github. |
| | | | |
| | HofK | In three.js sind ganz bewusst nur einige grundlegende Geometrien definiert.
Eine Frage mit ausufernder Diskussion beschäftigt sich mit weiteren Körpern. [...]
Mit einem Link [...] konnte ich dann etwas Sinnvolles dazu beitragen. Dort view-source:https://www.mathsisfun.com/geometry/images/poly-models.js Interessant Zeile 644 ff
In weiterer Folge der Diskussion habe ich ein sehr einfaches Beispiel einer BufferGeometry mit Normalen erstellt und auf threejs.hofk.de hinzugefügt. [...]
|
| | | | |
| | p.specht
| Gold-metallic: Besonders schwer darzustellen! Toll ! |
| | | XProfan 11Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'... | 23.12.2018 ▲ |
| |
| | HofK | Immer noch zu der seeehr ausgedehnten Sache!
Nun wollten auch die Kanten nicht gleich parieren.
Also habe ich für den einfachen Fall des beliebigen Polygons ein kleines Beispiel erstellt.
schwingendes Fünfeck / swinging pentagon
Die Verfahrensweise lässt sich auf Polyeder erweitern. Dort schauen wie es schwingt: [...]
<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/swinging-polygon/5509 -->
<!-- http://threejs.hofk.de/SwingingPolygon/SwingingPolygon.html -->
<head>
<title> SwingingPolygon </title>
<meta charset="utf-8" />
<style>
body {
margin: 0;
}
</style>
</head>
<body>
</body>
<script src="../js/three.min.99.js"></script>
<script src="../js/OrbitControls.js"></script>
<script src="../js/THREEx.WindowResize.js"></script>
<script>
// @author hofk
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.01, 1000 );
camera.position.set( 0, 0, 20 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x44ff44, 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 );
scene.add( new THREE.AmbientLight( 0xffffff, 0.5) );
var light1 = new THREE.DirectionalLight( 0xeeffee, 0.8 );
light1.position.set( 0, 5, 9 );
scene.add( light1 );
//var material = new THREE.MeshPhongMaterial( { color: 0xff00ff, side: THREE.DoubleSide } );
var material = new THREE.MeshBasicMaterial( { color: 0xff00ff, side: THREE.DoubleSide, wireframe: true } );
//var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.VertexColors, side: THREE.DoubleSide } );
// .............. input values ....................
var corners = 5;// number of polygon corners
var detail = 20;// number of divisions of the edges
var c = {};// center point
c.x = 2;
c.y = 4;
c.z= -6;
var n = {};// polygone normal
n.x = 4;// .x and .y not both 0, simply for convenience, see e1
n.y = 2;
n.z = 1;
var r = 9;// radius
// ..................................................
// orthogonal unit vectors e1, e2 of polygon plane ( simplified calculation )
var e1 = {};
e1.x = -n.y;
e1.y = n.x;
e1.z = 0;// see vector n
var e2 = {};
e2 = normalize( cross( e1, n ) );// see also https://threejs.org/docs/index.html#api/en/math/Vector3
e1 = normalize( e1 );
var geometry = new THREE.BufferGeometry( );
var cd = corners * detail;
var indices = new Uint32Array( cd * 3 );
var positions = new Float32Array( ( cd + 2 ) * 3 );// + last ( = first) and center point
//var normals = new Float32Array( cd * 3 );
var cors = [];// corners
var edgs = [];// edges
var v = {};
for( let i = 0, phi = 0; i < corners; i ++, phi += Math.PI * 2 / corners ) {
// equation of circle in 3D space
cors.push( {
x: c.x + r * Math.cos( phi) * e1.x + r * Math.sin( phi ) * e2.x,
y: c.y + r * Math.cos( phi) * e1.y + r * Math.sin( phi ) * e2.y,
z: c.z + r * Math.cos( phi) * e1.z + r * Math.sin( phi ) * e2.z
} );
}
for( let i = 0; i < corners; i ++ ) {
let j = i < corners - 1 ? i + 1 : 0;
edgs.push( {
x: cors[ j ].x - cors[ i ].x,
y: cors[ j ].y - cors[ i ].y,
z: cors[ j ].z - cors[ i ].z
} );
}
for( let i = 0; i < corners; i ++ ) {
for( let j = 0; j < detail; j ++ ) {
v = {
x: cors[ i ].x + j / detail * edgs[ i ].x,
y: cors[ i ].y + j / detail * edgs[ i ].y,
z: cors[ i ].z + j / detail * edgs[ i ].z
}
positions[ ( i * detail + j ) * 3 ] = v.x;
positions[ ( i * detail + j ) * 3 + 1 ] = v.y;
positions[ ( i * detail + j ) * 3 + 2 ] = v.z;
}
}
// last point equals first point
positions[ cd * 3 ] = positions[ 0 ];
positions[ cd * 3 + 1 ] = positions[ 1 ];
positions[ cd * 3 + 2 ] = positions[ 2 ];
// center point
positions[ cd * 3 + 3 ] = c.x;
positions[ cd * 3 + 4 ] = c.y;
positions[ cd * 3 + 5 ] = c.z;
for( let i = 0; i < corners; i ++ ) {
for( let j = 0; j < detail; j ++ ) {
idx1 = i * detail + j;
idx2 = i * detail + j + 1;
indices[ ( i * detail + j ) * 3 ] = cd + 1;
indices[ ( i * detail + j ) * 3 + 1 ] = idx1;
indices[ ( i * detail + j ) * 3 + 2 ] = idx2;
}
}
var pos = [];
for ( i = 0; i < positions.length; i ++ ) {
pos[ i ] = positions[ i ];
}
geometry.setIndex( new THREE.BufferAttribute( indices, 1 ) );
geometry.addAttribute('position', new THREE.BufferAttribute( positions, 3 ).setDynamic( true ) );
//geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ));
geometry.computeVertexNormals( );// from three.js core
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
var t = 0;
animate();
function animate() {
requestAnimationFrame( animate );
t += 0.01;
for ( let i = 0; i < corners; i ++ ) {
swinging( i , t );
}
geometry.attributes.position.needsUpdate = true;
renderer.render( scene, camera );
controls.update();
}
function swinging( i , t ) {
let swingX, swingY, swingZ ;
for( let j = 0; j < detail; j ++ ) {
// ....... swinging function .......
swingX = n.x * 0.1 * Math.sin( j / detail * Math.PI * 4 + t );
swingY = n.y * 0.05 * Math.cos( j / detail * Math.PI * 4 + t );
swingZ = n.z * 0.03 * Math.sin( j / detail * Math.PI * 4 + t );
// .................................
positions[ ( i * detail + j ) * 3 ] = pos[ ( i * detail + j ) * 3 ] + swingX;
positions[ ( i * detail + j ) * 3 + 1 ] = pos[ ( i * detail + j ) * 3 + 1 ] + swingY;
positions[ ( i * detail + j ) * 3 + 2 ] = pos[ ( i * detail + j ) * 3 + 2 ] + swingZ;
// last point equals first point
positions[ cd * 3 ] = positions[ 0 ];
positions[ cd * 3 + 1 ] = positions[ 1 ];
positions[ cd * 3 + 2 ] = positions[ 2 ];
}
}
function cross( v1, v2 ) {
let v = {};
v.x = v1.y * v2.z - v1.z * v2.y;
v.y = v1.z * v2.x - v1.x * v2.z;
v.z = v1.x * v2.y - v1.y * v2.x;
return v;
}
function normalize( v ) {
let l = Math.sqrt( v.x * v.x + v.y * v.y + v.z * v.z );
let vn = {};
vn.x = v.x / l;
vn.y = v.y / l;
vn.z = v.z / l;
return vn;
}
</script>
</html>
|
| | | | |
| | HofK | Pünktlich zu Sylvester.
Da kann man Neujahr am Computer nicht verpassen. [...] [...]
von prisoner849
|
| | | | |
| | HofK | Auf discourse.threejs.org [...] haben sich mittlerweile recht viele brauchbare Beispiele angesammelt. Damit die Sache nicht unüberschaubar wir, habe ich die Gliederung in Jahre vorgenommen. Da zwei Jahre abgeschlossen sind, stehen diese auch zum Download bereit.
So kann man auch lokal sehr einfach damit arbeiten. Die Texturen und Modelle hat man bei einigen Basisbeispielen dann auf dem Rechner. Mit Firefox kann man sie auch problemlos lokal laden. Natürlich kann man sich auch die Mühe machen und einen lokalen Server aufsetzen.
unter discourse.threejs.hofk.de/
Der direkte (alte) Link für die erweiterten Beispiele [...] wird umgeleitet. |
| | | | |
| | HofK | Der Schauraum benötigt einige Rahmen für Fenster, Türen und Bilder.
Dazu habe ich die Lösung von prisoner849 benutzt. [...]
Allerdings ist bei dieser Lösung kein Multimaterial machbar. Deshalb möchte ich die Rahmen in einer detaillierten Konstruktion grafisch erstellen und so auch Multimaterial ermöglichen.
Als erster Schritt ist die Konstruktionsbasis fertiggestellt. [...] [...]
Sie gründet sich auf die Lösung von looeee [...] und erweitert diese um die Möglichkeit der vertikalen Verschiebung.
So kann die linke obere Szene in der Größe verändert werden. Dort kann man in zwei separaten Koordinatensystemen Marker setzen. Trifft man auf einen Marker, ändert sich die Farbe des Fadenkreuzes. In Firefox folgt das Kreuz dem Kursor recht flott, Chrom trödelt.
In der rechten Szene wird später die fertige 3D Konstruktion dargestellt. Bisher nur ein Testkörper.
Anschließend wird dann die three.js Definition der BufferGeometry exportiert. Wie das geht, kann man in meinem Beispiel [...] sehen.
<!DOCTYPE html>
<!-- @author hofk -->
<!-- based on @author: looeee SceneComparsion https://codepen.io/looeee/pen/jpebjN -->
<head>
<title> ConstructionBasis </title>
<meta charset="utf-8" />
<style>
/* style based on @author: looeee */
body {
margin: 0px;
overflow: hidden;
text-align: center;
background-color: #66ccff;
}
.container {
position: absolute;
top: 0;
z-index: -1;
width: 100%;
height: 100%;
}
* {box-sizing: border-box;}
.comp {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
}
.comp canvas {
display: block;
vertical-align: middle;
}
.slider {
position: absolute;
z-index: 9;
cursor:nw-resize;
width: 40px;
height: 40px;
background-color: #2196F3;
opacity: 0.7;
border-radius: 50%;
}
</style>
</head>
<body>
<div class="container">
<div class="comp containerA"></div>
<div class="slider"> </div>
<div class="comp containerB"></div>
</div>
</body>
<script src="../js/three.min.100.js"></script>
<script src="../js/OrbitControls.js"></script>
<script>
// @author hofk
'use strict'
var containerA;
var containerB;
var slider;
var cameraA;
var cameraB;
var rendererA;
var rendererB;
var sceneA;
var sceneB;
var controlsA;
var controlsB;
var matMarkerL;
var matMarkerR;
var markerSize;
var aspectB;
var gBPointsL;
var gBPointsR;
var gReticle;
var matReticle;
var reticle;
var matReticleM;
var reticleM;
var markersL = [];
var markersR = [];
var idxMarkersL = -1;
var idxMarkersR = -1;
var epsilon = 0.004;
var idxHitL = -1;
var idxHitR = -1;
var posCount = 600;
containerA = document.querySelector('.containerA' );
containerB = document.querySelector('.containerB' );
slider = document.querySelector('.slider' );
containerB.addEventListener('mousemove', onContainerBMouseMove );
containerB.addEventListener('mouseup', onContainerBmouseUp );
// create scenes
sceneA = new THREE.Scene();
sceneA.background = new THREE.Color( 0x555555 );
sceneB = new THREE.Scene();
sceneB.background = new THREE.Color( 0xeeeeee );
// perspective / orthographic camera
cameraA = new THREE.PerspectiveCamera( 55, containerA.clientWidth / containerA.clientHeight, 0.1, 200 );
cameraA.position.set( 0, 0, 6 );
var widthB = containerB.clientWidth;
var heightB = containerB.clientHeight;
if ( widthB > 2 * heightB ) {
widthB = 2 * heightB;
} else {
heightB = widthB / 2;
}
aspectB = widthB / heightB;
cameraB = new THREE.OrthographicCamera( -aspectB, aspectB, 1, -1, 0.01, 10 );
cameraB.position.set( 0, 0, 0.1 );
// controls
controlsA = new THREE.OrbitControls( cameraA, containerA );// only controlsA
// lights
const lightA = new THREE.DirectionalLight();
lightA.position.set( 20, 20, 20 );
sceneA.add( lightA );
// renderer
rendererA = new THREE.WebGLRenderer( { antialias: true } );
rendererA.setSize( containerA.clientWidth, containerA.clientHeight );
rendererA.setPixelRatio( window.devicePixelRatio )
containerA.appendChild( rendererA.domElement );
rendererB = new THREE.WebGLRenderer( { antialias: true } );
rendererB.setSize( widthB, heightB );
rendererB.setPixelRatio( window.devicePixelRatio );
containerB.appendChild( rendererB.domElement );
// .....................only TEST: geometry/mesh A ...........................................
const geoA = new THREE.CylinderBufferGeometry( 1, 1, 2, 10, 10 );
const matA = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );
const meshA = new THREE.Mesh( geoA, matA );
meshA.position.x = 3;
sceneA.add( meshA );
//................................................................
createDesignArea( );
defineReticles( );
rendererA.setAnimationLoop( () => {
update();
render();
} );
rendererB.setAnimationLoop( () => {
update();
render();
} );
initComparisons();
// -------------------------------------------
function createDesignArea( ){
var gB1 = new THREE.BufferGeometry( );
var pos = [];
for ( let i = 1; i < 10; i ++ ) {
let j = i / 10;
rasterPosPush( j );
}
gB1.lineCount = 54;
gB1.positions = new Float32Array( gB1.lineCount * 6 );
for ( let i = 0; i < pos.length; i ++ ) gB1.positions[ i ] = pos[ i ];
gB1.addAttribute('position', new THREE.BufferAttribute( gB1.positions, 3 ) );
var matB1 = new THREE.LineBasicMaterial( { color: 0xcccccc } );
var gridB1 = new THREE.LineSegments( gB1, matB1 );
sceneB.add( gridB1 );
//.....
var gB0 = new THREE.BufferGeometry( );
pos = [];
pos.push( -2,0,0, -0.02,0,0 );// horizontal
pos.push( 0.02,0,0, 2,0,0 );
pos.push( -1,-1,0, -1,1,0 );// vertical
pos.push( 1,-1,0, 1,1,0 );
gB0.lineCount = 4;
gB0.positions = new Float32Array( gB0.lineCount * 6 );
for ( let i = 0; i < pos.length; i ++ ) gB0.positions[ i ] = pos[ i ];
gB0.addAttribute('position', new THREE.BufferAttribute( gB0.positions, 3 ) );
var matB0 = new THREE.LineBasicMaterial( { color: 0x888888 } );
var gridB0 = new THREE.LineSegments( gB0, matB0 );
sceneB.add( gridB0 );
//.....
var gBsplit = new THREE.BufferGeometry( );
gBsplit.positions = new Float32Array( 6 );
gBsplit.positions[ 0 ] = gBsplit.positions[ 2 ] = gBsplit.positions[ 3 ] = gBsplit.positions[ 5 ] = 0;
gBsplit.positions[ 1 ] = -1;
gBsplit.positions[ 4 ] = 1;
gBsplit.addAttribute('position', new THREE.BufferAttribute( gBsplit.positions, 3 ) );
var matBsplit = new THREE.LineBasicMaterial( { color: 0xffffff } );
var gridBsplit = new THREE.LineSegments( gBsplit, matBsplit );
sceneB.add( gridBsplit );
//.....
markerSize = 0.015;
matMarkerL = new THREE.MeshBasicMaterial( { color: 0x00aaaa, transparent: true, opacity: 0.5 } );
matMarkerR = new THREE.MeshBasicMaterial( { color: 0xaa00aa, transparent: true, opacity: 0.5 } );
//.....
gBPointsL = new THREE.BufferGeometry( );
gBPointsL.positions = new Float32Array( posCount );
gBPointsR = new THREE.BufferGeometry( );
gBPointsR.positions = new Float32Array( posCount );
// detail function
function rasterPosPush( j ){
pos.push( -2, j, 0, 2, j, 0 );// horizontal
pos.push( -2, -j, 0, 2, -j, 0 );
pos.push( -2+j, -1, 0, -2+j, 1, 0 );// vertical
pos.push( -1+j, -1, 0, -1+j, 1, 0 );
pos.push( 1-j, -1, 0, 1-j, 1, 0 );
pos.push( 2-j, -1, 0, 2-j, 1, 0 );
}
}
function defineReticles( ) {
gReticle = new THREE.BufferGeometry( );
gReticle.positions = new Float32Array( 4 * 3 );
gReticle.positions[ 0 ] = 0;
gReticle.positions[ 1 ] = -0.02;
gReticle.positions[ 2 ] = 0;
gReticle.positions[ 3 ] = 0;
gReticle.positions[ 4 ] = 0.02;
gReticle.positions[ 5 ] = 0;
gReticle.positions[ 6 ] = -0.02;
gReticle.positions[ 7 ] = 0;
gReticle.positions[ 8 ] = 0;
gReticle.positions[ 9 ] = 0.02;
gReticle.positions[ 10 ] = 0;
gReticle.positions[ 11 ] = 0;
gReticle.addAttribute('position', new THREE.BufferAttribute( gReticle.positions, 3 ) );
matReticle = new THREE.LineBasicMaterial( { color: 0xff0000 } );// hit
reticle = new THREE.LineSegments( gReticle, matReticle );
sceneB.add( reticle );
reticle.visible = false;
matReticleM = new THREE.LineBasicMaterial( { color: 0x444444 } );// Move
reticleM = new THREE.LineSegments( gReticle, matReticleM );
sceneB.add( reticleM );
reticleM.visible = true;
}
function onContainerBMouseMove( event ) {
event.preventDefault();
var markerX = Math.round( 100 * ( event.clientX / widthB * 4 - 2 ) ) / 100;
var markerY = Math.round( 100 * ( -event.clientY / heightB * 2 + 1 ) ) / 100;
reticle.position.set( markerX, markerY, 0 );
if( markerX === 0 ) {
reticleM.visible = false;
}
if( markerX < 0 ) {// left
if ( hitMarkerL( markerX, markerY ) === -1 ) {
reticleM.visible = true;
reticleM.position.set( markerX, markerY, 0 );
reticle.visible = false;
} else {
reticleM.visible = false;
reticle.visible = true;
reticle.position.set( markerX, markerY, 0 );
}
}
if( markerX > 0 ) {// right
if ( hitMarkerR( markerX, markerY ) === -1 ) {
reticleM.visible = true;
reticleM.position.set( markerX, markerY, 0 );
reticle.visible = false;
} else {
reticleM.visible = false;
reticle.visible = true;
reticle.position.set( markerX, markerY, 0 );
}
}
}
function onContainerBmouseUp( event ) {
event.preventDefault();
var markerX = Math.round( 100 * ( event.clientX / widthB * 4 - 2 ) ) / 100;
var markerY = Math.round( 100 * ( -event.clientY / heightB * 2 + 1 ) ) / 100;
if ( markerX < 0 ) {// left
idxMarkersL ++;
markersL[ idxMarkersL ] = new THREE.Sprite( matMarkerL );
markersL[ idxMarkersL ].position.x = markerX;
markersL[ idxMarkersL ].position.y = markerY;
markersL[ idxMarkersL ].scale.x = markerSize;
markersL[ idxMarkersL ].scale.y = markerSize;
sceneB.add( markersL[ idxMarkersL ] );
for ( let i = idxMarkersL * 3 ; i < gBPointsL.positions.length; i += 3 ) {// fill with last value
gBPointsL.positions[ i ] = markerX;
gBPointsL.positions[ i + 1 ] = markerY;
gBPointsL.positions[ i + 2 ] = 0;
}
}
if ( markerX > 0 ) {// right
idxMarkersR ++;
markersR[ idxMarkersR ] = new THREE.Sprite( matMarkerR );
markersR[ idxMarkersR ].position.x = markerX;
markersR[ idxMarkersR ].position.y = markerY;
markersR[ idxMarkersR ].scale.x = markerSize;
markersR[ idxMarkersR ].scale.y = markerSize;
sceneB.add( markersR[ idxMarkersR ] );
for ( let i = idxMarkersR * 3 ; i < gBPointsR.positions.length; i += 3 ) {// fill with last value
gBPointsR.positions[ i ] = markerX;
gBPointsR.positions[ i + 1 ] = markerY;
gBPointsR.positions[ i + 2 ] = 0;
}
}
}
function hitMarkerL( markerX, markerY ) {
var x0;
var x1;
var y0;
var y1;
var hitL = false;
var j = idxMarkersL * 3 + 3;
while ( !hitL && j > 2 ) {
j -= 3;
x0 = gBPointsL.positions[ j ] - epsilon;
x1 = gBPointsL.positions[ j ] + epsilon;
y0 = gBPointsL.positions[ j + 1 ] - epsilon;
y1 = gBPointsL.positions[ j + 1 ] + epsilon;
hitL = ( markerX > x0 ) && ( markerX < x1 ) && ( markerY > y0 ) && ( markerY < y1 );
}
return hitL ? j : -1;// idxHitL
}
function hitMarkerR( markerX, markerY ) {
var x0;
var x1;
var y0;
var y1;
var hitR = false;
var j = idxMarkersR * 3 + 3;
while ( !hitR && j > 2 ) {
j -= 3;
x0 = gBPointsR.positions[ j ] - epsilon;
x1 = gBPointsR.positions[ j ] + epsilon;
y0 = gBPointsR.positions[ j + 1 ] - epsilon;
y1 = gBPointsR.positions[ j + 1 ] + epsilon;
hitR = ( markerX > x0 ) && ( markerX < x1 ) && ( markerY > y0 ) && ( markerY < y1 );
}
return hitR ? j : -1;// idxHitR
}
function update() {
// ??????
}
function render() {
rendererA.render( sceneA, cameraA );
rendererB.render( sceneB, cameraB );
}
function initComparisons() {
// modified/ extended ( based on @author: looeee )
containerB.style.width = ( 0.75 * containerB.offsetWidth ) +'px';
containerB.style.height = ( 0.75 * containerB.offsetHeight ) +'px';
let pX = containerB.offsetWidth;
let pY = containerB.offsetHeight;
if ( pX > widthB ) {
slider.style.left = widthB - 20 + "px";
} else {
slider.style.left = pX - 20 + "px";
}
if ( pY > heightB ) {
slider.style.top = heightB - 20 + "px";
} else {
slider.style.top = pY - 20 + "px";
}
let clicked = 0;
// only controlsA
const slideReady = () => {
clicked = 1;
controlsA.enabled = false;
};
const slideFinish = () => {
clicked = 0;
controlsA.enabled = true;
};
const slideMove = ( e ) => {
if ( clicked === 0 ) return false;
let posX = getCursorPosX( e );
let posY = getCursorPosY( e );
//prevent the slider from being positioned outside the canvas
if ( posX < 0 ) posX = 0;
if ( posX > widthB ) posX = widthB;
slideX( posX );
if ( posY < 0 ) posY = 0;
if ( posY > heightB ) posY = heightB;
slideY( posY );
}
//detail functions
function getCursorPosX( e ) {
let getCur = ( e.pageX - containerB.offsetLeft ) - window.pageXOffset;
return getCur;
}
function getCursorPosY( e ) {
let getCur = ( e.pageY - containerB.offsetTop ) - window.pageYOffset;
return getCur;
}
function slideX(x) {
containerB.style.width = x + "px";
//position the slider
slider.style.left = containerB.offsetWidth - ( 0.5 * slider.offsetWidth) + "px";
}
function slideY(y) {
containerB.style.height = y + "px";
//position the slider
slider.style.top = containerB.offsetHeight - ( 0.5 * slider.offsetHeight) + "px";
}
slider.addEventListener('mousedown', slideReady );
window.addEventListener('mouseup', slideFinish );
window.addEventListener('mousemove', slideMove );
}
</script>
</html>
|
| | | | |
| | HofK | Die Geometriedefinition für Rahmen mit Multimaterial ist fertig. Dabei gibt es zwei verschiedene Modi.
Anders als in der Lösung von prisoner849 [...] benutze ich neben THREE.BufferGeometry( ) keine weiteren Objekte von three.js.
Damit wird es einfach Multimaterial zu ermöglichen. Für Texturen benötigt man uv Werte. In der allgemeinen Form macht das wenig Sinn. Hat man allerdings eine konkrete Form wie einen Türrahmen, kann man die uv Werte leicht ermitteln und integrieren.
Hier der Link: [...]
Ich werde die Geometrie in mein Addon THREEg [...] aufnehmen.
<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/profiledcontourgeometry-multimaterial/5801 -->
<!-- http://threejs.hofk.de/ProfiledContourGeometryMM/ProfiledContourGeometryMM.html -->
<head>
<title> ProfiledContourGeometryMM </title>
<meta charset="utf-8" />
<style>
body {
margin: 0;
}
</style>
</head>
<body> </body>
<script src="../js/three.min.100.js"></script>
<script src="../js/OrbitControls.js"></script>
<script>
'use strict'
// @author hofk
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( -8, 10, 20 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var light = new THREE.DirectionalLight( 0xffffff, 0.6);
light.position.setScalar( 10 );
scene.add( light );
scene.add(new THREE.AmbientLight( 0xffffff, 0.8));
var helper = new THREE.GridHelper( 20, 20);
scene.add( helper );
var detail = 7
var profileShape1 = [];
for ( var i = 0; i < detail + 1; i ++ ){
profileShape1.push ( 0.5 * Math.cos( i / detail * Math.PI * 2 ), 0.5 * Math.sin( i / detail * Math.PI * 2 ) );
}
var contour1 = [
-3, 4,
0, 4,
4, 4,
2, 1,
4, -2,
0, -3,
-4, -3,
-4, 0
];
var profileShape2 = [ -1,1, 1,1, 1,-1, -1,-1 ];
var contour2 = [
4, 0,
4, 8,
8, 8,
12, 8,
12, 2,// here only to show that angle of 180° vertikal works
12, 0,
];
var materials = [// rainbow-colored
new THREE.MeshPhongMaterial( { color: 0xfa0001, side: THREE.DoubleSide } ),
new THREE.MeshPhongMaterial( { color: 0xff7b00, side: THREE.DoubleSide } ),
new THREE.MeshPhongMaterial( { color: 0xf9f901, side: THREE.DoubleSide } ),
new THREE.MeshPhongMaterial( { color: 0x008601, side: THREE.DoubleSide } ),
new THREE.MeshPhongMaterial( { color: 0x01bbbb, side: THREE.DoubleSide } ),
new THREE.MeshPhongMaterial( { color: 0x250290, side: THREE.DoubleSide } ),
new THREE.MeshPhongMaterial( { color: 0xfc4ea5, side: THREE.DoubleSide } ),
new THREE.MeshPhongMaterial( { color: 0x83058a, side: THREE.DoubleSide } ),
new THREE.MeshPhongMaterial( { color: 0x83058a, side: THREE.DoubleSide } )
]
var material = materials[ 2 ].clone();
material.wireframe = true;
//..................................................... contourClosed, openEnded, profileMaterial
var geometry1 = ProfiledContourMMgeometry(profileShape1, contour1, false, false, true );
var fullProfile1 = new THREE.Mesh( geometry1, materials );
fullProfile1.position.z = 6;
scene.add( fullProfile1 );
var fullProfile12 = new THREE.Mesh( geometry1, material );
fullProfile12.position.z = -8;
scene.add( fullProfile12 );
var geometry13 = ProfiledContourMMgeometry(profileShape1, contour1 );
var fullProfile13 = new THREE.Mesh( geometry13, materials );
fullProfile13.position.x = -5;
scene.add( fullProfile13 );
var geometry2 = ProfiledContourMMgeometry(profileShape2, contour2, false, true );
var fullProfile2 = new THREE.Mesh( geometry2, materials );
fullProfile2.scale.set( 0.5, 0.5, 0.5 );
scene.add( fullProfile2 );
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
function ProfiledContourMMgeometry( profileShape, contour, contourClosed, openEnded, profileMaterial ) {
contourClosed = contourClosed !== undefined ? contourClosed : true;
openEnded = openEnded !== undefined ? openEnded : false;
openEnded = contourClosed === true ? false : openEnded;
profileMaterial = profileMaterial !== undefined ? profileMaterial : false;
if( contourClosed ) contour.push( contour[ 0 ], contour[ 1 ] );
var hs1 = contour.length / 2;
var rs1 = profileShape.length / 2;
var hs = hs1 - 1;// height segments
var rs = rs1 - 1;// radius segments
var faceCount = hs * rs * 2 + ( openEnded ? 0 : rs * 2 );
var posCount = hs1 * rs1 + ( openEnded ? 0 : 2 );
var g = new THREE.BufferGeometry( );
g.indices = new Uint32Array( faceCount * 3 );
g.positions = new Float32Array( posCount * 3 );
g.setIndex( new THREE.BufferAttribute( g.indices, 1 ) );
g.addAttribute('position', new THREE.BufferAttribute( g.positions, 3 ) );
var a, b1, c1, b2, c2;
var i1, i2;
var xc0, yc0, xc1, yc1, xc2, yc2, xSh, xDiv;
var dx0, dy0, dx2, dy2;
var e0x, e0y,e0Length, e2x, e2y, e2Length, ex, ey, eLength;
var phi, bend;
var x, y, z;
var vIdx, posIdx;
var epsilon = 0.000001;
var idx = 0;
for ( var i = 0; i < hs; i ++ ) {
if ( profileMaterial ) g.addGroup( idx, rs * 6, i );// MultiMaterial support
i1 = i + 1;
for ( var j = 0; j < rs; j ++ ) {
// 2 faces / segment, 3 vertex indices
a = rs1 * i + j;
c1 = rs1 * i1 + j;// left
b1 = c1 + 1;
//c2 = b1; // right
b2 = a + 1;
g.indices[ idx ] = a;// left
g.indices[ idx + 1 ] = b1;
g.indices[ idx + 2 ] = c1;
g.indices[ idx + 3 ] = a;// right
g.indices[ idx + 4 ] = b2,
g.indices[ idx + 5 ] = b1;// = c2
if ( !profileMaterial ) g.addGroup( idx, 6, j );// MultiMaterial support
idx += 6;
}
}
if( !openEnded ) {
g.addGroup( idx, rs * 3, rs );// MultiMaterial support
a = hs1 * rs1;
for ( var j = 0; j < rs; j ++ ) {
g.indices[ idx ] = a;
g.indices[ idx + 1 ] = j + 1;
g.indices[ idx + 2 ] = j;
idx += 3;
}
g.addGroup( idx, rs * 3, rs + 1 );// MultiMaterial support
a += 1;
for ( var j = rs1 + 1; j > 1; j -- ) {
g.indices[ idx ] = a;
g.indices[ idx + 1 ] = a - j;
g.indices[ idx + 2 ] = a - j + 1;
idx += 3;
}
}
for ( var i = 0; i < hs1; i ++ ) {
i2 = 2 * i;
xc1 = contour[ i2 ];
yc1 = contour[ i2 + 1 ];
if ( i === 0 ) {
xc0 = contour[ ( hs - 1 ) * 2 ];// penultimate point
yc0 = contour[ ( hs - 1 ) * 2 + 1 ];
} else {
xc0 = contour[ i2 - 2 ];// previous point
yc0 = contour[ i2 - 1 ];
}
if ( i === hs ) {
xc2 = contour[ 2 ];// second point
yc2 = contour[ 3 ];
} else {
xc2 = contour[ i2 + 2 ];// next point
yc2 = contour[ i2 + 3 ];
}
if ( !contourClosed ) {
if ( i === 0 ) {
// direction
dx2 = xc2 - xc1;
dy2 = yc2 - yc1;
// unit vector
e2Length = Math.sqrt( dx2 * dx2 + dy2 * dy2 );
e2x = dx2 / e2Length;
e2y = dy2 / e2Length;
// orthogonal
ex = e2y;
ey = -e2x;
}
if ( i === hs ) {
// direction
dx0 = xc1 - xc0;
dy0 = yc1 - yc0;
// unit vector
e0Length = Math.sqrt( dx0 * dx0 + dy0 * dy0 );
e0x = dx0 / e0Length;
e0y = dy0 / e0Length;
// orthogonal
ex = e0y;
ey = -e0x;
}
xDiv = 1;
bend = 1;
}
if ( ( i > 0 && i < hs ) || contourClosed ) {
// directions
dx0 = xc0 - xc1;
dy0 = yc0 - yc1;
dx2 = xc2 - xc1;
dy2 = yc2 - yc1;
if( Math.abs( ( dy2 / dx2 ) - ( dy0 / dx0 ) ) < epsilon ) {// prevent 0
dy0 += epsilon;
}
if( Math.abs( ( dx2 / dy2 ) - ( dx0 / dy0 ) ) < epsilon ) {// prevent 0
dx0 += epsilon;
}
// unit vectors
e0Length = Math.sqrt( dx0 * dx0 + dy0 * dy0 );
e0x = dx0 / e0Length;
e0y = dy0 / e0Length;
e2Length = Math.sqrt( dx2 * dx2 + dy2 * dy2 );
e2x = dx2 / e2Length;
e2y = dy2 / e2Length;
// direction transformed
ex = e0x + e2x;
ey = e0y + e2y;
eLength = Math.sqrt( ex * ex + ey * ey );
ex = ex / eLength;
ey = ey / eLength;
phi = Math.acos( e2x * e0x + e2y * e0y ) / 2;
bend = Math.sign( dx0 * dy2 - dy0 * dx2 );// z cross -> curve bending
xDiv = Math.sin( phi );
}
for ( var j = 0; j < rs1; j ++ ) {
xSh = profileShape[ j * 2 ];
x = xc1 + xSh / xDiv * bend * ex;
y = yc1 + xSh / xDiv * bend * ey;
z = profileShape[ j * 2 + 1 ];// ySh
vIdx = rs1 * i + j;
posIdx = vIdx * 3;
g.positions[ posIdx ] = x;
g.positions[ posIdx + 1 ] = y;
g.positions[ posIdx + 2 ] = z;
}
}
if( !openEnded ) {
g.positions[ hs1 * rs1 * 3 ] = contour[ 0 ];
g.positions[ hs1 * rs1 * 3 + 1 ] = contour[ 1 ];
g.positions[ hs1 * rs1 * 3 + 2 ] = 0;
g.positions[ hs1 * rs1 * 3 + 3 ] = contour[ hs * 2 ];
g.positions[ hs1 * rs1 * 3 + 4 ] = contour[ hs * 2 + 1 ];
g.positions[ hs1 * rs1 * 3 + 5 ] = 0;
}
g.computeVertexNormals();
return g;
}
</script>
</html>
|
| | | | |
| | HofK | Die Rahmengeometrie ist in das Addon THREEg integriert und auf Github [...] verfügbar.
Auch die Konstruktion macht Fortschritte. Man kann schon Punkte setzen, verschieben, löschen und einfügen. Für beide Koordinatensysteme kann ein Maßstab unabhängig gewählt werden.
|
| | | | |
| | HofK | Da einige Autoren auch im neuen Jahr schon fleißig waren, gibt es interessante Beispiele von discourse.threejs.org in der Sammlung [...]
|
| | | | |
| | HofK | Beim einfügen der Rahmen habe ich festgestellt, dass es sehr ungünstig ist, wenn man für jede Wandöffnung extra Teilwände definieren muss. Also davor, bei Türen über, bei Fenstern dazu noch unter und dann hinter der Wandöffnung. Hinzu kommt das Problem der Textur. Möchte man eine einheitlich strukturierte Wand haben, ist der Aufwand zur Ermittlung und Eintragung der uv-Werte für die Teilwände nicht unerheblich. Dann wird die Sache auch schnell unübersichtlich.
Alter Zustand: Das Problem einfach mit Backstein über der Tür umgangen.
Also habe ich für "dünne" Wände - Aussenwände - eine einheitliche Definition ermöglicht.
// bei unterschiedlichem Niveau zu Anfangspunkt Höhen y00,y01 einfügen
// x0,z0, (y00,y01,) x1,z1, y10,y11 ( , Dicke ) oder ( ,Wandöffnungen ) ( optional )
Beispiel:
[ 0,2, 0,12, 0,4, 1,1,1,1.5, 1,2,0,2.5, 1,1,1,1.5 ], // 3 Wandöffnungen
Wandöffnungen d, w, l, h - distance, width, level, height
Da der Koordinatenursprung hinten rechts in der Ecke ist, sind die Werte (vom Innenraum aus gesehen ) von rechts nach links zu werten. Die Wand steht auf der z Achse.
Das Verfahren funktioniert auch mit Wänden die beliebig schräg im Raum stehen und auch mit unterschiedlichen Werten für die Höhen von Anfangs- und Endpunkt der Wand.
Bei der Anwendung ist nun der Aufwand geringer, im Javascript ein wenig größer.
Die Handhabung der optionalen Werte:
wls = [];
wallGeometries[ w ] = new THREE.BufferGeometry(); wls.push( walls[ w ][ 0 ], walls[ w ][ 1 ] ); // x0,z0, thick = ( walls[ w ].length === 7 || walls[ w ].length === 9 ) ? true : false; equlev = ( walls[ w ].length - 2 ) % 4 < 2 ? true: false; if ( equlev ) { wls.push( walls[ w ][ 4 ], walls[ w ][ 5 ] ); // (y00,y01,) <-- y10,y11 (identical, equal level) wls.push( walls[ w ][ 2 ], walls[ w ][ 3 ], walls[ w ][ 4 ], walls[ w ][ 5 ] ); // x1,z1, y10,y11 } else { wls.push( walls[ w ][ 2 ], walls[ w ][ 3 ], walls[ w ][ 4 ], walls[ w ][ 5 ], walls[ w ][ 6 ], walls[ w ][ 7 ] ); } if ( equlev && thick ) wls.push( walls[ w ][ 6 ] ); if ( !equlev && thick ) wls.push( walls[ w ][ 8 ] ); if( !thick ) { for ( let i = 6 + ( equlev ? 0 : 2 ); i < walls[ w ].length; i += 4 ) { // each 4 values wall openings wls.push( walls[ w ][ i ], walls[ w ][ i + 1 ], walls[ w ][ i + 2 ], walls[ w ][ i + 3 ] ); } }
Dazu kommen dann noch einige Berechnungen zur Bestimmung der Positionsanzahl und zur Bestimmung der Positionen und uv-Werte. Man benötigt die Gleichung der Geraden im Raum. |
| | | | |
|
AntwortenThemenoptionen | 333.533 Betrachtungen |
ThemeninformationenDieses Thema hat 10 Teilnehmer: |