|
<!DOCTYPE html> |
|
<html lang="ja"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>モザイク画像の3D変換</title> |
|
<style> |
|
body { margin: 0; overflow: hidden; } |
|
canvas { display: block; } |
|
#upload { position: fixed; top: 10px; left: 10px; z-index: 10; } |
|
</style> |
|
</head> |
|
<body> |
|
<input type="file" id="upload" accept="image/*" /> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> |
|
<script> |
|
|
|
let scene, camera, renderer, controls; |
|
const cubes = []; |
|
const pixelSize = 5; |
|
|
|
function init() { |
|
scene = new THREE.Scene(); |
|
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); |
|
camera.position.z = 300; |
|
|
|
renderer = new THREE.WebGLRenderer(); |
|
renderer.setSize(window.innerWidth, window.innerHeight); |
|
document.body.appendChild(renderer.domElement); |
|
|
|
animate(); |
|
} |
|
|
|
function animate() { |
|
requestAnimationFrame(animate); |
|
cubes.forEach(cube => { |
|
|
|
cube.position.x += (0 - cube.position.x) * 0.02; |
|
cube.position.y += (0 - cube.position.y) * 0.02; |
|
cube.position.z += (0 - cube.position.z) * 0.02; |
|
}); |
|
camera.rotation.y += 0.01; |
|
renderer.render(scene, camera); |
|
} |
|
|
|
|
|
function createMosaicImage(image) { |
|
const canvas = document.createElement("canvas"); |
|
const ctx = canvas.getContext("2d"); |
|
const width = 50; |
|
const height = 50; |
|
canvas.width = width; |
|
canvas.height = height; |
|
|
|
|
|
ctx.drawImage(image, 0, 0, width, height); |
|
const imageData = ctx.getImageData(0, 0, width, height).data; |
|
|
|
|
|
for (let y = 0; y < height; y++) { |
|
for (let x = 0; x < width; x++) { |
|
const i = (y * width + x) * 4; |
|
const r = imageData[i]; |
|
const g = imageData[i + 1]; |
|
const b = imageData[i + 2]; |
|
const color = new THREE.Color(`rgb(${r},${g},${b})`); |
|
|
|
const geometry = new THREE.BoxGeometry(pixelSize, pixelSize, pixelSize); |
|
const material = new THREE.MeshBasicMaterial({ color }); |
|
const cube = new THREE.Mesh(geometry, material); |
|
|
|
|
|
cube.position.x = Math.random() * 600 - 300; |
|
cube.position.y = Math.random() * 600 - 300; |
|
cube.position.z = Math.random() * 600 - 300; |
|
|
|
|
|
const targetX = (x - width / 2) * pixelSize; |
|
const targetY = (y - height / 2) * pixelSize; |
|
cube.userData = { targetX, targetY, targetZ: 0 }; |
|
|
|
cubes.push(cube); |
|
scene.add(cube); |
|
} |
|
} |
|
} |
|
|
|
|
|
document.getElementById("upload").addEventListener("change", (event) => { |
|
const file = event.target.files[0]; |
|
const reader = new FileReader(); |
|
reader.onload = (e) => { |
|
const image = new Image(); |
|
image.onload = () => createMosaicImage(image); |
|
image.src = e.target.result; |
|
}; |
|
reader.readAsDataURL(file); |
|
}); |
|
|
|
|
|
init(); |
|
</script> |
|
</body> |
|
</html> |
|
|