fix(glass): preserve horizontal lens while easing text stretch

This commit is contained in:
InfinityPacer
2026-09-06 01:32:14 +08:00
parent dbc75f9165
commit 59d9244f9e
2 changed files with 29 additions and 3 deletions
@@ -15,10 +15,10 @@ describe('createGlassNavbarDisplacementField', () => {
expect(field.height).toBe(41)
expect(pixelAt(field, 50, 0)).toEqual([128, 128, 128, 255])
expect(pixelAt(field, 50, 20)).toEqual([128, 128, 128, 255])
expect(pixelAt(field, 50, 5)[2]).toBeLessThan(120)
expect(pixelAt(field, 50, 5)[2]).toBeLessThan(128)
expect(pixelAt(field, 5, 20)[0]).toBeLessThan(120)
expect(pixelAt(field, 95, 20)[0]).toBeGreaterThan(136)
expect(pixelAt(field, 50, 35)[2]).toBeGreaterThan(136)
expect(pixelAt(field, 50, 35)[2]).toBeGreaterThan(128)
})
it.each([
@@ -68,6 +68,27 @@ describe('createGlassNavbarDisplacementField', () => {
expect(field.height).toBe(1)
expect([...field.pixels]).toEqual([128, 128, 128, 255])
})
it('limits vertical text stretching without flattening the horizontal lens', () => {
const field = createGlassNavbarDisplacementField({ width: 1423, height: 64, radius: 16 })
const displacement = (x: number, y: number, channel: number) => -34 * (pixelAt(field, x, y)[channel] / 255 - 0.5)
let maximumHorizontal = 0
let maximumVertical = 0
let minimumVerticalStep = Infinity
let maximumVerticalStep = 0
for (let y = 1; y < field.height; y += 1) {
const previous = displacement(711, y - 1, 2)
const current = displacement(711, y, 2)
maximumVertical = Math.max(maximumVertical, Math.abs(current))
minimumVerticalStep = Math.min(minimumVerticalStep, 1 + current - previous)
maximumVerticalStep = Math.max(maximumVerticalStep, 1 + current - previous)
}
for (let x = 0; x < 32; x += 1) maximumHorizontal = Math.max(maximumHorizontal, Math.abs(displacement(x, 32, 0)))
expect(maximumHorizontal).toBeGreaterThan(7)
expect(maximumVertical).toBeLessThan(2.6)
expect(minimumVerticalStep).toBeGreaterThan(0.59)
expect(maximumVerticalStep).toBeLessThan(1.41)
})
})
describe('supportsGlassNavbarLiveRefraction', () => {
+6 -1
View File
@@ -37,6 +37,8 @@ const REFRACTION_BAND_PX = 24
// 峰值靠近外沿,内侧有足够距离释放放大率;对称波峰会在窄轮廓内反向采样。
const MAX_DISPLACEMENT_BAND_RATIO = 0.42
const PEAK_DEPTH_RATIO = 0.16
// 文本沿纵向滚动穿过长边时,限制字形高度的局部伸缩;短边保留更强的水平透镜。
const VERTICAL_DISPLACEMENT_BAND_RATIO = 0.1
function normalizePixelSize(value: number) {
return Number.isFinite(value) ? Math.max(1, Math.round(value)) : 1
@@ -107,6 +109,9 @@ export function createGlassNavbarDisplacementField({
if (signedDistance > 0 || distanceInside <= outerGuard || distanceInside >= bandWidth) continue
const profile = refractionProfile(distanceInside, bandWidth, outerGuard)
const verticalProgress = (distanceInside - outerGuard) / (bandWidth - outerGuard)
const verticalProfile = Math.sin(Math.PI * verticalProgress) ** 2
const verticalAmplitude = (bandWidth * VERTICAL_DISPLACEMENT_BAND_RATIO * 255) / HIGH_REFRACTION_SCALE_PX
const gradientX =
roundedRectangleSignedDistance(sampleX + 0.5, sampleY, pixelWidth, pixelHeight, pixelRadius) -
roundedRectangleSignedDistance(sampleX - 0.5, sampleY, pixelWidth, pixelHeight, pixelRadius)
@@ -120,7 +125,7 @@ export function createGlassNavbarDisplacementField({
DISPLACEMENT_NEUTRAL_CHANNEL + (channelAmplitude * gradientX * profile) / gradientLength,
)
pixels[offset + 2] = clampChannel(
DISPLACEMENT_NEUTRAL_CHANNEL + (channelAmplitude * gradientY * profile) / gradientLength,
DISPLACEMENT_NEUTRAL_CHANNEL + (verticalAmplitude * gradientY * verticalProfile) / gradientLength,
)
}
}