592 三角面0.63 × 1.64 × 1.08 m
在代码中使用
在编辑器中改编deer.js · 319 行
自包含的 ES 模块,仅依赖 three。调用工厂函数,然后把返回的 group 添加到场景中。
/**
* Deer — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 592 · Size (W × H × D): 0.63 × 1.64 × 1.08 m
*
* Usage:
* import { createDeer } from './deer.js';
*
* const model = createDeer();
* 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 createDeer() {
const root = new THREE.Group();
root.name = 'Deer';
// Materials
const furMat = new THREE.MeshStandardMaterial({ name: 'fur', color: 0xb4773f, roughness: 0.85, flatShading: true });
const furDarkMat = new THREE.MeshStandardMaterial({ name: 'furDark', color: 0x7e532c, roughness: 0.85, flatShading: true });
const whiteMat = new THREE.MeshStandardMaterial({ name: 'white', color: 0xf5eee2, roughness: 0.9, flatShading: true });
const hoofMat = new THREE.MeshStandardMaterial({ name: 'hoof', color: 0x3a2a24, roughness: 0.7, flatShading: true });
const antlerMat = new THREE.MeshStandardMaterial({ name: 'antler', color: 0xeadcc0, roughness: 0.7, flatShading: true });
const eyeMat = new THREE.MeshStandardMaterial({ name: 'eye', color: 0x1b1615, roughness: 0.3, flatShading: true });
const shineMat = new THREE.MeshStandardMaterial({ name: 'shine', color: 0xffffff, roughness: 0.3, flatShading: true });
const pinkMat = new THREE.MeshStandardMaterial({ name: 'pink', color: 0xe9a9a4, roughness: 0.7, flatShading: true });
// Shared geometries
const boxGeo = new THREE.BoxGeometry(0.1, 0.22, 0.12);
const boxGeo2 = new THREE.BoxGeometry(0.08, 0.3, 0.08);
const boxGeo3 = new THREE.BoxGeometry(0.09, 0.06, 0.095);
const boxGeo4 = new THREE.BoxGeometry(0.13, 0.26, 0.18);
const boxGeo5 = new THREE.BoxGeometry(0.046, 0.06, 0.01);
const boxGeo6 = new THREE.BoxGeometry(0.017, 0.017, 0.006);
const boxGeo7 = new THREE.BoxGeometry(0.01, 0.06, 0.06);
const extrudeGeo = extrude([[-0.035, 0], [0.035, 0], [0.055, 0.075], [0, 0.15], [-0.055, 0.075]], 0.025);
const extrudeGeo2 = extrude([[-0.021, 0.015], [0.021, 0.015], [0.033, 0.0675], [0, 0.12], [-0.033, 0.0675]], 0.01);
const boxGeo8 = new THREE.BoxGeometry(0.05, 0.03, 0.05);
const boxGeo9 = new THREE.BoxGeometry(0.042, 0.1783, 0.042);
const boxGeo10 = new THREE.BoxGeometry(0.042, 0.1872, 0.042);
const boxGeo11 = new THREE.BoxGeometry(0.0357, 0.1615, 0.0357);
const boxGeo12 = new THREE.BoxGeometry(0.0336, 0.1757, 0.0336);
const boxGeo13 = new THREE.BoxGeometry(0.0336, 0.16, 0.0336);
const boxGeo14 = new THREE.BoxGeometry(0.0315, 0.1528, 0.0315);
// Parts
const legFL = new THREE.Group();
legFL.name = 'legFL';
legFL.position.set(0.11, 0.5, 0.25);
root.add(legFL);
const legFLUpper = new THREE.Mesh(boxGeo, furMat);
legFLUpper.name = 'legFLUpper';
legFLUpper.position.set(0, -0.1, 0);
legFL.add(legFLUpper);
const legFLShin = new THREE.Mesh(boxGeo2, furMat);
legFLShin.name = 'legFLShin';
legFLShin.position.set(0, -0.33, 0);
legFL.add(legFLShin);
const legFLHoof = new THREE.Mesh(boxGeo3, hoofMat);
legFLHoof.name = 'legFLHoof';
legFLHoof.position.set(0, -0.47, 0.005);
legFL.add(legFLHoof);
const legFR = new THREE.Group();
legFR.name = 'legFR';
legFR.position.set(-0.11, 0.5, 0.25);
root.add(legFR);
const legFRUpper = new THREE.Mesh(boxGeo, furMat);
legFRUpper.name = 'legFRUpper';
legFRUpper.position.set(0, -0.1, 0);
legFR.add(legFRUpper);
const legFRShin = new THREE.Mesh(boxGeo2, furMat);
legFRShin.name = 'legFRShin';
legFRShin.position.set(0, -0.33, 0);
legFR.add(legFRShin);
const legFRHoof = new THREE.Mesh(boxGeo3, hoofMat);
legFRHoof.name = 'legFRHoof';
legFRHoof.position.set(0, -0.47, 0.005);
legFR.add(legFRHoof);
const legBL = new THREE.Group();
legBL.name = 'legBL';
legBL.position.set(0.11, 0.5, -0.24);
root.add(legBL);
const legBLHaunch = new THREE.Mesh(boxGeo4, furMat);
legBLHaunch.name = 'legBLHaunch';
legBLHaunch.position.set(0, -0.1, -0.01);
legBL.add(legBLHaunch);
const legBLShin = new THREE.Mesh(boxGeo2, furMat);
legBLShin.name = 'legBLShin';
legBLShin.position.set(0, -0.33, 0);
legBL.add(legBLShin);
const legBLHoof = new THREE.Mesh(boxGeo3, hoofMat);
legBLHoof.name = 'legBLHoof';
legBLHoof.position.set(0, -0.47, 0.005);
legBL.add(legBLHoof);
const legBR = new THREE.Group();
legBR.name = 'legBR';
legBR.position.set(-0.11, 0.5, -0.24);
root.add(legBR);
const legBRHaunch = new THREE.Mesh(boxGeo4, furMat);
legBRHaunch.name = 'legBRHaunch';
legBRHaunch.position.set(0, -0.1, -0.01);
legBR.add(legBRHaunch);
const legBRShin = new THREE.Mesh(boxGeo2, furMat);
legBRShin.name = 'legBRShin';
legBRShin.position.set(0, -0.33, 0);
legBR.add(legBRShin);
const legBRHoof = new THREE.Mesh(boxGeo3, hoofMat);
legBRHoof.name = 'legBRHoof';
legBRHoof.position.set(0, -0.47, 0.005);
legBR.add(legBRHoof);
const body = new THREE.Group();
body.name = 'body';
root.add(body);
const torso = new THREE.Mesh(new THREE.BoxGeometry(0.34, 0.34, 0.72), furMat);
torso.name = 'torso';
torso.position.set(0, 0.59, 0);
body.add(torso);
const chest = new THREE.Mesh(new THREE.BoxGeometry(0.24, 0.2, 0.02), whiteMat);
chest.name = 'chest';
chest.position.set(0, 0.53, 0.365);
body.add(chest);
const belly = new THREE.Mesh(new THREE.BoxGeometry(0.28, 0.012, 0.56), whiteMat);
belly.name = 'belly';
belly.position.set(0, 0.415, 0.02);
body.add(belly);
const rump = new THREE.Mesh(new THREE.BoxGeometry(0.22, 0.2, 0.02), whiteMat);
rump.name = 'rump';
rump.position.set(0, 0.64, -0.365);
body.add(rump);
const backStripe = new THREE.Mesh(new THREE.BoxGeometry(0.22, 0.02, 0.62), furDarkMat);
backStripe.name = 'backStripe';
backStripe.position.set(0, 0.765, 0);
body.add(backStripe);
const tail = new THREE.Group();
tail.name = 'tail';
tail.position.set(0, 0.7, -0.37);
tail.rotation.set(deg(-30), 0, 0);
root.add(tail);
const tailTop = new THREE.Mesh(new THREE.BoxGeometry(0.08, 0.13, 0.04), furMat);
tailTop.name = 'tailTop';
tailTop.position.set(0, 0.065, -0.02);
tail.add(tailTop);
const tailUnder = new THREE.Mesh(new THREE.BoxGeometry(0.084, 0.11, 0.02), whiteMat);
tailUnder.name = 'tailUnder';
tailUnder.position.set(0, 0.06, 0.007);
tail.add(tailUnder);
const head = new THREE.Group();
head.name = 'head';
head.position.set(0, 0.68, 0.26);
head.rotation.set(deg(-6), 0, 0);
root.add(head);
const neck = new THREE.Mesh(new THREE.BoxGeometry(0.16, 0.32, 0.17), furMat);
neck.name = 'neck';
neck.position.set(0, 0.13, 0.04);
neck.rotation.set(deg(22), 0, 0);
head.add(neck);
const skull = new THREE.Mesh(new THREE.BoxGeometry(0.28, 0.25, 0.26), furMat);
skull.name = 'skull';
skull.position.set(0, 0.38, 0.13);
head.add(skull);
const snout = new THREE.Mesh(new THREE.BoxGeometry(0.15, 0.13, 0.12), furMat);
snout.name = 'snout';
snout.position.set(0, 0.32, 0.31);
head.add(snout);
const jaw = new THREE.Mesh(new THREE.BoxGeometry(0.154, 0.045, 0.124), whiteMat);
jaw.name = 'jaw';
jaw.position.set(0, 0.2725, 0.31);
head.add(jaw);
const nose = new THREE.Mesh(new THREE.BoxGeometry(0.08, 0.05, 0.02), hoofMat);
nose.name = 'nose';
nose.position.set(0, 0.35, 0.375);
head.add(nose);
const eyeL = new THREE.Mesh(boxGeo5, eyeMat);
eyeL.name = 'eyeL';
eyeL.position.set(0.098, 0.42, 0.265);
head.add(eyeL);
const eyeShineL = new THREE.Mesh(boxGeo6, shineMat);
eyeShineL.name = 'eyeShineL';
eyeShineL.position.set(0.104, 0.434, 0.271);
head.add(eyeShineL);
const eyeRingL = new THREE.Mesh(boxGeo7, whiteMat);
eyeRingL.name = 'eyeRingL';
eyeRingL.position.set(0.1425, 0.41, 0.21);
head.add(eyeRingL);
const eyeR = new THREE.Mesh(boxGeo5, eyeMat);
eyeR.name = 'eyeR';
eyeR.position.set(-0.098, 0.42, 0.265);
head.add(eyeR);
const eyeShineR = new THREE.Mesh(boxGeo6, shineMat);
eyeShineR.name = 'eyeShineR';
eyeShineR.position.set(-0.104, 0.434, 0.271);
head.add(eyeShineR);
const eyeRingR = new THREE.Mesh(boxGeo7, whiteMat);
eyeRingR.name = 'eyeRingR';
eyeRingR.position.set(-0.1425, 0.41, 0.21);
head.add(eyeRingR);
const earL = new THREE.Group();
earL.name = 'earL';
earL.position.set(0.125, 0.47, 0.08);
earL.rotation.set(deg(-10), deg(10), deg(-62));
earL.scale.setScalar(1.25);
head.add(earL);
const earOuterL = new THREE.Mesh(extrudeGeo, furMat);
earOuterL.name = 'earOuterL';
earL.add(earOuterL);
const earInnerL = new THREE.Mesh(extrudeGeo2, pinkMat);
earInnerL.name = 'earInnerL';
earInnerL.position.set(0, 0, 0.0155);
earL.add(earInnerL);
const earR = new THREE.Group();
earR.name = 'earR';
earR.position.set(-0.125, 0.47, 0.08);
earR.rotation.set(deg(-10), deg(-10), deg(62));
earR.scale.setScalar(1.25);
head.add(earR);
const earOuterR = new THREE.Mesh(extrudeGeo, furMat);
earOuterR.name = 'earOuterR';
earR.add(earOuterR);
const earInnerR = new THREE.Mesh(extrudeGeo2, pinkMat);
earInnerR.name = 'earInnerR';
earInnerR.position.set(0, 0, 0.0155);
earR.add(earInnerR);
const antlers = new THREE.Group();
antlers.name = 'antlers';
antlers.position.set(0, 0.505, 0.11);
head.add(antlers);
const pedicel = new THREE.Mesh(boxGeo8, furMat);
pedicel.name = 'pedicel';
pedicel.position.set(0.07, 0, 0);
antlers.add(pedicel);
const antlerBeam1 = new THREE.Mesh(boxGeo9, antlerMat);
antlerBeam1.name = 'antlerBeam1';
antlerBeam1.position.set(0.1, 0.065, -0.015);
antlerBeam1.rotation.set(deg(-49.0856), deg(-52.6404), deg(-42.5248));
antlers.add(antlerBeam1);
const antlerBeam2 = new THREE.Mesh(boxGeo10, antlerMat);
antlerBeam2.name = 'antlerBeam2';
antlerBeam2.position.set(0.16, 0.2, -0.045);
antlerBeam2.rotation.set(deg(-46.9749), deg(-53.7662), deg(-40.8345));
antlers.add(antlerBeam2);
const antlerBeam3 = new THREE.Mesh(boxGeo11, antlerMat);
antlerBeam3.name = 'antlerBeam3';
antlerBeam3.position.set(0.18, 0.335, -0.04);
antlerBeam3.rotation.set(deg(-158.9625), deg(25.0172), deg(170.7617));
antlers.add(antlerBeam3);
const antlerTineBrow = new THREE.Mesh(boxGeo12, antlerMat);
antlerTineBrow.name = 'antlerTineBrow';
antlerTineBrow.position.set(0.115, 0.185, 0.02);
antlerTineBrow.rotation.set(deg(-135.2616), deg(12.0297), deg(168.3311));
antlers.add(antlerTineBrow);
const antlerTineOuter = new THREE.Mesh(boxGeo13, antlerMat);
antlerTineOuter.name = 'antlerTineOuter';
antlerTineOuter.position.set(0.24, 0.315, -0.07);
antlerTineOuter.rotation.set(deg(-80.1807), deg(-40.4545), deg(-75.0643));
antlers.add(antlerTineOuter);
const antlerTineInner = new THREE.Mesh(boxGeo14, antlerMat);
antlerTineInner.name = 'antlerTineInner';
antlerTineInner.position.set(0.14, 0.39, -0.0625);
antlerTineInner.rotation.set(deg(-65.3441), deg(43.6372), deg(56.3699));
antlers.add(antlerTineInner);
const pedicel2 = new THREE.Mesh(boxGeo8, furMat);
pedicel2.name = 'pedicel';
pedicel2.position.set(-0.07, 0, 0);
antlers.add(pedicel2);
const antlerBeam12 = new THREE.Mesh(boxGeo9, antlerMat);
antlerBeam12.name = 'antlerBeam1';
antlerBeam12.position.set(-0.1, 0.065, -0.015);
antlerBeam12.rotation.set(deg(-49.0856), deg(52.6404), deg(42.5248));
antlers.add(antlerBeam12);
const antlerBeam22 = new THREE.Mesh(boxGeo10, antlerMat);
antlerBeam22.name = 'antlerBeam2';
antlerBeam22.position.set(-0.16, 0.2, -0.045);
antlerBeam22.rotation.set(deg(-46.9749), deg(53.7662), deg(40.8345));
antlers.add(antlerBeam22);
const antlerBeam32 = new THREE.Mesh(boxGeo11, antlerMat);
antlerBeam32.name = 'antlerBeam3';
antlerBeam32.position.set(-0.18, 0.335, -0.04);
antlerBeam32.rotation.set(deg(-158.9625), deg(-25.0172), deg(-170.7617));
antlers.add(antlerBeam32);
const antlerTineBrow2 = new THREE.Mesh(boxGeo12, antlerMat);
antlerTineBrow2.name = 'antlerTineBrow';
antlerTineBrow2.position.set(-0.115, 0.185, 0.02);
antlerTineBrow2.rotation.set(deg(-135.2616), deg(-12.0297), deg(-168.3311));
antlers.add(antlerTineBrow2);
const antlerTineOuter2 = new THREE.Mesh(boxGeo13, antlerMat);
antlerTineOuter2.name = 'antlerTineOuter';
antlerTineOuter2.position.set(-0.24, 0.315, -0.07);
antlerTineOuter2.rotation.set(deg(-80.1807), deg(40.4545), deg(75.0643));
antlers.add(antlerTineOuter2);
const antlerTineInner2 = new THREE.Mesh(boxGeo14, antlerMat);
antlerTineInner2.name = 'antlerTineInner';
antlerTineInner2.position.set(-0.14, 0.39, -0.0625);
antlerTineInner2.rotation.set(deg(-65.3441), deg(-43.6372), deg(-56.3699));
antlers.add(antlerTineInner2);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createDeer;
评分与评论
0 条评论
暂无评论。分享一下你是如何使用这个模型的,或者有哪些可以改进的地方。
相关模型
同一分类或相似标签









