Rewrite hole so that the background can appear through it
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m17s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m17s
This commit is contained in:
parent
d4d1e112fe
commit
e8e6e12450
5 changed files with 122 additions and 51 deletions
|
@ -1,21 +1,25 @@
|
|||
<template>
|
||||
<TresGroup ref="groupRef" v-if="renderer">
|
||||
<TresMesh v-for="i in rows * cols" :position="[((i % cols) - cols / 2) * 304, (Math.floor((i - 1) / cols) - rows / 2) * 304, 0]" >
|
||||
<TresGroup ref="groupRef" v-if="renderer" :renderOrder="1">
|
||||
<TresMesh v-for="i in rows * cols" :position="[((i % cols) - cols / 2) * 304, (Math.floor((i - 1) / cols) - rows / 2) * 304, 1]">
|
||||
<TresShapeGeometry :args="[shapes]" />
|
||||
<TresShaderMaterial :vertexShader="vertexShader" :fragmentShader="fragmentShader" :uniforms="uniforms" :blending="AdditiveBlending" />
|
||||
<TresShaderMaterial :vertexShader="vertexShader" :fragmentShader="fragmentShader" :uniforms="uniforms" :blending="AdditiveBlending" :stencilWrite="mask != null" :stencilRef="mask ?? 0" :stencilFunc="EqualStencilFunc" :stencilFail="KeepStencilOp" :stencilZFail="KeepStencilOp" :stencilZPass="KeepStencilOp" />
|
||||
</TresMesh>
|
||||
</TresGroup>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useLoader, useRenderLoop, useTresContext } from '@tresjs/core';
|
||||
import { AdditiveBlending, Group, Vector2 } from "three";
|
||||
import { AdditiveBlending, EqualStencilFunc, Group, KeepStencilOp, Vector2, Vector3 } from "three";
|
||||
import { SVGLoader } from "three/examples/jsm/loaders/SVGLoader.js";
|
||||
import { computed, onMounted, onUnmounted, ref, shallowRef } from "vue";
|
||||
import noise from "./noise.glsl?raw";
|
||||
|
||||
const { renderer, sizes } = useTresContext();
|
||||
|
||||
const props = defineProps<{
|
||||
mask?: number;
|
||||
}>();
|
||||
|
||||
// Load SVG
|
||||
const { paths } = await useLoader(SVGLoader, '/circuit-board.svg');
|
||||
const shapes = paths.map(path => SVGLoader.createShapes(path)).reduce((acc, curr) => [...acc, ...curr]);
|
||||
|
@ -26,7 +30,8 @@ const cols = computed(() => Math.ceil(sizes.width.value / 304));
|
|||
// Handle mouse position
|
||||
const mousePos = ref(new Vector2(Infinity, Infinity));
|
||||
function updateMousePos(event: MouseEvent) {
|
||||
mousePos.value = new Vector2(event.screenX, window.screen.availHeight - event.screenY);
|
||||
const {x, y, height} = renderer.value.domElement.getBoundingClientRect();
|
||||
mousePos.value = new Vector2(event.screenX - x, height + y + (window.outerHeight - window.innerHeight) - event.screenY);
|
||||
if (groupRef.value) {
|
||||
groupRef.value.children.forEach(child => {
|
||||
child.material.uniforms.uMouse.value = mousePos.value;
|
||||
|
@ -54,10 +59,20 @@ onUnmounted(() => {
|
|||
window.removeEventListener("mouseout", handleMouseLeave);
|
||||
});
|
||||
|
||||
const { onLoop } = useRenderLoop();
|
||||
onLoop(({ elapsed }) => {
|
||||
if (groupRef.value) {
|
||||
groupRef.value.children.forEach(child => {
|
||||
child.material.uniforms.uTime.value = elapsed;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Shaders
|
||||
const groupRef = shallowRef<Group | null>(null);
|
||||
|
||||
const uniforms = {
|
||||
uColor: computed(() => props.mask == null ? new Vector3() : new Vector3(0.23, 0.26, 0.32)),
|
||||
uTime: { value: 0 },
|
||||
uMouse: { value: new Vector2(Infinity, Infinity) }
|
||||
}
|
||||
|
@ -72,26 +87,19 @@ void main() {
|
|||
vUv = uv;
|
||||
}
|
||||
`;
|
||||
const fragmentShader = noise + `
|
||||
const fragmentShader = `
|
||||
${noise}
|
||||
precision mediump float;
|
||||
uniform float uTime;
|
||||
uniform vec2 uMouse;
|
||||
uniform vec3 uColor;
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
float dist = distance(gl_FragCoord.xy, uMouse);
|
||||
float alpha = max(0., 1. - dist / 304.);
|
||||
alpha += max(0., snoise(vec3(gl_FragCoord.xy / 304., uTime / 4.)));
|
||||
gl_FragColor = vec4(0, 0, 0, alpha);
|
||||
gl_FragColor = vec4(mix(uColor, vec3(0.), alpha), uColor == vec3(0.) ? alpha : 1.);
|
||||
}
|
||||
`;
|
||||
|
||||
const { onLoop } = useRenderLoop();
|
||||
onLoop(({ elapsed }) => {
|
||||
if (groupRef.value) {
|
||||
groupRef.value.children.forEach(child => {
|
||||
child.material.uniforms.uTime.value = elapsed;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
<template>
|
||||
<TresOrthographicCamera :position="[0, 0, 10]" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useTresContext } from '@tresjs/core';
|
||||
import { OrthographicCamera } from 'three';
|
||||
import { watch } from "vue";
|
||||
|
||||
const context = useTresContext();
|
||||
watch([context.sizes.width, context.sizes.height, context.camera], ([width, height, camera]) => {
|
||||
const cam = camera as OrthographicCamera;
|
||||
if (cam) {
|
||||
cam.left = 0;
|
||||
cam.bottom = 0
|
||||
cam.right = width;
|
||||
cam.top = height;
|
||||
cam.updateProjectionMatrix();
|
||||
}
|
||||
});
|
||||
</script>
|
84
site/.vitepress/theme/Hole.vue
Normal file
84
site/.vitepress/theme/Hole.vue
Normal file
|
@ -0,0 +1,84 @@
|
|||
<template>
|
||||
<TresMesh :position="[Math.min(sizes.width.value, sizes.height.value) / 2 * .05,Math.min(sizes.width.value, sizes.height.value) / 2 * .05,0]">
|
||||
<TresCircleGeometry :args="[Math.min(sizes.width.value, sizes.height.value) / 2 * .9, 360]" />
|
||||
<TresShaderMaterial :vertexShader="vertexShader" :fragmentShader="fragmentShader" :uniforms="uniforms" :blending="NormalBlending" :transparent="true" />
|
||||
</TresMesh>
|
||||
<TresMesh :position="[Math.min(sizes.width.value, sizes.height.value) / 2 * .05,Math.min(sizes.width.value, sizes.height.value) / 2 * .05,0]" :renderOrder="0">
|
||||
<TresCircleGeometry :args="[Math.min(sizes.width.value, sizes.height.value) / 2 * .9, 360]" />
|
||||
<TresShaderMaterial :vertexShader="vertexShader" :fragmentShader="fragmentShaderBorderless" :uniforms="uniforms" :blending="NormalBlending" :colorWrite="false" :depthWrite="false" :depthTest="false" :stencilWrite="true" :stencilRef="1" :stencilFunc="AlwaysStencilFunc" :stencilFail="KeepStencilOp" :stencilZFail="KeepStencilOp" :stencilZPass="ReplaceStencilOp" />
|
||||
</TresMesh>
|
||||
<Background :mask="1" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useTresContext } from '@tresjs/core';
|
||||
import { AlwaysStencilFunc, KeepStencilOp, NormalBlending, ReplaceStencilOp, Vector3 } from "three";
|
||||
import Background from "./Background.vue";
|
||||
import noise from "./noise.glsl?raw";
|
||||
|
||||
const { sizes } = useTresContext();
|
||||
|
||||
const uniforms = {
|
||||
uColor: { value: new Vector3(0.23, 0.26, 0.32) },
|
||||
uSeed: { value: Math.random() * 100 }
|
||||
};
|
||||
|
||||
const vertexShader = `
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vec4 modelPosition = modelMatrix * vec4(position, 1.0);
|
||||
vec4 viewPosition = viewMatrix * modelPosition;
|
||||
gl_Position = projectionMatrix * viewPosition;
|
||||
vUv = uv / .8 - 0.1;
|
||||
}
|
||||
`;
|
||||
const fragmentVariables = `
|
||||
precision mediump float;
|
||||
uniform vec3 uColor;
|
||||
uniform float uTime;
|
||||
uniform float uSeed;
|
||||
uniform vec2 uMouse;
|
||||
varying vec2 vUv;
|
||||
`;
|
||||
const fragmentShader = `
|
||||
${noise}
|
||||
${fragmentVariables}
|
||||
|
||||
vec4 getColor(vec2 pos) {
|
||||
float dst = distance(pos, vec2(0.5, 0.5));
|
||||
if (dst < 0.475) {
|
||||
return vec4(uColor, 1.);
|
||||
} else if (dst < 0.5) {
|
||||
return vec4(.83, .83, .83, 1.);
|
||||
}
|
||||
return vec4(0.);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 distortion = vec2(0., 0.);
|
||||
distortion.x += (snoise(vec3(vUv * 50., 0. + uSeed))) / 200.;
|
||||
distortion.y += (snoise(vec3(vUv * 50., 10. + uSeed))) / 200.;
|
||||
distortion.x += (snoise(vec3(vUv * 5., 20. + uSeed))) / 8.;
|
||||
distortion.y += (snoise(vec3(vUv * 5., 30. + uSeed))) / 8.;
|
||||
gl_FragColor = getColor(vUv + distortion);
|
||||
}
|
||||
`;
|
||||
const fragmentShaderBorderless = `
|
||||
${noise}
|
||||
${fragmentVariables}
|
||||
void main() {
|
||||
vec2 distortion = vec2(0., 0.);
|
||||
distortion.x += (snoise(vec3(vUv * 50., 0. + uSeed))) / 200.;
|
||||
distortion.y += (snoise(vec3(vUv * 50., 10. + uSeed))) / 200.;
|
||||
distortion.x += (snoise(vec3(vUv * 5., 20. + uSeed))) / 8.;
|
||||
distortion.y += (snoise(vec3(vUv * 5., 30. + uSeed))) / 8.;
|
||||
float dst = distance(vUv + distortion, vec2(0.5, 0.5));
|
||||
if (dst < 0.475) {
|
||||
gl_FragColor = vec4(1.);
|
||||
return;
|
||||
}
|
||||
discard;
|
||||
}
|
||||
`;
|
||||
</script>
|
|
@ -5,7 +5,7 @@
|
|||
<ClientOnly>
|
||||
<div class="background">
|
||||
<TresCanvas>
|
||||
<Camera />
|
||||
<TresOrthographicCamera :position="[0, 0, 10]" />
|
||||
<TresAmbientLight :intensity="1" />
|
||||
<Suspense>
|
||||
<Background />
|
||||
|
|
|
@ -8,7 +8,17 @@ next: false
|
|||
I'm Anthony, or The Paper Pilot, and welcome to my [digital garden](/garden/digital-gardens/index.md)!
|
||||
|
||||
<div class="hero-wrapper">
|
||||
<div class="hole"></div>
|
||||
<TresCanvas :stencil="true" >
|
||||
<TresOrthographicCamera :position="[0, 0, 10]" />
|
||||
<TresAmbientLight :intensity="1" />
|
||||
<TresMesh>
|
||||
<TresTorusGeometry :args="[1, 0.5, 16, 32]" />
|
||||
<TresMeshBasicMaterial color="orange" />
|
||||
</TresMesh>
|
||||
<Suspense>
|
||||
<Hole />
|
||||
</Suspense>
|
||||
</TresCanvas>
|
||||
<img class="hero" src="/paperpilot.png" :style="`--x-offset: ${xOffset * 20}%`" />
|
||||
</div>
|
||||
|
||||
|
@ -32,6 +42,8 @@ This is a public website collecting all my (public) thoughts and projects all in
|
|||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
import { TresCanvas } from '@tresjs/core'
|
||||
import Hole from "./.vitepress/theme/Hole.vue";
|
||||
|
||||
const xOffset = ref(0);
|
||||
function mouseMoveHandler(event) {
|
||||
|
@ -69,18 +81,6 @@ This is a public website collecting all my (public) thoughts and projects all in
|
|||
}
|
||||
}
|
||||
|
||||
.hole {
|
||||
height: 80%;
|
||||
aspect-ratio: 1;
|
||||
border: solid 10px lightgrey;
|
||||
border-radius: 50%;
|
||||
background: #3b4252;
|
||||
position: absolute;
|
||||
left: 33%;
|
||||
transform: translateX(-50%);
|
||||
filter: url(#displacementFilter);
|
||||
}
|
||||
|
||||
.hero {
|
||||
height: 80%;
|
||||
width: unset;
|
||||
|
|
Loading…
Reference in a new issue