여기서 캔버스의 빈 공간을 클릭했을 때의 이벤트를 받고싶었는데, 특별히 이 때만을 위해 구현된 것은 없었다.
오브젝트의 Transform(Translate, Rotation, Scale)을 만지는 동안에는 TransformControls가 활성화되어야 한다. 꺼지면 안된다.
오브젝트의 Transform을 만지고 있다는 것은
만지고 있지 않다는 것은
https://lab.tresjs.org/experiments/simple-editor
아쉽게도 오브젝트 선택 해제 자체가 구현되어있지 않다.
배신감을 느끼며 창을 닫는다.
곧 제가 풀리퀘스트를 올려드리겠습니다.
상황이 Tres.js보다는 좀 낫다
오브젝트 바깥을 클릭하면 이동모드가 해제된다.
TransformContorls를 드래그해서 커서가 오브젝트 밖으로 나가도 오브젝트 이동모드가 유지된다.
그런데?
Tres.js의 @pointer-missed
이벤트를 TresCanvas에 먹인다.
오브젝트를 클릭하지 않은 경우 이벤트핸들러가 호출된다.
event.button===2
) early-return시키고 <Suspense>
<TresCanvas class="tres-canvas" @pointer-missed="onEmptySpaceClicked">
<TransformControls ... />
<primitive ... />
<primitive ... />
</TresCanvas>
</Suspense>
function onEmptySpaceClicked(ev) {
// right click
if (ev.event.button === 2) return;
// others
transformTarget.value = null;
}
일반적으로는 잘 된다. 그러나 모든 요구사항을 만족시키지 못함.
온갖 구멍을 다 틀어막아보자
<template>
<Suspense>
<TresCanvas
class="tres-canvas"
clear-color="#333333"
@mouseup="onCanvasMouseup"
@mousedown="onCanvasMousedown"
>
<TresPerspectiveCamera ref="pCameraRef" :position="[0, 5, 10]" />
<MapControls make-default :enablePan="!isDraggingModel" />
<TransformControls
ref="transformControlsRef"
v-if="transformTarget"
...
@mouse-down="isDraggingModel = true"
/>
...
<primitive
...
@pointer-down="onModelMousedown"
@pointer-up="onModelMouseup"
/>
<primitive
...
@pointer-down="onModelMousedown"
@pointer-up="onModelMouseup"
/>
...
</TresCanvas>
</Suspense>
</template>
<script setup>
import { ref, onMounted, shallowRef } from "vue";
// CANVAS
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { TresCanvas } from "@tresjs/core";
import { MapControls, TransformControls } from "@tresjs/cientos";
// transform control
const transformControlsRef = ref(null);
const transformMode = ref("translate");
const transformTarget = ref(null);
const isDraggingModel = ref(false); // model을 드래깅중이거나 transformControl을 조작중인지 여부
function onModelMousedown(ev) {
ev.stopPropagation();
isDraggingModel.value = true;
if (ev && ev.eventObject) {
// transform control 제어 대상 오브젝트 결정
transformTarget.value = ev.eventObject.uuid;
}
}
function onModelMouseup(ev) {
ev.stopPropagation();
isDraggingModel.value = false;
}
// disable transform controls when empty space clicked
const pCameraRef = ref(null);
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const mouseCoords = {
downX: 0,
downY: 0,
upX: 0,
upY: 0,
};
function onCanvasMousedown(ev) {
mouseCoords.downX = ev.clientX;
mouseCoords.downY = ev.clientY;
}
function onCanvasMouseup(ev) {
// 오브젝트 이동모드 아니면 무시
if (!transformTarget.value) {
return;
}
// 오브젝트 이동(transformControl 조작)하는 중이었으면 무시
else if (isDraggingModel.value) {
isDraggingModel.value = false;
return;
}
// 오른쪽 클릭 시 무시
else if (ev.button === 2) {
return;
}
// 클릭이 아니라 드래그를 했으면 무시
mouseCoords.upX = ev.clientX;
mouseCoords.upY = ev.clientY;
const { downX, downY, upX, upY } = mouseCoords;
if (Math.abs(downX - upX) > 5 || Math.abs(downY - upY) > 5) {
return;
}
// 현재 마우스 커서와 transformTarget이 겹치면 무시
// -- 마우스 위치 정규화
const rect = ev.target.getBoundingClientRect();
mouse.x = ((ev.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((ev.clientY - rect.top) / rect.height) * 2 + 1;
// -- intersect확인 (마우스위치와 현재 transformTarget.)
raycaster.setFromCamera(mouse, pCameraRef.value);
const targetRef = itemRefs.value[transformTarget.value];
const intersects = raycaster.intersectObject(targetRef);
if (intersects.length !== 0) {
console.log("asdfasdfdfsadfasdfsdafds");
return;
}
// 축하합니다. transformControl을 이제 죽입니다.
transformTarget.value = null;
}
</script>