1384 三角面1.80 × 2.40 × 1.71 m
在代码中使用
在编辑器中改编throne.js · 375 行
自包含的 ES 模块,仅依赖 three。调用工厂函数,然后把返回的 group 添加到场景中。
/**
* Royal Throne — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 1,384 · Size (W × H × D): 1.80 × 2.40 × 1.71 m
*
* Usage:
* import { createThrone } from './throne.js';
*
* const model = createThrone();
* model.position.set(0, 0, 0);
* scene.add(model);
*/
import * as THREE from 'three';
const deg = THREE.MathUtils.degToRad;
// Extrude a 2D outline along Z (centered). bevel = [thickness, size, segments].
function extrude(outline, depth, holes = [], bevel = null) {
const shape = new THREE.Shape(outline.map(([x, y]) => new THREE.Vector2(x, y)));
for (const hole of holes) shape.holes.push(new THREE.Path(hole.map(([x, y]) => new THREE.Vector2(x, y))));
const options = bevel
? { depth, bevelEnabled: true, bevelThickness: bevel[0], bevelSize: bevel[1], bevelSegments: bevel[2] }
: { depth, bevelEnabled: false };
return new THREE.ExtrudeGeometry(shape, options).translate(0, 0, -depth / 2);
}
export function createThrone() {
const root = new THREE.Group();
root.name = 'Throne';
// Materials
const frameMat = new THREE.MeshStandardMaterial({ name: 'frame', color: 0x5e2f1d, roughness: 0.7, flatShading: true });
const frameDarkMat = new THREE.MeshStandardMaterial({ name: 'frameDark', color: 0x3d1f13, roughness: 0.8, flatShading: true });
const goldMat = new THREE.MeshStandardMaterial({ name: 'gold', color: 0xe2b346, roughness: 0.3, metalness: 0.6, flatShading: true });
const velvetMat = new THREE.MeshStandardMaterial({ name: 'velvet', color: 0xa8232e, roughness: 1, flatShading: true });
const velvetDarkMat = new THREE.MeshStandardMaterial({ name: 'velvetDark', color: 0x761920, roughness: 1, flatShading: true });
const gemMat = new THREE.MeshStandardMaterial({ name: 'gem', color: 0x3d7be0, roughness: 0.15, metalness: 0.2, emissive: 0x1b3f9a, emissiveIntensity: 0.6, flatShading: true });
const stoneMat = new THREE.MeshStandardMaterial({ name: 'stone', color: 0x77736d, roughness: 0.95, flatShading: true });
const stoneDarkMat = new THREE.MeshStandardMaterial({ name: 'stoneDark', color: 0x615d58, roughness: 0.95, flatShading: true });
// Shared geometries
const boxGeo = new THREE.BoxGeometry(0.6, 0.11, 0.006);
const boxGeo2 = new THREE.BoxGeometry(0.025, 0.008, 0.26);
const cylinderGeo = new THREE.CylinderGeometry(0.045, 0.06, 0.06, 6);
const coneGeo = new THREE.ConeGeometry(0.022, 0.08, 6);
const boxGeo3 = new THREE.BoxGeometry(0.13, 0.62, 0.74);
const boxGeo4 = new THREE.BoxGeometry(0.012, 0.36, 0.5);
const octahedronGeo = new THREE.OctahedronGeometry(0.08, 0);
const boxGeo5 = new THREE.BoxGeometry(0.18, 0.05, 0.82);
const boxGeo6 = new THREE.BoxGeometry(0.19, 0.02, 0.83);
const extrudeGeo = extrude([[0.047, 0.235], [0.04, 0.242], [-0.0399, 0.242], [-0.047, 0.235], [-0.047, -0.2349], [-0.0399, -0.242], [0.04, -0.242], [0.047, -0.2349]], 0.009, [], [0.018, 0.018, 1]);
const cylinderGeo2 = new THREE.CylinderGeometry(0.03, 0.04, 0.04, 6);
const sphereGeo = new THREE.SphereGeometry(0.05, 6, 4);
const octahedronGeo2 = new THREE.OctahedronGeometry(0.017, 0);
const coneGeo2 = new THREE.ConeGeometry(0.022, 0.07, 4);
const boxGeo7 = new THREE.BoxGeometry(0.09, 1.42, 0.12);
const boxGeo8 = new THREE.BoxGeometry(0.11, 0.03, 0.14);
const sphereGeo2 = new THREE.SphereGeometry(0.055, 6, 4);
const coneGeo3 = new THREE.ConeGeometry(0.025, 0.09, 6);
// Parts
const daisLower = new THREE.Mesh(new THREE.BoxGeometry(1.8, 0.11, 1.7), stoneDarkMat);
daisLower.name = 'daisLower';
daisLower.position.set(0, 0.055, 0);
root.add(daisLower);
const daisUpper = new THREE.Mesh(new THREE.BoxGeometry(1.42, 0.11, 1.3), stoneMat);
daisUpper.name = 'daisUpper';
daisUpper.position.set(0, 0.165, -0.05);
root.add(daisUpper);
const carpet = new THREE.Mesh(new THREE.BoxGeometry(0.6, 0.006, 0.42), velvetDarkMat);
carpet.name = 'carpet';
carpet.position.set(0, 0.223, 0.39);
root.add(carpet);
const carpetRiser = new THREE.Mesh(boxGeo, velvetDarkMat);
carpetRiser.name = 'carpetRiser';
carpetRiser.position.set(0, 0.165, 0.603);
root.add(carpetRiser);
const carpet2 = new THREE.Mesh(new THREE.BoxGeometry(0.6, 0.006, 0.25), velvetDarkMat);
carpet2.name = 'carpet';
carpet2.position.set(0, 0.113, 0.725);
root.add(carpet2);
const carpetRiser2 = new THREE.Mesh(boxGeo, velvetDarkMat);
carpetRiser2.name = 'carpetRiser';
carpetRiser2.position.set(0, 0.055, 0.853);
root.add(carpetRiser2);
const carpetTrim = new THREE.Mesh(boxGeo2, goldMat);
carpetTrim.name = 'carpetTrim';
carpetTrim.position.set(-0.3, 0.114, 0.725);
root.add(carpetTrim);
const carpetTrim2 = new THREE.Mesh(boxGeo2, goldMat);
carpetTrim2.name = 'carpetTrim';
carpetTrim2.position.set(0.3, 0.114, 0.725);
root.add(carpetTrim2);
const throne = new THREE.Group();
throne.name = 'throne';
throne.position.set(0, 0.22, -0.18);
root.add(throne);
const foot = new THREE.Mesh(cylinderGeo, goldMat);
foot.name = 'foot';
foot.position.set(-0.44, 0.03, -0.31);
throne.add(foot);
const foot2 = new THREE.Mesh(cylinderGeo, goldMat);
foot2.name = 'foot';
foot2.position.set(-0.44, 0.03, 0.35);
throne.add(foot2);
const foot3 = new THREE.Mesh(cylinderGeo, goldMat);
foot3.name = 'foot';
foot3.position.set(0.44, 0.03, -0.31);
throne.add(foot3);
const foot4 = new THREE.Mesh(cylinderGeo, goldMat);
foot4.name = 'foot';
foot4.position.set(0.44, 0.03, 0.35);
throne.add(foot4);
const seatBox = new THREE.Mesh(new THREE.BoxGeometry(0.76, 0.38, 0.68), frameMat);
seatBox.name = 'seatBox';
seatBox.position.set(0, 0.25, 0.04);
throne.add(seatBox);
const seatPanel = new THREE.Mesh(new THREE.BoxGeometry(0.58, 0.22, 0.012), frameDarkMat);
seatPanel.name = 'seatPanel';
seatPanel.position.set(0, 0.25, 0.385);
throne.add(seatPanel);
const seatMedallion = new THREE.Mesh(new THREE.OctahedronGeometry(0.07, 0), goldMat);
seatMedallion.name = 'seatMedallion';
seatMedallion.position.set(0, 0.25, 0.392);
seatMedallion.scale.set(1, 1, 0.25);
throne.add(seatMedallion);
const seatTrim = new THREE.Mesh(new THREE.BoxGeometry(0.78, 0.028, 0.025), goldMat);
seatTrim.name = 'seatTrim';
seatTrim.position.set(0, 0.429, 0.375);
throne.add(seatTrim);
const seatTrimLow = new THREE.Mesh(new THREE.BoxGeometry(0.78, 0.022, 0.025), goldMat);
seatTrimLow.name = 'seatTrimLow';
seatTrimLow.position.set(0, 0.081, 0.375);
throne.add(seatTrimLow);
const seatCushion = new THREE.Mesh(extrude([[0.335, 0.2508], [0.2907, 0.295], [-0.2907, 0.295], [-0.335, 0.2508], [-0.335, -0.2508], [-0.2907, -0.295], [0.2907, -0.295], [0.335, -0.2508]], 0.03, [], [0.035, 0.035, 1]), velvetMat);
seatCushion.name = 'seatCushion';
seatCushion.position.set(0, 0.49, 0.05);
seatCushion.rotation.set(deg(-90), 0, 0);
throne.add(seatCushion);
const tassel = new THREE.Mesh(coneGeo, goldMat);
tassel.name = 'tassel';
tassel.position.set(-0.35, 0.42, 0.38);
throne.add(tassel);
const tassel2 = new THREE.Mesh(coneGeo, goldMat);
tassel2.name = 'tassel';
tassel2.position.set(0.35, 0.42, 0.38);
throne.add(tassel2);
const armPanel = new THREE.Mesh(boxGeo3, frameMat);
armPanel.name = 'armPanel';
armPanel.position.set(-0.445, 0.37, 0.02);
throne.add(armPanel);
const armInlay = new THREE.Mesh(boxGeo4, frameDarkMat);
armInlay.name = 'armInlay';
armInlay.position.set(-0.511, 0.36, 0.03);
throne.add(armInlay);
const armMedallion = new THREE.Mesh(octahedronGeo, goldMat);
armMedallion.name = 'armMedallion';
armMedallion.position.set(-0.517, 0.36, 0.03);
armMedallion.scale.set(0.25, 1, 1);
throne.add(armMedallion);
const armRest = new THREE.Mesh(boxGeo5, frameMat);
armRest.name = 'armRest';
armRest.position.set(-0.445, 0.705, 0.04);
throne.add(armRest);
const armTrim = new THREE.Mesh(boxGeo6, goldMat);
armTrim.name = 'armTrim';
armTrim.position.set(-0.445, 0.675, 0.04);
throne.add(armTrim);
const armPad = new THREE.Mesh(extrudeGeo, velvetMat);
armPad.name = 'armPad';
armPad.position.set(-0.445, 0.752, -0.02);
armPad.rotation.set(deg(-90), 0, 0);
throne.add(armPad);
const orbCollar = new THREE.Mesh(cylinderGeo2, goldMat);
orbCollar.name = 'orbCollar';
orbCollar.position.set(-0.445, 0.75, 0.38);
throne.add(orbCollar);
const armOrb = new THREE.Mesh(sphereGeo, goldMat);
armOrb.name = 'armOrb';
armOrb.position.set(-0.445, 0.81, 0.38);
throne.add(armOrb);
const armPanel2 = new THREE.Mesh(boxGeo3, frameMat);
armPanel2.name = 'armPanel';
armPanel2.position.set(0.445, 0.37, 0.02);
throne.add(armPanel2);
const armInlay2 = new THREE.Mesh(boxGeo4, frameDarkMat);
armInlay2.name = 'armInlay';
armInlay2.position.set(0.511, 0.36, 0.03);
throne.add(armInlay2);
const armMedallion2 = new THREE.Mesh(octahedronGeo, goldMat);
armMedallion2.name = 'armMedallion';
armMedallion2.position.set(0.517, 0.36, 0.03);
armMedallion2.scale.set(0.25, 1, 1);
throne.add(armMedallion2);
const armRest2 = new THREE.Mesh(boxGeo5, frameMat);
armRest2.name = 'armRest';
armRest2.position.set(0.445, 0.705, 0.04);
throne.add(armRest2);
const armTrim2 = new THREE.Mesh(boxGeo6, goldMat);
armTrim2.name = 'armTrim';
armTrim2.position.set(0.445, 0.675, 0.04);
throne.add(armTrim2);
const armPad2 = new THREE.Mesh(extrudeGeo, velvetMat);
armPad2.name = 'armPad';
armPad2.position.set(0.445, 0.752, -0.02);
armPad2.rotation.set(deg(-90), 0, 0);
throne.add(armPad2);
const orbCollar2 = new THREE.Mesh(cylinderGeo2, goldMat);
orbCollar2.name = 'orbCollar';
orbCollar2.position.set(0.445, 0.75, 0.38);
throne.add(orbCollar2);
const armOrb2 = new THREE.Mesh(sphereGeo, goldMat);
armOrb2.name = 'armOrb';
armOrb2.position.set(0.445, 0.81, 0.38);
throne.add(armOrb2);
const back = new THREE.Mesh(extrude([[-0.45, 0], [0.45, 0], [0.45, 1.3], [0.436, 1.444], [0.3947, 1.5827], [0.3275, 1.7108], [0.2369, 1.8236], [0.1264, 1.917], [0, 1.9874], [-0.1264, 1.917], [-0.2369, 1.8236], [-0.3275, 1.7108], [-0.3947, 1.5827], [-0.436, 1.444], [-0.45, 1.3]], 0.1), frameMat);
back.name = 'back';
back.position.set(0, 0.06, -0.35);
throne.add(back);
const backFrame = new THREE.Mesh(extrude([[-0.45, 0], [0.45, 0], [0.45, 1.3], [0.4421, 1.4083], [0.4187, 1.5143], [0.3802, 1.6159], [0.3275, 1.7108], [0.2616, 1.7971], [0.1839, 1.873], [0.0961, 1.9369], [0, 1.9874], [-0.0961, 1.9369], [-0.1839, 1.873], [-0.2616, 1.7971], [-0.3275, 1.7108], [-0.3802, 1.6159], [-0.4187, 1.5143], [-0.4421, 1.4083], [-0.45, 1.3]], 0.024, [[[-0.395, 1.3], [-0.3881, 1.3974], [-0.3677, 1.4928], [-0.3341, 1.5845], [-0.288, 1.6705], [-0.2303, 1.7492], [-0.1621, 1.8191], [-0.0849, 1.8787], [0, 1.9269], [0.0849, 1.8787], [0.1621, 1.8191], [0.2303, 1.7492], [0.288, 1.6705], [0.3341, 1.5845], [0.3677, 1.4928], [0.3881, 1.3974], [0.395, 1.3], [0.395, 0.055], [-0.395, 0.055]]]), goldMat);
backFrame.name = 'backFrame';
backFrame.position.set(0, 0.06, -0.288);
throne.add(backFrame);
const backCushion = new THREE.Mesh(extrude([[-0.365, 0.445], [0.365, 0.445], [0.365, 1.3], [0.3587, 1.3914], [0.3399, 1.481], [0.3089, 1.5672], [0.2664, 1.6484], [0.2132, 1.7229], [0.1502, 1.7894], [0.0787, 1.8466], [0, 1.8935], [-0.0787, 1.8466], [-0.1502, 1.7894], [-0.2132, 1.7229], [-0.2664, 1.6484], [-0.3089, 1.5672], [-0.3399, 1.481], [-0.3587, 1.3914], [-0.365, 1.3]], 0.03, [], [0.02, 0.02, 1]), velvetMat);
backCushion.name = 'backCushion';
backCushion.position.set(0, 0.06, -0.265);
throne.add(backCushion);
const button = new THREE.Mesh(octahedronGeo2, goldMat);
button.name = 'button';
button.position.set(-0.2, 0.72, -0.229);
button.scale.set(1, 1, 0.5);
throne.add(button);
const button2 = new THREE.Mesh(octahedronGeo2, goldMat);
button2.name = 'button';
button2.position.set(0, 0.72, -0.229);
button2.scale.set(1, 1, 0.5);
throne.add(button2);
const button3 = new THREE.Mesh(octahedronGeo2, goldMat);
button3.name = 'button';
button3.position.set(0.2, 0.72, -0.229);
button3.scale.set(1, 1, 0.5);
throne.add(button3);
const button4 = new THREE.Mesh(octahedronGeo2, goldMat);
button4.name = 'button';
button4.position.set(-0.1, 0.91, -0.229);
button4.scale.set(1, 1, 0.5);
throne.add(button4);
const button5 = new THREE.Mesh(octahedronGeo2, goldMat);
button5.name = 'button';
button5.position.set(0.1, 0.91, -0.229);
button5.scale.set(1, 1, 0.5);
throne.add(button5);
const button6 = new THREE.Mesh(octahedronGeo2, goldMat);
button6.name = 'button';
button6.position.set(-0.2, 1.1, -0.229);
button6.scale.set(1, 1, 0.5);
throne.add(button6);
const button7 = new THREE.Mesh(octahedronGeo2, goldMat);
button7.name = 'button';
button7.position.set(0, 1.1, -0.229);
button7.scale.set(1, 1, 0.5);
throne.add(button7);
const button8 = new THREE.Mesh(octahedronGeo2, goldMat);
button8.name = 'button';
button8.position.set(0.2, 1.1, -0.229);
button8.scale.set(1, 1, 0.5);
throne.add(button8);
const button9 = new THREE.Mesh(octahedronGeo2, goldMat);
button9.name = 'button';
button9.position.set(-0.1, 1.29, -0.229);
button9.scale.set(1, 1, 0.5);
throne.add(button9);
const button10 = new THREE.Mesh(octahedronGeo2, goldMat);
button10.name = 'button';
button10.position.set(0.1, 1.29, -0.229);
button10.scale.set(1, 1, 0.5);
throne.add(button10);
const button11 = new THREE.Mesh(octahedronGeo2, goldMat);
button11.name = 'button';
button11.position.set(-0.2, 1.48, -0.229);
button11.scale.set(1, 1, 0.5);
throne.add(button11);
const button12 = new THREE.Mesh(octahedronGeo2, goldMat);
button12.name = 'button';
button12.position.set(0, 1.48, -0.229);
button12.scale.set(1, 1, 0.5);
throne.add(button12);
const button13 = new THREE.Mesh(octahedronGeo2, goldMat);
button13.name = 'button';
button13.position.set(0.2, 1.48, -0.229);
button13.scale.set(1, 1, 0.5);
throne.add(button13);
const crownBase = new THREE.Mesh(new THREE.OctahedronGeometry(0.06, 0), goldMat);
crownBase.name = 'crownBase';
crownBase.position.set(0, 2.0374, -0.35);
crownBase.scale.set(1.3, 0.6, 1);
throne.add(crownBase);
const crownBand = new THREE.Mesh(new THREE.CylinderGeometry(0.085, 0.07, 0.07, 8), goldMat);
crownBand.name = 'crownBand';
crownBand.position.set(0, 2.0824, -0.35);
throne.add(crownBand);
const crownPoint = new THREE.Mesh(coneGeo2, goldMat);
crownPoint.name = 'crownPoint';
crownPoint.position.set(0, 2.1474, -0.278);
throne.add(crownPoint);
const crownPoint2 = new THREE.Mesh(coneGeo2, goldMat);
crownPoint2.name = 'crownPoint';
crownPoint2.position.set(-0.0685, 2.1474, -0.3278);
throne.add(crownPoint2);
const crownPoint3 = new THREE.Mesh(coneGeo2, goldMat);
crownPoint3.name = 'crownPoint';
crownPoint3.position.set(-0.0423, 2.1474, -0.4082);
throne.add(crownPoint3);
const crownPoint4 = new THREE.Mesh(coneGeo2, goldMat);
crownPoint4.name = 'crownPoint';
crownPoint4.position.set(0.0423, 2.1474, -0.4082);
throne.add(crownPoint4);
const crownPoint5 = new THREE.Mesh(coneGeo2, goldMat);
crownPoint5.name = 'crownPoint';
crownPoint5.position.set(0.0685, 2.1474, -0.3278);
throne.add(crownPoint5);
const crownGem = new THREE.Mesh(new THREE.OctahedronGeometry(0.03, 0), gemMat);
crownGem.name = 'crownGem';
crownGem.position.set(0, 2.0824, -0.268);
crownGem.scale.set(1, 1.2, 0.6);
throne.add(crownGem);
const backGem = new THREE.Mesh(new THREE.OctahedronGeometry(0.045, 0), gemMat);
backGem.name = 'backGem';
backGem.position.set(0, 1.76, -0.226);
backGem.scale.set(1, 1.25, 0.5);
throne.add(backGem);
const backPost = new THREE.Mesh(boxGeo7, frameDarkMat);
backPost.name = 'backPost';
backPost.position.set(-0.49, 0.77, -0.35);
throne.add(backPost);
const postCap = new THREE.Mesh(boxGeo8, goldMat);
postCap.name = 'postCap';
postCap.position.set(-0.49, 1.495, -0.35);
throne.add(postCap);
const finial = new THREE.Mesh(sphereGeo2, goldMat);
finial.name = 'finial';
finial.position.set(-0.49, 1.565, -0.35);
throne.add(finial);
const finialSpike = new THREE.Mesh(coneGeo3, goldMat);
finialSpike.name = 'finialSpike';
finialSpike.position.set(-0.49, 1.645, -0.35);
throne.add(finialSpike);
const backPost2 = new THREE.Mesh(boxGeo7, frameDarkMat);
backPost2.name = 'backPost';
backPost2.position.set(0.49, 0.77, -0.35);
throne.add(backPost2);
const postCap2 = new THREE.Mesh(boxGeo8, goldMat);
postCap2.name = 'postCap';
postCap2.position.set(0.49, 1.495, -0.35);
throne.add(postCap2);
const finial2 = new THREE.Mesh(sphereGeo2, goldMat);
finial2.name = 'finial';
finial2.position.set(0.49, 1.565, -0.35);
throne.add(finial2);
const finialSpike2 = new THREE.Mesh(coneGeo3, goldMat);
finialSpike2.name = 'finialSpike';
finialSpike2.position.set(0.49, 1.645, -0.35);
throne.add(finialSpike2);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createThrone;
评分与评论
0 条评论
暂无评论。分享一下你是如何使用这个模型的,或者有哪些可以改进的地方。
相关模型
同一分类或相似标签









