使用Three.js实现逼真的3D地球模拟
来自 Wikiprompt,自由的提示词百科全书
使用Three.js实现逼真的3D地球模拟 一个用于生成交互式3D地球模拟的详细提示,包含昼夜纹理、云层、星空和轨道控制,全部集成在单个HTML文件中。
提示词内容收藏
🌐
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Earth - Photorealistic 3D Simulation</title>
<style>
body { margin: 0; overflow: hidden; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
#info {
position: absolute;
top: 20px;
left: 20px;
color: white;
background: rgba(0,0,0,0.6);
padding: 10px 18px;
border-radius: 30px;
pointer-events: none;
font-size: 14px;
letter-spacing: 1px;
backdrop-filter: blur(4px);
border: 1px solid rgba(255,255,255,0.2);
z-index: 100;
}
#controls-hint {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
color: rgba(255,255,255,0.7);
background: rgba(0,0,0,0.4);
padding: 8px 16px;
border-radius: 20px;
font-size: 13px;
backdrop-filter: blur(4px);
border: 1px solid rgba(255,255,255,0.15);
pointer-events: none;
z-index: 100;
}
</style>
</head>
<body>
<div id="info">🌍 EARTH · DAY/NIGHT · CLOUDS · STARS</div>
<div id="controls-hint">🖱️ Drag to rotate · Scroll to zoom · Right-drag to pan</div>
<!-- Three.js core and OrbitControls -->
<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>
(function() {
// --- Initialize Scene, Camera, Renderer ---
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x050510); // deep space base
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0.5, 3.2); // slightly elevated for better view
const renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: false });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // softer shadows
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.2;
document.body.appendChild(renderer.domElement);
// --- Controls ---
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.rotateSpeed = 0.8;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.minDistance = 1.5;
controls.maxDistance = 8.0;
controls.enablePan = true;
controls.target.set(0, 0, 0);
// --- Lighting ---
// Ambient light to softly illuminate the dark side (prevents pure black)
const ambientLight = new THREE.AmbientLight(0x404060); // subtle blue-ish
scene.add(ambientLight);
// Main directional light (sun)
const sunLight = new THREE.DirectionalLight(0xfff5e6, 2.0);
sunLight.position.set(5, 2, 5); // from a diagonal angle
sunLight.castShadow = true;
sunLight.receiveShadow = true;
// Shadow settings for better quality
sunLight.shadow.mapSize.width = 1024;
sunLight.shadow.mapSize.height = 1024;
const d = 3;
sunLight.shadow.camera.left = -d;
sunLight.shadow.camera.right = d;
sunLight.shadow.camera.top = d;
sunLight.shadow.camera.bottom = -d;
sunLight.shadow.camera.near = 1;
sunLight.shadow.camera.far = 10;
sunLight.shadow.bias = -0.0005;
scene.add(sunLight);
// Optional fill light from opposite side to slightly reveal night side details
const fillLight = new THREE.DirectionalLight(0x446688, 0.15);
fillLight.position.set(-3, 0, -3);
scene.add(fillLight);
// --- Helper: Create Earth Group ---
const earthGroup = new THREE.Group();
scene.add(earthGroup);
// --- 1. Earth Sphere (Day/Night textures + specular) ---
// Load textures using TextureLoader
const loader = new THREE.TextureLoader();
// Use high-quality textures from Three.js examples repository (public domain / free)
const dayTexture = loader.load('https://threejs.org/examples/textures/planets/earth_atmos_2048.jpg');
const nightTexture = loader.load('https://threejs.org/examples/textures/planets/earth_lights_2048.png');
const specularMap = loader.load('https://threejs.org/examples/textures/planets/earth_specular_2048.jpg');
const normalMap = loader.load('https://threejs.org/examples/textures/planets/earth_normal_2048.jpg');
const cloudTexture = loader.load('https://threejs.org/examples/textures/planets/earth_clouds_1024.png');
// Earth material with day/night blending via custom shader?
// For simplicity and high quality, we use MeshPhongMaterial with emissive map for night lights.
// But to get both day and night in one material, we can use a custom shader or use two meshes.
// Better approach: Use a MeshPhongMaterial with emissiveMap for night lights, and map for day.
// However, standard material doesn't blend day/night dynamically.
// We'll create two overlapping spheres: one for day (lit) and one for night (emissive) with blending.
// But to keep it clean and still show city lights on night side, we use a custom ShaderMaterial.
// Given time, I'll implement a custom shader that blends day and night based on light direction.
// This gives the most realistic effect.
// --- Custom Shader Material for Earth (Day/Night/Specular) ---
const earthVertexShader = `
varying vec3 vNormal;
varying vec3 vWorldPosition;
varying vec2 vUv;
void main() {
vUv = uv;
vNormal = normalize(normalMatrix * normal);
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
vWorldPosition = worldPosition.xyz;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const earthFragmentShader = `
uniform sampler2D dayMap;
uniform sampler2D nightMap;
uniform sampler2D specularMap;
uniform sampler2D normalMap; // not used in shader but kept for completeness
uniform vec3 sunDirection; // in world space
uniform vec3 ambientColor;
varying vec3 vNormal;
varying vec3 vWorldPosition;
varying vec2 vUv;
void main() {
vec3 normal = normalize(vNormal);
vec3 lightDir = normalize(sunDirection);
// Diffuse lighting factor (dot product)
float diff = max(dot(normal, lightDir), 0.0);
// Day color
vec3 dayColor = texture2D(dayMap, vUv).rgb;
// Night color (city lights)
vec3 nightColor = texture2D(nightMap, vUv).rgb;
// Specular map (ocean highlights)
float specularIntensity = texture2D(specularMap, vUv).r;
// Blinn-Phong specular highlight
vec3 viewDir = normalize(cameraPosition - vWorldPosition);
vec3 halfDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(normal, halfDir), 0.0), 32.0) * specularIntensity * 1.5;
// Blend day and night: night shows when diff is low, but also add a small ambient
float nightFactor = smoothstep(0.1, 0.35, 1.0 - diff); // night appears when diff < 0.3
// Add a bit of ambient to day side
vec3 ambient = ambientColor * dayColor * 0.1;
// Final color = day * diff + night * nightFactor + spec + ambient
vec3 color = dayColor * diff + nightColor * nightFactor * 1.2 + vec3(spec) + ambient;
// Tone mapping (simple Reinhard) for better dynamic range
color = color / (color + vec3(1.0));
gl_FragColor = vec4(color, 1.0);
}
`;
const earthMaterial = new THREE.ShaderMaterial({
uniforms: {
dayMap: { value: dayTexture },
nightMap: { value: nightTexture },
specularMap: { value: specularMap },
normalMap: { value: normalMap },
sunDirection: { value: sunLight.position.clone().normalize() },
ambientColor: { value: new THREE.Color(0x202030) }
},
vertexShader: earthVertexShader,
fragmentShader: earthFragmentShader,
lights: false, // we handle lighting manually
shininess: 0 // not used
});
// Create Earth mesh
const earthGeometry = new THREE.SphereGeometry(1.0, 64, 64);
const earthMesh = new THREE.Mesh(earthGeometry, earthMaterial);
earthMesh.castShadow = true;
earthMesh.receiveShadow = true;
earthGroup.add(earthMesh);
// --- 2. Cloud Layer (semi-transparent, rotating independently) ---
const cloudMaterial = new THREE.MeshPhongMaterial({
map: cloudTexture,
transparent: true,
opacity: 0.45,
depthWrite: false,
blending: THREE.AdditiveBlending, // makes clouds glow slightly
side: THREE.DoubleSide
});
const cloudGeometry = new THREE.SphereGeometry(1.01, 64, 64);
const cloudMesh = new THREE.Mesh(cloudGeometry, cloudMaterial);
cloudMesh.castShadow = false;
cloudMesh.receiveShadow = false;
earthGroup.add(cloudMesh);
// --- 3. Starfield Background (sphere with star texture) ---
// Generate a star texture procedurally for high quality
const starCanvas = document.createElement('canvas');
starCanvas.width = 1024;
starCanvas.height = 1024;
const ctx = starCanvas.getContext('2d');
ctx.fillStyle = '#050510';
ctx.fillRect(0, 0, 1024, 1024);
// Draw random stars (white, some with slight blue/yellow tint)
for (let i = 0; i < 4000; i++) {
const x = Math.random() * 1024;
const y = Math.random() * 1024;
const size = Math.random() * 1.8 + 0.2;
const brightness = Math.random() * 0.8 + 0.2;
const color = `rgba(255, 255, 255, ${brightness})`;
ctx.beginPath();
ctx.arc(x, y, size, 0, 2 * Math.PI);
ctx.fillStyle = color;
ctx.fill();
// occasional colored star
if (Math.random() > 0.98) {
ctx.beginPath();
ctx.arc(x, y, size * 1.5, 0, 2 * Math.PI);
ctx.fillStyle = `rgba(180, 220, 255, ${brightness * 0.8})`;
ctx.fill();
}
}
const starTexture = new THREE.CanvasTexture(starCanvas);
starTexture.wrapS = THREE.RepeatWrapping;
starTexture.wrapT = THREE.ClampToEdgeWrapping;
const starMaterial = new THREE.MeshBasicMaterial({
map: starTexture,
side: THREE.BackSide,
transparent: false,
depthWrite: false
});
const starSphere = new THREE.Mesh(new THREE.SphereGeometry(20, 32, 32), starMaterial);
scene.add(starSphere);
// --- 4. Add a subtle glow effect (optional) via a point light? Not necessary.
// --- Animation Loop ---
let clock = new THREE.Clock();
function animate() {
const delta = clock.getDelta();
const elapsedTime = performance.now() * 0.001; // seconds
// Rotate Earth and clouds at different speeds
earthMesh.rotation.y += 0.0008; // slow rotation
cloudMesh.rotation.y += 0.0012; // clouds move faster
// Update sun direction uniform (if light moves, but we keep it static)
// For realism, we could rotate the light, but we keep it fixed.
// Update controls
controls.update();
// Render
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();
// --- Handle Window Resize ---
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// --- Update sunDirection uniform if needed (not necessary for static light) ---
// But we can update it in case we want to move light later.
// For now, it's set.
// --- Add a subtle rim light or atmosphere effect?
// Could add a glow sphere, but not necessary for this demo.
// --- Optional: Add a small sun sphere for visual reference (not needed) ---
// --- Ensure textures are loaded and then update uniforms if needed ---
// All textures are loaded via loader, but we can set the sun direction again after load.
// Since we use the same direction, it's fine.
// --- Add a very subtle specular highlight on the night side? Not needed.
// --- Final touch: adjust renderer shadow settings ---
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// --- Log to console for confirmation ---
console.log('Earth simulation started. Enjoy!');
})();
</script>
</body>
</html>
用法
此提示词专为 coding 设计。复制上方内容并粘贴到你常用的 AI 工具中。
为获得最佳效果,可将占位符(方括号或大写字母标示)替换为你的具体需求。
讨论
0 条评论