Skip to content

Commit 2dd51a4

Browse files
committed
Web - fix cube manipulation
now matches intro glsl shader interaction
1 parent 3a7d5a1 commit 2dd51a4

File tree

1 file changed

+76
-74
lines changed

1 file changed

+76
-74
lines changed

server/assets/js/lib/tau5_shader.js

Lines changed: 76 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,22 @@ export class Tau5Shader {
66
this.startTime = Date.now();
77
this.uniforms = {};
88
this.animationFrame = null;
9-
9+
1010
// Mouse interaction state
1111
this.isDragging = false;
1212
this.lastMouseX = 0;
1313
this.lastMouseY = 0;
14-
this.velocityX = 0;
15-
this.velocityY = 0;
16-
this.rotationX = 0;
17-
this.rotationY = 0;
18-
this.rotationZ = 0;
19-
this.baseSpeed = 0.0002; // Base rotation speed when not interacting (slower)
20-
this.damping = 0.98; // Inertia damping factor (higher = longer spin)
14+
15+
// Camera rotation (view space) - controlled by mouse
16+
this.cameraVelocityX = 0; // Pitch velocity
17+
this.cameraVelocityY = 0; // Yaw velocity
18+
this.cameraPitch = 0; // Camera pitch (up/down)
19+
this.cameraYaw = 0; // Camera yaw (left/right)
20+
21+
// Auto rotation (object space) - automatic spinning
22+
this.autoRotationTime = 0;
23+
this.baseSpeed = 0.05; // Auto rotation speed
24+
this.damping = 0.985; // Inertia damping factor (higher = longer spin)
2125
}
2226

