삼각형 1천개2.23 × 0.72 × 0.87 m
코드에서 사용하기
에디터에서 리믹스fallen-log.js · 192줄
독립형 ES 모듈이에요 — three에만 의존해요. 팩토리 함수를 호출하고 그룹을 씬에 추가하세요.
/**
* Fallen Log — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 1,036 · Size (W × H × D): 2.23 × 0.72 × 0.87 m
*
* Usage:
* import { createFallenLog } from './fallen-log.js';
*
* const model = createFallenLog();
* 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 createFallenLog() {
const root = new THREE.Group();
root.name = 'FallenLog';
// Materials
const barkMat = new THREE.MeshStandardMaterial({ name: 'bark', color: 0x5f4631, roughness: 0.95, flatShading: true });
const cutMat = new THREE.MeshStandardMaterial({ name: 'cut', color: 0xd3a262, roughness: 0.85, flatShading: true });
const ringMat = new THREE.MeshStandardMaterial({ name: 'ring', color: 0x9c6a3a, roughness: 0.9, flatShading: true });
const mossMat = new THREE.MeshStandardMaterial({ name: 'moss', color: 0x5b8a35, roughness: 1, flatShading: true });
const capMat = new THREE.MeshStandardMaterial({ name: 'cap', color: 0xd8662f, roughness: 0.7, flatShading: true });
const stemMat = new THREE.MeshStandardMaterial({ name: 'stem', color: 0xefe2c4, roughness: 0.8, flatShading: true });
// Parts
const log = new THREE.Group();
log.name = 'log';
log.position.set(0, 0.2757, 0);
root.add(log);
const trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.2576, 0.28, 2.2, 9), barkMat);
trunk.name = 'trunk';
trunk.rotation.set(0, 0, deg(90));
log.add(trunk);
const cutLeft = new THREE.Mesh(new THREE.CylinderGeometry(0.2215, 0.2215, 0.02, 9), cutMat);
cutLeft.name = 'cutLeft';
cutLeft.position.set(-1.103, 0, 0);
cutLeft.rotation.set(0, 0, deg(90));
log.add(cutLeft);
const ringL1 = new THREE.Mesh(new THREE.RingGeometry(0.038, 0.0492, 16), ringMat);
ringL1.name = 'ringL1';
ringL1.position.set(-1.1145, 0, 0);
ringL1.rotation.set(0, deg(-90), 0);
log.add(ringL1);
const ringL2 = new THREE.Mesh(new THREE.RingGeometry(0.0996, 0.1108, 16), ringMat);
ringL2.name = 'ringL2';
ringL2.position.set(-1.1145, 0, 0);
ringL2.rotation.set(0, deg(-90), 0);
log.add(ringL2);
const ringL3 = new THREE.Mesh(new THREE.RingGeometry(0.1611, 0.1723, 16), ringMat);
ringL3.name = 'ringL3';
ringL3.position.set(-1.1145, 0, 0);
ringL3.rotation.set(0, deg(-90), 0);
log.add(ringL3);
const cutRight = new THREE.Mesh(new THREE.CylinderGeometry(0.2408, 0.2408, 0.02, 9), cutMat);
cutRight.name = 'cutRight';
cutRight.position.set(1.103, 0, 0);
cutRight.rotation.set(0, 0, deg(90));
log.add(cutRight);
const ringR1 = new THREE.Mesh(new THREE.RingGeometry(0.0423, 0.0535, 16), ringMat);
ringR1.name = 'ringR1';
ringR1.position.set(1.1145, 0, 0);
ringR1.rotation.set(0, deg(90), 0);
log.add(ringR1);
const ringR2 = new THREE.Mesh(new THREE.RingGeometry(0.1092, 0.1204, 16), ringMat);
ringR2.name = 'ringR2';
ringR2.position.set(1.1145, 0, 0);
ringR2.rotation.set(0, deg(90), 0);
log.add(ringR2);
const ringR3 = new THREE.Mesh(new THREE.RingGeometry(0.1761, 0.1873, 16), ringMat);
ringR3.name = 'ringR3';
ringR3.position.set(1.1145, 0, 0);
ringR3.rotation.set(0, deg(90), 0);
log.add(ringR3);
const stub1 = new THREE.Mesh(new THREE.CylinderGeometry(0.056, 0.084, 0.3676, 6), barkMat);
stub1.name = 'stub1';
stub1.position.set(-0.4215, 0.175, 0.3031);
stub1.rotation.set(deg(59.3595), deg(4.5633), deg(7.9981));
log.add(stub1);
const stub2 = new THREE.Mesh(new THREE.CylinderGeometry(0.056, 0.084, 0.3674, 6), barkMat);
stub2.name = 'stub2';
stub2.position.set(0.6189, 0.2681, -0.225);
stub2.rotation.set(deg(-39.6136), deg(2.8174), deg(-7.812));
log.add(stub2);
const moss1 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(1, 1), 0.12, 40), mossMat);
moss1.name = 'moss1';
moss1.position.set(-0.484, 0.224, 0.0243);
moss1.rotation.set(deg(10), 0, 0);
moss1.scale.set(0.374, 0.0896, 0.2016);
log.add(moss1);
const moss2 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(1, 1), 0.12, 41), mossMat);
moss2.name = 'moss2';
moss2.position.set(0.132, 0.224, -0.0362);
moss2.rotation.set(deg(-15), 0, 0);
moss2.scale.set(0.242, 0.0896, 0.2016);
log.add(moss2);
const moss3 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(1, 1), 0.12, 42), mossMat);
moss3.name = 'moss3';
moss3.position.set(-0.924, 0.224, 0.0592);
moss3.rotation.set(deg(25), 0, 0);
moss3.scale.set(0.132, 0.0896, 0.2016);
log.add(moss3);
const mushroom1 = new THREE.Group();
mushroom1.name = 'mushroom1';
mushroom1.position.set(0.66, 0.1674, 0.1995);
mushroom1.rotation.set(deg(16.1649), 0, 0);
log.add(mushroom1);
const stem = new THREE.Mesh(new THREE.CylinderGeometry(0.0304, 0.038, 0.133, 6), stemMat);
stem.name = 'stem';
stem.position.set(0, 0.0665, 0);
mushroom1.add(stem);
const cap = new THREE.Mesh(new THREE.SphereGeometry(0.0855, 8, 3, 0, Math.PI * 2, 0, Math.PI / 2), capMat);
cap.name = 'cap';
cap.position.set(0, 0.1178, 0);
cap.scale.set(1, 0.75, 1);
mushroom1.add(cap);
const mushroom2 = new THREE.Group();
mushroom2.name = 'mushroom2';
mushroom2.position.set(0.814, 0.11, 0.236);
mushroom2.rotation.set(deg(20.511), 0, 0);
log.add(mushroom2);
const stem2 = new THREE.Mesh(new THREE.CylinderGeometry(0.0228, 0.0285, 0.0998, 6), stemMat);
stem2.name = 'stem';
stem2.position.set(0, 0.0499, 0);
mushroom2.add(stem2);
const cap2 = new THREE.Mesh(new THREE.SphereGeometry(0.0641, 8, 3, 0, Math.PI * 2, 0, Math.PI / 2), capMat);
cap2.name = 'cap';
cap2.position.set(0, 0.0884, 0);
cap2.scale.set(1, 0.75, 1);
mushroom2.add(cap2);
const mushroom3 = new THREE.Group();
mushroom3.name = 'mushroom3';
mushroom3.position.set(0.528, 0.0891, 0.2447);
mushroom3.rotation.set(deg(21.8622), 0, 0);
log.add(mushroom3);
const stem3 = new THREE.Mesh(new THREE.CylinderGeometry(0.0182, 0.0228, 0.0798, 6), stemMat);
stem3.name = 'stem';
stem3.position.set(0, 0.0399, 0);
mushroom3.add(stem3);
const cap3 = new THREE.Mesh(new THREE.SphereGeometry(0.0513, 8, 3, 0, Math.PI * 2, 0, Math.PI / 2), capMat);
cap3.name = 'cap';
cap3.position.set(0, 0.0707, 0);
cap3.scale.set(1, 0.75, 1);
mushroom3.add(cap3);
const mushroom4 = new THREE.Group();
mushroom4.name = 'mushroom4';
mushroom4.position.set(-0.66, 0.1995, 0.1674);
mushroom4.rotation.set(deg(13.0825), 0, 0);
log.add(mushroom4);
const stem4 = new THREE.Mesh(new THREE.CylinderGeometry(0.0213, 0.0266, 0.0931, 6), stemMat);
stem4.name = 'stem';
stem4.position.set(0, 0.0466, 0);
mushroom4.add(stem4);
const cap4 = new THREE.Mesh(new THREE.SphereGeometry(0.0598, 8, 3, 0, Math.PI * 2, 0, Math.PI / 2), capMat);
cap4.name = 'cap';
cap4.position.set(0, 0.0825, 0);
cap4.scale.set(1, 0.75, 1);
mushroom4.add(cap4);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createFallenLog;
평점 및 댓글
댓글 0개
아직 댓글이 없어요. 이 모델을 어떻게 사용했는지, 어떤 점이 더 나아질 수 있을지 공유해 주세요.
관련 모델
같은 카테고리 또는 비슷한 태그









