3d-camera-interaction
30
总安装量
3
周安装量
#12150
全站排名
安装命令
npx skills add https://github.com/project-n-e-k-o/n.e.k.o --skill 3d-camera-interaction
Agent 安装分布
windsurf
3
codex
3
cursor
3
gemini-cli
2
github-copilot
2
zencoder
2
Skill 文档
3D ç¸æºäº¤äºï¼ææ½ä¸è¾¹çæ£æµ
çç¶
- 缩æ¾åææ½æ¨¡åï¼é¼ æ ç§»å¨ 100px 使¨¡åç§»å¨çå±å¹è·ç¦»ä¸æ¯ 100px
- æ¾å¤§æ¨¡åååªè½çå°è ¿/身ä½çä¸é¨åï¼æ æ³æ£å¸¸å¹³ç§»
- æå¨å¼å§æ¶æ¨¡åä½ç½®”è·³å”
æ ¹æ¬åå
åå 1: åºå® panSpeed 导è´ç§»å¨ä¸åæ¥
é®é¢: 使ç¨åºå®ç panSpeed = 0.01 è¿è¡å¹³ç§»è®¡ç®
// â é误æ¹å¼
const panSpeed = 0.01;
newPosition.add(right.multiplyScalar(deltaX * panSpeed));
为ä»ä¹åç: ç¸æºè·ç¦»ååæ¶ï¼åæ ·çä¸ç空é´è·ç¦»å¨å±å¹ä¸çåç´ è¡¨ç°ä¸åãè·ç¦»è¿æ¶åç´ å¤ï¼è·ç¦»è¿æ¶åç´ å°ã
è§£å³æ¹æ¡: æ ¹æ®ç¸æºè·ç¦»å FOV å¨æè®¡ç®åç´ âä¸ç空é´çæ å°
// â
æ£ç¡®æ¹å¼ï¼å¨æè®¡ç®
const cameraDistance = camera.position.distanceTo(modelCenter);
const fov = camera.fov * (Math.PI / 180);
const screenHeight = renderer.domElement.clientHeight;
const screenWidth = renderer.domElement.clientWidth;
// å¨ç¸æºè·ç¦»å¤ï¼è§å£çä¸ç空é´é«åº¦
const worldHeight = 2 * Math.tan(fov / 2) * cameraDistance;
const worldWidth = worldHeight * (screenWidth / screenHeight);
// æ¯åç´ å¯¹åºçä¸ç空é´è·ç¦»
const pixelToWorldX = worldWidth / screenWidth;
const pixelToWorldY = worldHeight / screenHeight;
// åºç¨ï¼é¼ æ ç§»å¨çåç´ Ã æ¯åç´ å¯¹åºçä¸ç空é´è·ç¦»
newPosition.add(right.multiplyScalar(deltaX * pixelToWorldX));
newPosition.add(up.multiplyScalar(-deltaY * pixelToWorldY));
åå 2: åºäºä¸å¿ç¹çè¾¹çéå¶
é®é¢: ä½¿ç¨æ¨¡åä¸å¿ç¹ç NDC åæ å¤ææ¯å¦åºç
// â é误æ¹å¼ï¼éå¶ä¸å¿ç¹ä½ç½®
const ndc = position.clone().project(camera);
if (ndc.y > 0.2) clampedY = 0.2; // éå¶é¡¶é¨
为ä»ä¹åç: æ¨¡åæ¾å¤§åï¼ä¸å¿ç¹å¨å±å¹ä¸å¿ï¼ä½èº«ä½å¤§é¨åå·²è¶ åºå±å¹ãéå¶ä¸å¿ç¹ = éå¶åªè½çå°èº«ä½ä¸é´é¨åã
è§£å³æ¹æ¡: è®¡ç®æ¨¡åå¨å±å¹ä¸çå¯è§åºåï¼åç´ ï¼ï¼åªå¨å¯è§åºåè¿å°æ¶ææ ¡æ£
// â
æ£ç¡®æ¹å¼ï¼åºäºå¯è§åç´
const MIN_VISIBLE_PIXELS = 50;
// 1. è®¡ç®æ¨¡åå
å´çå¹¶æå½±å°å±å¹
const box = new THREE.Box3().setFromObject(vrm.scene);
const corners = [/* 8ä¸ªé¡¶ç¹ */];
let modelMinX = Infinity, modelMaxX = -Infinity;
let modelMinY = Infinity, modelMaxY = -Infinity;
corners.forEach(corner => {
const projected = corner.clone().project(camera);
const screenX = (projected.x * 0.5 + 0.5) * screenWidth;
const screenY = (-projected.y * 0.5 + 0.5) * screenHeight;
// æ´æ°è¾¹ç...
});
// 2. 计ç®å¯è§åºå
const visibleWidth = Math.max(0, Math.min(screenWidth, modelMaxX) - Math.max(0, modelMinX));
const visibleHeight = Math.max(0, Math.min(screenHeight, modelMaxY) - Math.max(0, modelMinY));
const visiblePixels = visibleWidth * visibleHeight;
// 3. åªå¨å¯è§åºåå¤ªå°æ¶æ ¡æ£
if (visiblePixels < MIN_VISIBLE_PIXELS) {
// å°æ¨¡åæåå¯è§åºå
}
å ³é®å ¬å¼
åç´ å°ä¸ç空é´è½¬æ¢
worldHeight = 2 Ã tan(fov/2) Ã cameraDistance
pixelToWorld = worldHeight / screenHeight
ä¸çåæ å°å±å¹åæ
const ndc = worldPos.clone().project(camera);
const screenX = (ndc.x * 0.5 + 0.5) * screenWidth;
const screenY = (-ndc.y * 0.5 + 0.5) * screenHeight; // Y è½´åå
å ³é®ç»éª
- ð ç¸æºè·ç¦»å½±åä¸å: ææåç´ âä¸ç空é´ç转æ¢é½éè¦èèç¸æºè·ç¦»
- ð² 使ç¨å å´çèéä¸å¿ç¹: è¾¹çæ£æµåºåºäºæ¨¡åå®é å ç¨çå±å¹åºå
- ð ä¸ 2D ä¿æä¸è´: Live2D/VRM çä¸åç±»åæ¨¡ååºä½¿ç¨ç¸åç交äºé»è¾éå¼