<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gamera 3 - The Final Duel (Fixed)</title>
<style>
body { margin: 0; overflow: hidden; background-color: #000; font-family: 'Hiragino Kaku Gothic ProN', 'Meiryo', sans-serif; }
#ui { position: absolute; top: 20px; left: 20px; color: #fff; text-shadow: 0 0 20px #ff0000; pointer-events: none; z-index: 10; }
#instructions { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); color: #777; font-size: 0.8rem; pointer-events: none; text-align: center; }
canvas { display: block; }
</style>
</head>
<body>
<div id="ui">
<h1 style="margin: 0; font-size: 1.5rem; letter-spacing: 0.2em;">ガメラ3:邪神降臨</h1>
<p style="margin: 5px 0 0 0; font-size: 0.8rem; opacity: 0.8;">GAMERA G3 VS IRIS - FINAL CONFRONTATION</p>
</div>
<div id="instructions">
DRAG: ROTATE | WHEEL: ZOOM<br>
京都駅・火の海での決戦
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
<script>
let scene, camera, renderer, controls;
let irisGroup, gameraGroup, ground;
let tentacles = [];
let flames = [];
let clock = new THREE.Clock();
// Materials - Iris
const irisMeatMat = new THREE.MeshStandardMaterial({ color: 0xaa2200, roughness: 0.7 });
const irisShellMat = new THREE.MeshStandardMaterial({ color: 0x111111, roughness: 0.2, metalness: 0.9 });
const irisGlowMat = new THREE.MeshStandardMaterial({ color: 0x00ffff, emissive: 0x0088ff, emissiveIntensity: 3 });
// Materials - Gamera (Based on image_827e33.png)
const gameraSkinMat = new THREE.MeshStandardMaterial({ color: 0x2a2f35, roughness: 0.9 });
const gameraShellMat = new THREE.MeshStandardMaterial({ color: 0x1a2420, roughness: 0.8, metalness: 0.1 });
const gameraBellyMat = new THREE.MeshStandardMaterial({ color: 0x3d352b, roughness: 1.0 });
const gameraGlowMat = new THREE.MeshStandardMaterial({ color: 0xffff00, emissive: 0xaaaa00, emissiveIntensity: 2 });
const tuskMat = new THREE.MeshStandardMaterial({ color: 0xd2c4a3, roughness: 0.5 });
function init() {
// Fix: Initializing scene correctly
scene = new THREE.Scene();
scene.background = new THREE.Color(0x020205);
scene.fog = new THREE.FogExp2(0x020205, 0.035);
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(18, 10, 18);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.target.set(0, 4, 0);
scene.add(new THREE.AmbientLight(0xffffff, 0.1));
const spotLight = new THREE.SpotLight(0xffffff, 1.0);
spotLight.position.set(20, 40, 20);
spotLight.castShadow = true;
scene.add(spotLight);
const groundGeom = new THREE.PlaneGeometry(200, 200);
const groundMat = new THREE.MeshStandardMaterial({ color: 0x0a0a0a, roughness: 1 });
ground = new THREE.Mesh(groundGeom, groundMat);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
createIris();
createGamera();
createEnvironmentFlames();
window.addEventListener('resize', onWindowResize, false);
animate();
}
function createIris() {
irisGroup = new THREE.Group();
irisGroup.position.set(-8, 3.2, 0);
irisGroup.rotation.y = Math.PI / 2;
scene.add(irisGroup);
const body = new THREE.Group();
irisGroup.add(body);
// Head with Multi-layered crest
const headGroup = new THREE.Group();
headGroup.position.y = 3.6;
body.add(headGroup);
const skullUpper = new THREE.Mesh(new THREE.ConeGeometry(0.35, 1.2, 4), irisShellMat);
skullUpper.rotation.x = -1.2;
headGroup.add(skullUpper);
for(let i=0; i<3; i++) {
const crest = new THREE.Mesh(new THREE.BoxGeometry(0.05, 1.5, 0.4), irisShellMat);
crest.position.set(0, 0.6 + (i*0.1), -0.6 - (i*0.2));
crest.rotation.x = -0.8 - (i*0.2);
headGroup.add(crest);
}
// Chest Gems
const chest = new THREE.Mesh(new THREE.SphereGeometry(1, 16, 16), irisMeatMat);
chest.scale.set(1.1, 1.4, 0.8);
chest.position.y = 2.0;
body.add(chest);
const gemL = new THREE.Mesh(new THREE.SphereGeometry(0.35, 16, 16), irisGlowMat);
gemL.position.set(0.45, 2.4, 0.65);
gemL.scale.set(1, 1.4, 0.4);
const gemR = gemL.clone();
gemR.position.set(-0.45, 2.4, 0.65);
body.add(gemL, gemR);
const createArm = (side) => {
const armContainer = new THREE.Group();
armContainer.position.set(side * 0.8, 2.8, 0.2);
const blade = new THREE.Mesh(new THREE.ConeGeometry(0.3, 5.5, 4), irisShellMat);
blade.position.set(side * 0.9, -1.4, 1.7);
blade.rotation.set(1.5, 0, side * 0.1);
blade.scale.set(1.5, 1, 0.15);
armContainer.add(blade);
return armContainer;
};
body.add(createArm(1), createArm(-1));
for(let i=0; i<4; i++){
const tGroup = new THREE.Group();
const segments = [];
let prev = tGroup;
const angle = (i/4) * Math.PI * 2 + Math.PI/4;
tGroup.position.set(Math.cos(angle)*1.6, 3.8, -1.5);
for(let j=0; j<35; j++){
const seg = new THREE.Mesh(new THREE.CylinderGeometry(0.16 - j*0.0035, 0.18 - j*0.0035, 0.65, 6), irisMeatMat);
seg.position.y = -0.55;
const sub = new THREE.Group();
sub.add(seg);
sub.position.y = -0.55;
prev.add(sub);
segments.push(sub);
prev = sub;
}
irisGroup.add(tGroup);
tentacles.push(segments);
}
}
function createGamera() {
gameraGroup = new THREE.Group();
gameraGroup.position.set(8, 0.1, 0);
gameraGroup.rotation.y = -Math.PI / 2;
scene.add(gameraGroup);
const bodyCore = new THREE.Mesh(new THREE.SphereGeometry(3.2, 16, 16), gameraSkinMat);
bodyCore.scale.set(1, 0.8, 1.1);
bodyCore.position.y = 3;
gameraGroup.add(bodyCore);
const belly = new THREE.Mesh(new THREE.SphereGeometry(2.8, 16, 16), gameraBellyMat);
belly.scale.set(0.9, 0.6, 1.0);
belly.position.set(0, 2.8, 0.8);
gameraGroup.add(belly);
// Detailed Layered Shell
const shellGroup = new THREE.Group();
shellGroup.position.y = 3.5;
gameraGroup.add(shellGroup);
for(let i=0; i<6; i++) {
const scute = new THREE.Mesh(new THREE.BoxGeometry(4.5 - i*0.5, 0.4, 1.8), gameraShellMat);
scute.position.set(0, 1.8 - i*0.3, -1.0 - i*0.8);
scute.rotation.x = -0.4;
shellGroup.add(scute);
}
const head = new THREE.Group();
head.position.set(0, 5.0, 3.2);
head.rotation.x = 0.2;
gameraGroup.add(head);
const skull = new THREE.Mesh(new THREE.BoxGeometry(1.6, 1.2, 2.2), gameraSkinMat);
head.add(skull);
const eyeL = new THREE.Mesh(new THREE.SphereGeometry(0.12, 8, 8), gameraGlowMat);
eyeL.position.set(0.65, 0.3, 1.0);
const eyeR = eyeL.clone();
eyeR.position.x = -0.65;
head.add(eyeL, eyeR);
const jaw = new THREE.Mesh(new THREE.BoxGeometry(1.5, 0.6, 2.0), gameraSkinMat);
jaw.position.y = -0.6;
jaw.position.z = 0.2;
head.add(jaw);
const createTusk = (x, rotZ) => {
const tusk = new THREE.Mesh(new THREE.ConeGeometry(0.2, 0.9, 4), tuskMat);
tusk.position.set(x, 0, 1.1);
tusk.rotation.set(0.5, 0, rotZ);
return tusk;
};
head.add(createTusk(0.6, -0.4), createTusk(-0.6, 0.4));
const createLimb = (x, y, z, rotX, isArm) => {
const limbGroup = new THREE.Group();
limbGroup.position.set(x, y, z);
const segment = new THREE.Mesh(new THREE.CylinderGeometry(0.8, 1.0, 3.0, 8), gameraSkinMat);
segment.rotation.x = rotX;
limbGroup.add(segment);
return limbGroup;
};
gameraGroup.add(createLimb(2.2, 3.0, 2.2, 0.6, true));
gameraGroup.add(createLimb(-2.2, 3.0, 2.2, 0.6, true));
gameraGroup.add(createLimb(2.2, 1.5, -1.0, -0.2, false));
gameraGroup.add(createLimb(-2.2, 1.5, -1.0, -0.2, false));
}
function createEnvironmentFlames() {
const flameGeom = new THREE.ConeGeometry(0.8, 4.0, 6);
const flameMat = new THREE.MeshBasicMaterial({ color: 0xff4400, transparent: true, opacity: 0.6, blending: THREE.AdditiveBlending });
for(let i=0; i<60; i++){
const flame = new THREE.Mesh(flameGeom, flameMat);
const r = 5 + Math.random() * 20;
const angle = Math.random() * Math.PI * 2;
flame.position.set(Math.cos(angle)*r, 0, Math.sin(angle)*r);
flame.scale.set(Math.random()+0.5, Math.random()+1.5, Math.random()+0.5);
scene.add(flame);
flames.push(flame);
if(i % 5 === 0){
const pLight = new THREE.PointLight(0xff5500, 2, 12);
pLight.position.copy(flame.position);
pLight.position.y = 2;
scene.add(pLight);
}
}
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate); // Fix: Re-calling animate for loop
const t = clock.getElapsedTime();
// Iris animation
if(irisGroup) {
irisGroup.position.y = 3.2 + Math.sin(t * 0.5) * 0.08;
tentacles.forEach((segments, i) => {
segments.forEach((seg, j) => {
const offset = i * Math.PI / 2;
seg.rotation.x = Math.sin(t * 1.3 + j * 0.12 + offset) * 0.14;
seg.rotation.z = Math.cos(t * 0.9 + j * 0.18 + offset) * 0.09;
});
});
}
// Gamera animation
if(gameraGroup) {
gameraGroup.position.y = 0.1 + Math.sin(t * 0.3) * 0.03;
}
// Flames animation
flames.forEach((f, i) => {
f.scale.y = (Math.sin(t * 5 + i) * 0.8 + 1.6);
f.position.y = f.scale.y * 1.8;
});
controls.update();
renderer.render(scene, camera);
}
window.onload = init;
</script>
</body>
</html>
ガメラ3をモデルとしました