CSS3DRenderer禁用缩放

时间:2018-12-04 15:07:16

标签: javascript three.js

请参阅我之前的问题here,以参考我要实现的目标

TL; DR: 我正在尝试使HTML元素与<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <svg version="1.1" id="mySVG" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" xml:space="preserve" viewBox="0 0 1425.1 5483.3"> <style type="text/css"> .st0{fill:none;stroke:#292929;stroke-width:2;stroke-linecap:square;stroke-miterlimit:10;stroke-dasharray:10,7;} .st1{fill:none;} .st2{fill:none;stroke:url(#SVGID_1_);stroke-width:2;stroke-miterlimit:10;} .st3{fill:none;stroke:url(#SVGID_2_);stroke-width:2;stroke-miterlimit:10;stroke-dasharray:9.3333,6.5333;} .st4{fill:none;stroke:url(#SVGID_3_);stroke-width:2;stroke-miterlimit:10;} .st5{fill-rule:evenodd;clip-rule:evenodd;fill:url(#SVGID_4_);} .st6{fill-rule:evenodd;clip-rule:evenodd;fill:url(#SVGID_5_);} .st7{fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:10;} .st8{fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:10;stroke-dasharray:10.4762,7.3333;} </style> <path class="st0" id="path1" d="M635.5,152.3V1072l177.7-0.4c0,0,34.5-3.8,64.6,21.4c0,0,18.4,12.7,29.8,41.7c0,0,7.5,15.6,5.8,49.5v290.4c0,0-0.8,34.5,5.8,46c0,0,10.2,29,28.3,41.8c0,0,19.5,21.6,62.1,25.1h20.7l479.6,0.1v861h-478.2c0,0-60-8.7-95.8,35.1c0,0-22.6,23.1-22.6,64.5v322.4l0.1,200.9c0,0,1.6,33.1,14.2,51.8c0,0,11.1,25.5,46.1,46.9c0,0,20.5,12.7,51.2,15.1l105.2,0.2c0,0,36.2,2.3,65.2-15.6c0,0,41.9-23.6,53.1-60.3c0,0,11.5-22.9,8.9-70.6l-0.4-153.2c0,0-0.9-32.2-23.1-59.2c0,0-21-28.7-56.4-38.1c0,0-20.2-6.3-46.3-4.3H754.8H635.5v606h295c0,0,47.7-3.1,92.9,35.5c0,0,27,22.3,38.2,56.4c0,0,10,15.3,7.9,64.8v194.5v186.4v77.6c0,0,0.5,44.2-12.4,71.9c0,0-17.2,45.5-42.9,67.8c0,0-27.8,31.4-87.6,51.3l-119.1,55.9c0,0-39.3,13.7-64.5,59c0,0-18.2,26.9-21.9,68.2c0,0-0.7,19-0.7,32.1l-0.6,284.1l-0.2,74.5c0,0-0.8,26.4,13.3,46.2c0,0,18.9,29,52.9,34.6c0,0,18.4,1.2,37.1,1.2h252.4h188.4c0,0,29.9-0.4,49.6-17.2c0,0,30-24.2,30.2-57.4l0-140.1c0,0-1.9-30-17.8-44.9c0,0-19.9-27.7-59.1-29.4l-254.8-0.1H802.1c0,0-43-1.1-66.9,33.9c0,0-17.5,21.6-15.7,56.9"/> <path class="st0" id="path2" d="M915.5,150c0,0-0.7,52.5-9.6,73.4c0,0-22.2,83.3-75.3,131.8c0,0-44.4,51.3-125.9,75.4c0,0-33.9,10.3-77,11.8l-385,0.1c0,0-50.4-3.9-94,22.5c0,0-32.5,15.5-62.2,63.4c0,0-22.6,37.4-20.9,82.5v286.9V1578v325.4v135.2c0,0-3.5,35.2,23.2,59.1c0,0,16.1,17.9,45.3,20.6c0,0,31.5,0.3,35.7,0.3h306.4h301.2h33.9c0,0,25.2,3,54.3-16.4c0,0,29.4-18.7,37.4-53.9c0,0,4.1-14,2.8-52.8v-184.7v-187.3c0,0,1.7-39.2-14.1-62.9c0,0-18.1-33.4-54-47.2c0,0-19.7-10.2-65.1-7.8H381.5H-29.8v2363h224.1h507.9H1101c0,0,109.3,12.4,167-45.7c0,0,42.1-35.8,56.8-88c0,0,10.6-19.8,7.7-95.7v-137.6c0,0-0.4-50.3,27.5-80.9c0,0,24.8-32.8,67.1-43.9c0,0,21.8-6.4,56.1-4.2h218.8"/> <polyline class="st1" points="-7.5,5248.7 1432.6,5248.7 1432.6,234.7 -7.5,234.7 "/> <polyline class="st1" points="-3299.4,5248.7 -1859.3,5248.7 -1859.3,234.7 -3299.4,234.7 "/> <g class="lineactive" id="lineactive"> <g> <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="41.558" y1="32.0825" x2="19.692" y2="37.9415"> <stop offset="0" style="stop-color:#292929"/> <stop offset="0.4124" style="stop-color:#0777D0"/> <stop offset="0.539" style="stop-color:#68E0BE"/> <stop offset="1" style="stop-color:#292929"/> </linearGradient> <line class="st2" x1="40" y1="30" x2="40" y2="35"/> <linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="51.3413" y1="68.5944" x2="29.4753" y2="74.4534"> <stop offset="0" style="stop-color:#292929"/> <stop offset="0.4124" style="stop-color:#0777D0"/> <stop offset="0.539" style="stop-color:#68E0BE"/> <stop offset="1" style="stop-color:#292929"/> </linearGradient> <line class="st3" x1="40" y1="41.5" x2="40" y2="101.7"/> <linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="60.308" y1="102.0585" x2="38.442" y2="107.9175"> <stop offset="0" style="stop-color:#292929"/> <stop offset="0.4124" style="stop-color:#0777D0"/> <stop offset="0.539" style="stop-color:#68E0BE"/> <stop offset="1" style="stop-color:#292929"/> </linearGradient> <line class="st4" x1="40" y1="105" x2="40" y2="110"/> </g> </g> <g transform="translate(34 65)" class="lineactive" id="lineactive2"> <linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-454.75" y1="470.8333" x2="-453.75" y2="470.8333" gradientTransform="matrix(12 0 0 -12 5457 5656)"> <stop offset="0" style="stop-color:#EEF8FF"/> <stop offset="1" style="stop-color:#68E0BE"/> </linearGradient> <circle class="st5" cx="6" cy="6" r="6"/> <linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="-454.7299" y1="471.3137" x2="-453.9361" y2="470.5191" gradientTransform="matrix(12 0 0 -12 5457 5656)"> <stop offset="0" style="stop-color:#0777D0"/> <stop offset="1" style="stop-color:#68E0BE"/> </linearGradient> <circle class="st6" cx="6" cy="6" r="6"/> </g> <g class="lineactive" id="lineactive3"> <g> <line class="st7" x1="79.9" y1="-0.1" x2="79.9" y2="4.9"/> <line class="st8" x1="79.9" y1="12.3" x2="79.9" y2="133.3"/> <line class="st7" x1="79.9" y1="136.9" x2="79.9" y2="141.9"/> </g> </g> <g class="lineactive" id="lineactive4"> <g> <line class="st7" x1="1.2" y1="0" x2="1.2" y2="5"/> <line class="st8" x1="1.2" y1="12.3" x2="1.2" y2="133.3"/> <line class="st7" x1="1.2" y1="137" x2="1.2" y2="142"/> </g> </g> </svg>一起旋转,以使这些HTML元素似乎卡在地球上并随其移动。 (考虑某些国家/地区上方3D地球上的地图标记)

