Skip to content

Commit

Permalink
Merge pull request Tresjs#107 from damienmontastier/feature/repulsion…
Browse files Browse the repository at this point in the history
…-effect

feat(repulsion effect): Add example of Repulsion Effect
  • Loading branch information
JaimeTorrealba authored Feb 28, 2024
2 parents 13c0d45 + b8c3103 commit 86cc1c9
Show file tree
Hide file tree
Showing 6 changed files with 286 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
140 changes: 140 additions & 0 deletions components/content/repulsion-effect/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<script setup lang="ts">
const gl = {
alpha: true,
shadows: true,
powerPreference: "high-performance",
}
</script>

<template>
<div class="repulsion-effect__content">
<h2>PERRIN</h2>
<h3>chocolaterie</h3>
</div>

<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 color="#341212" :decay="0" :width="1000" :height="1000" :position="[5, 20, 50]"
:look-at="[0, 0, 0]" />
<Scene />
</TresCanvas>
</template>

<style>
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Sacramento&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: 6.5%;
z-index: 3;
}
.repulsion-effect__infos {
margin-top: auto;
position: absolute;
bottom: 40px;
left: 60px;
z-index: 3;
}
.repulsion-effect__infos p {
font-family: 'Montserrat', sans-serif;
color: #FFF;
}
.repulsion-effect__infos a {
pointer-events: auto;
color: #ad836d;
transition: color 0.25s;
font-weight: 500;
font-family: 'Montserrat', sans-serif;
}
.repulsion-effect__infos a:hover {
color: #79573e;
}
.repulsion-effect__content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
pointer-events: none;
}
h3 {
color: #c13535;
font-size: 7vw;
font-family: 'Sacramento', cursive;
font-weight: 400;
margin: 0;
line-height: 1;
}
h2 {
font-size: 13vw;
color: #48271b;
text-transform: uppercase;
margin: 0;
font-family: 'Montserrat', sans-serif;
font-weight: 700;
line-height: 1;
}
canvas {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
</style>
126 changes: 126 additions & 0 deletions components/content/repulsion-effect/scene.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<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="[.25, .08, 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="[.3, .3, .2, 64]" />
<TresMeshPhysicalMaterial color="#3e2917" :metalness=".58" emissive="#000000" :roughness=".05" />
</TresMesh>
</TresGroup>
</TresGroup>

</TresGroup>
</template>

<script setup lang="ts">
import { degToRad } from 'three/src/math/MathUtils'
import { gsap } from 'gsap'
const meshesRef = shallowRef(null)
const shapesGroupRef = shallowRef(null)
const grid = reactive({ rows: 6, cols: 14, gutter: 2.2 })
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' || mesh.name === 'cylinder' ? 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 = map(mouseDistance, 7, 0, 0, 6);
gsap.to(mesh.position, { y: y < 1 ? 1 : y, duration: .3 });
const scaleFactor = mesh.position.y / 1.2;
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: map(mesh.position.y, -1, 1, degToRad(270), mesh.initialRotation.x),
z: map(mesh.position.y, -1, 1, degToRad(-90), mesh.initialRotation.z),
y: map(mesh.position.y, -1, 1, degToRad(45), mesh.initialRotation.y),
});
})
}
const distance = (x1, y1, x2, y2) => {
return Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2));
}
const map = (value, start1, stop1, start2, stop2) => {
return (value - start1) / (stop1 - start1) * (stop2 - start2) + start2
}
const getShapeType = (row, col) => {
const randomIndex = Math.floor(Math.random() * 3); // Generate a random number between 0 and 2
// Assigning shape types based on the random index
if (randomIndex === 0) return 'torus';
if (randomIndex === 1) return 'cone';
return 'cylinder';
}
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 />
Binary file added public/repulsion-effect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 86cc1c9

Please sign in to comment.