This commit is contained in:
Morten Olsen
2021-08-26 14:40:51 +02:00
parent 315fb5721c
commit 0cc7078b1b
21 changed files with 4051 additions and 109 deletions

View File

@@ -1,96 +1,131 @@
// https://redstapler.co/cool-nebula-background-effect-three-js/
import * as THREE from 'three';
import React, { useEffect } from 'react';
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import React, { useEffect, useMemo, useState } from 'react';
const setup = () => {
let scene, camera, renderer;
let cloudParticles = [];
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60,window.innerWidth / window.innerHeight,1,1000);
camera.position.z = 1;
camera.rotation.x = 1.16;
camera.rotation.y = -0.12;
camera.rotation.z = 0.27;
let ambient = new THREE.AmbientLight(0x555555);
scene.add(ambient);
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
scene.fog = new THREE.FogExp2(0x03544e, 0.001);
renderer.setClearColor(scene.fog.color);
renderer.domElement.style.position = 'fixed';
renderer.domElement.style.top = '0';
renderer.domElement.style.left = '0';
renderer.domElement.style.width = '100%';
renderer.domElement.style.height = '100%';
renderer.domElement.style.zIndex = -1;
renderer.domElement.style.opacity = 1;
document.body.appendChild(renderer.domElement);
addParticles();
addLights();
render();
}
const addParticles = () => {
let loader = new THREE.TextureLoader();
loader.load("/images/smoke.png", (texture) => {
const cloudGeo = new THREE.PlaneBufferGeometry(500,500);
const cloudMaterial = new THREE.MeshLambertMaterial({
map:texture,
transparent: true
});
for(let p=0; p<50; p++) {
let cloud = new THREE.Mesh(cloudGeo, cloudMaterial);
cloud.position.set(
Math.random()*800 -400,
500,
Math.random()*500-500
);
cloud.rotation.x = 1.16;
cloud.rotation.y = -0.12;
cloud.rotation.z = Math.random()*2*Math.PI;
cloud.material.opacity = 0.55;
cloudParticles.push(cloud);
scene.add(cloud);
}
});
}
const addLights = () => {
let directionalLight = new THREE.DirectionalLight(0xff8c19);
directionalLight.position.set(0,0,1);
scene.add(directionalLight);
let orangeLight = new THREE.PointLight(0xcc6600,50,450,1.7);
orangeLight.position.set(200,300,100);
scene.add(orangeLight);
let redLight = new THREE.PointLight(0xd8547e,50,450,1.7);
redLight.position.set(100,300,100);
scene.add(redLight);
let blueLight = new THREE.PointLight(0x3677ac,50,450,1.7);
blueLight.position.set(300,300,200);
scene.add(blueLight);
interface CloudProps {
texture: THREE.Texture;
position: [number, number, number];
rotation: {
x: number;
y: number;
z: number;
};
}
function render() {
cloudParticles.forEach(p => {
p.rotation.z -=0.001;
});
renderer.render(scene,camera);
requestAnimationFrame(render);
}
const initialClouds = new Array(30).fill(undefined).map((_, i) => ({
name: `id_${i}`,
position: [
Math.random() * 800 - 400,
500,
Math.random() * 500 - 500,
] as [number, number, number],
rotation: {
x: 1.16,
y: -0.12,
z: Math.random() * 2 * Math.PI,
},
}));
init();
const Cloud: React.FC<CloudProps> = ({ texture, position, rotation }) => {
return (
<mesh position={position} rotation={[ rotation.x, rotation.y, rotation.z ]}>
<planeBufferGeometry args={[500, 500]} />
<meshLambertMaterial opacity={.5} map={texture} transparent={true} />
</mesh>
);
};
const Background: React.FC<{}> = () => {
const Clouds: React.FC<{}> = () => {
const { camera } = useThree();
const loader = useMemo(() => new THREE.TextureLoader(), []);
const [texture, setTexture] = useState<THREE.Texture | undefined>();
const [clouds, setClouds] = useState(initialClouds);
useEffect(() => {
setup();
console.log(camera);
camera.rotateX(1.16);
camera.rotateY(-0.12);
camera.rotateZ(0.27);
}, []);
return <></>
useEffect(() => {
loader.load('images/smoke.png', (loadedTexture) => {
setTexture(loadedTexture);
});
}, []);
useFrame(() => {
setClouds(current => current.map(c => ({
...c,
rotation: {
...c.rotation,
z: c.rotation.z -= 0.001,
}
})));
});
if (!texture) {
return <></>;
}
return (
<>
{clouds.map((cloud) => (
<Cloud
key={cloud.name}
texture={texture}
position={cloud.position}
rotation={cloud.rotation}
/>
))}
</>
)
}
const style = {
width: '100%',
height: '100%',
top: 0,
left: 0,
position: 'fixed' as any,
zIndex: -1,
}
const Background: React.FC<{}> = () => {
const fog = useMemo(() => new THREE.FogExp2(0x03544e, 0.001), []);
const [aspect, setAspect] = useState(global.window ? window.innerWidth / window.innerHeight : 1);
if (!global.window) {
return <Canvas style={style}><></></Canvas>
}
useEffect(() => {
const update = () => {
setAspect(window.innerWidth / window.innerHeight);
};
window.addEventListener('resize', update);
return () => {
window.removeEventListener('resize', update);
}
}, []);
return (
<Canvas style={style}>
<color attach="background" args={[0x03544e]} />
<scene fog={fog}>
<perspectiveCamera
args={[60, aspect, 1, 1000]}
aspect={aspect}
position={[0, 0, 0]}
/>
<ambientLight args={[0x555555]} />
<directionalLight args={[0xff8c19]} position={[0,0,1]} />
<pointLight args={[0xcc6600, 50, 450, 1.7]} position={[200,300,100]} />
<pointLight args={[0xd8547e, 50, 450, 1.7]} position={[100,300,100]} />
<pointLight args={[0x3677ac, 50, 450, 1.7]} position={[300,300,200]} />
<Clouds />
</scene>
</Canvas>
);
};
export default Background;

View File

@@ -1,28 +1,24 @@
import React from 'react';
import styled from 'styled-components';
import Image from 'next/image'
import image from '../public/images/me.jpg';
const Wrapper = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px;
padding: 80px;
`;
const ImageWrapper = styled.div`
border-radius: 50%;
border: solid 15px rgba(255, 255, 255, .5);
box-shadow: 0 0 15px rgba(0, 0, 0, .5);
border: solid 30px rgba(255, 255, 255, .5);
box-shadow: 0 0 35px rgba(255, 255, 255, .5);
overflow: hidden;
margin: 0 40px;
width: 100%;
max-width: 360px;
`;
const Image = styled.div<{ src: string }>`
width: 100%;
background: url('${({ src }) => src}');
background-size: cover;
position: relative;
`;
const Spacer = styled.div`
@@ -31,6 +27,7 @@ const Spacer = styled.div`
const Title = styled.h1`
text-transform: uppercase;
text-align: center;
color: #fff;
font-size: 28px;
font-family: 'Source Code Pro', monospace;
@@ -42,6 +39,7 @@ const Title = styled.h1`
const SubTitle = styled.h2`
text-transform: uppercase;
text-align: center;
color: #fff;
font-size: 14px;
font-family: 'Source Code Pro', monospace;
@@ -62,12 +60,11 @@ const Divider = styled.div`
const Me: React.FC<{}> = () => (
<Wrapper>
<ImageWrapper>
<Image src="/images/me.jpg">
<Spacer />
</Image>
<Image layout="fill" {...image} />
<Spacer />
</ImageWrapper>
<Title>Morten Olsen</Title>
<SubTitle>...One part genius, on part crazy</SubTitle>
<SubTitle>...One part genius, one part crazy</SubTitle>
<Divider />
</Wrapper>
);

View File

@@ -5,7 +5,7 @@ interface Props {
sites: {
title: string,
link: string,
logo: string,
logo: any,
}[];
}
@@ -75,7 +75,7 @@ const Social: React.FC<Props> = ({ sites }) => (
{sites.map(({ title, link, logo }) => (
<ItemWrapper target="_blank" href={link} key={link}>
<InnerWrapper>
<Image src={`/images/logos/${logo}`} />
<Image src={logo.src} />
{title}
</InnerWrapper>
</ItemWrapper>