three-stuff 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/fpscontrols.js ADDED
@@ -0,0 +1,148 @@
1
+ import * as THREE from 'three';
2
+ import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
3
+
4
+ export class FpsControls {
5
+ constructor(camera, domElement, weaponModel = null) {
6
+ this.camera = camera;
7
+ this.controls = new PointerLockControls(camera, domElement);
8
+ this.domElement = domElement;
9
+
10
+ // --- Physics Config ---
11
+ this.acceleration = 100.0;
12
+ this.friction = 10.0;
13
+ this.gravity = 30.0;
14
+ this.jumpForce = 12.0;
15
+ this.playerHeight = 1.6;
16
+ this.playerRadius = 0.6; // Width of the player (keep this larger than your move speed)
17
+
18
+ this.jump = false;
19
+ this.allobj = false;
20
+ this.collidableObjects = [];
21
+
22
+ // --- Internal State ---
23
+ this.velocity = new THREE.Vector3();
24
+ this.move = { forward: false, backward: false, left: false, right: false, sprint: false };
25
+ this.canJump = false;
26
+ this.prevTime = performance.now();
27
+
28
+ // --- Raycasters ---
29
+ this.raycaster = new THREE.Raycaster();
30
+
31
+ this.initUI();
32
+ this.initListeners();
33
+ }
34
+
35
+ set sensitivity(val) { this.controls.pointerSpeed = val / 50; }
36
+
37
+ initUI() {
38
+ const dot = document.createElement('div');
39
+ dot.style.cssText = `position:fixed;top:50%;left:50%;width:4px;height:4px;background:white;border-radius:50%;transform:translate(-50%,-50%);pointer-events:none;z-index:1000;mix-blend-mode:difference;`;
40
+ document.body.appendChild(dot);
41
+ }
42
+
43
+ initListeners() {
44
+ this.domElement.addEventListener('click', () => this.controls.lock());
45
+ window.addEventListener('keydown', (e) => this.updateKey(e.code, true));
46
+ window.addEventListener('keyup', (e) => this.updateKey(e.code, false));
47
+ }
48
+
49
+ addobj(...objs) { this.collidableObjects.push(...objs); }
50
+
51
+ updateKey(code, isPressed) {
52
+ switch (code) {
53
+ case 'KeyW': this.move.forward = isPressed; break;
54
+ case 'KeyS': this.move.backward = isPressed; break;
55
+ case 'KeyA': this.move.left = isPressed; break;
56
+ case 'KeyD': this.move.right = isPressed; break;
57
+ case 'ShiftLeft': this.move.sprint = isPressed; break;
58
+ case 'Space':
59
+ if (isPressed && this.jump && this.canJump) {
60
+ this.velocity.y = this.jumpForce;
61
+ this.canJump = false;
62
+ }
63
+ break;
64
+ }
65
+ }
66
+
67
+ update() {
68
+ if (!this.controls.isLocked) return;
69
+
70
+ const time = performance.now();
71
+ const delta = Math.min((time - this.prevTime) / 1000, 0.05);
72
+ this.prevTime = time;
73
+
74
+ const targets = this.allobj && this.camera.parent ? this.camera.parent.children : this.collidableObjects;
75
+
76
+ // 1. Physics Calculations
77
+ this.velocity.x -= this.velocity.x * this.friction * delta;
78
+ this.velocity.z -= this.velocity.z * this.friction * delta;
79
+ this.velocity.y -= this.gravity * delta;
80
+
81
+ const multiplier = this.move.sprint ? 2.0 : 1.0;
82
+ const accel = this.acceleration * multiplier * delta;
83
+
84
+ if (this.move.forward) this.velocity.z += accel;
85
+ if (this.move.backward) this.velocity.z -= accel;
86
+ if (this.move.left) this.velocity.x -= accel;
87
+ if (this.move.right) this.velocity.x += accel;
88
+
89
+ // 2. HORIZONTAL COLLISION (Wall Checking)
90
+ // We create a vector of where we WANT to go
91
+ const moveVector = new THREE.Vector3();
92
+ moveVector.x = this.velocity.x * delta;
93
+ moveVector.z = this.velocity.z * delta;
94
+
95
+ if (moveVector.length() > 0) {
96
+ // Get movement direction in world space
97
+ const worldDir = new THREE.Vector3(moveVector.x, 0, -moveVector.z).applyQuaternion(this.camera.quaternion);
98
+ worldDir.y = 0; // Keep check horizontal
99
+ worldDir.normalize();
100
+
101
+ // Cast a ray from "hip height" so we don't trip over the floor we are standing on
102
+ const rayOrigin = this.camera.position.clone();
103
+ rayOrigin.y -= 0.5;
104
+
105
+ this.raycaster.set(rayOrigin, worldDir);
106
+ this.raycaster.far = this.playerRadius;
107
+
108
+ const wallHits = this.raycaster.intersectObjects(targets, true);
109
+
110
+ if (wallHits.length > 0) {
111
+ // We hit a wall! Stop horizontal velocity
112
+ this.velocity.x = 0;
113
+ this.velocity.z = 0;
114
+ } else {
115
+ // Path clear, apply horizontal movement
116
+ this.controls.moveRight(moveVector.x);
117
+ this.controls.moveForward(moveVector.z);
118
+ }
119
+ }
120
+
121
+ // 3. VERTICAL COLLISION (Floor/Gravity)
122
+ this.camera.position.y += this.velocity.y * delta;
123
+
124
+ this.raycaster.set(this.camera.position, new THREE.Vector3(0, -1, 0));
125
+ this.raycaster.far = this.playerHeight;
126
+
127
+ const floorHits = this.raycaster.intersectObjects(targets, true);
128
+
129
+ if (floorHits.length > 0) {
130
+ const hit = floorHits[0];
131
+ // Only snap to floor if we are actually falling ONTO it,
132
+ // not if the floor is magically above our heads.
133
+ if (this.velocity.y <= 0) {
134
+ this.camera.position.y = hit.point.y + this.playerHeight;
135
+ this.velocity.y = 0;
136
+ this.canJump = true;
137
+ }
138
+ } else {
139
+ this.canJump = false;
140
+ // Basic ground plane at 0
141
+ if (this.camera.position.y < this.playerHeight) {
142
+ this.camera.position.y = this.playerHeight;
143
+ this.velocity.y = 0;
144
+ this.canJump = true;
145
+ }
146
+ }
147
+ }
148
+ }
package/package.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "three-stuff",
3
+ "version": "1.0.0",
4
+ "description": "this is ibaads files of modules that he made with easy acces to things like fps controls, physics, and shadows without having to write complicated stuff",
5
+ "main": "fpscontrols.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "type": "commonjs"
13
+ }
package/physics.js ADDED
@@ -0,0 +1,57 @@
1
+ import * as CANNON from 'cannon-es';
2
+ import * as THREE from 'three';
3
+
4
+ export class PhysicsEngine {
5
+ constructor() {
6
+ this.world = new CANNON.World();
7
+ this.world.gravity.set(0, -9.82, 0);
8
+ this.meshMap = new Map();
9
+ }
10
+
11
+ update(scene) {
12
+ this.world.step(1 / 60);
13
+
14
+ scene.traverse((obj) => {
15
+ if (obj.isMesh && (obj.dynamic === true || obj.static === true)) {
16
+ if (!this.meshMap.has(obj)) {
17
+ this._addBody(obj);
18
+ }
19
+
20
+ if (obj.dynamic) {
21
+ const body = this.meshMap.get(obj);
22
+ obj.position.copy(body.position);
23
+ obj.quaternion.copy(body.quaternion);
24
+ }
25
+ }
26
+ });
27
+ }
28
+
29
+ _addBody(mesh) {
30
+ // Measure the geometry
31
+ mesh.geometry.computeBoundingBox();
32
+ const size = new THREE.Vector3();
33
+ mesh.geometry.boundingBox.getSize(size);
34
+
35
+ // --- THE FIX IS HERE ---
36
+ // We ensure no dimension is 0. If it's a plane, we give it 0.1 thickness.
37
+ const hitBoxSize = new CANNON.Vec3(
38
+ Math.max(size.x * mesh.scale.x, 0.1) / 2,
39
+ Math.max(size.y * mesh.scale.y, 0.1) / 2,
40
+ Math.max(size.z * mesh.scale.z, 0.1) / 2
41
+ );
42
+
43
+ const shape = new CANNON.Box(hitBoxSize);
44
+
45
+ const body = new CANNON.Body({
46
+ mass: mesh.dynamic ? (mesh.mass || 1) : 0,
47
+ shape: shape
48
+ });
49
+
50
+ // Sync initial state
51
+ body.position.copy(mesh.position);
52
+ body.quaternion.copy(mesh.quaternion);
53
+
54
+ this.world.addBody(body);
55
+ this.meshMap.set(mesh, body);
56
+ }
57
+ }
package/shadowinit.js ADDED
@@ -0,0 +1,262 @@
1
+ // ShadowInit.js
2
+ import * as THREE from 'https://esm.sh/three@0.160.0';
3
+ import { EffectComposer } from 'https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/postprocessing/EffectComposer.js/+esm';
4
+ import { RenderPass } from 'https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/postprocessing/RenderPass.js/+esm';
5
+ import { SSAOPass } from 'https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/postprocessing/SSAOPass.js/+esm';
6
+ import { UnrealBloomPass } from 'https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/postprocessing/UnrealBloomPass.js/+esm';
7
+ import { SSRPass } from 'https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/postprocessing/SSRPass.js/+esm';
8
+
9
+ export class ShadowInit {
10
+ constructor() {
11
+ this.scene = null;
12
+ this.renderer = null;
13
+ this.camera = null;
14
+
15
+ this.emissiveLights = new Map();
16
+ this.reflectionCameras = new Map();
17
+
18
+ this._patched = false;
19
+ this._raytracing = false;
20
+
21
+ // Composer and passes for hybrid RTX-like mode
22
+ this.composer = null;
23
+ this.renderPass = null;
24
+ this.ssaoPass = null;
25
+ this.ssrPass = null;
26
+ this.bloomPass = null;
27
+ }
28
+
29
+ /* ------------------------ ATTACH ------------------------ */
30
+ attach(scene, renderer, camera) {
31
+ this.scene = scene;
32
+ this.renderer = renderer;
33
+ this.camera = camera;
34
+
35
+ this._enableRasterMode(); // <-- set default shadows
36
+ this._addSunLight(); // default directional light
37
+
38
+ if (!this._patched) {
39
+ this._patchSceneAdd(); // auto-detect new meshes
40
+ this._patched = true;
41
+ }
42
+
43
+ // Process all existing meshes in the scene
44
+ scene.traverse(obj => this._processObject(obj));
45
+ }
46
+
47
+ /* ------------------------ RASTER MODE ------------------------ */
48
+ _enableRasterMode() {
49
+ if (!this.renderer) return;
50
+
51
+ this.renderer.shadowMap.enabled = true;
52
+ this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
53
+ this.renderer.physicallyCorrectLights = true;
54
+ this.renderer.outputColorSpace = THREE.SRGBColorSpace;
55
+ this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
56
+ this.renderer.toneMappingExposure = 1.25;
57
+ }
58
+
59
+ /* ------------------------ PATCH SCENE.ADD ------------------------ */
60
+ _patchSceneAdd() {
61
+ const originalAdd = this.scene.add.bind(this.scene);
62
+ this.scene.add = (...objects) => {
63
+ objects.forEach(obj => this._processObject(obj));
64
+ originalAdd(...objects);
65
+ };
66
+ }
67
+
68
+ /* ------------------------ PROCESS OBJECT ------------------------ */
69
+ _processObject(obj) {
70
+ if (!obj || obj.__shadowEngineProcessed) return;
71
+
72
+ if (obj.isMesh) {
73
+ obj.castShadow = true;
74
+ obj.receiveShadow = true;
75
+
76
+ if (!obj.shadows) obj.shadows = {};
77
+
78
+ // eLight property
79
+ Object.defineProperty(obj.shadows, "eLight", {
80
+ set: v => this._applyEmissiveLight(obj, v)
81
+ });
82
+
83
+ // reflective property
84
+ Object.defineProperty(obj.shadows, "reflective", {
85
+ set: v => this._applyReflection(obj, v)
86
+ });
87
+
88
+ // helper to update reflection
89
+ obj.shadows.updateReflection = () => this._updateReflection(obj);
90
+ }
91
+
92
+ obj.__shadowEngineProcessed = true;
93
+
94
+ if (obj.children) obj.children.forEach(c => this._processObject(c));
95
+ }
96
+
97
+ /* ------------------------ DEFAULT SUN ------------------------ */
98
+ _addSunLight() {
99
+ const sun = new THREE.DirectionalLight(0xffffff, 1.2);
100
+ sun.position.set(15, 25, 15);
101
+ sun.castShadow = true;
102
+ sun.shadow.mapSize.set(2048, 2048);
103
+ sun.shadow.camera.near = 1;
104
+ sun.shadow.camera.far = 150;
105
+ sun.shadow.camera.left = -40;
106
+ sun.shadow.camera.right = 40;
107
+ sun.shadow.camera.top = 40;
108
+ sun.shadow.camera.bottom = -40;
109
+ sun.shadow.bias = -0.0002;
110
+
111
+ this.scene.add(sun);
112
+ this.scene.add(sun.target);
113
+ }
114
+
115
+ /* ------------------------ EMISSIVE LIGHT ------------------------ */
116
+ _applyEmissiveLight(mesh, value) {
117
+ if (!Array.isArray(value)) return;
118
+
119
+ const baseIntensity = value[0] ?? 1;
120
+ const color = new THREE.Color(value[1] ?? 0xffffff).convertSRGBToLinear();
121
+
122
+ // remove old lights
123
+ if (this.emissiveLights.has(mesh)) {
124
+ this.emissiveLights.get(mesh).forEach(l => mesh.remove(l));
125
+ }
126
+
127
+ // compute mesh size
128
+ const box = new THREE.Box3().setFromObject(mesh);
129
+ const size = box.getSize(new THREE.Vector3());
130
+ const area = size.x * size.y + size.y * size.z + size.x * size.z;
131
+ const intensity = baseIntensity * area * 0.15;
132
+
133
+ const lights = [];
134
+
135
+ // area-light approximation
136
+ const offsets = [
137
+ [0.5, 0, 0], [-0.5, 0, 0],
138
+ [0, 0.5, 0], [0, -0.5, 0],
139
+ [0, 0, 0.5], [0, 0, -0.5]
140
+ ];
141
+
142
+ for (const o of offsets) {
143
+ const light = new THREE.PointLight(color, intensity / offsets.length);
144
+ light.castShadow = true;
145
+ light.shadow.mapSize.set(1024, 1024);
146
+ light.shadow.bias = -0.00025;
147
+ light.distance = Math.max(size.x, size.y, size.z) * 8;
148
+ light.position.set(o[0]*size.x, o[1]*size.y, o[2]*size.z);
149
+ mesh.add(light);
150
+ lights.push(light);
151
+ }
152
+
153
+ // fake bounce light
154
+ const bounce = new THREE.PointLight(color, intensity * 0.25);
155
+ bounce.castShadow = false;
156
+ bounce.distance = Math.max(size.x, size.y, size.z) * 12;
157
+ bounce.position.set(0, -size.y*0.6, 0);
158
+ mesh.add(bounce);
159
+ lights.push(bounce);
160
+
161
+ if (mesh.material?.isMeshStandardMaterial) {
162
+ mesh.material.emissive = color.clone();
163
+ mesh.material.emissiveIntensity = baseIntensity;
164
+ mesh.material.needsUpdate = true;
165
+ }
166
+
167
+ this.emissiveLights.set(mesh, lights);
168
+ }
169
+
170
+ /* ------------------------ REFLECTION ------------------------ */
171
+ _applyReflection(mesh, strength = 0.5) {
172
+ strength = THREE.MathUtils.clamp(strength, 0, 1);
173
+ if (!mesh.material?.isMeshStandardMaterial) return;
174
+
175
+ let cam = this.reflectionCameras.get(mesh);
176
+ if (!cam) {
177
+ cam = new THREE.CubeCamera(0.1, 1500, 256);
178
+ this.scene.add(cam);
179
+ this.reflectionCameras.set(mesh, cam);
180
+ }
181
+
182
+ mesh.material.envMap = cam.renderTarget.texture;
183
+ mesh.material.metalness = strength;
184
+ mesh.material.roughness = 1 - strength*0.9;
185
+ mesh.material.needsUpdate = true;
186
+
187
+ this._updateReflection(mesh);
188
+ }
189
+
190
+ _updateReflection(mesh) {
191
+ const cam = this.reflectionCameras.get(mesh);
192
+ if (!cam) return;
193
+ mesh.visible = false;
194
+ cam.position.copy(mesh.getWorldPosition(new THREE.Vector3()));
195
+ cam.update(this.renderer, this.scene);
196
+ mesh.visible = true;
197
+ }
198
+
199
+ /* ------------------------ HYBRID RTX-LIKE PIPELINE ------------------------ */
200
+ set raytracing(val) {
201
+ this._raytracing = val;
202
+
203
+ if (!this.renderer || !this.camera) return;
204
+
205
+ if (val) this._enableHybridPipeline();
206
+ else this._disableHybridPipeline();
207
+ }
208
+
209
+ get raytracing() { return this._raytracing; }
210
+
211
+ _enableHybridPipeline() {
212
+ if (!this.renderer || !this.camera) return;
213
+
214
+ if (!this.composer) {
215
+ this.composer = new EffectComposer(this.renderer);
216
+ this.renderPass = new RenderPass(this.scene, this.camera);
217
+ this.composer.addPass(this.renderPass);
218
+
219
+ this.ssaoPass = new SSAOPass(this.scene, this.camera, window.innerWidth, window.innerHeight);
220
+ this.ssaoPass.kernelRadius = 8;
221
+ this.composer.addPass(this.ssaoPass);
222
+
223
+ this.ssrPass = new SSRPass({
224
+ renderer: this.renderer,
225
+ scene: this.scene,
226
+ camera: this.camera,
227
+ width: window.innerWidth,
228
+ height: window.innerHeight,
229
+ groundReflector: null,
230
+ selects: []
231
+ });
232
+ this.composer.addPass(this.ssrPass);
233
+
234
+ this.bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 0.6, 0.4, 0.85);
235
+ this.composer.addPass(this.bloomPass);
236
+ }
237
+
238
+ this.renderer.shadowMap.enabled = false;
239
+ }
240
+
241
+ _disableHybridPipeline() {
242
+ if (this.composer) {
243
+ this.composer.passes = [];
244
+ this.composer = null;
245
+ }
246
+ this._enableRasterMode();
247
+ }
248
+
249
+ /* ------------------------ RENDER ------------------------ */
250
+ render() {
251
+ if (this._raytracing && this.composer) {
252
+ if (this.renderer.domElement.parentElement) this.composer.render();
253
+ } else {
254
+ if (this.renderer && this.scene && this.camera) this.renderer.render(this.scene, this.camera);
255
+ }
256
+ }
257
+
258
+ /* ------------------------ OPTIONAL: VOLMETRICS ------------------------ */
259
+ enableVolumetrics(color = 0x0a0a0a, density = 0.02) {
260
+ this.scene.fog = new THREE.FogExp2(color, density);
261
+ }
262
+ }