|
|
@@ -35,25 +35,24 @@
|
|
|
<script type="module">
|
|
|
|
|
|
import * as THREE from 'three';
|
|
|
- import { uniform, varying, vec4, add, sub, max, sin, mat3, uint, negate, cameraProjectionMatrix, cameraViewMatrix, positionLocal, modelWorldMatrix, sqrt, attribute, property, float, storage, storageObject, Fn, If, cos, Loop, Continue, normalize, instanceIndex, length } from 'three/tsl';
|
|
|
+ import { uniform, varying, vec4, add, sub, max, dot, sin, mat3, uint, negate, cameraProjectionMatrix, cameraViewMatrix, positionLocal, modelWorldMatrix, sqrt, attribute, property, float, storage, storageObject, Fn, If, cos, Loop, Continue, normalize, instanceIndex, length } from 'three/tsl';
|
|
|
+
|
|
|
+ import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
|
|
|
|
import Stats from 'three/addons/libs/stats.module.js';
|
|
|
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
|
|
|
|
|
|
let container, stats;
|
|
|
let camera, scene, renderer;
|
|
|
- let mouseX = 0, mouseY = 0;
|
|
|
-
|
|
|
- let windowHalfX = window.innerWidth / 2, windowHalfY = window.innerHeight / 2;
|
|
|
|
|
|
let last = performance.now();
|
|
|
|
|
|
+ let pointer, raycaster;
|
|
|
let computeVelocity, computePosition, effectController;
|
|
|
|
|
|
const BIRDS = 16384;
|
|
|
const SPEED_LIMIT = 9.0;
|
|
|
const BOUNDS = 800, BOUNDS_HALF = BOUNDS / 2;
|
|
|
- const UPPER_BOUNDS = BOUNDS;
|
|
|
|
|
|
// Custom Geometry - using 3 triangles each. No normals currently.
|
|
|
class BirdGeometry extends THREE.BufferGeometry {
|
|
|
@@ -140,6 +139,11 @@
|
|
|
scene = new THREE.Scene();
|
|
|
scene.fog = new THREE.Fog( 0xffffff, 700, 3000 );
|
|
|
|
|
|
+ // Pointer
|
|
|
+
|
|
|
+ pointer = new THREE.Vector2();
|
|
|
+ raycaster = new THREE.Raycaster();
|
|
|
+
|
|
|
// Sky
|
|
|
|
|
|
const geometry = new THREE.IcosahedronGeometry( 1, 6 );
|
|
|
@@ -158,9 +162,11 @@
|
|
|
|
|
|
const mesh = new THREE.Mesh( geometry, material );
|
|
|
mesh.rotation.z = 0.75;
|
|
|
- mesh.scale.setScalar( 1000 );
|
|
|
+ mesh.scale.setScalar( 1200 );
|
|
|
scene.add( mesh );
|
|
|
|
|
|
+ //
|
|
|
+
|
|
|
renderer = new THREE.WebGPURenderer( { antialiasing: true } );
|
|
|
renderer.setPixelRatio( window.devicePixelRatio );
|
|
|
renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
@@ -168,6 +174,9 @@
|
|
|
renderer.toneMapping = THREE.NeutralToneMapping;
|
|
|
container.appendChild( renderer.domElement );
|
|
|
|
|
|
+ const controls = new OrbitControls( camera, renderer.domElement );
|
|
|
+ controls.connect( /* renderer.domElement */ );
|
|
|
+
|
|
|
// Initialize position, velocity, and phase values
|
|
|
|
|
|
const positionArray = new Float32Array( BIRDS * 3 );
|
|
|
@@ -226,7 +235,8 @@
|
|
|
freedom: uniform( 0.75 ).label( 'freedom' ),
|
|
|
now: uniform( 0.0 ),
|
|
|
deltaTime: uniform( 0.0 ).label( 'deltaTime' ),
|
|
|
- predator: uniform( new THREE.Vector3() ).label( 'predator' ),
|
|
|
+ rayOrigin: uniform( new THREE.Vector3() ).label( 'rayOrigin' ),
|
|
|
+ rayDirection: uniform( new THREE.Vector3() ).label( 'rayDirection' )
|
|
|
};
|
|
|
|
|
|
// Create geometry
|
|
|
@@ -303,7 +313,7 @@
|
|
|
const limit = property( 'float', 'limit' ).assign( SPEED_LIMIT );
|
|
|
|
|
|
// Destructure uniforms
|
|
|
- const { alignment, separation, cohesion, predator, deltaTime } = effectController;
|
|
|
+ const { alignment, separation, cohesion, deltaTime, rayOrigin, rayDirection } = effectController;
|
|
|
|
|
|
const zoneRadius = separation.add( alignment ).add( cohesion );
|
|
|
const separationThresh = separation.div( zoneRadius );
|
|
|
@@ -313,21 +323,24 @@
|
|
|
const position = positionStorage.element( instanceIndex );
|
|
|
const velocity = velocityStorage.element( instanceIndex );
|
|
|
|
|
|
- // Add influence of mouse position to velocity.
|
|
|
- const dirToPredator = predator.mul( UPPER_BOUNDS ).sub( position );
|
|
|
- dirToPredator.z.assign( 0.0 );
|
|
|
- const distToPredator = length( dirToPredator );
|
|
|
- const distToPreadatorSq = distToPredator.mul( distToPredator );
|
|
|
+ // Add influence of pointer position to velocity.
|
|
|
+ const directionToRay = rayOrigin.sub( position );
|
|
|
+ const projectionLength = dot( directionToRay, rayDirection );
|
|
|
|
|
|
- const preyRadius = float( 150.0 );
|
|
|
- const preyRadiusSq = preyRadius.mul( preyRadius );
|
|
|
+ const closestPoint = rayOrigin.sub( rayDirection.mul( projectionLength ) );
|
|
|
+
|
|
|
+ const directionToClosestPoint = closestPoint.sub( position );
|
|
|
+ const distanceToClosestPoint = length( directionToClosestPoint );
|
|
|
+ const distanceToClosestPointSq = distanceToClosestPoint.mul( distanceToClosestPoint );
|
|
|
+
|
|
|
+ const rayRadius = float( 150.0 );
|
|
|
+ const rayRadiusSq = rayRadius.mul( rayRadius );
|
|
|
+
|
|
|
+ If( distanceToClosestPointSq.lessThan( rayRadiusSq ), () => {
|
|
|
|
|
|
- // Move birds away from predator if they are within the predator's area.
|
|
|
- If( distToPredator.lessThan( preyRadius ), () => {
|
|
|
-
|
|
|
// Scale bird velocity inversely with distance from prey radius center.
|
|
|
- const velocityAdjust = ( distToPreadatorSq.div( preyRadiusSq ).sub( 1.0 ) ).mul( deltaTime ).mul( 100.0 );
|
|
|
- velocity.addAssign( normalize( dirToPredator ).mul( velocityAdjust ) );
|
|
|
+ const velocityAdjust = ( distanceToClosestPointSq.div( rayRadiusSq ).sub( 1.0 ) ).mul( deltaTime ).mul( 100.0 );
|
|
|
+ velocity.addAssign( normalize( directionToClosestPoint ).mul( velocityAdjust ) );
|
|
|
limit.addAssign( 5.0 );
|
|
|
|
|
|
} );
|
|
|
@@ -441,9 +454,6 @@
|
|
|
|
|
|
function onWindowResize() {
|
|
|
|
|
|
- windowHalfX = window.innerWidth / 2;
|
|
|
- windowHalfY = window.innerHeight / 2;
|
|
|
-
|
|
|
camera.aspect = window.innerWidth / window.innerHeight;
|
|
|
camera.updateProjectionMatrix();
|
|
|
|
|
|
@@ -455,8 +465,8 @@
|
|
|
|
|
|
if ( event.isPrimary === false ) return;
|
|
|
|
|
|
- mouseX = event.clientX - windowHalfX;
|
|
|
- mouseY = event.clientY - windowHalfY;
|
|
|
+ pointer.x = ( event.clientX / window.innerWidth ) * 2.0 - 1.0;
|
|
|
+ pointer.y = 1.0 - ( event.clientY / window.innerHeight ) * 2.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -475,17 +485,20 @@
|
|
|
if ( deltaTime > 1 ) deltaTime = 1; // safety cap on large deltas
|
|
|
last = now;
|
|
|
|
|
|
+ raycaster.setFromCamera( pointer, camera );
|
|
|
+
|
|
|
effectController.now.value = now;
|
|
|
effectController.deltaTime.value = deltaTime;
|
|
|
- effectController.predator.value.set( 0.5 * mouseX / windowHalfX, - 0.5 * mouseY / windowHalfY, 0 );
|
|
|
-
|
|
|
- mouseX = 10000;
|
|
|
- mouseY = 10000;
|
|
|
+ effectController.rayOrigin.value.copy( raycaster.ray.origin );
|
|
|
+ effectController.rayDirection.value.copy( raycaster.ray.direction );
|
|
|
|
|
|
renderer.compute( computeVelocity );
|
|
|
renderer.compute( computePosition );
|
|
|
renderer.render( scene, camera );
|
|
|
|
|
|
+ // Move pointer away so we only affect birds when moving the mouse
|
|
|
+ pointer.y = 10;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
init();
|