我使用THREE.js OrbitControls几乎成功地做到了这一点,并且能够通过纬度/经度计算将HTML元素固定在3D地球仪上的某个位置,并在{{ 1}}。

问题

我唯一遇到的问题是HTML元素的缩放比例与它们离相机的距离有多远。通常,我认为这是理想的效果,有助于感觉更近/更远,但是缩放导致我无法正确且一致地调整HTML元素的大小,并且还导致元素内的文本和SVG模糊/变得像素化

我想要的

我正在寻找一种关闭这种缩放的方法,以便HTML元素仍然可以其他方式进行变换,但是无论它们在何处都保持相同的大小(即scale(1、1、1)或它们的原始缩放)在CSS3DRenderer创建的3D渲染器中。

我认为我必须为此编辑CSS3DRenderer.js代码,但是我绝对不知道从哪里开始,而且在其他任何地方都找不到任何信息。

谢谢。

我的一些代码:

创建OrbitControls

CSS3DRenderer

调整大小功能(在窗口调整大小事件上调用)

CSS3DRenderer

从HTML中的//CSS3D Renderer rendererHTML = new THREE.CSS3DRenderer(); rendererHTML.setSize(WIDTH, HEIGHT); rendererHTML.domElement.classList.add('CSS3D-container'); containerHTML = document.querySelector('.globe__container'); containerHTML.appendChild(rendererHTML.domElement); 元素创建CSS3DSprite对象,并设置其在地球上的初始位置

HEIGHT = sizeControlElem.getBoundingClientRect().width;
WIDTH = sizeControlElem.getBoundingClientRect().width;

renderer.setSize(WIDTH, HEIGHT);
rendererHTML.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();

您可以在问题here

中看到更多我的代码

2 个答案:

答案 0 :(得分:0)

唯一停止缩放的方法是使用Vector3.project()方法将3D位置投影到2D。看一下下面的代码示例,我评论了JavaScript代码中的关键点,但是快速的解释是:

  1. 将希望热点的3D位置复制到新矢量中。
  2. 使用vector.project(camera)将3D点转换为2D坐标。
  3. 将2D坐标的范围从[-1,1]转换为[0,window.width]
  4. 通过CSS将这些坐标应用于您的热点。

