Rewrite hole so that the background can appear through it
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m17s

This commit is contained in:
thepaperpilot 2024-06-27 23:14:26 -05:00
parent d4d1e112fe
commit e8e6e12450
5 changed files with 122 additions and 51 deletions

View file

@ -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>

View file

@ -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>

View 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>

View file

@ -5,7 +5,7 @@
<ClientOnly>
<div class="background">
<TresCanvas>
<Camera />
<TresOrthographicCamera :position="[0, 0, 10]" />
<TresAmbientLight :intensity="1" />
<Suspense>
<Background />

View file

@ -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;