我怎样才能将文字环绕在 3D 球体周围
How can i wrap a text arround 3D sphere
我正在寻找一种在 babylon 或 threejs 中将文本环绕在球体周围的方法。我对改变 javascript 技术
持开放态度
我会看看 an example of generating text。然后我会分别生成每个字母,记录它们各自的宽度,并使用它们来计算我想要显示的字符串的总宽度
然后我可以将每个网格作为 Object3D
的父级,并将 Object3D
的旋转 y 设置为
widthSoFar = 0;
for each letter
obj3d.rotation.y = widthSoFar / totalWidth * Math.PI * 2;
widthSoFar += widthOfCurrentLetter;
并将字母的 position.z 设置为某个半径,使字母围绕一个圆。
什么半径?
circumference = 2 * PI * radius
所以
radius = circumference / (2 * PI)
我们知道我们需要的周长,它是字符串的总宽度。
您可能会发现 this tutorial 有助于理解如何使用场景图节点(如 Object3D 节点)组织场景以满足您的需要。
'use strict';
/* global THREE */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 40;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 70;
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
function addLight(...pos) {
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(...pos);
scene.add(light);
}
addLight(-4, 4, 4);
addLight(5, -4, 4);
const lettersTilt = new THREE.Object3D();
scene.add(lettersTilt);
lettersTilt.rotation.set(
THREE.Math.degToRad(-15),
0,
THREE.Math.degToRad(-15));
const lettersBase = new THREE.Object3D();
lettersTilt.add(lettersBase);
{
const letterMaterial = new THREE.MeshPhongMaterial({
color: 'red',
});
const loader = new THREE.FontLoader();
loader.load('https://threejsfundamentals.org/threejs/resources/threejs/fonts/helvetiker_regular.typeface.json', (font) => {
const spaceSize = 1.0;
let totalWidth = 0;
let maxHeight = 0;
const letterGeometries = {
' ': { width: spaceSize, height: 0 }, // prepopulate space ' '
};
const size = new THREE.Vector3();
const str = 'threejs fundamentals ';
const letterInfos = str.split('').map((letter, ndx) => {
if (!letterGeometries[letter]) {
const geometry = new THREE.TextBufferGeometry(letter, {
font: font,
size: 3.0,
height: .2,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 0.5,
bevelSize: .3,
bevelSegments: 5,
});
geometry.computeBoundingBox();
geometry.boundingBox.getSize(size);
letterGeometries[letter] = {
geometry,
width: size.x / 2, // no idea why size.x is double size
height: size.y,
};
}
const {geometry, width, height} = letterGeometries[letter];
const mesh = geometry
? new THREE.Mesh(geometry, letterMaterial)
: null;
totalWidth += width;
maxHeight = Math.max(maxHeight, height);
return {
mesh,
width,
};
});
let t = 0;
const radius = totalWidth / Math.PI;
for (const {mesh, width} of letterInfos) {
if (mesh) {
const offset = new THREE.Object3D();
lettersBase.add(offset);
offset.add(mesh);
offset.rotation.y = t / totalWidth * Math.PI * 2;
mesh.position.z = radius;
mesh.position.y = -maxHeight / 2;
}
t += width;
}
{
const geo = new THREE.SphereBufferGeometry(radius - 1, 32, 24);
const mat = new THREE.MeshPhongMaterial({
color: 'cyan',
});
const mesh = new THREE.Mesh(geo, mat);
scene.add(mesh);
}
camera.position.z = radius * 3;
});
}
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
lettersBase.rotation.y = time * -0.5;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
body {
margin: 0;
}
#c {
width: 100vw;
height: 100vh;
display: block;
}
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>
我正在寻找一种在 babylon 或 threejs 中将文本环绕在球体周围的方法。我对改变 javascript 技术
持开放态度我会看看 an example of generating text。然后我会分别生成每个字母,记录它们各自的宽度,并使用它们来计算我想要显示的字符串的总宽度
然后我可以将每个网格作为 Object3D
的父级,并将 Object3D
的旋转 y 设置为
widthSoFar = 0;
for each letter
obj3d.rotation.y = widthSoFar / totalWidth * Math.PI * 2;
widthSoFar += widthOfCurrentLetter;
并将字母的 position.z 设置为某个半径,使字母围绕一个圆。
什么半径?
circumference = 2 * PI * radius
所以
radius = circumference / (2 * PI)
我们知道我们需要的周长,它是字符串的总宽度。
您可能会发现 this tutorial 有助于理解如何使用场景图节点(如 Object3D 节点)组织场景以满足您的需要。
'use strict';
/* global THREE */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 40;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 70;
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
function addLight(...pos) {
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(...pos);
scene.add(light);
}
addLight(-4, 4, 4);
addLight(5, -4, 4);
const lettersTilt = new THREE.Object3D();
scene.add(lettersTilt);
lettersTilt.rotation.set(
THREE.Math.degToRad(-15),
0,
THREE.Math.degToRad(-15));
const lettersBase = new THREE.Object3D();
lettersTilt.add(lettersBase);
{
const letterMaterial = new THREE.MeshPhongMaterial({
color: 'red',
});
const loader = new THREE.FontLoader();
loader.load('https://threejsfundamentals.org/threejs/resources/threejs/fonts/helvetiker_regular.typeface.json', (font) => {
const spaceSize = 1.0;
let totalWidth = 0;
let maxHeight = 0;
const letterGeometries = {
' ': { width: spaceSize, height: 0 }, // prepopulate space ' '
};
const size = new THREE.Vector3();
const str = 'threejs fundamentals ';
const letterInfos = str.split('').map((letter, ndx) => {
if (!letterGeometries[letter]) {
const geometry = new THREE.TextBufferGeometry(letter, {
font: font,
size: 3.0,
height: .2,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 0.5,
bevelSize: .3,
bevelSegments: 5,
});
geometry.computeBoundingBox();
geometry.boundingBox.getSize(size);
letterGeometries[letter] = {
geometry,
width: size.x / 2, // no idea why size.x is double size
height: size.y,
};
}
const {geometry, width, height} = letterGeometries[letter];
const mesh = geometry
? new THREE.Mesh(geometry, letterMaterial)
: null;
totalWidth += width;
maxHeight = Math.max(maxHeight, height);
return {
mesh,
width,
};
});
let t = 0;
const radius = totalWidth / Math.PI;
for (const {mesh, width} of letterInfos) {
if (mesh) {
const offset = new THREE.Object3D();
lettersBase.add(offset);
offset.add(mesh);
offset.rotation.y = t / totalWidth * Math.PI * 2;
mesh.position.z = radius;
mesh.position.y = -maxHeight / 2;
}
t += width;
}
{
const geo = new THREE.SphereBufferGeometry(radius - 1, 32, 24);
const mat = new THREE.MeshPhongMaterial({
color: 'cyan',
});
const mesh = new THREE.Mesh(geo, mat);
scene.add(mesh);
}
camera.position.z = radius * 3;
});
}
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
lettersBase.rotation.y = time * -0.5;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
body {
margin: 0;
}
#c {
width: 100vw;
height: 100vh;
display: block;
}
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>