在示例编辑器中,Three.js 如何渲染显示顶点和三角形数量的图例以及 3 轴辅助图例,我添加了带有这些图例的场景屏幕截图。
我想在我的场景中显示,但找不到如何添加这些。是否有此类东西的插件或自定义几何形状?
基本上你可以看看这个thread,但是那里的一些信息需要更新。
可以使用 .info 属性,但要注意:
wireframe: true
,您将获得 0
顶点,
您必须将其设置为 false
。此外,正如 pailhead 正确指出的那样,由于
non-indexed
和 indexed
的几何形状,获得统一的值可能很困难。在第一个中,三角形之间不共享顶点,这意味着它们的数量会更多,而在第二个中,顶点更少,因为它们共享它们。
至于
rStats
,它将不再起作用,因为WebGL1
标准自r117/153
以来已被弃用,并在r163
中完全删除。如果您将使用(不太可能)带有 WebGL1
的旧版本,那么您可以使用它,在最新版本中,由于使用 WebGL2
,它将无法工作。
您可以使用 TextGeometry
创建一个
quasi-rStat:
对于这个相机助手,您可以使用一些库(例如
GSAP
,TWEEN
)来制作视图之间的过渡动画
body { margin: 0; }
#cameraSwitcher {
position: fixed;
bottom: 10px;
right: 10px;
display: flex;
flex-direction: column;
}
.camera-button {
width: 40px;
height: 40px;
margin: 5px;
background-color: #800080;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
}
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/[email protected]/build/three.module.js",
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
}
}
</script>
<div id="cameraSwitcher">
<button class="camera-button" id="camera1">1</button>
<button class="camera-button" id="camera2">2</button>
</div>
<script type="module">
import * as THREE from "https://esm.sh/three";
import { OrbitControls } from "https://esm.sh/three/addons/controls/OrbitControls.js";
import { FontLoader } from "https://esm.sh/three/addons/loaders/FontLoader.js";
import { TextGeometry } from "https://esm.sh/three/addons/geometries/TextGeometry.js";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
const camera2 = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera2.position.set(5, 5, 5);
camera2.lookAt(new THREE.Vector3(0, 0, 0));
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(2);
document.body.appendChild(renderer.domElement);
const indexedGeometry = new THREE.ConeGeometry(1, 2, 32);
const indexedMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true });
const indexedCone = new THREE.Mesh(indexedGeometry, indexedMaterial);
scene.add(indexedCone);
indexedCone.position.x = 2;
const nonIndexedGeometry = indexedGeometry.toNonIndexed();
const nonIndexedMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true });
const nonIndexedCone = new THREE.Mesh(nonIndexedGeometry, nonIndexedMaterial);
scene.add(nonIndexedCone);
nonIndexedCone.position.x = -2;
function getVertexCount(geometry) {
return geometry.attributes.position.count;
}
function getTriangleCount(geometry) {
if (geometry.index) {
return geometry.index.count / 3;
} else {
return geometry.attributes.position.count / 3;
}
}
const fontLoader = new FontLoader();
fontLoader.load('https://threejs.org/examples/fonts/helvetiker_regular.typeface.json', (font) => {
const indexedVertexCount = getVertexCount(indexedGeometry);
const indexedTriangleCount = getTriangleCount(indexedGeometry);
const indexedTextGeometry = new TextGeometry(`Indexed Cone: Vertices: ${indexedVertexCount} Triangles: ${indexedTriangleCount}`, {
font: font,
size: 0.2,
depth: 0.01
});
const indexedTextMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const indexedTextMesh = new THREE.Mesh(indexedTextGeometry, indexedTextMaterial);
indexedTextMesh.position.set(-2, 3, 0);
scene.add(indexedTextMesh);
const nonIndexedVertexCount = getVertexCount(nonIndexedGeometry);
const nonIndexedTriangleCount = getTriangleCount(nonIndexedGeometry);
const nonIndexedTextGeometry = new TextGeometry(`Non-Indexed Cone: Vertices: ${nonIndexedVertexCount} Triangles: ${nonIndexedTriangleCount}`, {
font: font,
size: 0.2,
depth: 0.01
});
const nonIndexedTextMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const nonIndexedTextMesh = new THREE.Mesh(nonIndexedTextGeometry, nonIndexedTextMaterial);
nonIndexedTextMesh.position.set(-2, 2, 0);
scene.add(nonIndexedTextMesh);
});
//const controls = new OrbitControls( camera, renderer.domElement );
//controls.enableDamping = true
let currentCamera = camera;
document.getElementById('camera1').addEventListener('click', () => {
currentCamera = camera;
});
document.getElementById('camera2').addEventListener('click', () => {
currentCamera = camera2;
});
function animate() {
requestAnimationFrame(animate);
indexedCone.rotation.x += 0.01;
indexedCone.rotation.y += 0.01;
nonIndexedCone.rotation.x += 0.01;
nonIndexedCone.rotation.y += 0.01;
//controls.update();
renderer.render(scene, currentCamera);
}
animate();
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
camera2.aspect = window.innerWidth / window.innerHeight;
camera2.updateProjectionMatrix();
});
</script>
或者你可以使用 HTML layer
body { margin: 0; }
canvas { display: block; }
#hud {
position: absolute;
top: 10px;
left: 10px;
color: white;
font-family: Arial, sans-serif;
font-size: 16px;
z-index: 1;
}
button {
position: absolute;
top: 10px;
background-color: #800080;
color: white;
border: none;
border-radius: 5px;
padding: 10px;
font-size: 16px;
cursor: pointer;
z-index: 2;
}
#camera1 {
right: 120px;
}
#camera2 {
right: 10px;
}
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/[email protected]/build/three.module.js",
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
}
}
</script>
<div id="hud">
<div id="indexed-info"></div>
<div id="non-indexed-info"></div>
</div>
<button id="camera1">Camera 1</button>
<button id="camera2">Camera 2</button>
<script type="module">
import * as THREE from "https://esm.sh/three";
import { OrbitControls } from "https://esm.sh/three/addons/controls/OrbitControls.js";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
const camera2 = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera2.position.set(5, 5, 5);
camera2.lookAt(new THREE.Vector3(0, 0, 0));
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(2);
document.body.appendChild(renderer.domElement);
const indexedGeometry = new THREE.ConeGeometry(1, 2, 32);
const indexedMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true });
const indexedCone = new THREE.Mesh(indexedGeometry, indexedMaterial);
scene.add(indexedCone);
indexedCone.position.x = 2;
const nonIndexedGeometry = indexedGeometry.toNonIndexed();
const nonIndexedMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true });
const nonIndexedCone = new THREE.Mesh(nonIndexedGeometry, nonIndexedMaterial);
scene.add(nonIndexedCone);
nonIndexedCone.position.x = -2;
function getVertexCount(geometry) {
return geometry.attributes.position.count;
}
function getTriangleCount(geometry) {
if (geometry.index) {
return geometry.index.count / 3;
} else {
return geometry.attributes.position.count / 3;
}
}
function updateHUD() {
const indexedVertexCount = getVertexCount(indexedGeometry);
const indexedTriangleCount = getTriangleCount(indexedGeometry);
const nonIndexedVertexCount = getVertexCount(nonIndexedGeometry);
const nonIndexedTriangleCount = getTriangleCount(nonIndexedGeometry);
document.getElementById('indexed-info').textContent = `Indexed Cone: Vertices: ${indexedVertexCount} Triangles: ${indexedTriangleCount}`;
document.getElementById('non-indexed-info').textContent = `Non-Indexed Cone: Vertices: ${nonIndexedVertexCount} Triangles: ${nonIndexedTriangleCount}`;
}
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
let currentCamera = camera;
document.getElementById('camera1').addEventListener('click', () => {
currentCamera = camera;
});
document.getElementById('camera2').addEventListener('click', () => {
currentCamera = camera2;
});
function animate() {
requestAnimationFrame(animate);
indexedCone.rotation.x += 0.01;
indexedCone.rotation.y += 0.01;
nonIndexedCone.rotation.x += 0.01;
nonIndexedCone.rotation.y += 0.01;
controls.update();
updateHUD();
renderer.render(scene, currentCamera);
}
animate();
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
camera2.aspect = window.innerWidth / window.innerHeight;
camera2.updateProjectionMatrix();
});
</script>