<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Anguirus 1955 - Classic Movie Diorama</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
body { margin: 0; overflow: hidden; background-color: #222; font-family: 'Hiragino Mincho ProN', 'serif'; }
canvas { display: block; }
#info {
position: absolute;
top: 20px;
left: 20px;
color: #ddd;
background: rgba(0,0,0,0.8);
padding: 15px;
border-radius: 4px;
pointer-events: none;
border-left: 2px solid #666;
}
#info h1 { margin: 0 0 5px 0; font-size: 18px; color: #fff; letter-spacing: 2px; }
#controls {
position: absolute;
bottom: 20px;
left: 20px;
color: #888;
font-size: 12px;
background: rgba(0,0,0,0.4);
padding: 5px 10px;
}
</style>
</head>
<body>
<div id="info">
<h1>暴竜アンギラス (1955 映画再現)</h1>
<p>映画『ゴジラの逆襲』スチール写真に基づく造形</p>
<p style="font-size: 11px; color: #999;">• 四足歩行ポーズの再現<br>• モノクローム・特撮ライティング<br>• 劇中背景(大阪・コンクリート建築)</p>
</div>
<div id="controls">
ドラッグ: 視点回転 | ホイール: ズーム
</div>
<script>
let scene, camera, renderer;
let lon = 150;
let lat = 10;
let distance = 28;
let isDragging = false;
let previousMousePosition = { x: 0, y: 0 };
window.onload = function() {
init();
animate();
};
function init() {
scene = new THREE.Scene();
// 写真のような曇天のモノクロ背景
scene.background = new THREE.Color(0x444444);
scene.fog = new THREE.Fog(0x444444, 20, 70);
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);
// --- ライティング (特撮スタジオ風のモノクロライティング) ---
const ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
scene.add(ambientLight);
// 主光源
const sunLight = new THREE.DirectionalLight(0xffffff, 0.8);
sunLight.position.set(20, 20, 10);
sunLight.castShadow = true;
sunLight.shadow.mapSize.width = 2048;
sunLight.shadow.mapSize.height = 2048;
scene.add(sunLight);
// 逆光(トゲの輪郭を強調)
const rimLight = new THREE.SpotLight(0xffffff, 1.2);
rimLight.position.set(-20, 15, -15);
scene.add(rimLight);
// --- 地面 ---
const groundMat = new THREE.MeshPhongMaterial({ color: 0x333333, flatShading: true });
const ground = new THREE.Mesh(new THREE.PlaneGeometry(100, 100), groundMat);
ground.rotation.x = -Math.PI / 2;
ground.position.y = -1.5;
ground.receiveShadow = true;
scene.add(ground);
createEnvironment();
createAnguirus1955();
// 操作イベント
document.addEventListener('mousedown', (e) => { isDragging = true; previousMousePosition = { x: e.clientX, y: e.clientY }; });
document.addEventListener('mouseup', () => isDragging = false);
document.addEventListener('mousemove', (e) => {
if (isDragging) {
const deltaX = e.clientX - previousMousePosition.x;
const deltaY = e.clientY - previousMousePosition.y;
lon -= deltaX * 0.3;
lat += deltaY * 0.2;
lat = Math.max(0, Math.min(60, lat));
}
previousMousePosition = { x: e.clientX, y: e.clientY };
});
window.addEventListener('wheel', (e) => {
distance += e.deltaY * 0.03;
distance = Math.max(10, Math.min(distance, 60));
});
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
}
function createEnvironment() {
const env = new THREE.Group();
const buildingMat = new THREE.MeshPhongMaterial({ color: 0x555555, flatShading: true });
// --- 写真の建物の再現 (窓の並んだ長い建物) ---
const createBuilding = (w, h, d, x, z) => {
const bGroup = new THREE.Group();
const box = new THREE.Mesh(new THREE.BoxGeometry(w, h, d), buildingMat);
bGroup.add(box);
// 窓の表現
const windowGeo = new THREE.BoxGeometry(0.2, 0.4, 0.1);
const windowMat = new THREE.MeshBasicMaterial({ color: 0x222222 });
for(let iy=0; iy<3; iy++) {
for(let ix=0; ix<w*1.5; ix++) {
const win = new THREE.Mesh(windowGeo, windowMat);
win.position.set(-w/2 + 0.5 + ix*0.6, h/2 - 0.5 - iy*0.8, d/2 + 0.01);
bGroup.add(win);
}
}
bGroup.position.set(x, h/2 - 1.5, z);
return bGroup;
};
env.add(createBuilding(10, 5, 4, -8, -5));
env.add(createBuilding(12, 4, 3, 5, -8));
// 瓦礫と樹木
const debrisMat = new THREE.MeshPhongMaterial({ color: 0x333333 });
for(let i=0; i<20; i++) {
const rock = new THREE.Mesh(new THREE.DodecahedronGeometry(Math.random()*0.5 + 0.2), debrisMat);
rock.position.set((Math.random()-0.5)*20, -1.3, (Math.random()-0.5)*15);
env.add(rock);
}
// 前景の木
const treeMat = new THREE.MeshPhongMaterial({ color: 0x222222 });
const tree = new THREE.Mesh(new THREE.ConeGeometry(1, 3, 8), treeMat);
tree.position.set(-5, 0, 8);
env.add(tree);
env.traverse(n => { n.castShadow = true; n.receiveShadow = true; });
scene.add(env);
}
function createAnguirus1955() {
const anguirus = new THREE.Group();
const mat = new THREE.MeshPhongMaterial({ color: 0x333333, flatShading: true });
const shellMat = new THREE.MeshPhongMaterial({ color: 0x222222, flatShading: true });
const spikeMat = new THREE.MeshPhongMaterial({ color: 0x999999, flatShading: true });
// --- 胴体 (四足歩行用の水平ポーズ) ---
const torso = new THREE.Mesh(new THREE.CylinderGeometry(1.2, 1.4, 4.5, 16), mat);
torso.rotation.z = Math.PI / 2;
torso.position.y = 0.5;
anguirus.add(torso);
// --- 甲羅 (低く、平たく) ---
const shell = new THREE.Mesh(new THREE.SphereGeometry(1.6, 24, 12, 0, Math.PI * 2, 0, Math.PI / 2), shellMat);
shell.scale.set(1.1, 0.6, 1.8);
shell.position.y = 0.8;
anguirus.add(shell);
// --- トゲ (写真通り、非常に密で鋭い) ---
const spikeBase = new THREE.ConeGeometry(0.08, 0.8, 4);
for(let i=0; i<220; i++) {
const spike = new THREE.Mesh(spikeBase, spikeMat);
const phi = Math.random() * Math.PI * 2;
const theta = Math.random() * (Math.PI / 2.2);
const x = Math.sin(theta) * Math.cos(phi) * 1.7;
const y = Math.cos(theta) * 1.0 + 0.8;
const z = Math.sin(theta) * Math.sin(phi) * 2.8;
spike.position.set(x, y, z);
// トゲを少し後ろ向きに傾ける
const target = new THREE.Vector3(x, y*2, z*2 + 1);
spike.lookAt(target);
spike.rotateX(Math.PI / 2);
anguirus.add(spike);
}
// --- 頭 (低く構えて咆哮) ---
const headGroup = new THREE.Group();
const head = new THREE.Mesh(new THREE.BoxGeometry(1.1, 1, 1.8), mat);
headGroup.add(head);
// 下顎 (咆哮中)
const jaw = new THREE.Mesh(new THREE.BoxGeometry(0.9, 0.4, 1.3), mat);
jaw.position.set(0, -0.4, 1.0);
jaw.rotation.x = 0.6;
headGroup.add(jaw);
// 角 (鼻先と後頭部)
const hornGeo = new THREE.ConeGeometry(0.12, 0.6, 6);
const noseHorn = new THREE.Mesh(hornGeo, spikeMat);
noseHorn.position.set(0, 0.4, 1.6);
noseHorn.rotation.x = -0.3;
headGroup.add(noseHorn);
for(let i=0; i<2; i++) {
const h = new THREE.Mesh(hornGeo, spikeMat);
h.position.set(i === 0 ? 0.3 : -0.3, 0.5, 0);
h.rotation.x = -0.6;
headGroup.add(h);
}
headGroup.position.set(0, 0.8, 2.5);
headGroup.rotation.x = -0.4; // 斜め上を向く
anguirus.add(headGroup);
// --- 脚 (四足歩行、短め) ---
const legGeo = new THREE.CylinderGeometry(0.4, 0.5, 1.5, 12);
const lp = [[1.0, -0.7, 1.8], [-1.0, -0.7, 1.8], [1.0, -0.7, -1.8], [-1.0, -0.7, -1.8]];
lp.forEach(p => {
const leg = new THREE.Mesh(legGeo, mat);
leg.position.set(p[0], p[1], p[2]);
anguirus.add(leg);
});
// --- 長い尻尾 ---
const tail = new THREE.Group();
const segmentCount = 18;
for(let i=0; i<segmentCount; i++) {
const s = 0.8 * (1 - i/segmentCount);
const seg = new THREE.Mesh(new THREE.SphereGeometry(s, 12, 8), mat);
// 大きくうねる尻尾
seg.position.z = -i * 0.8;
seg.position.x = Math.sin(i * 0.4) * 2;
seg.position.y = -0.2 - i * 0.05;
// 尻尾のトゲ
if(i < 12) {
const ts = new THREE.Mesh(new THREE.ConeGeometry(0.1, 0.5, 4), spikeMat);
ts.position.y = s;
seg.add(ts);
}
tail.add(seg);
}
tail.position.set(0, 0.2, -2.2);
anguirus.add(tail);
anguirus.position.set(3, -0.1, 0);
anguirus.rotation.y = -0.5;
anguirus.traverse(n => { n.castShadow = true; n.receiveShadow = true; });
scene.add(anguirus);
}
function animate() {
requestAnimationFrame(animate);
const phi = THREE.MathUtils.degToRad(90 - lat);
const theta = THREE.MathUtils.degToRad(lon);
camera.position.x = distance * Math.sin(phi) * Math.cos(theta);
camera.position.y = distance * Math.cos(phi);
camera.position.z = distance * Math.sin(phi) * Math.sin(theta);
camera.lookAt(0, 1, 0);
renderer.render(scene, camera);
}
</script>
</body>
</html>
1995のアンギラスをモデルにしました