take only building layers to the thumbnail

This commit is contained in:
wass08
2026-03-02 10:01:22 +09:00
parent 8e097537d0
commit 0f271985d8
9 changed files with 142 additions and 74 deletions
@@ -3,8 +3,10 @@
import { type CameraControlEvent, emitter, sceneRegistry, useScene } from '@pascal-app/core'
import { useViewer } from '@pascal-app/viewer'
import { CameraControls, CameraControlsImpl } from '@react-three/drei'
import { useThree } from '@react-three/fiber'
import { useCallback, useEffect, useMemo, useRef } from 'react'
import { Vector3 } from 'three'
import { EDITOR_LAYER } from '@/lib/constants'
const currentTarget = new Vector3()
@@ -13,6 +15,11 @@ export const CustomCameraControls = () => {
const currentLevelId = useViewer((state) => state.selection.levelId)
const firstLoad = useRef(true)
const camera = useThree((state) => state.camera)
useEffect(() => {
camera.layers.enable(EDITOR_LAYER)
}, [camera])
useEffect(() => {
let targetY = 0
if (currentLevelId) {
+11 -13
View File
@@ -2,14 +2,13 @@
import { emitter, type GridEvent, sceneRegistry } from '@pascal-app/core'
import { useViewer } from '@pascal-app/viewer'
import { useFrame } from '@react-three/fiber'
import { useEffect, useMemo, useRef, useState } from 'react'
import { MathUtils, type Mesh, Vector2 } from 'three'
import { color, float, fract, fwidth, mix, positionLocal, uniform } from 'three/tsl'
import { MeshBasicNodeMaterial } from 'three/webgpu'
import { useGridEvents } from '@/hooks/use-grid-events'
import { EDITOR_LAYER } from '@/lib/constants'
export const Grid = ({
cellSize = 0.5,
@@ -103,16 +102,15 @@ export const Grid = ({
depthWrite: false,
})
}, [
cellSize,
cellThickness,
effectiveCellColor,
sectionSize,
sectionThickness,
effectiveSectionColor,
fadeDistance,
fadeStrength,
revealRadius,
theme,
cellSize,
cellThickness,
effectiveCellColor,
sectionSize,
sectionThickness,
effectiveSectionColor,
fadeDistance,
fadeStrength,
revealRadius
])
const gridRef = useRef<Mesh>(null!)
@@ -150,7 +148,7 @@ export const Grid = ({
const showGrid = useViewer((state) => state.showGrid)
return (
<mesh rotation-x={-Math.PI / 2} material={material} ref={gridRef} visible={showGrid}>
<mesh rotation-x={-Math.PI / 2} material={material} ref={gridRef} visible={showGrid} layers={EDITOR_LAYER}>
<planeGeometry args={[fadeDistance * 2, fadeDistance * 2]} />
</mesh>
)
@@ -1,11 +1,13 @@
'use client'
import { emitter, useScene } from '@pascal-app/core'
import { snapLevelsToTruePositions } from '@pascal-app/viewer'
import { useThree } from '@react-three/fiber'
import { useCallback, useEffect, useRef } from 'react'
import * as THREE from 'three'
import { uploadProjectThumbnail } from '@/features/community/lib/projects/actions'
import { useProjectStore } from '@/features/community/lib/projects/store'
import { EDITOR_LAYER } from '@/lib/constants'
const THUMBNAIL_WIDTH = 1920
const THUMBNAIL_HEIGHT = 1080
@@ -46,14 +48,18 @@ export const ThumbnailGenerator = ({ projectId: propProjectId }: ThumbnailGenera
thumbnailCamera.position.set(8, 8, 8)
thumbnailCamera.lookAt(0, 0, 0)
}
thumbnailCamera.layers.disable(EDITOR_LAYER) // Render only default layer to exclude helper visuals
// Match camera aspect to current canvas so the render looks correct
const { width, height } = gl.domElement
thumbnailCamera.aspect = width / height
thumbnailCamera.updateProjectionMatrix()
// Render with thumbnail camera — main canvas is never resized
// Snap levels to true stacked positions so the thumbnail always shows a clean view,
// regardless of the current levelMode (exploded, solo, etc.)
const restoreLevels = snapLevelsToTruePositions()
gl.render(scene, thumbnailCamera)
restoreLevels()
// Center-crop the canvas to the thumbnail aspect ratio, then scale — avoids deformation
const srcAspect = width / height
@@ -2,6 +2,7 @@ import { emitter, type GridEvent, sceneRegistry } from '@pascal-app/core'
import { createPortal } from '@react-three/fiber'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { BufferGeometry, Float32BufferAttribute, type Mesh } from 'three'
import { EDITOR_LAYER } from '@/lib/constants'
import { sfxEmitter } from '@/lib/sfx-bus'
const Y_OFFSET = 0.02
@@ -212,10 +213,10 @@ export const PolygonEditor: React.FC<PolygonEditorProps> = ({
const canDelete = displayPolygon.length > minVertices
const editorContent = (
<group>
<group >
{/* Border line */}
{/* @ts-ignore */}
<line ref={lineRef} frustumCulled={false} renderOrder={10} raycast={() => {}}>
<line ref={lineRef} frustumCulled={false} renderOrder={10} raycast={() => {}} layers={EDITOR_LAYER}>
<bufferGeometry />
<lineBasicNodeMaterial
color={color}
@@ -236,6 +237,7 @@ export const PolygonEditor: React.FC<PolygonEditorProps> = ({
return (
<mesh
layers={EDITOR_LAYER}
key={`vertex-${index}`}
position={[x!, editY + height / 2, z!]}
castShadow
@@ -286,6 +288,7 @@ export const PolygonEditor: React.FC<PolygonEditorProps> = ({
return (
<mesh
layers={EDITOR_LAYER}
key={`midpoint-${index}`}
position={[x!, editY + height / 2, z!]}
onPointerEnter={(e) => {
+3
View File
@@ -0,0 +1,3 @@
/** Three.js layer used for editor-only objects (helpers, grid, polygon editors).
* The thumbnail camera renders only layer 0, so these are excluded from thumbnails. */
export const EDITOR_LAYER = 1