infinite-agents-public/threejs_viz/threejs_viz_6.html

314 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Three.js - Texture Mapping & Filter Comparison</title>
<style>
body {
margin: 0;
overflow: hidden;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
canvas {
display: block;
width: 100vw;
height: 100vh;
}
#info {
position: absolute;
top: 10px;
left: 10px;
color: white;
background: rgba(0, 0, 0, 0.7);
padding: 15px;
border-radius: 8px;
font-size: 14px;
max-width: 400px;
z-index: 100;
}
#info h2 {
margin: 0 0 10px 0;
font-size: 18px;
}
#info .web-source {
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid rgba(255,255,255,0.3);
font-size: 12px;
opacity: 0.8;
}
</style>
</head>
<body>
<div id="info">
<h2>Texture Filter Comparison</h2>
<p><strong>Technique:</strong> TextureLoader, minFilter, magFilter comparison</p>
<p><strong>Learning:</strong> Demonstrates NearestFilter (pixelated) vs LinearFilter (smooth blending), texture wrapping, and UV mapping with procedural textures.</p>
<p><strong>Features:</strong></p>
<ul style="margin: 5px 0; padding-left: 20px;">
<li>Left cube: NearestFilter (crisp pixels)</li>
<li>Center sphere: LinearFilter (smooth)</li>
<li>Right torus: Repeating texture with wrapping</li>
<li>All use procedural canvas textures</li>
</ul>
<div class="web-source">
<strong>Web Source:</strong><br>
<a href="https://threejs.org/manual/en/textures.html" target="_blank" style="color: #4fc3f7;">https://threejs.org/manual/en/textures.html</a><br>
<em>Applied: TextureLoader patterns, filter types (NearestFilter vs LinearFilter), texture wrapping (RepeatWrapping), and UV repeat settings</em>
</div>
</div>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Scene setup
let camera, scene, renderer, controls;
let cube, sphere, torus;
init();
animate();
function init() {
// Camera setup
camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0, 2, 8);
// Scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);
// Renderer (WebGL)
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// OrbitControls for interaction
controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Create visualization using learned texture techniques
createVisualization();
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(5, 5, 5);
scene.add(directionalLight);
const pointLight = new THREE.PointLight(0x4fc3f7, 0.6);
pointLight.position.set(-5, 3, -5);
scene.add(pointLight);
// Handle resize
window.addEventListener('resize', onWindowResize);
}
function createVisualization() {
// Create procedural textures using canvas
// This demonstrates texture creation without external image files
// Texture 1: Checkerboard pattern for NearestFilter demonstration
const canvas1 = document.createElement('canvas');
canvas1.width = 128;
canvas1.height = 128;
const ctx1 = canvas1.getContext('2d');
// Draw checkerboard
const tileSize = 16;
for (let y = 0; y < canvas1.height; y += tileSize) {
for (let x = 0; x < canvas1.width; x += tileSize) {
const isEven = ((x / tileSize) + (y / tileSize)) % 2 === 0;
ctx1.fillStyle = isEven ? '#ff6b6b' : '#4ecdc4';
ctx1.fillRect(x, y, tileSize, tileSize);
}
}
const texture1 = new THREE.CanvasTexture(canvas1);
texture1.colorSpace = THREE.SRGBColorSpace;
// NearestFilter: No interpolation, shows crisp pixels when magnified
texture1.magFilter = THREE.NearestFilter;
texture1.minFilter = THREE.NearestFilter;
// Texture 2: Gradient pattern for LinearFilter demonstration
const canvas2 = document.createElement('canvas');
canvas2.width = 256;
canvas2.height = 256;
const ctx2 = canvas2.getContext('2d');
// Create radial gradient
const gradient = ctx2.createRadialGradient(128, 128, 0, 128, 128, 128);
gradient.addColorStop(0, '#ffd93d');
gradient.addColorStop(0.5, '#6bcf7f');
gradient.addColorStop(1, '#4d96ff');
ctx2.fillStyle = gradient;
ctx2.fillRect(0, 0, canvas2.width, canvas2.height);
// Add some detail
ctx2.strokeStyle = 'rgba(255, 255, 255, 0.3)';
ctx2.lineWidth = 2;
for (let i = 0; i < 8; i++) {
ctx2.beginPath();
ctx2.arc(128, 128, 20 + i * 15, 0, Math.PI * 2);
ctx2.stroke();
}
const texture2 = new THREE.CanvasTexture(canvas2);
texture2.colorSpace = THREE.SRGBColorSpace;
// LinearFilter: Interpolates between pixels, creates smooth appearance
texture2.magFilter = THREE.LinearFilter;
texture2.minFilter = THREE.LinearMipmapLinearFilter; // Best quality with mipmaps
// Texture 3: Pattern with wrapping and repeating
const canvas3 = document.createElement('canvas');
canvas3.width = 64;
canvas3.height = 64;
const ctx3 = canvas3.getContext('2d');
// Create repeating pattern
ctx3.fillStyle = '#2d3561';
ctx3.fillRect(0, 0, 64, 64);
ctx3.strokeStyle = '#f72585';
ctx3.lineWidth = 3;
ctx3.beginPath();
ctx3.moveTo(0, 0);
ctx3.lineTo(64, 64);
ctx3.moveTo(64, 0);
ctx3.lineTo(0, 64);
ctx3.stroke();
ctx3.fillStyle = '#7209b7';
ctx3.beginPath();
ctx3.arc(32, 32, 15, 0, Math.PI * 2);
ctx3.fill();
const texture3 = new THREE.CanvasTexture(canvas3);
texture3.colorSpace = THREE.SRGBColorSpace;
texture3.magFilter = THREE.LinearFilter;
texture3.minFilter = THREE.LinearMipmapLinearFilter;
// Enable texture wrapping for repeating patterns
texture3.wrapS = THREE.RepeatWrapping;
texture3.wrapT = THREE.RepeatWrapping;
// Repeat the texture 3 times in both directions
texture3.repeat.set(3, 3);
// Create three objects with different textures and filters
// 1. Cube with NearestFilter (pixelated look)
const cubeGeometry = new THREE.BoxGeometry(2, 2, 2);
const cubeMaterial = new THREE.MeshStandardMaterial({
map: texture1,
roughness: 0.7,
metalness: 0.3
});
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.x = -4;
scene.add(cube);
// 2. Sphere with LinearFilter (smooth blending)
const sphereGeometry = new THREE.SphereGeometry(1.2, 32, 32);
const sphereMaterial = new THREE.MeshStandardMaterial({
map: texture2,
roughness: 0.5,
metalness: 0.4
});
sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.position.x = 0;
scene.add(sphere);
// 3. Torus with repeating texture and wrapping
const torusGeometry = new THREE.TorusGeometry(1.2, 0.5, 16, 50);
const torusMaterial = new THREE.MeshStandardMaterial({
map: texture3,
roughness: 0.6,
metalness: 0.5
});
torus = new THREE.Mesh(torusGeometry, torusMaterial);
torus.position.x = 4;
scene.add(torus);
// Add labels (optional floating text indicators)
addLabel('NearestFilter', -4, -2, 0);
addLabel('LinearFilter', 0, -2, 0);
addLabel('Repeating Texture', 4, -2, 0);
}
function addLabel(text, x, y, z) {
// Create a simple text sprite using canvas
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 128;
context.fillStyle = 'rgba(0, 0, 0, 0.6)';
context.fillRect(0, 0, canvas.width, canvas.height);
context.font = 'Bold 48px Arial';
context.fillStyle = 'white';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(text, 256, 64);
const texture = new THREE.CanvasTexture(canvas);
texture.colorSpace = THREE.SRGBColorSpace;
const spriteMaterial = new THREE.SpriteMaterial({ map: texture });
const sprite = new THREE.Sprite(spriteMaterial);
sprite.position.set(x, y, z);
sprite.scale.set(2, 0.5, 1);
scene.add(sprite);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
// Animate objects to show textures from different angles
const time = Date.now() * 0.001;
// Cube rotates to show filter differences clearly
cube.rotation.x = time * 0.3;
cube.rotation.y = time * 0.5;
// Sphere rotates slowly
sphere.rotation.y = time * 0.4;
// Torus rotates to show wrapping pattern
torus.rotation.x = time * 0.2;
torus.rotation.y = time * 0.6;
// Update controls
controls.update();
renderer.render(scene, camera);
}
</script>
</body>
</html>