Construction base with two scenes

Based on the @looeee solution Compare three.js scenes with overlay slider, I moved one of the scenes horizontally and vertically.

Once again I made two stupid mistakes after another. If you leave it a bit, you’ll have a better chance of finding the mistake afterwards. :confused:

The result:


On the top left side two independent coordinate systems with orthographic camera are shown. You can mark points. If the cross meets a set marker again, this becomes clear in color. In Firefox the cross follows the cursor quite fast, in Chrome it dawdles clearly behind.

The mesh on the right scene is for test only. But on this basis, you can immediately inspect top left constructions on the right.

Try it out: http://threejs.hofk.de/ConstructionBasis/ConstructionBasis.html

Then you can output the three.js definition of the BufferGeometry as in
Modify indexed BufferGeometry (mouse or input)


<!DOCTYPE html>
<!-- @author hofk  http://threejs.hofk.de/ConstructionBasis/ConstructionBasis.html -->
<!-- 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>
3 Likes