首页 > 解决方案 > 三.js动态改变物距

问题描述

我将three.js 用于图形网站。

它的概念是有许多文本的宇宙。

如果我单击文本,无论距离多远,对象都必须移动到固定位置(或相机的前面)

所以我写了这样的代码。

[索引.html]

<html>
<head>
  <script
  src="https://code.jquery.com/jquery-3.3.1.min.js"
  integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
  crossorigin="anonymous"></script>
  <script src="https://gitcdn.xyz/repo/thesmart/jquery-scrollspy/0.1.3/scrollspy.js"></script>
  <script src="./src/WOW.js"></script>
  <script src="./src/three.js"></script>
  <script src="//cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/ColladaLoader.js"></script>
  <script src="https://unpkg.com/three.texttexture"></script>
  <script src="https://unpkg.com/three.textsprite"></script>
  <script src="./src/DeviceOrientationControls.js"></script>
  <script src="./src/hammer.js"></script>
  <script src="./src/Detector.js"></script>
  <script src="./src/perlin.js"></script>
  <link rel="stylesheet" type="text/css" href="style.css">
  <link rel="stylesheet" href="animate.css">
  <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
  <meta charset="UTF-8">
</head>
<body>
  <header>
    <div class="header-left">
      <a href="#loading-screen" onclick="topFunction()">MAIN</a>
    </div>
    <div class="header-right">
      <a href="#">MISSION</a>
      <a href="#section1">PRODUCT</a>
      <a href="#">CULTURE</a>
      <a href="#">STORY</a>
    </div>
  </header>
  <main>
    <!-- Universe -->
    <section id="universe" class="wow" data-wow-duration="0.5s"></section>
    <!-- Main -->
    <section class="main" id="main">
    </section>
    <script src="./src/src.js"></script>
  </main>
</body>
</html>

[src.js]

// VARIABLES
let clock, camera, scene, renderer, mixer;
const sleep = ms => new Promise(res => setTimeout(res, ms));

var myElement = document.getElementById("threejs");
const mouse = new THREE.Vector2();
const clicked = new THREE.Vector2();
const target = new THREE.Vector2();
const windowHalf = new THREE.Vector2( window.innerWidth / 2, window.innerHeight / 2 );
const moveState = {forward: 0, back: 0};
var isMobile = false;
var textCount = 500;
var firstTime = true;
var fontFamily = '"Courier New", Courier, monospace';
var lock = true;
var group = new THREE.Group();

const scrollPosition = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;

checkMobile()

// WOW.js
var wow = new WOW();
wow.init();

init();

async function init() {
  if ( ! Detector.webgl ) Detector.addGetWebGLMessage();

  scene = new THREE.Scene();

  // CAMERA
  camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2100 );
  camera.position.x = 0;
  camera.position.y = 0;
  camera.position.z = 1200;
  camera.lookAt(scene.position);

  clock = new THREE.Clock();

  // HELPER
  const gridHelper = new THREE.PolarGridHelper( 8, 16 );
  scene.add( gridHelper );

  // LIGHT
  const ambientLight = new THREE.AmbientLight( 0xffffff, 0.2 );
  scene.add( ambientLight );

  const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
  directionalLight.position.set( 1, 1, - 1 );
  scene.add( directionalLight );

  // CONTROLS
  if(isMobile) { // 모바일이면 
    var controls = new THREE.DeviceOrientationControls(camera);
    console.log('isMobile true');
  } else {
    console.log('isMobile false');
  }
  // SATISFY THE DESIRES OF LOVE
  let sprite = new THREE.TextSprite({
    textSize: 5,
    redrawInterval: 250,
    texture: {
      text: 'MAIN TEST',
      fontFamily: fontFamily,
    },
    material: {
      color: 'white',
    },
  });
  sprite.position.x = 0;
  sprite.position.y = 0;
  sprite.position.z = 10;
  scene.add(sprite);

  // ADD MESH
  var size = ( isMobile ? 2 : 2 );
  var starsLights = new THREE.Group();

  var starGeometry = new THREE.SphereGeometry(0.3, 16, 16);
  var emptyGeometry = new THREE.Geometry();

  for ( let i = 0; i < textCount; i ++ ) {
    var lod = new THREE.LOD();

    // Text
    let sprite = new THREE.TextSprite({
      textSize: size,
      redrawInterval: 250,
      texture: {
        text: 'For Test',
        fontFamily: fontFamily,
      },
      material: {
        color: 'white',
        transparent: true,
      },
    });

    // Star
    var starMaterial = new THREE.MeshBasicMaterial({color: 0xffffff, transparent: true});
    var star = new THREE.Mesh(starGeometry, starMaterial);

    // Dummy
    var dummy = new THREE.Mesh(emptyGeometry, new THREE.MeshBasicMaterial());

    // Add
    lod.addLevel(sprite, 1);
    lod.addLevel(star, 100, 240);
    lod.addLevel(dummy, 200, 300);

    lod.position.x = (Math.random() * 180-100);
    lod.position.y = Math.random() * 180-100;
    lod.position.z = Math.random() * 1000-40;

    group.add(lod);
  }
  scene.add(group);

  // Renderer
  renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
  renderer.setPixelRatio( window.devicePixelRatio );
  renderer.setSize( window.innerWidth, window.innerHeight );
  document.getElementById("universe").appendChild(renderer.domElement);

  // Event handler
  window.addEventListener('load', refreshCheck, false);
  window.addEventListener('resize', onWindowResize, false); 
  document.addEventListener('mousemove', onMouseMove, false);
  document.addEventListener('mousewheel', onMouseWheel, false); 
  document.addEventListener('contextmenu', onContextMenu, false); 
  document.addEventListener('mouseup', onMouseClick, false); 


  function animate() {
    target.x = ( 1 - mouse.x ) * 0.002;
    target.y = ( 1 - mouse.y ) * 0.002;
    camera.rotation.x += 0.05 * ( target.y - camera.rotation.x );
    camera.rotation.y += 0.05 * ( target.x - camera.rotation.y );

    if(isMobile) {
      controls.update();
    }
    // Object change related to distance
    group.children.forEach(function(child) {
      child.update(camera);
    })
    // Render
    requestAnimationFrame( animate );
    render(scene, camera);
  }

  animate();
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize( window.innerWidth, window.innerHeight );
}

