828 三角面0.44 × 0.12 × 0.10 m
在代码中使用
在编辑器中改编scroll.js · 127 行
自包含的 ES 模块,仅依赖 three。调用工厂函数,然后把返回的 group 添加到场景中。
/**
* Magic Scroll — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 828 · Size (W × H × D): 0.43 × 0.12 × 0.10 m
*
* Usage:
* import { createScroll } from './scroll.js';
*
* const model = createScroll();
* model.position.set(0, 0, 0);
* scene.add(model);
*/
import * as THREE from 'three';
const deg = THREE.MathUtils.degToRad;
// Tube along a smooth curve through the given points.
function tube(path, radius, tubularSegments, radialSegments, closed = false) {
const curve = new THREE.CatmullRomCurve3(path.map(([x, y, z]) => new THREE.Vector3(x, y, z)), closed);
return new THREE.TubeGeometry(curve, tubularSegments, radius, radialSegments, closed);
}
export function createScroll() {
const root = new THREE.Group();
root.name = 'Scroll';
// Materials
const paperMat = new THREE.MeshStandardMaterial({ name: 'paper', color: 0xe8d29c, roughness: 0.9, flatShading: true });
const edgeMat = new THREE.MeshStandardMaterial({ name: 'edge', color: 0xb89a63, roughness: 0.9, flatShading: true });
const woodMat = new THREE.MeshStandardMaterial({ name: 'wood', color: 0x7a4b2a, roughness: 0.8, flatShading: true });
const ribbonMat = new THREE.MeshStandardMaterial({ name: 'ribbon', color: 0xb8312f, roughness: 0.7, flatShading: true });
const waxMat = new THREE.MeshStandardMaterial({ name: 'wax', color: 0xa3241f, roughness: 0.45, flatShading: true });
// Shared geometries
const cylinderGeo = new THREE.CylinderGeometry(0.011, 0.011, 0.045, 6);
const sphereGeo = new THREE.SphereGeometry(0.02, 7, 5);
const torusGeo = new THREE.TorusGeometry(0.017, 0.006, 4, 10);
const boxGeo = new THREE.BoxGeometry(0.013, 0.003, 0.04);
// Parts
const roll = new THREE.Mesh(new THREE.CylinderGeometry(0.042, 0.042, 0.3, 12), paperMat);
roll.name = 'roll';
roll.position.set(0, 0.045, 0);
roll.rotation.set(0, 0, deg(90));
root.add(roll);
const rollSpiralR = new THREE.Mesh(tube([[0.151, 0.045, 0.0084], [0.151, 0.0527, 0.0066], [0.151, 0.0568, -0.0019], [0.151, 0.0522, -0.0117], [0.151, 0.0402, -0.0148], [0.151, 0.029, -0.0066], [0.151, 0.028, 0.0087], [0.151, 0.0401, 0.0203], [0.151, 0.0583, 0.0183], [0.151, 0.0694, 0.0019], [0.151, 0.0636, -0.0186], [0.151, 0.0428, -0.0279], [0.151, 0.0209, -0.0175], [0.151, 0.0143, 0.0074], [0.151, 0.0298, 0.0298], [0.151, 0.0585, 0.0325], [0.151, 0.0802, 0.0114]], 0.0028, 26, 3), edgeMat);
rollSpiralR.name = 'rollSpiralR';
root.add(rollSpiralR);
const rollRodR = new THREE.Mesh(cylinderGeo, woodMat);
rollRodR.name = 'rollRodR';
rollRodR.position.set(0.17, 0.045, 0);
rollRodR.rotation.set(0, 0, deg(90));
root.add(rollRodR);
const rollKnobR = new THREE.Mesh(sphereGeo, woodMat);
rollKnobR.name = 'rollKnobR';
rollKnobR.position.set(0.202, 0.045, 0);
rollKnobR.scale.set(0.85, 1, 1);
root.add(rollKnobR);
const rollSpiralL = new THREE.Mesh(tube([[-0.151, 0.045, 0.0084], [-0.151, 0.0527, 0.0066], [-0.151, 0.0568, -0.0019], [-0.151, 0.0522, -0.0117], [-0.151, 0.0402, -0.0148], [-0.151, 0.029, -0.0066], [-0.151, 0.028, 0.0087], [-0.151, 0.0401, 0.0203], [-0.151, 0.0583, 0.0183], [-0.151, 0.0694, 0.0019], [-0.151, 0.0636, -0.0186], [-0.151, 0.0428, -0.0279], [-0.151, 0.0209, -0.0175], [-0.151, 0.0143, 0.0074], [-0.151, 0.0298, 0.0298], [-0.151, 0.0585, 0.0325], [-0.151, 0.0802, 0.0114]], 0.0028, 26, 3), edgeMat);
rollSpiralL.name = 'rollSpiralL';
root.add(rollSpiralL);
const rollRodL = new THREE.Mesh(cylinderGeo, woodMat);
rollRodL.name = 'rollRodL';
rollRodL.position.set(-0.17, 0.045, 0);
rollRodL.rotation.set(0, 0, deg(90));
root.add(rollRodL);
const rollKnobL = new THREE.Mesh(sphereGeo, woodMat);
rollKnobL.name = 'rollKnobL';
rollKnobL.position.set(-0.202, 0.045, 0);
rollKnobL.scale.set(0.85, 1, 1);
root.add(rollKnobL);
const ribbonBand = new THREE.Mesh(new THREE.CylinderGeometry(0.045, 0.045, 0.03, 12), ribbonMat);
ribbonBand.name = 'ribbonBand';
ribbonBand.position.set(0, 0.045, 0);
ribbonBand.rotation.set(0, 0, deg(90));
root.add(ribbonBand);
const bowLoopR = new THREE.Mesh(torusGeo, ribbonMat);
bowLoopR.name = 'bowLoopR';
bowLoopR.position.set(0.018, 0.099, 0.012);
bowLoopR.rotation.set(0, deg(20), deg(35));
root.add(bowLoopR);
const tailR = new THREE.Group();
tailR.name = 'tailR';
tailR.position.set(0.006, 0.0874, 0.0225);
tailR.rotation.set(deg(28), 0, 0);
root.add(tailR);
const tailStripR = new THREE.Mesh(boxGeo, ribbonMat);
tailStripR.name = 'tailStripR';
tailStripR.position.set(0, 0, 0.012);
tailStripR.rotation.set(0, deg(22), 0);
tailR.add(tailStripR);
const bowLoopL = new THREE.Mesh(torusGeo, ribbonMat);
bowLoopL.name = 'bowLoopL';
bowLoopL.position.set(-0.018, 0.099, 0.012);
bowLoopL.rotation.set(0, deg(-20), deg(-35));
root.add(bowLoopL);
const tailL = new THREE.Group();
tailL.name = 'tailL';
tailL.position.set(-0.006, 0.0874, 0.0225);
tailL.rotation.set(deg(28), 0, 0);
root.add(tailL);
const tailStripL = new THREE.Mesh(boxGeo, ribbonMat);
tailStripL.name = 'tailStripL';
tailStripL.position.set(0, 0, 0.012);
tailStripL.rotation.set(0, deg(-22), 0);
tailL.add(tailStripL);
const knot = new THREE.Mesh(new THREE.SphereGeometry(0.011, 6, 4), ribbonMat);
knot.name = 'knot';
knot.position.set(0, 0.093, 0.006);
root.add(knot);
const seal = new THREE.Mesh(new THREE.CylinderGeometry(0.024, 0.026, 0.008, 10), waxMat);
seal.name = 'seal';
seal.position.set(0, 0.051, 0.048);
seal.rotation.set(deg(80), 0, 0);
root.add(seal);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createScroll;
评分与评论
0 条评论
暂无评论。分享一下你是如何使用这个模型的,或者有哪些可以改进的地方。
相关模型
同一分类或相似标签