奖金:您仍然可以使用2D矢量的.z属性来确定它是否在相机的视锥范围内。

var camera, controls, scene, renderer;

// This array will hold all positions in 3D space
var posArray3D = [];

// This array will hold all hotspot DIVs
var divArray = [];

// Create temp vector to reuse on loops
var tempVec = new THREE.Vector3();

init();
animate();

function init() {

	scene = new THREE.Scene();
	scene.background = new THREE.Color( 0xcccccc );

	renderer = new THREE.WebGLRenderer( { antialias: true } );
	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.setSize( window.innerWidth, window.innerHeight );
	document.body.appendChild( renderer.domElement );

	camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 3000 );
	camera.position.set( 400, 200, 0 );

	// controls
	controls = new THREE.OrbitControls( camera, renderer.domElement );

	controls.enableDamping = true;
	controls.dampingFactor = 0.25;

	controls.screenSpacePanning = false;

	controls.minDistance = 100;
	controls.maxDistance = 500;

	controls.maxPolarAngle = Math.PI / 2;



	// world
	var geometry = new THREE.CylinderBufferGeometry( 0, 10, 30, 4, 1 );
	var material = new THREE.MeshPhongMaterial( { color: 0xffffff, flatShading: true } );

	// This is where all hotspot DIVs will go
	var hotspotBox = document.getElementById("hotspotBox");

	for ( var i = 0; i < 100; i ++ ) {
		var mesh = new THREE.Mesh( geometry, material );
		mesh.position.x = Math.random() * 1600 - 800;
		mesh.position.y = 0;
		mesh.position.z = Math.random() * 1600 - 800;
		mesh.updateMatrix();
		mesh.matrixAutoUpdate = false;
		scene.add( mesh );

		// Populate array of 3D positions
		posArray3D.push(mesh.position);

		// Create 'hotspot' DIV, and place within 'hotspotBox' holder
		divArray.push(document.createElement("div"));
		divArray[i].classList.add("hotspot");
		hotspotBox.appendChild(divArray[i]);
	}


	// lights
	var light = new THREE.DirectionalLight( 0xffffff );
	light.position.set( 1, 1, 1 );
	scene.add( light );

	var light = new THREE.DirectionalLight( 0x002288 );
	light.position.set( - 1, - 1, - 1 );
	scene.add( light );

	var light = new THREE.AmbientLight( 0x222222 );
	scene.add( light );

	window.addEventListener( 'resize', onWindowResize, false );

}

function onWindowResize() {

	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();

	renderer.setSize( window.innerWidth, window.innerHeight );

}

// Loops through all divs and updates their positions based on the camera
function updateDivs() {
	var vectorScreen = new THREE.Vector3();

	// Loop through all positions
	for (var i = 0; i < posArray3D.length; i ++) {
		vectorScreen.copy(worldToScreen(posArray3D[i], camera));

		// Update CSS attributes of each DIV
		divArray[i].style.transform = "translate(" + vectorScreen.x + "px, " + vectorScreen.y + "px)";

		// Checks for depth, hides if it's behind the camera
		if(vectorScreen.z <= 1) {
			divArray[i].style.display = "block";
		} else {
			divArray[i].style.display = "none";
		}
	}
}

// Projects 3D coordinates into 2D space 
function worldToScreen(_position, _cam) {
	tempVec.copy(_position);

	tempVec.project(_cam);

	// Converts range from [-1, 1] to [0, windowWidth]
	tempVec.x = (   tempVec.x + 1 ) * window.innerWidth  / 2;
	tempVec.y = ( - tempVec.y + 1 ) * window.innerHeight / 2;

	return tempVec;
}

function animate() {

	requestAnimationFrame( animate );

	controls.update();
	updateDivs();

	render();

}

function render() {

	renderer.render( scene, camera );

}
body {
	color: #000;
	font-family:Monospace;
	font-size:13px;
	text-align:center;
	font-weight: bold;

	background-color: #fff;
	margin: 0px;
	overflow: hidden;
}
/*hotspotBox holds all .hotspots It's placed on top of WebGL canvas*/
#hotspotBox{
	position: absolute;
	width: 100%;
	height: 100%;
	top: 0;
	left: 0;
	border: 1px dashed #f90;
	pointer-events: none;
}
/*100 hotspots to be placed within #hotspotBox */
.hotspot {
	background: #f90;
	width: 10px;
	height: 10px;
	border-radius: 5px;
	position: absolute;
	cursor: pointer;
	pointer-events: auto;
}
<div id="hotspotBox"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>

答案 1 :(得分:0)

事实证明,对我的问题最简单的解决方案是仅使用CSS2DRenderer而不是CSS3DRenderer

它实际上具有相同的作用,但仅使用translate转换HTML元素,而不转换rotatescale,这意味着您可以使用来自由修改HTML元素的大小CSS宽度和大小等...这就是我想要做的。

它的实现方式完全相同,我唯一需要更改的代码就是将CSS3DSprite替换为CSS2DObject

详细了解CSS2DRenderer here