<div id="container" class="container"></div>
.container {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}
import * as THREE from "https://cdn.skypack.dev/three@0.133.1";
import { OrbitControls } from "https://cdn.skypack.dev/three@0.133.1/examples/jsm/controls/OrbitControls";

// 建立場景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x040014);

// 建立相機
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.set(100, 100, 100); // 相機位置
camera.lookAt(scene.position) // 相機焦點

// 建立物體
// 球形體
const sphereGeometry = new THREE.IcosahedronGeometry(20, 1);
const sphereMaterial = new THREE.MeshPhongMaterial({
  color: 0xffffff,
  emissive: 0x000000,
  specular: 0xffffff,
  shininess: 100,
  flatShading: true
});
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);

// 行星環
const RingInsideGeometry = new THREE.RingGeometry(37, 28, 30, 30);
const RingMaterial = opacity => {
  return new THREE.MeshPhongMaterial({
    color: 0xffffff,
    emissive: 0x000000,
    specular: 0xffffff,
    shininess: 100,
    flatShading: true,
    transparent: true,
    opacity
  });
}
const ringInside = new THREE.Mesh(RingInsideGeometry, RingMaterial(0.9));

const RingOutsideGeometry = new THREE.RingGeometry(42, 38, 30, 30);
const ringOutside = new THREE.Mesh(RingOutsideGeometry, RingMaterial(0.65));

const ringGroup = new THREE.Group();
ringGroup.rotation.x = THREE.MathUtils.degToRad(90);
ringGroup.add(ringInside, ringOutside);

const planet = new THREE.Group();
planet.add(sphere, ringGroup);
planet.rotation.x = THREE.MathUtils.degToRad(-30);
planet.rotation.y = THREE.MathUtils.degToRad(-10);
scene.add(planet);

// 群星背景
const geometry = new THREE.BufferGeometry();
const particleAmount = 2000;
const vertices = [...Array(particleAmount * 3)].map(() => 2000 * Math.random() - 1000);
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
const particleTexture = new THREE.TextureLoader().load('https://i.imgur.com/9TwBBHH.png');
const material = new THREE.PointsMaterial({ size: 5, sizeAttenuation: true, map: particleTexture, transparent: true, alphaTest: 0.5, color: 0xf3f3af });
const particles = new THREE.Points(geometry, material);
scene.add(particles);

// 建立光源
// 環境光
const ambientLight = new THREE.AmbientLight(0x222222);
// 點光源
const pointLight = new THREE.PointLight(0x777777, 1, 0);
pointLight.position.set(100, 100, 0);
// 聚光燈
const spotLight = new THREE.SpotLight(0xffffff, 3, 150, Math.PI / 15, 1, 1);
			spotLight.position.set(50, 100, -80);
spotLight.castShadow = true;
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
spotLight.shadow.camera.near = 10;
spotLight.shadow.camera.far = 200;
spotLight.shadow.focus = 1;
scene.add(ambientLight, pointLight, spotLight);

// 建立渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('container')?.appendChild(renderer.domElement);

// 建立軌道控制器
const control = new OrbitControls(camera, renderer.domElement);

// 執行渲染
function animate() {
  requestAnimationFrame(animate);
  planet.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

// 監聽螢幕寬高變化來做簡單 RWD 設定
window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight)
})

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.