更多有趣示例 尽在 小红砖社区
示例
HTML
<div id="universe"/>
<footer>
<a target="_blank" href="https://www.made-on-mars.com"><svg id="Calque_logo2" data-name="Calque logo2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 1306.42"><defs><style>.cls-logo2{fill:#ffffff;}</style></defs><path class="cls-logo2" d="M2043.47,2428a39,39,0,1,0,23.28,8.1c55.42,11,96.65,60.62,96.65,117.45a120,120,0,0,1-119.93,119.91,118.29,118.29,0,0,1-48.7-10.47v-359.6a38.92,38.92,0,0,0-38.87-38.87h-87.24v-32a38.92,38.92,0,0,0-38.87-38.87h-87.18v-27.75a38.92,38.92,0,0,0-38.87-38.87H1638.8a69.8,69.8,0,0,0,0,139.6,16.78,16.78,0,1,0-16.76-16.76,16.6,16.6,0,0,0,3,9.51,64.08,64.08,0,0,1,13.8-126.67,27,27,0,0,1,27,27v343.09a38.92,38.92,0,0,0,38.87,38.87h37.94V2199.38h22.23a27,27,0,0,1,27,27v276.43a38.92,38.92,0,0,0,38.87,38.87h37.94V2270.23h22.27a27,27,0,0,1,27,27v256.37A125.53,125.53,0,1,0,2043.47,2428Z" transform="translate(-1569 -2127.04)"></path><path class="cls-logo2" d="M2128.54,2873.92V3393H1609.46V2873.92h519.08m40.46-40.46H1569v600h600v-600Z" transform="translate(-1569 -2127.04)"></path><path class="cls-logo2" d="M1794.74,3133.7a44.44,44.44,0,0,1-2.74,15.88,36.33,36.33,0,0,1-7.74,12.43,34.6,34.6,0,0,1-12,8.09,43.16,43.16,0,0,1-31,0,34.73,34.73,0,0,1-12-8.09,36.33,36.33,0,0,1-7.74-12.43,47.39,47.39,0,0,1,0-31.75,36.67,36.67,0,0,1,7.74-12.47,34.69,34.69,0,0,1,12-8.13,42.72,42.72,0,0,1,31,0,34.55,34.55,0,0,1,12,8.13,36.67,36.67,0,0,1,7.74,12.47A44.48,44.48,0,0,1,1794.74,3133.7Zm-10.69,0a39.07,39.07,0,0,0-1.93-12.73,26.83,26.83,0,0,0-5.48-9.54,23.65,23.65,0,0,0-8.59-6,31.24,31.24,0,0,0-22.51,0,24,24,0,0,0-8.62,6,26.65,26.65,0,0,0-5.51,9.54,42.85,42.85,0,0,0,0,25.44,26.69,26.69,0,0,0,5.51,9.51,23.8,23.8,0,0,0,8.62,6,31.68,31.68,0,0,0,22.51,0,23.48,23.48,0,0,0,8.59-6,26.87,26.87,0,0,0,5.48-9.51A38.86,38.86,0,0,0,1784,3133.7Z" transform="translate(-1569 -2127.04)"></path><path class="cls-logo2" d="M1816.42,3095.52A5.55,5.55,0,0,1,1818,3097l44.59,58c-.1-.93-.18-1.84-.22-2.72s-.05-1.73-.05-2.55v-54.54h9.13v77h-5.27a4.52,4.52,0,0,1-2.07-.43,5.12,5.12,0,0,1-1.64-1.45l-44.54-58c.07.9.12,1.77.16,2.63s.06,1.65.06,2.36v54.86H1809v-77h5.37A4.71,4.71,0,0,1,1816.42,3095.52Z" transform="translate(-1569 -2127.04)"></path><path class="cls-logo2" d="M1759.12,3038.25c.36-1,28.53-53,28.53-53a3.1,3.1,0,0,1,1.45-1.5,6.66,6.66,0,0,1,2.15-.27h7.69v77h-9.13v-56.57c0-.76,0-1.56.05-2.42s.09-1.73.16-2.63L1763.63,3047a4.15,4.15,0,0,1-3.76,2.41h-1.51a4.14,4.14,0,0,1-3.76-2.41l-27-48.3c.11.93.19,1.85.24,2.74s.08,1.72.08,2.48v56.57h-9.13v-77h7.68a6.69,6.69,0,0,1,2.15.27,3.12,3.12,0,0,1,1.45,1.5S1758.76,3037.29,1759.12,3038.25Z" transform="translate(-1569 -2127.04)"></path><path class="cls-logo2" d="M1881,3060.5H1873a3.42,3.42,0,0,1-2.26-.7,4.16,4.16,0,0,1-1.29-1.77l-7.2-18.58h-34.55l-7.2,18.58a4.13,4.13,0,0,1-1.29,1.72,3.42,3.42,0,0,1-2.26.76h-8.06l30.79-77h10.58Zm-50.45-28.58h28.75l-12.09-31.32a59.28,59.28,0,0,1-2.31-7.25q-.59,2.2-1.15,4.06c-.37,1.23-.74,2.32-1.1,3.24Z" transform="translate(-1569 -2127.04)"></path><path class="cls-logo2" d="M1957.48,3022a43.32,43.32,0,0,1-2.74,15.74,34.84,34.84,0,0,1-7.74,12.14,34.37,34.37,0,0,1-12,7.82,41.65,41.65,0,0,1-15.48,2.77h-28.79v-77h28.79a41.65,41.65,0,0,1,15.48,2.77,34.42,34.42,0,0,1,12,7.84,35.27,35.27,0,0,1,7.74,12.17A43.36,43.36,0,0,1,1957.48,3022Zm-10.69,0a38.61,38.61,0,0,0-1.94-12.68,26.55,26.55,0,0,0-5.48-9.45,23.44,23.44,0,0,0-8.59-5.92,29.88,29.88,0,0,0-11.23-2h-18.32v60.12h18.32a29.88,29.88,0,0,0,11.23-2,23.62,23.62,0,0,0,8.59-5.89,26.36,26.36,0,0,0,5.48-9.43A38.57,38.57,0,0,0,1946.79,3022Z" transform="translate(-1569 -2127.04)"></path><path class="cls-logo2" d="M2019.11,2983.51V2992h-37v25.57h29.92v8.16h-29.92V3052h37v8.49h-47.44v-77Z" transform="translate(-1569 -2127.04)"></path><path class="cls-logo2" d="M1759.12,3260.68c.36-1,28.53-53,28.53-53a3.1,3.1,0,0,1,1.45-1.5,6.66,6.66,0,0,1,2.15-.27h7.69v77h-9.13v-56.57c0-.76,0-1.56.05-2.42s.09-1.73.16-2.63l-26.38,48.14a4.15,4.15,0,0,1-3.76,2.41h-1.51a4.14,4.14,0,0,1-3.76-2.41l-27-48.3c.11.93.19,1.85.24,2.74s.08,1.72.08,2.48v56.57h-9.13v-77h7.68a6.69,6.69,0,0,1,2.15.27,3.12,3.12,0,0,1,1.45,1.5S1758.76,3259.72,1759.12,3260.68Z" transform="translate(-1569 -2127.04)"></path><path class="cls-logo2" d="M1881,3282.93H1873a3.42,3.42,0,0,1-2.26-.7,4.16,4.16,0,0,1-1.29-1.77l-7.2-18.58h-34.55l-7.2,18.58a4.13,4.13,0,0,1-1.29,1.72,3.42,3.42,0,0,1-2.26.76h-8.06l30.79-77h10.58Zm-50.45-28.58h28.75L1847.24,3223a59.28,59.28,0,0,1-2.31-7.25q-.59,2.2-1.15,4.06c-.37,1.23-.74,2.32-1.1,3.24Z" transform="translate(-1569 -2127.04)"></path><path class="cls-logo2" d="M1902.2,3250.8v32.13h-10.37v-77h21.76a47.48,47.48,0,0,1,12.62,1.48,24,24,0,0,1,8.78,4.27,17.05,17.05,0,0,1,5.13,6.74,22.53,22.53,0,0,1,1.67,8.85,22.18,22.18,0,0,1-1.29,7.63,20.11,20.11,0,0,1-3.74,6.36,22.29,22.29,0,0,1-6,4.82,29.37,29.37,0,0,1-8,3,11,11,0,0,1,3.44,3.28l22.46,30.57h-9.24a4.55,4.55,0,0,1-4.19-2.2l-20-27.5a5.86,5.86,0,0,0-2-1.86,7.16,7.16,0,0,0-3.23-.57Zm0-7.58h10.91a26.51,26.51,0,0,0,8-1.1,16.32,16.32,0,0,0,5.8-3.12,12.87,12.87,0,0,0,3.52-4.81,15.71,15.71,0,0,0,1.18-6.18q0-6.88-4.54-10.37t-13.51-3.49H1902.2Z" transform="translate(-1569 -2127.04)"></path><path class="cls-logo2" d="M1999.39,3218a4.09,4.09,0,0,1-1,1.21,2.24,2.24,0,0,1-1.4.41,3.66,3.66,0,0,1-2.12-.92,34.71,34.71,0,0,0-3.06-2,26.49,26.49,0,0,0-4.46-2,19.19,19.19,0,0,0-6.31-.91,18.61,18.61,0,0,0-6.18.94,13.28,13.28,0,0,0-4.49,2.55,10.53,10.53,0,0,0-2.71,3.79,12,12,0,0,0-.91,4.7,8.72,8.72,0,0,0,1.58,5.35,13.52,13.52,0,0,0,4.19,3.62,31.77,31.77,0,0,0,5.91,2.61q3.31,1.1,6.77,2.28t6.77,2.67a23.9,23.9,0,0,1,5.91,3.73,17.2,17.2,0,0,1,4.19,5.54,18.43,18.43,0,0,1,1.58,8.06,25.86,25.86,0,0,1-1.72,9.48,21.77,21.77,0,0,1-5,7.71,23.68,23.68,0,0,1-8.11,5.16,30,30,0,0,1-10.93,1.88,33.27,33.27,0,0,1-13.62-2.72,31.81,31.81,0,0,1-10.5-7.34l3-4.94a3.92,3.92,0,0,1,1-1,2.41,2.41,0,0,1,1.37-.41,4.29,4.29,0,0,1,2.58,1.22,43.78,43.78,0,0,0,3.63,2.65,27.29,27.29,0,0,0,5.26,2.65,20.73,20.73,0,0,0,7.55,1.22,19.83,19.83,0,0,0,6.61-1,13.9,13.9,0,0,0,4.92-2.88,12.31,12.31,0,0,0,3.09-4.43,14.76,14.76,0,0,0,1.08-5.75,9.66,9.66,0,0,0-1.58-5.72,13.16,13.16,0,0,0-4.16-3.74,29.17,29.17,0,0,0-5.89-2.55l-6.77-2.15a69,69,0,0,1-6.77-2.55,22,22,0,0,1-5.89-3.77,17.21,17.21,0,0,1-4.16-5.77,20.51,20.51,0,0,1-1.58-8.57,20.53,20.53,0,0,1,6.18-14.66,22.3,22.3,0,0,1,7.45-4.73,27.17,27.17,0,0,1,10.18-1.77,32.54,32.54,0,0,1,11.77,2,26.92,26.92,0,0,1,9.29,5.91Z" transform="translate(-1569 -2127.04)"></path></svg></a>
</footer>
CSS
html, body {
height:100%;
width:100%;
margin:0;
padding:0;
overflow:hidden;
}
body {
background: linear-gradient(180deg, #373773, #235689, #2a9096, #364a7b, #4a367b, #5e3665, #2c294b, #31437a);
background-size: 1600% 1600%;
-webkit-animation: skygradient 180s ease infinite;
-moz-animation: skygradient 180s ease infinite;
-o-animation: skygradient 180s ease infinite;
animation: skygradient 180s ease infinite;
}
@-webkit-keyframes skygradient {
0%{background-position:50% 0%}
50%{background-position:50% 100%}
100%{background-position:50% 0%}
}
@-moz-keyframes skygradient {
0%{background-position:50% 0%}
50%{background-position:50% 100%}
100%{background-position:50% 0%}
}
@-o-keyframes skygradient {
0%{background-position:50% 0%}
50%{background-position:50% 100%}
100%{background-position:50% 0%}
}
@keyframes skygradient {
0%{background-position:50% 0%}
50%{background-position:50% 100%}
100%{background-position:50% 0%}
}
canvas {
width: 100%!important; height: 100%!important;
}
footer {
position:fixed;
z-index:1000;
left:0;
bottom:0;
display:block;
padding:20px;
box-sizing:border-box;
}
footer a {
text-decoration:none;
display:block;
width:50px;
}
footer a svg {
width:100%;
max-width:50px;
min-width:40px;
display:inline-block;
}
JS
function getMat(color){
// our material is a phong material, with no shininess (highlight) and a black specular
return new THREE.MeshStandardMaterial({
color:color,
roughness:.9,
transparent: true,
opacity: 0,
emissive:0x270000,
shading:THREE.FlatShading
});
}
var Colors = {
red : 0xf85051,
orange: 0xea8962,
yellow: 0xdacf75,
beige: 0xccc58f,
grey: 0xbab7a1,
blue: 0x4379a8,
ocean: 0x4993a8,
green: 0x24a99b
};
var colorsLength = Object.keys(Colors).length;
function randomRange(min,max) {
return Math.floor(Math.random()*(max-min+1)+min);
}
function getRandomColor(){
var colIndx = Math.floor(Math.random()*colorsLength);
var colorStr = Object.keys(Colors)[colIndx];
return Colors[colorStr];
}
function shiftPosition(pos, radius){
if(Math.abs(pos) < radius){
if(pos >= 0){
return pos + radius;
} else {
return pos - radius;
}
} else {
return pos;
}
}
// Default parameters
var parameters = {
minRadius : 30,
maxRadius : 50,
minSpeed:.015,
maxSpeed:.025,
particles:500,
minSize:.1,
maxSize:2
};
// For a THREEJS project we need at least
// a scene
// a renderer
// a camera
// a light (1 or many)
// a mesh (an object to display)
var scene, renderer, camera, light;
var stars = [];
var nbPlanetsMax = 4;
var planets = [];
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
// initialise the world
function initWorld(){
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, WIDTH/HEIGHT, .1, 2000);
camera.position.z = 100;
//
// THE RENDERER
//
renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true
});
renderer.setSize(WIDTH, HEIGHT);
renderer.shadowMap.enabled = true;
container = document.getElementById('universe');
container.appendChild(renderer.domElement);
// Lights
ambientLight = new THREE.AmbientLight(0x663344,2);
scene.add(ambientLight);
light = new THREE.DirectionalLight(0xffffff, 1.5);
light.position.set(200,100,200);
light.castShadow = true;
light.shadow.camera.left = -400;
light.shadow.camera.right = 400;
light.shadow.camera.top = 400;
light.shadow.camera.bottom = -400;
light.shadow.camera.near = 1;
light.shadow.camera.far = 1000;
light.shadow.mapSize.width = 2048;
light.shadow.mapSize.height = 2048;
scene.add(light);
//
// HANDLE SCREEN RESIZE
//
window.addEventListener('resize', handleWindowResize, false);
// Creating firts planets
for(var i = 0; i < nbPlanetsMax; i++){
planets.push(new Planet(-2000/nbPlanetsMax * i - 500));
}
addStarts();
loop();
}
function animateStars(z) {
// loop through each star
for(var i=0; i<stars.length; i++) {
star = stars[i];
// if the particle is too close move it to the back
if(star.position.z>z) star.position.z-=2000;
}
}
function addStarts(){
for ( var z= -2000; z < 0; z+=20 ) {
var geometry = new THREE.SphereGeometry(0.5, 32, 32)
var material = new THREE.MeshBasicMaterial( {color: 0xffffff} );
var sphere = new THREE.Mesh(geometry, material)
sphere.position.x = randomRange(-1 * Math.floor(WIDTH/2),Math.floor(WIDTH/2));
sphere.position.y = randomRange(-1 * Math.floor(HEIGHT/2),Math.floor(HEIGHT/2));
// Then set the z position to where it is in the loop (distance of camera)
sphere.position.z = z;
// scale it up a bit
sphere.scale.x = sphere.scale.y = 2;
//add the sphere to the scene
scene.add( sphere );
//finally push it to the stars array
stars.push(sphere);
}
}
var Planet = function(z){
// the geometry of the planet is a tetrahedron
this.planetRadius = randomRange(12,30);
var planetDetail = randomRange(2,3);
var geomPlanet = new THREE.TetrahedronGeometry(this.planetRadius, planetDetail);
var noise = randomRange(1,5);
for(var i=0; i<geomPlanet.vertices.length; i++){
var v = geomPlanet.vertices[i];
v.x += -noise/2 + Math.random()*noise;
v.y += -noise/2 + Math.random()*noise;
v.z += -noise/2 + Math.random()*noise;
}
// create a new material for the planet
var color = getRandomColor();
var matPlanet = getMat(color);
// create the mesh of the planet
this.planet = new THREE.Mesh(geomPlanet, matPlanet);
this.ring = new THREE.Mesh();
this.nParticles = 0;
// create the particles to populate the ring
this.updateParticlesCount();
// Create a global mesh to hold the planet and the ring
this.mesh = new THREE.Object3D();
this.mesh.add(this.planet);
this.mesh.add(this.ring);
this.planet.castShadow = true;
this.planet.receiveShadow = true;
// update the position of the particles => must be moved to the loop
this.mesh.rotation.x = (Math.random()*2-1) * 2 * Math.PI;
this.mesh.rotation.z = (Math.random()*2-1) * 2 * Math.PI;
var posX = randomRange(-1 * Math.floor(WIDTH/4),Math.floor(WIDTH/4));
var posY = randomRange(-1 * Math.floor(HEIGHT/4),Math.floor(HEIGHT/4));
posX = shiftPosition(posX, this.planetRadius);
posY = shiftPosition(posY, this.planetRadius);
this.mesh.position.set(posX,posY,z);
scene.add(this.mesh);
}
Planet.prototype.destroy = function(){
scene.remove( this.mesh );
}
Planet.prototype.updateParticlesCount = function(){
var parameters = {
minRadius : randomRange(this.planetRadius + 10 , 60),
maxRadius : randomRange(40,70),
minSpeed: randomRange(0,5)*0.1 + randomRange(0,9) * 0.01,
maxSpeed: randomRange(0,5)*0.1 + randomRange(0,9) * 0.01,
particles: randomRange(0,1) * randomRange(20,30),
minSize: randomRange(1,3) + randomRange(0,9) * 0.1,
maxSize: randomRange(1,3) + randomRange(0,9) * 0.1
};
if (this.nParticles < parameters.particles){
// Remove particles
for (var i=this.nParticles; i< parameters.particles; i++){
var p = new Particle();
p.mesh.rotation.x = Math.random()*Math.PI;
p.mesh.rotation.y = Math.random()*Math.PI;
p.mesh.position.y = -2 + Math.random()*4;
this.ring.add(p.mesh);
}
}else{
// add particles
while(this.nParticles > parameters.particles){
var m = this.ring.children[this.nParticles-1];
this.ring.remove(m);
m.userData.po = null;
this.nParticles--;
}
}
this.nParticles = parameters.particles;
// We will give a specific angle to each particle
// to cover the whole ring we need to
// dispatch them regularly
this.angleStep = Math.PI*2/this.nParticles;
this.updateParticlesDefiniton();
}
// Update particles definition
Planet.prototype.updateParticlesDefiniton = function(){
for(var i=0; i<this.nParticles; i++){
var m = this.ring.children[i];
var s = parameters.minSize + Math.random()*(parameters.maxSize - parameters.minSize);
m.scale.set(s,s,s);
// set a random distance
m.userData.distance = parameters.minRadius + Math.random()*(parameters.maxRadius-parameters.minRadius);
// give a unique angle to each particle
m.userData.angle = this.angleStep*i;
// set a speed proportionally to the distance
m.userData.angularSpeed = rule3(m.userData.distance,parameters.minRadius,parameters.maxRadius,parameters.minSpeed, parameters.maxSpeed);
}
}
var Particle = function(){
// Size of the particle, make it random
var s = 1;
// geometry of the particle, choose between different shapes
var geom,
random = Math.random();
if (random<.25){
// Cube
geom = new THREE.BoxGeometry(s,s,s);
}else if (random < .5){
// Pyramid
geom = new THREE.CylinderGeometry(0,s,s*2, 4, 1);
}else if (random < .75){
// potato shape
geom = new THREE.TetrahedronGeometry(s,2);
}else{
// thick plane
geom = new THREE.BoxGeometry(s/6,s,s); // thick plane
}
// color of the particle, make it random and get a material
var color = getRandomColor();
var mat = getMat(color);
// create the mesh of the particle
this.mesh = new THREE.Mesh(geom, mat);
this.mesh.receiveShadow = true;
this.mesh.castShadow = true;
this.mesh.userData.po = this;
}
// Update particles position
Planet.prototype.updateParticlesRotation = function(){
// increase the rotation of each particle
// and update its position
for(var i=0; i<this.nParticles; i++){
var m = this.ring.children[i];
// increase the rotation angle around the planet
m.userData.angle += m.userData.angularSpeed;
// calculate the new position
var posX = Math.cos(m.userData.angle)*m.userData.distance;
var posZ = Math.sin(m.userData.angle)*m.userData.distance;
m.position.x = posX;
m.position.z = posZ;
//*
// add a local rotation to the particle
m.rotation.x += Math.random()*.05;
m.rotation.y += Math.random()*.05;
m.rotation.z += Math.random()*.05;
//*/
}
}
function addPlanet(z){
planets.push(new Planet(z));
}
function loop(){
var horizon = - 2000 + camera.position.z;
for(var i = 0; i < planets.length; i++){
if(planets[i].mesh.position.z > camera.position.z){
planets[i].destroy();
planets.splice(i, 1);
}
// If the planet is arriving
if(planets[i].mesh.position.z > horizon && planets[i].planet.material.opacity < 1){
planets[i].planet.material.opacity += 0.005;
for(var j=0; j< planets[i].mesh.children[1].children.length; j++){
planets[i].mesh.children[1].children[j].material.opacity += 0.005;
}
}
}
// Adding stars
animateStars(camera.position.z);
if(planets.length < nbPlanetsMax){
addPlanet(camera.position.z - 2000);
}
for(var i = 0; i < planets.length; i++){
planets[i].planet.rotation.y-= 0.01;
planets[i].updateParticlesRotation();
}
camera.position.z -= 3;
//
// RENDER !
//
renderer.render(scene, camera);
//
// REQUEST A NEW FRAME
//
requestAnimationFrame(loop);
}
function handleWindowResize() {
// Recalculate Width and Height as they had changed
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
// Update the renderer and the camera
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
}
initWorld();
function rule3(v,vmin,vmax,tmin, tmax){
var nv = Math.max(Math.min(v,vmax), vmin);
var dv = vmax-vmin;
var pc = (nv-vmin)/dv;
var dt = tmax-tmin;
var tv = tmin + (pc*dt);
return tv;
}