背景也参与颜色混合显示
This commit is contained in:
1 parent
d4ecb1f896
commit
4b1a329e1b
7 files changed
+152
-131
No files matched your search
+31
-10
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="stage-wrap">
|
||||
<div ref="holder" class="stage-holder" :class="{ grid: store.settings.showGrid }" tabindex="0" @wheel.prevent="onWheelEvent" @pointerdown="onPanDown" @dblclick.prevent="onStageDoubleClick"></div>
|
||||
<div ref="holder" class="stage-holder" tabindex="0" @wheel.prevent="onWheelEvent" @pointerdown="onPanDown" @dblclick.prevent="onStageDoubleClick"></div>
|
||||
<img
|
||||
class="stage-watermark"
|
||||
:class="{ 'watermark-left-panel': !store.settings.parameterPanelOnRight }"
|
||||
@@ -51,7 +51,7 @@ import { drawBoneFollowTargets, drawGizmo, drawCollisionBodies, drawPaths } from
|
||||
import { appendStateBones, drawBones } from './stage/boneGuides'
|
||||
|
||||
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { Application, Container, Graphics, type Text, type Texture } from 'pixi.js'
|
||||
import { Application, Container, Graphics, Texture, TilingSprite, type Text } from 'pixi.js'
|
||||
import { ParticleEmitter, ensureEmitterConfig, type ParticleState } from '../core/particleEmitter'
|
||||
import { bakeLoopFrames } from '../core/loopFrameBaker'
|
||||
import { loopPlaybackRange } from '../core/loopSegmentTiming'
|
||||
@@ -101,6 +101,7 @@ if (store.settings.showGrid == null) store.settings.showGrid = true
|
||||
let app: Application | null = null
|
||||
let stageResizeObserver: ResizeObserver | null = null
|
||||
let world: Container | null = null
|
||||
let canvasGrid: TilingSprite | null = null
|
||||
let originGfx: Graphics | null = null
|
||||
let boneFollowTargetGfx: Graphics | null = null
|
||||
let boneGfx: Graphics | null = null
|
||||
@@ -136,6 +137,16 @@ let previewColliders: CollisionBody[] = []
|
||||
const emitterPreviewTransform = new Map<number, { x: number; y: number; rotation: number }>()
|
||||
|
||||
function createLayers() {
|
||||
// 棋盘格必须在 WebGL 底部,粒子混合模式才能读取它。
|
||||
const checker = document.createElement('canvas')
|
||||
checker.width = checker.height = 28
|
||||
const checkerContext = checker.getContext('2d')!
|
||||
checkerContext.fillStyle = '#141a26'
|
||||
checkerContext.fillRect(14, 0, 14, 14)
|
||||
checkerContext.fillRect(0, 14, 14, 14)
|
||||
canvasGrid = new TilingSprite(Texture.from(checker), app!.screen.width, app!.screen.height)
|
||||
canvasGrid.visible = store.settings.showGrid
|
||||
app!.stage.addChild(canvasGrid)
|
||||
world = new Container()
|
||||
app!.stage.addChild(world)
|
||||
axisLabelLayer = new Container() // 独立顶层,不随 world 缩放
|
||||
@@ -604,19 +615,33 @@ function loop() {
|
||||
|
||||
onMounted(async () => {
|
||||
const el = holder.value!
|
||||
app = new Application({ width: el.clientWidth || 800, height: el.clientHeight || 600, backgroundAlpha: 0, antialias: true })
|
||||
app = new Application({
|
||||
width: el.clientWidth || 800,
|
||||
height: el.clientHeight || 600,
|
||||
backgroundColor: 0x0e1219,
|
||||
backgroundAlpha: 1,
|
||||
antialias: true,
|
||||
})
|
||||
el.appendChild(app.view as unknown as HTMLCanvasElement)
|
||||
stageResizeObserver = new ResizeObserver(() => {
|
||||
if (!app) return
|
||||
const nextWidth = Math.max(1, el.clientWidth)
|
||||
const previousHeight = app.screen.height
|
||||
const nextHeight = Math.max(1, el.clientHeight)
|
||||
// Stage 高度变化时补偿视图中心,避免底部面板折叠导致画布内容整体跳动。
|
||||
if (Math.abs(nextHeight - previousHeight) > 0.5) store.editor.viewY -= (nextHeight - previousHeight) / 2
|
||||
app.renderer.resize(Math.max(1, el.clientWidth), nextHeight)
|
||||
app.renderer.resize(nextWidth, nextHeight)
|
||||
if (canvasGrid) {
|
||||
canvasGrid.width = nextWidth
|
||||
canvasGrid.height = nextHeight
|
||||
}
|
||||
})
|
||||
stageResizeObserver.observe(el)
|
||||
createLayers()
|
||||
watch(() => store.settings.backgroundImageData, (value) => background.syncTexture(value), { immediate: true })
|
||||
watch(() => store.settings.showGrid, (visible) => {
|
||||
if (canvasGrid) canvasGrid.visible = visible
|
||||
})
|
||||
const textures = await loadDefaultTextures()
|
||||
dotTex = textures.dotTex
|
||||
trailTex = textures.trailTex
|
||||
@@ -663,6 +688,8 @@ onUnmounted(() => {
|
||||
spineRuntime?.destroy()
|
||||
spineRuntime = null
|
||||
background.destroy()
|
||||
canvasGrid?.texture.destroy(true)
|
||||
canvasGrid = null
|
||||
if (world && app) emitterSync.destroy(world)
|
||||
if (app) { app.destroy(true, { children: true }); app = null }
|
||||
})
|
||||
@@ -672,16 +699,10 @@ watch(() => [store.activeObjectType, store.activeObjectId], () => pathEditing.re
|
||||
|
||||
<style scoped>
|
||||
.stage-wrap { position: relative; display: flex; width: 100%; height: 100%; min-height: 0; flex-direction: column; overflow: hidden; }
|
||||
/* 画布:默认纯色;开启网格时显示深色棋盘格 */
|
||||
.stage-holder {
|
||||
width: 100%; min-height: 0; flex: 1; cursor: grab; touch-action: none;
|
||||
background-color: #0e1219;
|
||||
outline: none;
|
||||
}
|
||||
.stage-holder.grid {
|
||||
background: conic-gradient(#141a26 90deg, transparent 90deg 180deg, #141a26 180deg 270deg, #141a26 180deg 270deg, transparent 270deg);
|
||||
background-size: 28px 28px;
|
||||
}
|
||||
.stage-holder:active { cursor: grabbing; }
|
||||
.stage-watermark {
|
||||
position: absolute; top: 14px; left: 14px; z-index: 1;
|
||||
|
||||
Reference in new issue
Block a user