Установить начало вращения куба 3d - PullRequest
1 голос
/ 01 мая 2019

У меня есть простой 3d-куб (BoxGeometry 100, 100, 100), и я пытаюсь повернуть его. Если мы назовем все 100x100x100 плиткой - когда я поворачиваю ее, я вижу, что она перекрывает нижнюю плитку.

(изменив цвет, теперь я полностью понимаю поведение).

tl.to(this.cube4.rotation, 0.5, {z: -45* Math.PI/180});

enter image description here [enter image description here

Что делать, если я хочу, чтобы повернуть его на основе опорной точки в правой нижней части? Таким образом, вместо переполнения внутри нижнего тайла эта часть будет перетекать в верхний тайл.

Так что это будет выглядеть как зеленый пример, а не как красный пример:

enter image description here enter image description here

Красный пример здесь достигается с помощью

tl.to(this.cube4.rotation, 0.5, {z: -45* Math.PI/180});
tl.to(this.cube4.position, 0.5, {x: 50 }, 0.5);

Я очень новичок в three.js, поэтому, если какая-то терминология неверна, пожалуйста, предупредите меня

Ответы [ 3 ]

1 голос
/ 01 мая 2019

Добавьте ("красный") куб к THREE.Group таким образом, чтобы ось вращения (ребро) находилась в начале группы. Это означает, что куб должен быть смещен на половину длины стороны.
Если вы вращаете объект группы, то куб (который находится внутри группы) будет вращаться вокруг края, а не вокруг его центра.

, например

var bbox = new THREE.Box3().setFromObject(cube);
cube.position.set(bbox.min.x, bbox.max.y, 0);

var pivot = new THREE.Group();
pivot.add(cube);

scene.add(pivot);

См. Также ответ на Как центрировать группу объектов? , который использует это решение для вращения группы объектов.


(function onLoad() {
  var camera, scene, renderer, orbitControls, pivot;
  var rot = 0.02;
  
  init();
  animate();

  function init() {
    container = document.getElementById('container');
    
    renderer = new THREE.WebGLRenderer({
      antialias: true,
      alpha: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);

    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 100);
    camera.position.set(4, 1, 2);
    //camera.lookAt( -1, 0, 0 );

    loader = new THREE.TextureLoader();
    loader.setCrossOrigin("");

    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff);
    scene.add(camera);
    
    window.onresize = function() {
      renderer.setSize(window.innerWidth, window.innerHeight);
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
    }
    
    orbitControls = new THREE.OrbitControls(camera);

    var ambientLight = new THREE.AmbientLight(0x404040);
    scene.add(ambientLight);

    var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
    directionalLight.position.set(1,2,-1.5);
    scene.add( directionalLight );
    
    addGridHelper();
    createModel();

  }

  function createModel() {

    var material = new THREE.MeshPhongMaterial({color:'#80f080'});
    var geometry = new THREE.BoxGeometry( 1, 1, 1 );
    
    var cube1 = new THREE.Mesh(geometry, material);
    cube1.position.set(0,-0.5,-0.5);

    var cube2 = new THREE.Mesh(geometry, material);
    cube2.position.set(0,0.5,-0.5);

    var cube3 = new THREE.Mesh(geometry, material);
    cube3.position.set(0,-0.5,0.5);

    var material2 = new THREE.MeshPhongMaterial({color:'#f08080'});
    var cube4 = new THREE.Mesh(geometry, material2);
    
    var bbox = new THREE.Box3().setFromObject(cube4);
    cube4.position.set(bbox.min.x, bbox.max.y, 0);

    pivot = new THREE.Group();
    pivot.add(cube4);
    pivot.position.set(-bbox.min.x, 0.5-bbox.max.y, 0.5);

    scene.add(cube1);
    scene.add(cube2);
    scene.add(cube3);
    scene.add(pivot);
  }

  function addGridHelper() {
    
    var helper = new THREE.GridHelper(100, 100);
    helper.material.opacity = 0.25;
    helper.material.transparent = true;
    scene.add(helper);

    var axis = new THREE.AxesHelper(1000);
    scene.add(axis);
  }

  function animate() {
    requestAnimationFrame(animate);
    orbitControls.update();
    pivot.rotation.z += rot;
    if (pivot.rotation.z > 0.0 || pivot.rotation.z < -Math.PI/2) rot *= -1;
    render();
  }

  function render() {
    renderer.render(scene, camera);
  }
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="container"></div>
0 голосов
/ 01 мая 2019

Из первого изображения видно, что ось вашей красной плитки находится в ее центре.

Для нужного вам вращения вы бы в идеале изменили ось в правом нижнем углу куба. Это невозможно без изменения геометрии куба.

НО простой трюк состоит в том, чтобы создать пустой узел в этой точке поворота, привязать ваш куб к этому пустому и применить ваше вращение к пустому. (Не забудьте удалить свой перевод, он вам больше не нужен)

Вот некоторый псевдокод, предполагая, что ваше красное поле центрировано в (0,0,0) и имеет ширину и высоту 100:

// create an empty node at desired rotation pivot
var empty = new Object3D or group
empty.position = (50, -50, 0)

// parent your cube to the empty
var cube = your box
empty.add(cube)

// you may need to change the local position of your cube to bring it back to its global position of (0,0,0)
cube.position = (-50, 50, 0)

rotate empty by 45°
0 голосов
/ 01 мая 2019

Я думаю, вы можете получить границы повернутого объекта следующим образом:

bounds = new THREE.Box3().setFromObject( theRedObject )

Затем измените положение объекта.y на основе его границ.min.y

let scene, camera, controls, ambient, point, loader, renderer, container, stats;

const targetRotation = 0;
const targetRotationOnMouseDown = 0;
const mouseX = 0;
const mouseXOnMouseDown = 0;
const windowHalfX = window.innerWidth / 2;
const windowHalfY = window.innerHeight / 2;


init();
animate();
var box, b1, b2, b3;

function init() {
  // Create a scene which will hold all our meshes to be rendered
  scene = new THREE.Scene();

  // Create and position a camera
  camera = new THREE.PerspectiveCamera(
     60, // Field of view
     window.innerWidth / window.innerHeight, // Aspect ratio
    /*window.innerWidth / -8,
    window.innerWidth / 8,
    window.innerHeight / 8,
    window.innerHeight / -8,
    */
    0.1, // Near clipping pane
    1000 // Far clipping pane
  );
scene.add(camera)
  // Reposition the camera
  camera.position.set(0, 5, 10);
  // Point the camera at a given coordinate
  camera.lookAt(new THREE.Vector3(0, 0, 0));
  // Add orbit control
  controls = new THREE.OrbitControls(camera);
  controls.target.set(0, -0.5, 0);
  controls.update();

  // Add an ambient lights
  ambient = new THREE.AmbientLight(0xffffff, 0.2);
  scene.add(ambient);

  // Add a point light that will cast shadows
  point = new THREE.PointLight(0xffffff, 1);
  point.position.set(25, 50, 25);
  point.castShadow = true;
  point.shadow.mapSize.width = 1024;
  point.shadow.mapSize.height = 1024;
  scene.add(point);

  group = new THREE.Group();
  group.position.y = 0;
  scene.add(group);
  rotationAnchor = new THREE.Object3D()
  group.add(rotationAnchor);

  box = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshStandardMaterial({
    color: 'grey'
  }))
  b1 = box.clone();
  b2 = box.clone();
  b3 = box.clone();
  b3.material = b3.material.clone()
  b3.material.color.set('red')
  group.add(box);
  group.add(b1);
  b1.position.y += 1
  group.add(b2);
  b2.position.z += 1
  rotationAnchor.add(b3);
  rotationAnchor.position.set(0.5, 0.5, 1.5)
  b3.position.set(-.5, -.5, -.5)
  // Create a renderer
  renderer = new THREE.WebGLRenderer({
    antialias: true
  });
  // Set size
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  // Set color
  renderer.setClearColor(0xf8a5c2);
  renderer.gammaOutput = true;
  // Enable shadow mapping
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;

  // Append to the document
  container = document.createElement("div");
  document.body.appendChild(container);
  document.body.appendChild(renderer.domElement);
  // Add resize listener
  window.addEventListener("resize", onWindowResize, false);

  // Enable FPS stats
  stats = new Stats();
  container.appendChild(stats.dom);

  var gui = new dat.GUI({
    height: 5 * 32 - 1
  });
  let params = {
    'test': 4,
    'bevelThickness': 1,
    'bevelSize': 1.5,
    'bevelSegments': 3
  }
  gui.add(params, 'test', 0, 10).onChange(val => {
    test = val
  })
}

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

function animate() {
  rotationAnchor.rotation.z = (Math.cos(performance.now() * 0.001) * Math.PI * 0.25) + (Math.PI * 1.25)
  requestAnimationFrame(animate);
  // Re-render scene
  renderer.render(scene, camera);
  // Update stats
  stats.update();
}
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.2/dat.gui.min.js"></script>
...