2327
async init() {
@@ -50,7 +54,8 @@ export class Tau5Shader {
5054
// Get uniform locations
5155
this.uniforms.time = this.gl.getUniformLocation(this.program, 'time');
5256
this.uniforms.resolution = this.gl.getUniformLocation(this.program, 'resolution');
53-
this.uniforms.rotation = this.gl.getUniformLocation(this.program, 'rotation');
57+
this.uniforms.autoRotation = this.gl.getUniformLocation(this.program, 'autoRotation');
58+
this.uniforms.cameraRotation = this.gl.getUniformLocation(this.program, 'cameraRotation');
5459

5560
// Enable alpha blending
5661
this.gl.enable(this.gl.BLEND);
@@ -108,20 +113,19 @@ export class Tau5Shader {
108113
precision mediump float;
109114
uniform float time;
110115
uniform vec2 resolution;
111-
uniform vec3 rotation;
112-
116+
uniform vec3 autoRotation;
117+
uniform vec2 cameraRotation;
118+
113119
#define PI 3.14159265359
114-
120+
115121
mat2 rot(float a) {
116122
float s = sin(a), c = cos(a);
117123
return mat2(c, -s, s, c);
118124
}
119-
125+
120126
vec3 cubeWireframe(vec2 p) {
121127
vec3 col = vec3(0.0);
122-
123-
vec3 angles = rotation;
124-
128+
125129
// Define cube vertices
126130
vec3 verts[8];
127131
verts[0] = vec3(-1.0, -1.0, -1.0);
@@ -132,17 +136,23 @@ export class Tau5Shader {
132136
verts[5] = vec3( 1.0, -1.0, 1.0);
133137
verts[6] = vec3( 1.0, 1.0, 1.0);
134138
verts[7] = vec3(-1.0, 1.0, 1.0);
135-
139+
136140
float scale = 0.3;
137-
141+
138142
// Project vertices
139143
vec2 proj[8];
140144
for(int i = 0; i < 8; i++) {
141145
vec3 v = verts[i];
142-
// Rotate
143-
v.yz = rot(angles.x) * v.yz;
144-
v.xz = rot(angles.y) * v.xz;
145-
v.xy = rot(angles.z) * v.xy;
146+
147+
// Apply auto-rotation (object space)
148+
v.yz *= rot(autoRotation.x);
149+
v.xz *= rot(autoRotation.y);
150+
v.xy *= rot(autoRotation.z);
151+
152+
// Apply camera rotation (view space) - this gives perfect screen-space control
153+
v.xz *= rot(cameraRotation.y); // Yaw (horizontal mouse movement)
154+
v.yz *= rot(cameraRotation.x); // Pitch (vertical mouse movement)
155+
146156
// Perspective projection
147157
float z = 4.0 + v.z;
148158
proj[i] = v.xy * (2.0 / z) * scale;
@@ -201,36 +211,39 @@ export class Tau5Shader {
201211
this.isDragging = true;
202212
this.lastMouseX = e.clientX;
203213
this.lastMouseY = e.clientY;
204-
this.velocityX = 0;
205-
this.velocityY = 0;
214+
this.cameraVelocityX = 0;
215+
this.cameraVelocityY = 0;
206216
this.canvas.style.cursor = 'grabbing';
207217
});
208-
218+
209219
// Mouse move - update rotation
210220
window.addEventListener('mousemove', (e) => {
211221
if (!this.isDragging) return;
212-
222+
213223
const deltaX = e.clientX - this.lastMouseX;
214224
const deltaY = e.clientY - this.lastMouseY;
215-
216-
// Update velocity for inertia
217-
this.velocityY = deltaX * 0.01; // X mouse movement -> Y rotation
218-
this.velocityX = -deltaY * 0.01; // Y mouse movement -> X rotation (inverted)
219-
220-
// Update rotation based on mouse movement
221-
this.rotationY += deltaX * 0.01; // Horizontal drag rotates around Y
222-
this.rotationX -= deltaY * 0.01; // Vertical drag rotates around X (inverted)
223-
225+
226+
// Camera rotation - perfect screen-space control
227+
const rotationSpeed = 0.01;
228+
229+
// Update camera velocities (inverted Y for intuitive control)
230+
this.cameraVelocityX = -deltaY * rotationSpeed; // Vertical drag -> pitch (inverted)
231+
this.cameraVelocityY = deltaX * rotationSpeed; // Horizontal drag -> yaw
232+
233+
// Apply camera rotations
234+
this.cameraPitch += this.cameraVelocityX;
235+
this.cameraYaw += this.cameraVelocityY;
236+
224237
this.lastMouseX = e.clientX;
225238
this.lastMouseY = e.clientY;
226239
});
227-
240+
228241
// Mouse up - stop dragging
229242
window.addEventListener('mouseup', () => {
230243
this.isDragging = false;
231244
this.canvas.style.cursor = 'grab';
232245
});
233-
246+
234247
// Add hover cursor
235248
this.canvas.style.cursor = 'grab';
236249
}
@@ -257,49 +270,38 @@ export class Tau5Shader {
257270

258271
this.gl.useProgram(this.program);
259272

260-
// Update physics when not dragging
273+
// Auto-rotation (always active)
274+
const time = (Date.now() - this.startTime) / 1000.0;
275+
this.autoRotationTime = time * this.baseSpeed;
276+
277+
// Update camera physics when not dragging
261278
if (!this.isDragging) {
262-
// Apply inertia
263-
this.rotationY += this.velocityY; // Y velocity affects Y rotation
264-
this.rotationX += this.velocityX; // X velocity affects X rotation
265-
266-
// Apply damping to velocity
267-
this.velocityX *= this.damping;
268-
this.velocityY *= this.damping;
269-
270-
// Smoothly blend in base rotation as velocity decreases
271-
const totalVelocity = Math.sqrt(this.velocityX * this.velocityX + this.velocityY * this.velocityY);
272-
const blendFactor = Math.max(0, 1 - totalVelocity / 0.001); // Smooth transition
273-
274-
// Always apply some base rotation, scaled by how still the cube is
275-
const time = (Date.now() - this.startTime) / 1000.0;
276-
this.rotationZ += this.baseSpeed * 30 * blendFactor;
277-
278-
// If nearly stopped, maintain minimum rotation in the last direction
279-
if (totalVelocity < 0.001) {
280-
// Smoothly add base rotation without jerking
281-
const baseX = this.baseSpeed * 0.7 * blendFactor;
282-
const baseY = this.baseSpeed * blendFactor;
283-
284-
// If we have some velocity direction, follow it
285-
if (totalVelocity > 0.0001) {
286-
const dirX = this.velocityX / totalVelocity;
287-
const dirY = this.velocityY / totalVelocity;
288-
this.velocityX = Math.max(Math.abs(this.velocityX), baseX) * dirX;
289-
this.velocityY = Math.max(Math.abs(this.velocityY), baseY) * dirY;
290-
} else {
291-
// Otherwise, gently start base rotation
292-
this.velocityX += baseX * 0.1;
293-
this.velocityY += baseY * 0.1;
294-
}
295-
}
279+
// Apply inertia to camera rotation
280+
this.cameraPitch += this.cameraVelocityX;
281+
this.cameraYaw += this.cameraVelocityY;
282+
283+
// Apply damping to camera velocity
284+
this.cameraVelocityX *= this.damping;
285+
this.cameraVelocityY *= this.damping;
286+
287+
// Stop when velocity is very small
288+
const minVelocity = 0.00001;
289+
if (Math.abs(this.cameraVelocityX) < minVelocity) this.cameraVelocityX = 0;
290+
if (Math.abs(this.cameraVelocityY) < minVelocity) this.cameraVelocityY = 0;
296291
}
297292

298293
// Set uniforms
299-
const time = (Date.now() - this.startTime) / 1000.0;
300294
this.gl.uniform1f(this.uniforms.time, time);
301295
this.gl.uniform2f(this.uniforms.resolution, this.canvas.width, this.canvas.height);
302-
this.gl.uniform3f(this.uniforms.rotation, this.rotationX, this.rotationY, this.rotationZ);
296+
297+
// Auto-rotation angles (object space)
298+
const autoRotX = this.autoRotationTime;
299+
const autoRotY = this.autoRotationTime * 0.7;
300+
const autoRotZ = this.autoRotationTime * 0.3;
301+
this.gl.uniform3f(this.uniforms.autoRotation, autoRotX, autoRotY, autoRotZ);
302+
303+
// Camera rotation (view space)
304+
this.gl.uniform2f(this.uniforms.cameraRotation, this.cameraPitch, this.cameraYaw);
303305

304306
// Draw
305307
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);

0 commit comments

Comments
 (0)