function onMouseWheel(event) {
  event.preventDefault();
  camera.position.z -= event.deltaY * 0.2;
}

function render() {
  const delta = clock.getDelta();
  if ( mixer !== undefined ) mixer.update( delta );
  renderer.render( scene, camera );
}

function onTransitionEnd( event ) {
  console.log("Loading Complete");
  event.target.remove();
}

// Exist functions
function checkMobile() {
  var UserAgent = navigator.userAgent;

  if (UserAgent.match(/iPhone|iPod|Android|Windows CE|BlackBerry|Symbian|Windows Phone|webOS|Opera Mini|Opera Mobi|POLARIS|IEMobile|lgtelecom|nokia|SonyEricsson/i) != null || UserAgent.match(/LG|SAMSUNG|Samsung/) != null) {
      isMobile = true;
  } else {
      isMobile = false;
  }
}

var raycaster = new THREE.Raycaster();
var mouseVector = new THREE.Vector3();

function getIntersects( x, y ) {
    x = ( x / window.innerWidth ) * 2 - 1;
    y = - ( y / window.innerHeight ) * 2 + 1;
    mouseVector.set( x, y, 0.5 );
    raycaster.setFromCamera( mouseVector, camera );
    return raycaster.intersectObject( group, true );
}

var selectedObject = null;
var intersects;

function onMouseMove(event) {
  event.preventDefault();
  mouse.x = ( (event.clientX/2) - (windowHalf.x/2) );
  mouse.y = ( (event.clientY/2) - (windowHalf.y/2) );
  clicked.x = ( event.clientX / window.innerWidth ) * 2 - 1;
  clicked.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

  // Select object
  if ( selectedObject ) {
      selectedObject.material.color.set( '#ffffff' );
      selectedObject = null;
  }
  intersects = getIntersects( event.layerX, event.layerY );

  if ( intersects.length > 0 ) {
    var res = intersects.filter( function ( res ) {
        return res && res.object;
    } )[ 0 ];
    if ( res && res.object ) {
      selectedObject = res.object;
      selectedObject.material.color.set( '#f00' );
    }
  }
}

function onMouseClick() {
  if(intersects[0]) {
    console.log(intersects[0].point);
    intersects[0].object.position.z += intersects[0].distance-70;
    intersects[0].object.position.x = 0;
    intersects[0].object.position.y = 0;
  }
}

function onResize(event) {
  const width = window.innerWidth;
  const height = window.innerHeight;

  windowHalf.set( width / 2, height / 2 );

  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize( width, height );
}

function onContextMenu(event) { // Mouse right click
  event.preventDefault();
}

function refreshCheck() {
  if(window.performance) {
    if(performance.navigation.type === 1) {
      setTimeout(() => {
        document.body.scrollTop = 0; // Other Browser
        document.documentElement.scrollTop = 0; // IE
      }, 0);
    }
  }
}

onMouseWheel()函数中,我检测当前光标是否指向对象。

因此,对象的信息将存储在var intersects.

同时添加onMouseClick(). 在该函数内部,我像这样更改对象的位置。

  if(intersects[0]) {
    console.log(intersects[0].point);
    intersects[0].object.position.z += intersects[0].distance-70;
    intersects[0].object.position.x = 0;
    intersects[0].object.position.y = 0;
  }

因此,如果您单击对象,对象的 x,y,z 坐标将更改为, 0, 0, distance-70。

但它不适用于场景。

参考本站https://50-jahre-hitparade.ch/

如果单击文本,文本将移动到相机前面。

我的目标是让它像上面的网站。

在此处输入图像描述 (像这样)

为什么它在我的代码中不起作用?

这里有什么解决办法吗?

谢谢。

(也许我必须更新为 animate()?)

来源:https ://github.com/teamhide/raycast

启动:https ://teamhide.github.io/raycast/

标签: three.js

解决方案


代替

if(intersects[0]) {
    intersects[0].point.z = 100;
    intersects[0].point.x = 100;
    intersects[0].point.y = 100;
}

尝试改变这样的位置intersects[0].object.position

if(intersects[0]) {
    intersects[0].object.position.z = 100;
    intersects[0].object.position.x = 100;
    intersects[0].object.position.y = 100;
}

推荐阅读