Attraction and repulsion

I wanted to try something like space time graph using replllers and attractors where a balls repelles the a certian part of plan in y direction like cusion regarding the mass it has but the i have use react three rapier fdor this

import { useEffect, useRef } from "react";
import { Environment, OrbitControls, Sphere } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import { Physics, RigidBody, useRapier } from "@react-three/rapier";
import { R3RapierBranding } from "r3-rapier-branding";
import { Attractor } from "@react-three/rapier-addons";
import { Suspense } from "react";
import Spinner from "./Spinner";
import "./styles.scss";

// Function to create a 2D array of positions
const create2DArray = () => {
  const array2D = [];
  for (let i = -20; i <= 20; i++) {
    const row = [];
    for (let j = -20; j <= 20; j++) {
      row.push([i, -2, j]); // Store positions
    }
    array2D.push(row);
  }
  return array2D;
};

function Scene() {
  const pos = create2DArray(); // Generate positions
  const rapier = useRapier();
  const originalPositions = useRef(pos); // Store original positions

  // Custom effect to apply Y-direction repulsion and restoration
  useEffect(() => {
    const attractorPosition = { x: 0, y: 0, z: 0 }; // Position of your repeller

    // This function will apply repulsion and restoration forces
    const applyForces = () => {
      pos.forEach((row, rowIndex) => {
        row.forEach((position, colIndex) => {
          const rigidBody = rapier.world.bodies[colIndex]; // Assuming colIndex corresponds to the body's index
          if (rigidBody) {
            const bodyPosition = rigidBody.translation(); // Get current position of the rigid body

            // Calculate distance in the Y direction from the attractor
            const distanceY = bodyPosition.y - attractorPosition.y;

            // Repulsive force if within a certain range
            const repulsiveForceMagnitude = 10; // Adjust this value as needed
            if (Math.abs(distanceY) < 5) {
              const repulsionForce = new rapier.Vector3(
                0,
                repulsiveForceMagnitude,
                0
              );
              rigidBody.applyImpulse(repulsionForce); // Apply the repulsive impulse
            }

            // Restorative force toward original position
            const originalPosition =
              originalPositions.current[rowIndex][colIndex]; // Get original position
            const restorationForceMagnitude = 5; // Adjust this value as needed
            const distanceToOriginalY = bodyPosition.y - originalPosition[1]; // Calculate distance from original position

            // Apply restorative force if further than a certain threshold from the original position
            if (Math.abs(distanceToOriginalY) > 0.1) {
              // Adjust threshold for better responsiveness
              const restorationForce = new rapier.Vector3(
                0,
                -restorationForceMagnitude * Math.sign(distanceToOriginalY),
                0
              ); // Y-direction restoration
              rigidBody.applyImpulse(restorationForce); // Apply the restoration impulse
            }
          }
        });
      });
    };

    const interval = setInterval(applyForces, 100); // Apply forces every 100ms

    return () => clearInterval(interval); // Cleanup on component unmount
  }, [pos, rapier]);

  return (
    <group>
      <Attractor position={0} strength={-1} range={3} />
      <Attractor position={0} strength={-1} range={3} />
      {pos.map((row, rowIndex) =>
        row.map((position, colIndex) => (
          <RigidBody
            key={`${rowIndex}-${colIndex}`}
            position={[position[0], position[1], position[2]]}
            colliders="ball"
            type="dynamic" // Change to "dynamic" to allow movement
          >
            <Sphere args={[0.3]}>
              <meshPhysicalMaterial />
            </Sphere>
          </RigidBody>
        ))
      )}
      <OrbitControls />
    </group>
  );
}

export default function App() {
  return (
    <div className="App">
      <R3RapierBranding title="Attractors" version="1.0.0">
        <Suspense fallback={<Spinner />}>
          <Canvas
            shadows
            camera={{
              position: [-8, 4, 8],
            }}
          >
            <Environment preset="studio" />
            <fog attach="fog" args={["#000", 2, 100]} />
            <Physics gravity={[0, 0, 0]} debug>
              <Scene />
            </Physics>
          </Canvas>
        </Suspense>
      </R3RapierBranding>
    </div>
  );
}

but here the balls are keep repelling i want them to have the tendency to get back in their original position




want to achieve something similar to this i want my points to have the tendancy to resist a repulsion i also tried add a attraction along with repulsion but didnt quite work

i

Maybe this example will be helpful/useful somehow:

8 Likes

thanks for this but can you explain me the ideology of how is it achieved in react three fiber . cuz i am unable to use dat.gui and other resources correctly. to be more precize this uses shader and i am pretty unexperienced with it. moreover this shader is coded to take only 1 sphere into consideration i want multiple spheres in it

I’m not a react guy at all.

It’s never too late to start to work with shaders.

Feel free to extend the functionality of shader.

  1. Good luck with your project. :handshake:
3 Likes