Skip to content

Commit

Permalink
new lab example
Browse files Browse the repository at this point in the history
  • Loading branch information
damienmontastier committed Feb 26, 2024
1 parent 13c0d45 commit 8e48714
Show file tree
Hide file tree
Showing 7 changed files with 21,635 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"prettier.enable": false,
"editor.formatOnSave": false,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
Expand Down
133 changes: 133 additions & 0 deletions components/content/repulsion-effect/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<script setup lang="ts">
import { TresCanvas, useTresContext } from '@tresjs/core'
import { PCFSoftShadowMap, BasicShadowMap, PCFShadowMap, NoColorSpace, LinearSRGBColorSpace, SRGBColorSpace, NoToneMapping } from 'three'
import { OrbitControls, Box, vAlwaysLookAt, vLightHelper } from '@tresjs/cientos';
const rectAreaLightRef = ref(null)
const gl = {
alpha: true,
shadows: true,
shadowMapType: PCFSoftShadowMap,
powerPreference: "high-performance",
}
watchEffect(() => {
if (rectAreaLightRef.value) {
rectAreaLightRef.value.lookAt(0, 0, 0);
}
})
</script>

<template>
<h1>PERRIN</h1>

<NuxtLink class="repulsion-effect__logo" to="/">
<img src="/lab.svg" alt="TresJS Logo" />
</NuxtLink>

<div class="repulsion-effect__infos">
<NuxtLink to="/">See more experiments and examples</NuxtLink>
<p>Repulsion Effect inspired by the
<a target="_blank" href="https://tympanus.net/codrops/2018/12/06/interactive-repulsion-effect-with-three-js/">
Codrops tutorial Interactive Repulsion Effect
</a>
</p>
</div>

<div class="repulsion-effect__bg" />

<TresCanvas window-size v-bind="gl">
<TresPerspectiveCamera :position="[0, 65, 0]" :rotation-x="-1.57" :fov="20" />
<!-- <OrbitControls /> -->

<TresAmbientLight color="#ffffff" />

<TresPointLight color="#fff000" :intensity="5" :decay="0" :position="[0, 5, -20]" />
<TresPointLight color="#79573e" :intensity="5" :decay="0" :position="[35, 5, 0]" />
<TresPointLight color="#c27439" :intensity="5" :decay="0" :position="[-35, 5, 0]" />
<TresPointLight color="#fff000" :intensity="5" :decay="0" :position="[0, 5, 20]" />

<TresSpotLight color="#7bccd7" :decay="0" cast-shadow :shadow-mapSize-width="2048" :shadow-mapSize-height="2048"
:position="[0, 25, 0]" />

<TresRectAreaLight ref="rectAreaLightRef" color="#341212" :decay="0" :width="1000" :height="1000"
:position="[5, 20, 50]" />
<Scene />
</TresCanvas>
</template>

