392 tris0,28 × 0,60 × 0,43 m
Utiliser dans le code
Remixer dans l’éditeurrabbit.js · 215 lignes
Module ES autonome — ne dépend que de three. Appelez la fonction factory et ajoutez le groupe à votre scène.
/**
* Rabbit — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 392 · Size (W × H × D): 0.28 × 0.60 × 0.42 m
*
* Usage:
* import { createRabbit } from './rabbit.js';
*
* const model = createRabbit();
* model.position.set(0, 0, 0);
* scene.add(model);
*/
import * as THREE from 'three';
const deg = THREE.MathUtils.degToRad;
// Deterministic vertex displacement (organic low-poly look).
function jitter(geometry, amount, seed) {
const pos = geometry.attributes.position;
const h = (a, b, c, s) => {
let x = Math.imul(a, 73856093) ^ Math.imul(b, 19349663) ^ Math.imul(c, 83492791) ^ Math.imul(s, 2654435761);
x = Math.imul(x ^ (x >>> 16), 2246822507);
x = Math.imul(x ^ (x >>> 13), 3266489909);
return ((x ^ (x >>> 16)) >>> 0) / 4294967295 - 0.5;
};
for (let i = 0; i < pos.count; i++) {
const x = pos.getX(i), y = pos.getY(i), z = pos.getZ(i);
const qx = Math.round(x * 1000), qy = Math.round(y * 1000), qz = Math.round(z * 1000);
pos.setXYZ(i, x + h(qx, qy, qz, seed) * 2 * amount, y + h(qx, qy, qz, seed + 1) * 2 * amount, z + h(qx, qy, qz, seed + 2) * 2 * amount);
}
pos.needsUpdate = true;
geometry.computeVertexNormals();
return geometry;
}
export function createRabbit() {
const root = new THREE.Group();
root.name = 'Rabbit';
// Materials
const furMat = new THREE.MeshStandardMaterial({ name: 'fur', color: 0xbf8e64, roughness: 0.9, flatShading: true });
const whiteMat = new THREE.MeshStandardMaterial({ name: 'white', color: 0xf6f0e6, roughness: 0.95, flatShading: true });
const pinkMat = new THREE.MeshStandardMaterial({ name: 'pink', color: 0xf2a1b3, roughness: 0.6, flatShading: true });
const eyeMat = new THREE.MeshStandardMaterial({ name: 'eye', color: 0x1b1617, roughness: 0.3, flatShading: true });
const shineMat = new THREE.MeshStandardMaterial({ name: 'shine', color: 0xffffff, roughness: 0.3, flatShading: true });
// Shared geometries
const boxGeo = new THREE.BoxGeometry(0.075, 0.11, 0.15);
const boxGeo2 = new THREE.BoxGeometry(0.07, 0.04, 0.17);
const boxGeo3 = new THREE.BoxGeometry(0.074, 0.044, 0.035);
const boxGeo4 = new THREE.BoxGeometry(0.05, 0.12, 0.05);
const boxGeo5 = new THREE.BoxGeometry(0.055, 0.03, 0.065);
const boxGeo6 = new THREE.BoxGeometry(0.034, 0.045, 0.01);
const boxGeo7 = new THREE.BoxGeometry(0.013, 0.013, 0.006);
const boxGeo8 = new THREE.BoxGeometry(0.03, 0.015, 0.006);
const boxGeo9 = new THREE.BoxGeometry(0.06, 0.22, 0.032);
const boxGeo10 = new THREE.BoxGeometry(0.034, 0.17, 0.01);
// Parts
const legBL = new THREE.Group();
legBL.name = 'legBL';
legBL.position.set(0.1, 0.12, -0.05);
root.add(legBL);
const haunchL = new THREE.Mesh(boxGeo, furMat);
haunchL.name = 'haunchL';
haunchL.position.set(0, -0.055, 0);
legBL.add(haunchL);
const hindFootL = new THREE.Mesh(boxGeo2, furMat);
hindFootL.name = 'hindFootL';
hindFootL.position.set(0, -0.1, 0.05);
legBL.add(hindFootL);
const toesL = new THREE.Mesh(boxGeo3, whiteMat);
toesL.name = 'toesL';
toesL.position.set(0, -0.1, 0.1195);
legBL.add(toesL);
const legBR = new THREE.Group();
legBR.name = 'legBR';
legBR.position.set(-0.1, 0.12, -0.05);
root.add(legBR);
const haunchR = new THREE.Mesh(boxGeo, furMat);
haunchR.name = 'haunchR';
haunchR.position.set(0, -0.055, 0);
legBR.add(haunchR);
const hindFootR = new THREE.Mesh(boxGeo2, furMat);
hindFootR.name = 'hindFootR';
hindFootR.position.set(0, -0.1, 0.05);
legBR.add(hindFootR);
const toesR = new THREE.Mesh(boxGeo3, whiteMat);
toesR.name = 'toesR';
toesR.position.set(0, -0.1, 0.1195);
legBR.add(toesR);
const legFL = new THREE.Group();
legFL.name = 'legFL';
legFL.position.set(0.055, 0.12, 0.085);
root.add(legFL);
const armL = new THREE.Mesh(boxGeo4, furMat);
armL.name = 'armL';
armL.position.set(0, -0.06, 0);
legFL.add(armL);
const pawL = new THREE.Mesh(boxGeo5, whiteMat);
pawL.name = 'pawL';
pawL.position.set(0, -0.105, 0.008);
legFL.add(pawL);
const legFR = new THREE.Group();
legFR.name = 'legFR';
legFR.position.set(-0.055, 0.12, 0.085);
root.add(legFR);
const armR = new THREE.Mesh(boxGeo4, furMat);
armR.name = 'armR';
armR.position.set(0, -0.06, 0);
legFR.add(armR);
const pawR = new THREE.Mesh(boxGeo5, whiteMat);
pawR.name = 'pawR';
pawR.position.set(0, -0.105, 0.008);
legFR.add(pawR);
const body = new THREE.Group();
body.name = 'body';
root.add(body);
const torso = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.2, 0.24), furMat);
torso.name = 'torso';
torso.position.set(0, 0.125, -0.03);
body.add(torso);
const belly = new THREE.Mesh(new THREE.BoxGeometry(0.13, 0.15, 0.02), whiteMat);
belly.name = 'belly';
belly.position.set(0, 0.115, 0.094);
body.add(belly);
const tail = new THREE.Group();
tail.name = 'tail';
tail.position.set(0, 0.1, -0.16);
root.add(tail);
const cottonTail = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.05, 1), 0.008, 9), whiteMat);
cottonTail.name = 'cottonTail';
tail.add(cottonTail);
const head = new THREE.Group();
head.name = 'head';
head.position.set(0, 0.215, 0.03);
root.add(head);
const skull = new THREE.Mesh(new THREE.BoxGeometry(0.23, 0.19, 0.19), furMat);
skull.name = 'skull';
skull.position.set(0, 0.08, 0.04);
head.add(skull);
const muzzle = new THREE.Mesh(new THREE.BoxGeometry(0.1, 0.06, 0.04), whiteMat);
muzzle.name = 'muzzle';
muzzle.position.set(0, 0.04, 0.15);
head.add(muzzle);
const nose = new THREE.Mesh(new THREE.BoxGeometry(0.035, 0.022, 0.015), pinkMat);
nose.name = 'nose';
nose.position.set(0, 0.064, 0.173);
head.add(nose);
const teeth = new THREE.Mesh(new THREE.BoxGeometry(0.024, 0.02, 0.01), shineMat);
teeth.name = 'teeth';
teeth.position.set(0, 0.002, 0.16);
head.add(teeth);
const eyeL = new THREE.Mesh(boxGeo6, eyeMat);
eyeL.name = 'eyeL';
eyeL.position.set(0.065, 0.1, 0.139);
head.add(eyeL);
const eyeShineL = new THREE.Mesh(boxGeo7, shineMat);
eyeShineL.name = 'eyeShineL';
eyeShineL.position.set(0.07, 0.112, 0.145);
head.add(eyeShineL);
const cheekL = new THREE.Mesh(boxGeo8, pinkMat);
cheekL.name = 'cheekL';
cheekL.position.set(0.085, 0.055, 0.137);
head.add(cheekL);
const eyeR = new THREE.Mesh(boxGeo6, eyeMat);
eyeR.name = 'eyeR';
eyeR.position.set(-0.065, 0.1, 0.139);
head.add(eyeR);
const eyeShineR = new THREE.Mesh(boxGeo7, shineMat);
eyeShineR.name = 'eyeShineR';
eyeShineR.position.set(-0.07, 0.112, 0.145);
head.add(eyeShineR);
const cheekR = new THREE.Mesh(boxGeo8, pinkMat);
cheekR.name = 'cheekR';
cheekR.position.set(-0.085, 0.055, 0.137);
head.add(cheekR);
const earL = new THREE.Group();
earL.name = 'earL';
earL.position.set(0.05, 0.165, 0.02);
earL.rotation.set(deg(-6), 0, deg(-9));
head.add(earL);
const earFlapL = new THREE.Mesh(boxGeo9, furMat);
earFlapL.name = 'earFlapL';
earFlapL.position.set(0, 0.11, 0);
earL.add(earFlapL);
const earInnerL = new THREE.Mesh(boxGeo10, pinkMat);
earInnerL.name = 'earInnerL';
earInnerL.position.set(0, 0.11, 0.018);
earL.add(earInnerL);
const earR = new THREE.Group();
earR.name = 'earR';
earR.position.set(-0.05, 0.165, 0.02);
earR.rotation.set(deg(-6), 0, deg(9));
head.add(earR);
const earFlapR = new THREE.Mesh(boxGeo9, furMat);
earFlapR.name = 'earFlapR';
earFlapR.position.set(0, 0.11, 0);
earR.add(earFlapR);
const earInnerR = new THREE.Mesh(boxGeo10, pinkMat);
earInnerR.name = 'earInnerR';
earInnerR.position.set(0, 0.11, 0.018);
earR.add(earInnerR);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createRabbit;
Notes et commentaires
0 commentaire
Aucun commentaire pour l’instant. Dites comment vous avez utilisé ce modèle ou ce qui pourrait être amélioré.
Modèles similaires
Même catégorie ou étiquettes proches









