reze-engine 0.3.4 → 0.3.5

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/dist/pool.d.ts DELETED
@@ -1,38 +0,0 @@
1
- export interface PoolOptions {
2
- y?: number;
3
- size?: number;
4
- segments?: number;
5
- }
6
- export declare class Pool {
7
- private device;
8
- private vertexBuffer;
9
- private indexBuffer;
10
- private pipeline;
11
- private bindGroup;
12
- private bindGroupLayout;
13
- private uniformBuffer;
14
- private cameraBindGroupLayout;
15
- private cameraBindGroup;
16
- private cameraUniformBuffer;
17
- private indexCount;
18
- private y;
19
- private size;
20
- private segments;
21
- private seaColor;
22
- private seaLight;
23
- private startTime;
24
- constructor(device: GPUDevice, cameraBindGroupLayout: GPUBindGroupLayout, cameraUniformBuffer: GPUBuffer, options?: PoolOptions);
25
- init(): Promise<void>;
26
- private createGeometry;
27
- private createShader;
28
- private createUniforms;
29
- updateUniforms(): void;
30
- render(pass: GPURenderPassEncoder, restoreBuffers?: {
31
- vertexBuffer: GPUBuffer;
32
- jointsBuffer: GPUBuffer;
33
- weightsBuffer: GPUBuffer;
34
- indexBuffer: GPUBuffer;
35
- }): void;
36
- dispose(): void;
37
- }
38
- //# sourceMappingURL=pool.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,qBAAa,IAAI;IACf,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,YAAY,CAAY;IAChC,OAAO,CAAC,WAAW,CAAY;IAC/B,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,SAAS,CAAe;IAChC,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,qBAAqB,CAAqB;IAClD,OAAO,CAAC,eAAe,CAAe;IACtC,OAAO,CAAC,mBAAmB,CAAY;IACvC,OAAO,CAAC,UAAU,CAAY;IAC9B,OAAO,CAAC,CAAC,CAAQ;IACjB,OAAO,CAAC,IAAI,CAAQ;IACpB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,SAAS,CAA4B;gBAG3C,MAAM,EAAE,SAAS,EACjB,qBAAqB,EAAE,kBAAkB,EACzC,mBAAmB,EAAE,SAAS,EAC9B,OAAO,CAAC,EAAE,WAAW;IAaV,IAAI;IAMjB,OAAO,CAAC,cAAc;IA4DtB,OAAO,CAAC,YAAY;IAoQpB,OAAO,CAAC,cAAc;IA0Cf,cAAc;IAsBd,MAAM,CACX,IAAI,EAAE,oBAAoB,EAC1B,cAAc,CAAC,EAAE;QACf,YAAY,EAAE,SAAS,CAAA;QACvB,YAAY,EAAE,SAAS,CAAA;QACvB,aAAa,EAAE,SAAS,CAAA;QACxB,WAAW,EAAE,SAAS,CAAA;KACvB;IAqCI,OAAO;CAIf"}
package/dist/pool.js DELETED
@@ -1,422 +0,0 @@
1
- import { Vec3 } from "./math";
2
- export class Pool {
3
- constructor(device, cameraBindGroupLayout, cameraUniformBuffer, options) {
4
- this.indexCount = 0;
5
- this.startTime = performance.now();
6
- this.device = device;
7
- this.cameraBindGroupLayout = cameraBindGroupLayout;
8
- this.cameraUniformBuffer = cameraUniformBuffer;
9
- this.y = options?.y ?? 15;
10
- this.size = options?.size ?? 100;
11
- this.segments = options?.segments ?? 50;
12
- // Hardcoded dark night pool colors (not used in shader, but kept for uniform buffer)
13
- this.seaColor = new Vec3(0.02, 0.05, 0.12); // Dark night pool base
14
- this.seaLight = new Vec3(0.1, 0.3, 0.5); // Light cyan for lit areas
15
- }
16
- async init() {
17
- this.createGeometry();
18
- this.createShader();
19
- this.createUniforms();
20
- }
21
- createGeometry() {
22
- const segments = this.segments;
23
- const size = this.size;
24
- const halfSize = size / 2;
25
- const step = size / segments;
26
- // Generate vertices
27
- const vertices = [];
28
- for (let i = 0; i <= segments; i++) {
29
- for (let j = 0; j <= segments; j++) {
30
- const x = -halfSize + j * step;
31
- const z = -halfSize + i * step;
32
- const y = this.y;
33
- const u = j / segments;
34
- const v = i / segments;
35
- // Position (x, y, z) + UV (u, v)
36
- vertices.push(x, y, z, u, v);
37
- }
38
- }
39
- // Generate indices
40
- const indices = [];
41
- for (let i = 0; i < segments; i++) {
42
- for (let j = 0; j < segments; j++) {
43
- const topLeft = i * (segments + 1) + j;
44
- const topRight = topLeft + 1;
45
- const bottomLeft = (i + 1) * (segments + 1) + j;
46
- const bottomRight = bottomLeft + 1;
47
- // Two triangles per quad
48
- indices.push(topLeft, bottomLeft, topRight);
49
- indices.push(topRight, bottomLeft, bottomRight);
50
- }
51
- }
52
- this.indexCount = indices.length;
53
- // Create buffers
54
- this.vertexBuffer = this.device.createBuffer({
55
- label: "pool vertices",
56
- size: vertices.length * 4,
57
- usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
58
- });
59
- this.device.queue.writeBuffer(this.vertexBuffer, 0, new Float32Array(vertices));
60
- const indexBufferSize = indices.length * 4;
61
- this.indexBuffer = this.device.createBuffer({
62
- label: "pool indices",
63
- size: indexBufferSize,
64
- usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
65
- });
66
- this.device.queue.writeBuffer(this.indexBuffer, 0, new Uint32Array(indices));
67
- // Verify: segments=50 should give 50*50*6 = 15000 indices = 60000 bytes
68
- if (this.indexCount !== indices.length) {
69
- console.warn(`Pool index count mismatch: expected ${indices.length}, got ${this.indexCount}`);
70
- }
71
- }
72
- createShader() {
73
- const shaderModule = this.device.createShaderModule({
74
- label: "pool shader",
75
- code: /* wgsl */ `
76
- struct CameraUniforms {
77
- view: mat4x4f,
78
- projection: mat4x4f,
79
- viewPos: vec3f,
80
- _padding: f32,
81
- };
82
-
83
- struct PoolUniforms {
84
- time: f32,
85
- poolY: f32,
86
- seaColor: vec3f,
87
- seaLight: vec3f,
88
- };
89
-
90
- struct VertexOutput {
91
- @builtin(position) position: vec4f,
92
- @location(0) worldPos: vec3f,
93
- @location(1) uv: vec2f,
94
- };
95
-
96
- @group(0) @binding(0) var<uniform> camera: CameraUniforms;
97
- @group(1) @binding(0) var<uniform> pool: PoolUniforms;
98
-
99
- // Procedural noise function (simplified)
100
- fn hash(p: vec2f) -> f32 {
101
- var p3 = fract(vec3f(p.xyx) * vec3f(443.8975, 397.2973, 491.1871));
102
- p3 += dot(p3, p3.yzx + 19.19);
103
- return fract((p3.x + p3.y) * p3.z);
104
- }
105
-
106
- fn noise(p: vec2f) -> f32 {
107
- let i = floor(p);
108
- var f = fract(p);
109
- f = f * f * (3.0 - 2.0 * f);
110
-
111
- let a = hash(i);
112
- let b = hash(i + vec2f(1.0, 0.0));
113
- let c = hash(i + vec2f(0.0, 1.0));
114
- let d = hash(i + vec2f(1.0, 1.0));
115
-
116
- return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
117
- }
118
-
119
- // Layered noise for water height (adapted from Shadertoy - matches reference exactly)
120
- fn waterHeight(uv: vec2f, time: f32) -> f32 {
121
- var e = 0.0;
122
- // Match Shadertoy: time*mod(j,.789)*.1 - time*.05
123
- for (var j = 1.0; j < 6.0; j += 1.0) {
124
- let timeOffset = time * (j % 0.789) * 0.1 - time * 0.05;
125
- let scaledUV = uv * (j * 1.789) + j * 159.45 + timeOffset;
126
- e += noise(scaledUV) / j;
127
- }
128
- return e / 6.0;
129
- }
130
-
131
- // Calculate water normals from height gradients (matches Shadertoy reference)
132
- fn waterNormals(uv: vec2f, time: f32) -> vec3f {
133
- // Match Shadertoy: uv.x *= .25 (scale X differently for more wave detail)
134
- let scaledUV = vec2f(uv.x * 0.25, uv.y);
135
- let eps = 0.008; // Match Shadertoy epsilon
136
- let h = waterHeight(scaledUV, time);
137
- let hx = waterHeight(scaledUV + vec2f(eps, 0.0), time);
138
- let hz = waterHeight(scaledUV + vec2f(0.0, eps), time);
139
-
140
- // Match Shadertoy normal calculation exactly
141
- let n = vec3f(h - hx, 1.0, h - hz);
142
- return normalize(n);
143
- }
144
-
145
- @vertex fn vs(
146
- @location(0) position: vec3f,
147
- @location(1) uv: vec2f
148
- ) -> VertexOutput {
149
- var output: VertexOutput;
150
-
151
- // Displace Y based on water height - much higher waves
152
- let time = pool.time;
153
- // More wave detail - smaller scale for more waves
154
- // Wave direction: back-left to front-right (both U and V increase)
155
- let waveUV = uv * 12.0 + vec2f(time * 0.3, time * 0.2); // Front-right direction (both positive)
156
- let height = waterHeight(waveUV, time) * 2; // Much higher wave amplitude
157
- let displacedY = position.y + height;
158
-
159
- let worldPos = vec3f(position.x, displacedY, position.z);
160
- output.worldPos = worldPos;
161
- output.uv = uv;
162
- output.position = camera.projection * camera.view * vec4f(worldPos, 1.0);
163
-
164
- return output;
165
- }
166
-
167
- @fragment fn fs(input: VertexOutput) -> @location(0) vec4f {
168
- let time = pool.time;
169
- // More wave detail - smaller scale for more waves (matches Shadertoy approach)
170
- // Wave direction: back-left to front-right (both U and V increase)
171
- let uv = input.uv * 12.0 + vec2f(time * 0.3, time * 0.2); // Front-right direction (both positive)
172
-
173
- // Calculate water normals from height gradients (this creates the wave effect)
174
- let n = waterNormals(uv, time);
175
-
176
- // View direction
177
- let viewDir = normalize(camera.viewPos - input.worldPos);
178
-
179
- // Fresnel effect for reflection (stronger at glancing angles)
180
- var fresnel = 1.0 - max(dot(n, viewDir), 0.0);
181
- fresnel = fresnel * fresnel;
182
-
183
- // Dark night pool - very dark base
184
- let darkPoolColor = vec3f(0.01, 0.02, 0.05); // Very dark blue-black
185
-
186
- // Center spotlight effect - reflection-like bright center
187
- let centerUV = input.uv - vec2f(0.5, 0.5); // Center at (0.5, 0.5)
188
- let distFromCenter = length(centerUV);
189
- // Smaller spotlight area with very smooth, subtle gradient
190
- let spotlightFalloff = 1.0 - smoothstep(0.0, 0.12, distFromCenter); // Smaller radius (0.12)
191
-
192
- // Reflection-like bright center - brighter, balanced blue
193
- let spotlightColor = vec3f(0.2, 0.4, 0.6); // Balanced blue
194
- let spotlightCenter = vec3f(0.5, 0.65, 0.85); // More white center
195
-
196
- // Very smooth, subtle gradient mix - multiple smoothstep layers for smoother transition
197
- let falloff1 = smoothstep(0.0, 0.12, distFromCenter); // Outer edge
198
- let falloff2 = smoothstep(0.0, 0.08, distFromCenter); // Inner edge
199
- var color = mix(darkPoolColor, spotlightColor, (1.0 - falloff1) * 0.9); // Brighter outer gradient
200
- color = mix(color, spotlightCenter, (1.0 - falloff2) * (1.0 - falloff2) * 1.0); // Very bright inner reflection
201
-
202
- // Add reflection-like effect based on view angle and normals
203
- let reflectionFactor = max(dot(n, vec3f(0.0, 1.0, 0.0)), 0.0); // More reflection when looking down
204
- let reflectionBrightness = spotlightFalloff * reflectionFactor * 0.5;
205
- color += spotlightCenter * reflectionBrightness; // Add reflection-like brightness
206
-
207
- // Wave-based color variation (matches Shadertoy transparency approach)
208
- // Match Shadertoy: transparency = dot(n, vec3(0.,.2,1.5)) * 12. + 1.5
209
- var transparency = dot(n, vec3f(0.0, 0.2, 1.5));
210
- transparency = (transparency * 12.0 + 1.5);
211
-
212
- // Match Shadertoy color mixing: mix with seaColor and seaLight (brighter, balanced blue)
213
- let seaColor = vec3f(0.08, 0.18, 0.3); // Balanced blue
214
- let seaLight = vec3f(0.12, 0.25, 0.45); // Balanced blue
215
- // Only apply this mixing subtly to avoid green tint
216
- color = mix(color, seaColor, clamp(transparency, 0.0, 1.0) * 0.3);
217
- color = mix(color, seaLight, max(0.0, transparency - 1.5) * 0.2);
218
-
219
- // Enhanced wave-based color variation for more visible waves
220
- let waveHeight = waterHeight(uv, time);
221
- let waveContrast = (waveHeight - 0.5) * 0.3; // Amplify wave contrast
222
- color += vec3f(0.05, 0.08, 0.15) * waveContrast * spotlightFalloff; // Balanced blue wave highlights
223
-
224
- // Enhanced underwater glow - white/neutral glow with subtle blue tint, much brighter
225
- let glowIntensity = spotlightFalloff * 0.6 + fresnel * 0.3 + waveHeight * 0.2; // Stronger glow
226
- let glowColor = vec3f(0.35, 0.35, 0.45); // Brighter glow with subtle blue tint
227
- color += glowColor * glowIntensity;
228
-
229
- // Additional subtle white glow around the center, brighter and more white
230
- let centerGlow = spotlightFalloff * spotlightFalloff * 0.4; // Soft glow falloff
231
- let whiteGlow = vec3f(0.55, 0.55, 0.6); // Brighter white glow
232
- color += whiteGlow * centerGlow * 0.7; // Brighter white center glow
233
-
234
- // Reflection of dark night sky
235
- let nightSkyColor = vec3f(0.02, 0.04, 0.08); // Very dark night sky
236
- let reflection = mix(darkPoolColor, nightSkyColor, fresnel * 0.2);
237
- color = mix(color, reflection, fresnel * 0.3 * (1.0 - spotlightFalloff)); // Less reflection in spotlight
238
-
239
- // Specular highlights from underwater lights (bokeh-like bright spots)
240
- let lightDir1 = normalize(vec3f(0.3, -0.4, 0.6));
241
- let lightDir2 = normalize(vec3f(-0.3, -0.3, 0.7));
242
- let reflDir1 = reflect(-lightDir1, n);
243
- let reflDir2 = reflect(-lightDir2, n);
244
- var specular1 = max(dot(viewDir, reflDir1), 0.0);
245
- var specular2 = max(dot(viewDir, reflDir2), 0.0);
246
- specular1 = pow(specular1, 150.0); // Tight, bright highlights
247
- specular2 = pow(specular2, 180.0);
248
- // Subtle white/blue highlights (bokeh effect) - darker, less blue
249
- color += vec3f(0.8, 0.8, 0.9) * specular1 * 1.2 * spotlightFalloff; // Darker white
250
- color += vec3f(0.4, 0.5, 0.7) * specular2 * 0.9 * spotlightFalloff; // Darker, less blue
251
-
252
- return vec4f(color, 0.8); // Half transparent water
253
- }
254
- `,
255
- });
256
- // Create bind group layout for pool uniforms
257
- this.bindGroupLayout = this.device.createBindGroupLayout({
258
- label: "pool bind group layout",
259
- entries: [
260
- {
261
- binding: 0,
262
- visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
263
- buffer: {
264
- type: "uniform",
265
- },
266
- },
267
- ],
268
- });
269
- // Create render pipeline
270
- this.pipeline = this.device.createRenderPipeline({
271
- label: "pool pipeline",
272
- layout: this.device.createPipelineLayout({
273
- bindGroupLayouts: [this.cameraBindGroupLayout, this.bindGroupLayout],
274
- }),
275
- vertex: {
276
- module: shaderModule,
277
- entryPoint: "vs",
278
- buffers: [
279
- {
280
- arrayStride: 5 * 4, // 3 floats (position) + 2 floats (uv)
281
- attributes: [
282
- {
283
- shaderLocation: 0,
284
- offset: 0,
285
- format: "float32x3",
286
- },
287
- {
288
- shaderLocation: 1,
289
- offset: 3 * 4,
290
- format: "float32x2",
291
- },
292
- ],
293
- },
294
- ],
295
- },
296
- fragment: {
297
- module: shaderModule,
298
- entryPoint: "fs",
299
- targets: [
300
- {
301
- format: "bgra8unorm",
302
- blend: {
303
- color: {
304
- srcFactor: "src-alpha",
305
- dstFactor: "one-minus-src-alpha",
306
- },
307
- alpha: {
308
- srcFactor: "one",
309
- dstFactor: "one-minus-src-alpha",
310
- },
311
- },
312
- },
313
- ],
314
- },
315
- primitive: {
316
- topology: "triangle-list",
317
- cullMode: "none",
318
- },
319
- depthStencil: {
320
- depthWriteEnabled: true,
321
- depthCompare: "less-equal",
322
- format: "depth24plus-stencil8",
323
- },
324
- multisample: {
325
- count: 4,
326
- },
327
- });
328
- }
329
- createUniforms() {
330
- // Create uniform buffer
331
- // WGSL uniform buffers require 16-byte alignment:
332
- // time: f32 (4) + poolY (4) + padding (8) = 16 bytes
333
- // seaColor: vec3f (12) + padding (4) = 16 bytes
334
- // seaLight: vec3f (12) + padding (4) = 16 bytes
335
- // Total: 48 bytes
336
- this.uniformBuffer = this.device.createBuffer({
337
- label: "pool uniforms",
338
- size: 48,
339
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
340
- });
341
- // Create bind group
342
- this.bindGroup = this.device.createBindGroup({
343
- label: "pool bind group",
344
- layout: this.bindGroupLayout,
345
- entries: [
346
- {
347
- binding: 0,
348
- resource: {
349
- buffer: this.uniformBuffer,
350
- },
351
- },
352
- ],
353
- });
354
- // Create camera bind group
355
- this.cameraBindGroup = this.device.createBindGroup({
356
- label: "pool camera bind group",
357
- layout: this.cameraBindGroupLayout,
358
- entries: [
359
- {
360
- binding: 0,
361
- resource: {
362
- buffer: this.cameraUniformBuffer,
363
- },
364
- },
365
- ],
366
- });
367
- }
368
- updateUniforms() {
369
- const time = (performance.now() - this.startTime) / 1000.0;
370
- // WGSL uniform buffer layout (16-byte aligned):
371
- // offset 0: time (f32), poolY (f32), padding (8 bytes)
372
- // offset 16: seaColor (vec3f), padding (4 bytes)
373
- // offset 32: seaLight (vec3f), padding (4 bytes)
374
- const data = new Float32Array(12);
375
- data[0] = time;
376
- data[1] = this.y;
377
- // data[2-3] = padding (unused)
378
- data[4] = this.seaColor.x;
379
- data[5] = this.seaColor.y;
380
- data[6] = this.seaColor.z;
381
- // data[7] = padding (unused)
382
- data[8] = this.seaLight.x;
383
- data[9] = this.seaLight.y;
384
- data[10] = this.seaLight.z;
385
- // data[11] = padding (unused)
386
- this.device.queue.writeBuffer(this.uniformBuffer, 0, data);
387
- }
388
- render(pass, restoreBuffers) {
389
- this.updateUniforms();
390
- // Set pool's pipeline and bind groups FIRST
391
- pass.setPipeline(this.pipeline);
392
- pass.setBindGroup(0, this.cameraBindGroup);
393
- pass.setBindGroup(1, this.bindGroup);
394
- // IMPORTANT: Set pool's own buffers AFTER setting pipeline
395
- // Pool only needs vertex buffer 0 (position + UV), but we must keep buffers 1 and 2 set
396
- // for subsequent model rendering (eyes, hair, etc.)
397
- pass.setVertexBuffer(0, this.vertexBuffer);
398
- // Explicitly keep model's buffers 1 and 2 set - pool pipeline doesn't use them but they must stay
399
- if (restoreBuffers) {
400
- pass.setVertexBuffer(1, restoreBuffers.jointsBuffer);
401
- pass.setVertexBuffer(2, restoreBuffers.weightsBuffer);
402
- }
403
- // Set pool's index buffer - this MUST be set to override model's index buffer
404
- pass.setIndexBuffer(this.indexBuffer, "uint32");
405
- // Draw all pool indices starting from 0
406
- // Parameters: indexCount, instanceCount, firstIndex, baseVertex, firstInstance
407
- // We always draw from index 0 with all indices
408
- pass.drawIndexed(this.indexCount, 1, 0, 0, 0);
409
- // Restore model's buffers for subsequent rendering (eyes, hair, etc.)
410
- // This ensures vertex buffer 0 and index buffer are restored to model's buffers
411
- if (restoreBuffers) {
412
- pass.setVertexBuffer(0, restoreBuffers.vertexBuffer);
413
- pass.setVertexBuffer(1, restoreBuffers.jointsBuffer);
414
- pass.setVertexBuffer(2, restoreBuffers.weightsBuffer);
415
- pass.setIndexBuffer(restoreBuffers.indexBuffer, "uint32");
416
- }
417
- }
418
- dispose() {
419
- // Buffers will be cleaned up automatically when device is lost
420
- // But we could explicitly destroy them if needed
421
- }
422
- }
@@ -1,47 +0,0 @@
1
- /**
2
- * Bezier interpolation for VMD animations
3
- * Based on the reference implementation from babylon-mmd
4
- */
5
-
6
- /**
7
- * Bezier interpolation function
8
- * @param x1 First control point X (0-127, normalized to 0-1)
9
- * @param x2 Second control point X (0-127, normalized to 0-1)
10
- * @param y1 First control point Y (0-127, normalized to 0-1)
11
- * @param y2 Second control point Y (0-127, normalized to 0-1)
12
- * @param t Interpolation parameter (0-1)
13
- * @returns Interpolated value (0-1)
14
- */
15
- export function bezierInterpolate(x1: number, x2: number, y1: number, y2: number, t: number): number {
16
- // Clamp t to [0, 1]
17
- t = Math.max(0, Math.min(1, t))
18
-
19
- // Binary search for the t value that gives us the desired x
20
- // We're solving for t in the Bezier curve: x(t) = 3*(1-t)^2*t*x1 + 3*(1-t)*t^2*x2 + t^3
21
- let start = 0
22
- let end = 1
23
- let mid = 0.5
24
-
25
- // Iterate until we find the t value that gives us the desired x
26
- for (let i = 0; i < 15; i++) {
27
- // Evaluate Bezier curve at mid point
28
- const x = 3 * (1 - mid) * (1 - mid) * mid * x1 + 3 * (1 - mid) * mid * mid * x2 + mid * mid * mid
29
-
30
- if (Math.abs(x - t) < 0.0001) {
31
- break
32
- }
33
-
34
- if (x < t) {
35
- start = mid
36
- } else {
37
- end = mid
38
- }
39
-
40
- mid = (start + end) / 2
41
- }
42
-
43
- // Now evaluate the y value at this t
44
- const y = 3 * (1 - mid) * (1 - mid) * mid * y1 + 3 * (1 - mid) * mid * mid * y2 + mid * mid * mid
45
-
46
- return y
47
- }