<style>
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
.repulsion-effect__bg {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 0;
background-color: #d8bcac;
pointer-events: none;
}
.repulsion-effect__logo {
align-self: flex-start;
position: absolute;
top: 40px;
left: 60px;
width: 7.5%;
z-index: 3;
}
.repulsion-effect__infos {
margin-top: auto;
position: absolute;
bottom: 40px;
left: 60px;
z-index: 3;
}
.repulsion-effect__infos p {
color: #FFF;
}
.repulsion-effect__infos a {
pointer-events: auto;
color: #ad836d;
transition: color 0.25s;
}
.repulsion-effect__infos a:hover {
color: #79573e;
}
h1 {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 13vw;
color: #48271b;
text-transform: uppercase;
margin: 0;
font-family: 'Montserrat', sans-serif;
font-weight: 700;
line-height: 1;
pointer-events: none;
z-index: 1;
}
canvas {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
</style>
122 changes: 122 additions & 0 deletions components/content/repulsion-effect/scene.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<template>
<Plane receive-shadow @pointer-move="onPointerMove" :args="[100, 100]" :rotation-x="- Math.PI / 2"
:position="[0, 0, 0]">
<TresShadowMaterial transparent :opacity=".3" />
</Plane>

<TresGroup ref="shapesGroupRef" name="shapes">
<TresGroup v-for="row in grid.rows" :key="`row-${row}`">
<TresGroup v-for="col in grid.cols" :key="`col-${col}-${row}`">
<!-- Torus Mesh -->
<TresMesh v-if="getShapeType(row, col) === 'torus'" name="torus" cast-shadow receive-shadow
:position="computePosition(col, row)">
<TresTorusGeometry :args="[.3, .12, 30, 200]" />
<TresMeshPhysicalMaterial color="#3e2917" :metalness=".58" emissive="#000000" :roughness=".05" />
</TresMesh>

<!-- Cone -->
<Cone v-else-if="getShapeType(row, col) === 'cone'" name="cone" :args="[.3, .5, 32]" cast-shadow receive-shadow
:position="computePosition(col, row)">
<TresMeshPhysicalMaterial color="#3e2917" :metalness=".58" emissive="#000000" :roughness=".05" />
</Cone>

<!-- Cylinder Mesh -->
<TresMesh v-else name="cylinder" cast-shadow receive-shadow :position="computePosition(col, row)">
<TresCylinderGeometry :args="[.25, .25, .75, 32]" />
<TresMeshPhysicalMaterial color="#3e2917" :metalness=".58" emissive="#000000" :roughness=".05" />
</TresMesh>
</TresGroup>
</TresGroup>

</TresGroup>
</template>

<script setup lang="ts">
import { mapLinear, degToRad } from 'three/src/math/MathUtils'
import gsap from 'gsap'
const meshesRef = shallowRef(null)
const shapesGroupRef = shallowRef(null)
const grid = reactive({ rows: 5, cols: 11, gutter: 2.65 })
const gridOffset = computed(() => {
const x = ((grid.cols - 1) * grid.gutter) / 2;
const z = ((grid.rows - 1) * grid.gutter) / 2;
return { x, z }
})
const { seekAll } = useSeek()
watch(shapesGroupRef, () => {
meshesRef.value = seekAll(shapesGroupRef.value, 'type', 'Mesh')
meshesRef.value.forEach(mesh => {
mesh.initialRotation = {
x: mesh.name === 'torus' ? degToRad(90) : mesh.rotation.x,
y: mesh.rotation.y,
z: mesh.name === 'cone' ? degToRad(-180) : mesh.rotation.z,
};
mesh.rotation.x = mesh.initialRotation.x
mesh.rotation.y = mesh.initialRotation.y
mesh.rotation.z = mesh.initialRotation.z
})
})
const onPointerMove = ({ point }) => {
if (!meshesRef.value) return
const { x, y, z } = point
meshesRef.value.forEach(mesh => {
const mouseDistance = distance(x, z,
mesh.position.x,
mesh.position.z);
const y = mapLinear(mouseDistance, 6, 0, 0, 10);
gsap.to(mesh.position, { y: y < 1 ? 1 : y, duration: .3 });
const scaleFactor = mesh.position.y / 2.5;
const scale = scaleFactor < 1 ? 1 : scaleFactor;
gsap.to(mesh.scale,
{
ease: "expo.Out",
x: scale,
y: scale,
z: scale,
duration: .3
});
gsap.to(mesh.rotation, {
duration: .7,
ease: "expo.Out",
x: mapLinear(mesh.position.y, -1, degToRad(45), 1, mesh.initialRotation.x),
z: mapLinear(mesh.position.y, -1, degToRad(-90), 1, mesh.initialRotation.y),
y: mapLinear(mesh.position.y, -1, degToRad(90), 1, mesh.initialRotation.z),
});
})
}
const distance = (x1, y1, x2, y2) => {
return Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2));
}
const getShapeType = (row, col) => {
const seed = (row + col) * row * col;
const result = seed % 3; // Divide by 3 to obtain a remainder of 0, 1 or 2
if (result === 0) return 'torus';
if (result === 1) return 'cone';
return 'cylinder'; // default
}
const computePosition = (col, row) => {
return [(col - 1) * grid.gutter - gridOffset.value.x, 0, (row - 1) * grid.gutter - gridOffset.value.z];
}
</script>

<style></style>
8 changes: 8 additions & 0 deletions content/authors/damienmontastier.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
name: Damien Montastier
slug: damienmontastier
email: [email protected]
twitter: dammontastier
github: damienmontastier
avatar: https://avatars.githubusercontent.com/u/33467958?v=4
---
11 changes: 11 additions & 0 deletions content/experiments/repulsion-effect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
thumbnail: /repulsion-effect.png
title: Repulsion Effect
slug: repulsion-effect
status: published
author: damienmontastier
description: Repulsion Effect
tags: ['repulsion', 'effect', 'basic' , 'hover']
---

<RepulsionEffect />
Loading

0 comments on commit 8e48714

Please sign in to comment.