668 ポリゴン0.26 × 0.36 × 0.50 m
コードで使う
エディターでリミックスfish.js · 140 行
自己完結型の ES モジュールで、依存先は three のみです。ファクトリー関数を呼び出し、返された group をシーンに追加してください。
/**
* Fish — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the model (it floats — pickups, planets)
* Triangles: 668 · Size (W × H × D): 0.26 × 0.36 × 0.50 m
*
* Usage:
* import { createFish } from './fish.js';
*
* const model = createFish();
* model.position.set(0, 0, 0);
* scene.add(model);
*/
import * as THREE from 'three';
const deg = THREE.MathUtils.degToRad;
// Revolve a 2D profile [[radius, y], ...] around the Y axis.
function lathe(points, segments, phiStart = 0, phiLength = Math.PI * 2) {
return new THREE.LatheGeometry(points.map(([x, y]) => new THREE.Vector2(x, y)), segments, phiStart, phiLength);
}
// 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 createFish() {
const root = new THREE.Group();
root.name = 'Fish';
// Materials
const bodyMat = new THREE.MeshStandardMaterial({ name: 'body', color: 0x3fa4e0, roughness: 0.55, flatShading: true });
const bellyMat = new THREE.MeshStandardMaterial({ name: 'belly', color: 0xf3ead6, roughness: 0.6, flatShading: true });
const finMat = new THREE.MeshStandardMaterial({ name: 'fin', color: 0xf2b13c, roughness: 0.6, flatShading: true });
const eyeWhiteMat = new THREE.MeshStandardMaterial({ name: 'eyeWhite', color: 0xffffff, roughness: 0.3, flatShading: true });
const pupilMat = new THREE.MeshStandardMaterial({ name: 'pupil', color: 0x161417, roughness: 0.2, flatShading: true });
// Shared geometries
const sphereGeo = new THREE.SphereGeometry(0.036, 8, 6);
const sphereGeo2 = new THREE.SphereGeometry(0.02, 8, 6);
const extrudeGeo = extrude([[0, 0.02], [0.07, 0.035], [0.08, -0.01], [0, -0.02]], 0.012);
// Parts
const fish = new THREE.Group();
fish.name = 'fish';
fish.position.set(0, -0.008, 0.07);
root.add(fish);
const body = new THREE.Group();
body.name = 'body';
fish.add(body);
const bodyShell = new THREE.Mesh(lathe([[0, -0.2], [0.04, -0.18], [0.085, -0.11], [0.115, -0.02], [0.118, 0.04], [0.1, 0.11], [0.065, 0.165], [0, 0.195]], 10), bodyMat);
bodyShell.name = 'bodyShell';
bodyShell.rotation.set(deg(90), 0, 0);
bodyShell.scale.set(0.62, 1, 1.12);
body.add(bodyShell);
const bellyShell = new THREE.Mesh(lathe([[0, -0.184], [0.0388, -0.1656], [0.0825, -0.1012], [0.1116, -0.0184], [0.1145, 0.0368], [0.0842, 0.1012], [0.0471, 0.1518], [0, 0.1794]], 10), bellyMat);
bellyShell.name = 'bellyShell';
bellyShell.position.set(0, -0.026, -0.006);
bellyShell.rotation.set(deg(90), 0, 0);
bellyShell.scale.set(0.5952, 1, 1.064);
body.add(bellyShell);
const eyeL = new THREE.Mesh(sphereGeo, eyeWhiteMat);
eyeL.name = 'eyeL';
eyeL.position.set(0.056, 0.03, 0.11);
eyeL.scale.set(0.7, 1, 1);
body.add(eyeL);
const pupilL = new THREE.Mesh(sphereGeo2, pupilMat);
pupilL.name = 'pupilL';
pupilL.position.set(0.076, 0.032, 0.116);
pupilL.scale.set(0.6, 1, 1);
body.add(pupilL);
const eyeR = new THREE.Mesh(sphereGeo, eyeWhiteMat);
eyeR.name = 'eyeR';
eyeR.position.set(-0.056, 0.03, 0.11);
eyeR.scale.set(0.7, 1, 1);
body.add(eyeR);
const pupilR = new THREE.Mesh(sphereGeo2, pupilMat);
pupilR.name = 'pupilR';
pupilR.position.set(-0.076, 0.032, 0.116);
pupilR.scale.set(0.6, 1, 1);
body.add(pupilR);
const tail = new THREE.Group();
tail.name = 'tail';
tail.position.set(0, 0, -0.17);
fish.add(tail);
const tailFin = new THREE.Mesh(extrude([[0, 0.03], [0.1, 0.12], [0.135, 0.11], [0.085, 0], [0.135, -0.11], [0.1, -0.12], [0, -0.03]], 0.022), finMat);
tailFin.name = 'tailFin';
tailFin.rotation.set(0, deg(90), 0);
tail.add(tailFin);
const dorsalFin = new THREE.Group();
dorsalFin.name = 'dorsalFin';
dorsalFin.position.set(0, 0.1088, -0.01);
fish.add(dorsalFin);
const dorsal = new THREE.Mesh(extrude([[-0.07, 0], [0.1, 0], [0.07, 0.07], [-0.01, 0.1]], 0.018), finMat);
dorsal.name = 'dorsal';
dorsal.rotation.set(0, deg(90), 0);
dorsalFin.add(dorsal);
const ventralFin = new THREE.Group();
ventralFin.name = 'ventralFin';
ventralFin.position.set(0, -0.1032, -0.04);
fish.add(ventralFin);
const ventral = new THREE.Mesh(extrude([[-0.03, 0], [0.06, 0], [0.06, -0.05]], 0.014), finMat);
ventral.name = 'ventral';
ventral.rotation.set(0, deg(90), 0);
ventralFin.add(ventral);
const finL = new THREE.Group();
finL.name = 'finL';
finL.position.set(0.0685, -0.035, 0.03);
finL.rotation.set(0, deg(-40), deg(25));
fish.add(finL);
const pectoralL = new THREE.Mesh(extrudeGeo, finMat);
pectoralL.name = 'pectoralL';
pectoralL.rotation.set(0, deg(90), 0);
finL.add(pectoralL);
const finR = new THREE.Group();
finR.name = 'finR';
finR.position.set(-0.0685, -0.035, 0.03);
finR.rotation.set(0, deg(40), deg(-25));
fish.add(finR);
const pectoralR = new THREE.Mesh(extrudeGeo, finMat);
pectoralR.name = 'pectoralR';
pectoralR.rotation.set(0, deg(90), 0);
finR.add(pectoralR);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createFish;
評価とコメント
0 件のコメント
まだコメントはありません。このモデルの使い方や改善できる点を共有しましょう。
関連モデル
同じカテゴリまたは似たタグ









