mirror of
https://github.com/supabase/supabase.git
synced 2026-10-15 22:29:11 +03:00
Fix wireframe size in debug mode
Signed-off-by: Piotr Goszczyński <pg@tonik.com>
This commit is contained in:
1 parent
84206336f8
commit
7a922e6678
2 files changed
+197
-61
No files matched your search
@@ -9,6 +9,7 @@ import { GlitchPass } from './glitch'
|
||||
import { CRTShader } from './crt-shader'
|
||||
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js'
|
||||
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js'
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
|
||||
|
||||
/**
|
||||
* Helper to simplifies controlling requestAnimationFrame
|
||||
@@ -66,11 +67,17 @@ export const createThreeSetup = (
|
||||
enabled: boolean
|
||||
}
|
||||
}
|
||||
debug?: boolean
|
||||
} = {}
|
||||
) => {
|
||||
// Create scene
|
||||
const scene = new THREE.Scene()
|
||||
|
||||
if (options.debug) {
|
||||
const axesHelper = new THREE.AxesHelper(5)
|
||||
scene.add(axesHelper)
|
||||
}
|
||||
|
||||
// Create camera
|
||||
const camera = new THREE.PerspectiveCamera(
|
||||
75,
|
||||
@@ -86,6 +93,12 @@ export const createThreeSetup = (
|
||||
renderer.setPixelRatio(window.devicePixelRatio)
|
||||
container.appendChild(renderer.domElement)
|
||||
|
||||
// Enable debug info if debug mode is enabled
|
||||
if (options.debug) {
|
||||
renderer.info.autoReset = false
|
||||
console.log('Three.js Debug Mode Enabled')
|
||||
}
|
||||
|
||||
// Create composer for post-processing
|
||||
const composer = new EffectComposer(renderer)
|
||||
const renderPass = new RenderPass(scene, camera)
|
||||
@@ -132,6 +145,33 @@ export const createThreeSetup = (
|
||||
}
|
||||
}
|
||||
|
||||
// Add stats display if debug mode is enabled
|
||||
let stats: { instance: Stats | null } = { instance: null }
|
||||
let orbitControls: { instance: OrbitControls | null } = { instance: null }
|
||||
if (options.debug) {
|
||||
import('three/examples/jsm/libs/stats.module.js').then(({ default: Stats }) => {
|
||||
const statsInstance = new Stats()
|
||||
statsInstance.showPanel(0) // 0: fps, 1: ms, 2: mb, 3+: custom
|
||||
statsInstance.dom.style.position = 'absolute'
|
||||
statsInstance.dom.style.top = '0px'
|
||||
statsInstance.dom.style.left = '0px'
|
||||
container.appendChild(statsInstance.dom)
|
||||
stats.instance = statsInstance
|
||||
})
|
||||
|
||||
import('three/examples/jsm/controls/OrbitControls.js').then(({ OrbitControls }) => {
|
||||
// Create OrbitControls after the setup
|
||||
const controls = new OrbitControls(camera, renderer.domElement)
|
||||
|
||||
// Configure controls as needed
|
||||
controls.enableDamping = true // Add smooth damping
|
||||
controls.dampingFactor = 0.05
|
||||
controls.enableZoom = true
|
||||
controls.enablePan = true
|
||||
orbitControls.instance = controls
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
scene,
|
||||
camera,
|
||||
@@ -141,6 +181,9 @@ export const createThreeSetup = (
|
||||
bloomPass,
|
||||
glitchPass,
|
||||
crtPass,
|
||||
stats,
|
||||
orbitControls,
|
||||
debug: options.debug || false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,6 +234,7 @@ export const createTicketMesh = async (
|
||||
height?: number
|
||||
forceTextureMode?: boolean
|
||||
enhanceEmissive?: boolean
|
||||
debug?: boolean
|
||||
materialOptions?: {
|
||||
transparent?: boolean
|
||||
emissiveColor?: THREE.Color | number
|
||||
@@ -200,9 +244,9 @@ export const createTicketMesh = async (
|
||||
} = {}
|
||||
): Promise<THREE.Object3D> => {
|
||||
try {
|
||||
const width = options.width || 4
|
||||
const height = options.height || 2
|
||||
|
||||
// const width = options.width || 4
|
||||
// const height = options.height || 2
|
||||
//
|
||||
// Determine if we should use texture mode
|
||||
const useTextureMode =
|
||||
options.forceTextureMode || !(source.endsWith('.glb') || source.endsWith('.gltf'))
|
||||
@@ -210,49 +254,73 @@ export const createTicketMesh = async (
|
||||
if (!useTextureMode) {
|
||||
// Load the GLTF model
|
||||
const model = await loadGLTFModel(source)
|
||||
const objectsNames = ['planet'] as const
|
||||
const namedObjects = getNamedTextObjects(objectsNames, model)
|
||||
const textures = {} as {
|
||||
[key in (typeof objectsNames)[number]]?: ReturnType<typeof createTextureForObject>
|
||||
}
|
||||
|
||||
const namedObject = model.getObjectByName('planetName')
|
||||
for (let i = 0; i < namedObjects.length; i++) {
|
||||
const namedObject = namedObjects[i]
|
||||
const objectName = objectsNames[i]
|
||||
|
||||
const boxHelper = new THREE.BoxHelper(namedObject, 0xff0000) // Red outline
|
||||
model.add(boxHelper) // Add to the model so it moves with it
|
||||
if (!namedObject) {
|
||||
console.error(`Named object ${objectsNames} not found`)
|
||||
continue
|
||||
}
|
||||
|
||||
const fontLoader = new FontLoader()
|
||||
let text = ''
|
||||
switch (objectName) {
|
||||
case 'planet':
|
||||
text = 'Earth'
|
||||
break
|
||||
default:
|
||||
objectName satisfies never
|
||||
}
|
||||
|
||||
fontLoader.load('/images/launchweek/14/Arial_Regular.json', function (font) {
|
||||
const textGeometry = new TextGeometry('Earth', {
|
||||
font: font,
|
||||
size: 96,
|
||||
depth: 0.05,
|
||||
})
|
||||
|
||||
const textMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff })
|
||||
const textMesh = new THREE.Mesh(textGeometry, textMaterial)
|
||||
|
||||
// Add text as child of your named object
|
||||
if (namedObject) namedObject.add(textMesh)
|
||||
else console.error('Named object not found')
|
||||
|
||||
// Position relative to parent
|
||||
textMesh.position.set(0, 0, 0.01) // Slight offset to avoid z-fighting
|
||||
})
|
||||
const texture = createTextureForObject(namedObject, text)
|
||||
textures[objectName] = texture
|
||||
namedObject.add(texture)
|
||||
}
|
||||
|
||||
// Calculate scale to fit the model within the specified width and height
|
||||
const box = new THREE.Box3().setFromObject(model)
|
||||
const size = box.getSize(new THREE.Vector3())
|
||||
|
||||
// Calculate scale factors to fit the model within the specified dimensions
|
||||
const scaleX = width / size.x
|
||||
const scaleY = height / size.y
|
||||
const scale = Math.min(scaleX, scaleY)
|
||||
|
||||
// Apply the scale
|
||||
model.scale.set(scale, scale, scale)
|
||||
|
||||
// Center the model
|
||||
box.setFromObject(model)
|
||||
const center = box.getCenter(new THREE.Vector3())
|
||||
model.position.sub(center)
|
||||
|
||||
// Add debug helpers if debug mode is enabled
|
||||
if (options.debug) {
|
||||
// Add bounding box helper
|
||||
const boxHelper = new THREE.BoxHelper(model, 0xff0000)
|
||||
model.add(boxHelper)
|
||||
|
||||
// Add wireframe helper for each mesh
|
||||
model.traverse((child) => {
|
||||
if (child instanceof THREE.Mesh) {
|
||||
const wireframe = new THREE.WireframeGeometry(child.geometry)
|
||||
const line = new THREE.LineSegments(wireframe)
|
||||
line.material = new THREE.LineBasicMaterial({ color: 0x00ffff })
|
||||
line.position.copy(child.position)
|
||||
line.rotation.copy(child.rotation)
|
||||
line.scale.copy(child.scale)
|
||||
model.add(line)
|
||||
|
||||
if(!child.name) {
|
||||
console.log('Debug: Mesh has no name', child)
|
||||
}
|
||||
|
||||
console.log('Debug: Added wireframe to mesh', child.name || 'unnamed')
|
||||
}
|
||||
})
|
||||
|
||||
console.log('Debug: Model dimensions', size)
|
||||
console.log('Debug: Center position', center)
|
||||
}
|
||||
|
||||
// Only enhance emissive properties if explicitly requested
|
||||
// This respects the original GLTF materials by default
|
||||
if (options.enhanceEmissive) {
|
||||
@@ -278,35 +346,8 @@ export const createTicketMesh = async (
|
||||
}
|
||||
|
||||
return model
|
||||
} else {
|
||||
// Load as a texture
|
||||
const texture = await loadTexture(source)
|
||||
|
||||
// Create a plane geometry for the ticket
|
||||
const geometry = new THREE.PlaneGeometry(width, height)
|
||||
|
||||
// Create a material with the loaded texture
|
||||
const material = new THREE.MeshStandardMaterial({
|
||||
map: texture,
|
||||
transparent:
|
||||
options.materialOptions?.transparent !== undefined
|
||||
? options.materialOptions.transparent
|
||||
: true,
|
||||
side: THREE.DoubleSide,
|
||||
emissive: options.materialOptions?.emissiveColor
|
||||
? new THREE.Color(options.materialOptions.emissiveColor)
|
||||
: new THREE.Color(0xffffff),
|
||||
emissiveIntensity: options.materialOptions?.emissiveIntensity ?? 0.2,
|
||||
color: options.materialOptions?.color
|
||||
? new THREE.Color(options.materialOptions.color)
|
||||
: new THREE.Color(0xffffff),
|
||||
})
|
||||
|
||||
// Create the mesh
|
||||
const mesh = new THREE.Mesh(geometry, material)
|
||||
|
||||
return mesh
|
||||
}
|
||||
}
|
||||
throw new Error(`Failed to load model from: ${source}`)
|
||||
} catch (error) {
|
||||
console.error('Error loading model/texture:', error)
|
||||
|
||||
@@ -381,3 +422,97 @@ export const useThreeJS = (
|
||||
|
||||
return { containerRef }
|
||||
}
|
||||
|
||||
function getNamedTextObjects<TNamedObjects extends readonly string[]>(
|
||||
names: TNamedObjects,
|
||||
model: THREE.Group<THREE.Object3DEventMap>
|
||||
): { [K in keyof TNamedObjects]: THREE.Object3D | null } {
|
||||
let namedObjects = Array(names.length).fill(null) as (THREE.Object3D | null)[]
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
const name = names[i]
|
||||
const obj = model.getObjectByName(name)
|
||||
if (obj) {
|
||||
namedObjects[i] = obj
|
||||
}
|
||||
}
|
||||
|
||||
return namedObjects as { [K in keyof TNamedObjects]: THREE.Object3D | null }
|
||||
}
|
||||
|
||||
function createTextureForObject(object: THREE.Object3D, text: string) {
|
||||
const box = new THREE.Box3().setFromObject(object)
|
||||
const size = box.getSize(new THREE.Vector3())
|
||||
|
||||
const canvas = document.createElement('canvas')
|
||||
const canvasWidth = 512 // Base canvas width
|
||||
const canvasHeight = Math.floor(canvasWidth * (size.y / size.x)) // Maintain aspect ratio
|
||||
|
||||
canvas.width = canvasWidth
|
||||
canvas.height = canvasHeight
|
||||
|
||||
// Get canvas context and set up text rendering
|
||||
const context = canvas.getContext('2d')
|
||||
|
||||
if (!context) {
|
||||
throw new Error(`Could not get 2D context for text "${text}"`)
|
||||
}
|
||||
|
||||
// Clear canvas
|
||||
context.clearRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
// Optional: fill background (can be transparent)
|
||||
context.fillStyle = 'rgba(0, 0, 0, 0.5)'
|
||||
context.fillRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
// Set text properties
|
||||
context.fillStyle = 'white'
|
||||
|
||||
// Calculate font size based on canvas dimensions
|
||||
// Adjust the divisor to control text size relative to canvas
|
||||
const fontSize = Math.floor(canvasWidth / 5)
|
||||
context.font = `bold ${fontSize}px Arial`
|
||||
|
||||
// Center text
|
||||
context.textAlign = 'center'
|
||||
context.textBaseline = 'middle'
|
||||
context.fillText(text, canvas.width / 2, canvas.height / 2)
|
||||
|
||||
// Debug info - draw canvas border
|
||||
context.strokeStyle = 'red'
|
||||
context.lineWidth = 4
|
||||
context.strokeRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
// Debug info - draw center point
|
||||
context.fillStyle = 'red'
|
||||
context.beginPath()
|
||||
context.arc(canvas.width / 2, canvas.height / 2, 5, 0, Math.PI * 2)
|
||||
context.fill()
|
||||
|
||||
// Create texture from canvas
|
||||
const texture = new THREE.CanvasTexture(canvas)
|
||||
texture.needsUpdate = true
|
||||
|
||||
// Create a plane geometry sized to match the named object
|
||||
const textPlane = new THREE.PlaneGeometry(20, 10)
|
||||
const textMaterial = new THREE.MeshBasicMaterial({
|
||||
map: texture,
|
||||
transparent: true,
|
||||
side: THREE.DoubleSide,
|
||||
depthWrite: false, // Prevents z-fighting
|
||||
})
|
||||
|
||||
const textMesh = new THREE.Mesh(textPlane, textMaterial)
|
||||
|
||||
// Position the text slightly in front of the object
|
||||
// Adjust the z-offset as needed to prevent z-fighting
|
||||
textMesh.position.set(0, 0, 0.01)
|
||||
textMesh.rotation.set(0, 0, 0) // Rotate 180 degrees to face the camera
|
||||
|
||||
console.log('canvasWidth', canvasWidth)
|
||||
console.log('canvasHeight', canvasHeight)
|
||||
console.log('size', size)
|
||||
console.log('text', text)
|
||||
console.log('fontSize', fontSize)
|
||||
|
||||
return textMesh
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"glyphs": {"0": {"ha": 833, "x_min": 99, "x_max": 735, "o": "m 417 -17 q 183 103 268 -17 q 99 446 99 224 q 183 786 99 669 q 417 903 268 903 q 650 786 565 903 q 735 446 735 669 q 650 103 735 224 q 417 -17 565 -17 m 417 75 q 569 165 510 75 q 628 446 628 256 q 613 610 628 542 q 569 724 597 679 q 501 790 540 769 q 417 811 463 811 q 332 790 371 811 q 265 724 293 769 q 221 610 236 679 q 206 446 206 542 q 265 165 206 256 q 417 75 324 75 m 417 363 q 356 387 382 363 q 331 456 331 411 q 356 523 331 499 q 417 547 382 547 q 477 523 451 547 q 503 456 503 499 q 477 387 503 411 q 417 363 451 363 z "}, "1": {"ha": 833, "x_min": 135, "x_max": 736, "o": "m 135 0 l 135 94 l 390 94 l 390 747 l 192 747 l 192 821 q 324 847 271 832 q 419 886 376 863 l 504 886 l 504 94 l 736 94 l 736 0 l 135 0 z "}, "2": {"ha": 833, "x_min": 96, "x_max": 725, "o": "m 101 0 l 101 68 q 301 249 214 168 q 447 397 388 329 q 536 522 506 464 q 567 636 567 581 q 519 761 567 713 q 374 810 472 810 q 258 778 311 810 q 161 703 204 747 l 96 768 q 224 866 156 829 q 388 903 293 903 q 508 884 454 903 q 599 831 561 865 q 656 749 636 797 q 676 642 676 700 q 647 516 676 579 q 563 385 617 453 q 433 245 508 318 q 268 90 358 172 q 351 96 310 93 q 433 99 393 99 l 725 99 l 725 0 l 101 0 z "}, "3": {"ha": 833, "x_min": 79, "x_max": 719, "o": "m 399 -17 q 206 22 283 -17 q 79 108 128 60 l 138 183 q 244 110 182 142 q 392 78 306 78 q 476 90 438 78 q 544 122 515 101 q 588 173 572 143 q 604 240 604 203 q 587 312 604 279 q 531 368 569 344 q 431 404 492 392 q 282 417 369 417 l 282 504 q 416 517 361 504 q 506 551 471 529 q 556 604 540 574 q 572 669 572 635 q 523 772 572 735 q 392 810 474 810 q 274 785 329 810 q 174 719 218 760 l 113 792 q 239 872 168 840 q 396 903 310 903 q 512 888 458 903 q 605 844 565 872 q 667 774 644 815 q 689 678 689 732 q 636 546 689 597 q 500 467 583 494 l 500 461 q 584 433 544 451 q 654 385 624 414 q 702 319 685 357 q 719 236 719 282 q 694 131 719 178 q 626 51 669 83 q 524 1 582 18 q 399 -17 465 -17 z "}, "4": {"ha": 833, "x_min": 54, "x_max": 757, "o": "m 511 0 l 511 244 l 54 244 l 54 321 l 497 886 l 619 886 l 619 336 l 757 336 l 757 244 l 619 244 l 619 0 l 511 0 m 181 336 l 511 336 l 511 611 q 514 690 513 647 q 518 768 515 732 l 511 768 q 467 703 490 736 q 421 639 443 671 l 181 336 z "}, "5": {"ha": 833, "x_min": 78, "x_max": 725, "o": "m 397 -17 q 290 -6 338 -17 q 203 21 242 4 q 134 59 165 38 q 78 104 103 81 l 135 179 q 182 141 157 160 q 237 108 207 122 q 303 86 267 94 q 385 78 340 78 q 473 92 432 78 q 544 133 514 107 q 592 197 575 160 q 610 281 610 235 q 551 424 610 372 q 392 475 492 475 q 297 461 336 475 q 211 421 258 447 l 150 460 l 179 886 l 681 886 l 681 788 l 281 788 l 257 525 q 333 551 296 542 q 421 561 369 561 q 540 544 485 561 q 637 494 596 528 q 701 408 678 460 q 725 283 725 356 q 698 156 725 211 q 625 62 671 100 q 520 3 579 24 q 397 -17 461 -17 z "}, "6": {"ha": 833, "x_min": 107, "x_max": 742, "o": "m 446 -17 q 312 10 374 -17 q 204 90 250 36 q 133 223 158 143 q 107 410 107 303 q 138 637 107 543 q 219 790 168 731 q 338 876 271 849 q 478 903 406 903 q 620 876 560 903 q 725 808 681 849 l 661 738 q 581 788 626 769 q 485 807 535 807 q 383 788 432 807 q 298 724 335 768 q 238 606 261 679 q 214 426 215 533 q 333 510 268 479 q 465 542 399 542 q 577 524 526 542 q 665 473 628 507 q 722 388 701 439 q 742 268 742 336 q 717 152 742 204 q 653 63 693 100 q 559 4 613 25 q 446 -17 506 -17 m 446 74 q 519 88 485 74 q 579 127 554 101 q 619 188 604 153 q 633 268 633 224 q 585 408 633 360 q 444 456 536 456 q 331 428 392 456 q 218 336 271 400 q 290 140 231 207 q 446 74 349 74 z "}, "7": {"ha": 833, "x_min": 97, "x_max": 739, "o": "m 314 0 q 338 230 319 126 q 390 426 356 333 q 478 607 425 519 q 608 788 532 694 l 97 788 l 97 886 l 739 886 l 739 815 q 594 624 651 715 q 503 437 538 532 q 453 236 468 342 q 433 0 438 131 l 314 0 z "}, "8": {"ha": 833, "x_min": 94, "x_max": 738, "o": "m 419 -17 q 284 1 344 -17 q 182 52 224 19 q 117 129 140 85 q 94 226 94 174 q 111 308 94 272 q 154 374 128 344 q 215 424 181 403 q 285 463 249 446 l 285 468 q 190 553 229 503 q 150 675 150 604 q 170 768 150 726 q 227 840 190 810 q 314 886 264 869 q 424 903 364 903 q 540 885 489 903 q 626 837 590 868 q 680 762 661 806 q 699 667 699 718 q 659 549 699 604 q 564 456 619 494 l 564 450 q 632 411 600 432 q 688 364 664 390 q 724 302 711 338 q 738 219 738 267 q 716 126 738 169 q 654 51 694 83 q 555 1 614 19 q 419 -17 496 -17 m 489 483 q 600 661 600 564 q 554 773 600 728 q 421 818 508 818 q 300 779 346 818 q 254 675 254 740 q 272 606 254 635 q 322 556 290 578 q 397 516 354 533 q 489 483 439 499 m 422 68 q 575 111 522 68 q 628 224 628 154 q 606 301 628 269 q 547 354 585 332 q 459 394 510 376 q 350 431 408 411 q 242 349 285 394 q 199 238 199 304 q 259 115 199 163 q 422 68 319 68 z "}, "9": {"ha": 833, "x_min": 93, "x_max": 728, "o": "m 390 431 q 503 458 443 431 q 617 549 563 486 q 545 746 603 679 q 389 813 488 813 q 315 799 349 813 q 256 759 281 785 q 216 697 231 733 q 201 618 201 661 q 249 478 201 526Line truncated
|
||||
Reference in new issue
Block a user