学习马老师的《宇宙》代码
本帖最后由 杨帆 于 2025-5-1 17:29 编辑 <br /><br /><!DOCTYPE html><html>
<head>
<meta charset="utf-8">
<title>宇宙天体</title>
</head>
<body>
<style>
#pa {
--state: running;
margin: 30px 0;
left: calc(50% - 81px);
transform: translateX(-50%);
width: clamp(600px, 90vw, 1400px);
height:750px;
aspect-ratio: 16/9;
background: url('https://cccimg.com/view.php/3d0eb4b2ff23f9071ec9c181368a9e89.jpg') no-repeat center/cover;
box-shadow: 2px 2px 10px rgba(0,0,0,.65);
z-index: 1;
position: relative;
}
#pa canvas {
display: block;
}
#player {
position: absolute;
left: 20px;
top: 20px;
z-index: 9;
clip-path: circle(45%);
transition: filter .7s;
cursor: pointer;
animation: rot 20s linear infinite var(--state);
}
#player:hover {
filter: hue-rotate(90deg);
}
@keyframes rot {
to {
transform: rotate(360deg);
}
}
#fullscreen { position: absolute; top:5%; left:88%;color:#ffffff; filter:drop-shadow( 1px 1px 1px #000000);font: normal 2.1em华文新魏; opacity: 0; cursor: pointer; z-index: 10}
#pa:hover #fullscreen{ color: #DC143C;opacity: 1;}
#vid1 {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
mix-blend-mode: screen;
-webkit-mask: linear-gradient(to right top, red 0%, transparent 90%, transparent);
opacity: 0.8;
object-fit: cover;
z-index: -1;
}
#vid2 {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
mix-blend-mode: screen;
-webkit-mask: radial-gradient(transparent 20%, red);
opacity: 0.8;
object-fit: cover;
z-index: -1;
}
</style>
<div id="pa">
<img id="player" src="https://cccimg.com/view.php/b40d9865baa914789669dbe9f4f2ee42.png" width="10%" title="播放/暂停" />
<audio id="aud" src="https://cccimg.com/view.php/e789ee539d15a3bac9ad56235ebf58b3.mp3" autoplay loop></audio>
<video id="vid1" src="https://video.699pic.com/videos/80/78/90/a_gXPEAH4VSuId1554807890_10s.mp4" loop muted></video>
<video id="vid2" src="https://bpic.588ku.com/video_listen/588ku_video/22/11/03/11/48/17/video63633a01b9973.mp4" loop muted></video>
<span id="fullscreen">全屏观赏</span>
</div>
<script type="module">
import * as THREE from "https://esm.sh/three";
import { OrbitControls } from "https://esm.sh/three/examples/jsm/controls/OrbitControls";
const aud = document.querySelector("#aud");
const player = document.querySelector("#player");
const pa = document.querySelector("#pa");
const vid1 = document.querySelector("#vid1");
const vid2 = document.querySelector("#vid2");
let w = pa.offsetWidth;
let h = pa.offsetHeight;
let raf;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, w / h, 0.001, 1000);
camera.position.set(0, 3, 24);
camera.lookAt(scene.position);
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(w, h);
renderer.setClearAlpha(0.1);
pa.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
const count1 = 50000;
const count2 = 100000;
const geometry = new THREE.BufferGeometry();
const positions = [];
const sizes = [];
const shifts = [];
for (let i = 0; i < count1 + count2; i++) {
let theta = Math.random() * Math.PI * 2;
let phi = Math.acos(Math.random() * 2 - 1);
let angle = (Math.random() * 0.9 + 0.1) * Math.PI * 0.1;
let strength = Math.random() * 0.9 + 0.1;
shifts.push(theta, phi, angle, strength);
let size = Math.random() * 1.5 + 0.5;
sizes.push(size);
if (i < count1) {
let r = Math.random() * 0.5 + 9.5;
let { x, y, z } = new THREE.Vector3()
.randomDirection()
.multiplyScalar(r);
positions.push(x, y, z);
} else {
let r = 10;
let R = 40;
let rand = Math.pow(Math.random(), 1.5);
let radius = Math.sqrt(R * R * rand + (1 - rand) * r * r);
let { x, y, z } = new THREE.Vector3().setFromCylindricalCoords(
radius,
Math.random() * 2 * Math.PI,
(Math.random() - 0.5) * 2
);
positions.push(x, y, z);
}
}
geometry.setAttribute(
"position",
new THREE.Float32BufferAttribute(positions, 3)
);
geometry.setAttribute("aSize", new THREE.Float32BufferAttribute(sizes, 1));
geometry.setAttribute("aShift", new THREE.Float32BufferAttribute(shifts, 4));
const vertexShader = `
attribute float aSize;
attribute vec4 aShift;
uniform float uTime;
varying vec3 vColor;
const float PI = 3.141592653589793238;
void main() {
float d = length(abs(position) / vec3(40., 10., 40.));
d = clamp(d, 0., 1.);
vec3 color1 = vec3(227., 155., 0.);
vec3 color2 = vec3(100., 50., 255.);
vColor = mix(color1, color2, d) / 255.;
vec3 transformed = position;
float theta = mod(aShift.x + aShift.z * uTime, PI * 2.);
float phi = mod(aShift.y + aShift.z * uTime, PI * 2.);
transformed += vec3(sin(phi) * cos(theta), cos(phi), sin(phi) * sin(theta)) * aShift.w;
vec4 mvPosition = modelViewMatrix * vec4(transformed, 1.0);
gl_PointSize = aSize * 50.0 / -mvPosition.z;
gl_Position = projectionMatrix * mvPosition;
}
`;
const fragmentShader = `
varying vec3 vColor;
void main() {
float d = length(gl_PointCoord.xy - 0.5);
if (d > 0.5) discard;
gl_FragColor = vec4(vColor, smoothstep(0.5, 0.1, d));
}
`;
const material = new THREE.ShaderMaterial({
vertexShader,
fragmentShader,
uniforms: {
uTime: { value: 0 },
},
transparent: true,
blending: THREE.AdditiveBlending,
depthTest: false,
});
const mesh = new THREE.Points(geometry, material);
mesh.rotation.order = "ZYX";
mesh.rotation.z = 0.2;
scene.add(mesh);
let clock = new THREE.Clock();
function render() {
let time = clock.getElapsedTime();
mesh.rotation.y = time * 0.01;
material.uniforms.uTime.value = time;
renderer.render(scene, camera);
controls.update();
raf = requestAnimationFrame(render);
}
function resize() {
w = pa.offsetWidth;
h = pa.offsetHeight;
renderer.setSize(w, h);
camera.aspect = w / h;
camera.updateProjectionMatrix();
}
function mState() {
if (aud.paused) {
cancelAnimationFrame(raf);
pa.style.setProperty("--state", "paused");
vid1.pause();
vid2.pause();
} else {
render();
pa.style.setProperty("--state", "running");
vid1.play().catch(e => console.error('Error playing video 1:', e));
vid2.play().catch(e => console.error('Error playing video 2:', e));
}
}
function play() {
aud.paused ? aud.play().catch(e => console.error('Error playing audio:', e)) : aud.pause();
}
aud.addEventListener("playing", mState);
aud.addEventListener("pause", mState);
window.addEventListener("resize", resize);
player.addEventListener("click", play);
let fs = true;
fullscreen.onclick = () => {
fs ? (fullscreen.innerText = '退出全屏',pa.requestFullscreen()) : (fullscreen.innerText = '全屏欣赏', document.exitFullscreen());
fs = !fs;
};
</script>
</body>
</html>
这背景图也是黑黑的?哦,杨帆加了视频,更漂亮了{:4_187:} 欣赏杨帆好帖{:4_187:} 佳作欣赏,祝五一节快乐!{:4_199:} 红影 发表于 2025-4-30 20:12
这背景图也是黑黑的?哦,杨帆加了视频,更漂亮了
是的,特喜欢马老师的大佬级分享,祝五一快乐{:4_204:} 梦江南 发表于 2025-5-1 10:09
佳作欣赏,祝五一节快乐!
欢迎江南观赏,祝五一快乐{:4_187:} 杨帆 发表于 2025-5-1 14:36
是的,特喜欢马老师的大佬级分享,祝五一快乐
谢谢扬帆,也祝你节日快乐{:4_187:} 问好杨帆,你把全屏欣赏去了就可惜了,这个宇宙效果最让人震撼的就是全屏欣赏 小辣椒 发表于 2025-5-1 16:38
问好杨帆,你把全屏欣赏去了就可惜了,这个宇宙效果最让人震撼的就是全屏欣赏
谢谢小辣椒,幸好可以加上。祝五一快乐{:4_187:}
页:
[1]