feat: 裁剪组裁剪跟随选择组移动
This commit is contained in:
@@ -79,12 +79,7 @@ export class LiquifyCPUManager {
|
||||
this.canvas.width = imageSource.width;
|
||||
this.canvas.height = imageSource.height;
|
||||
this.ctx.drawImage(imageSource, 0, 0);
|
||||
this.originalImageData = this.ctx.getImageData(
|
||||
0,
|
||||
0,
|
||||
imageSource.width,
|
||||
imageSource.height
|
||||
);
|
||||
this.originalImageData = this.ctx.getImageData(0, 0, imageSource.width, imageSource.height);
|
||||
} else {
|
||||
throw new Error("不支持的图像类型");
|
||||
}
|
||||
@@ -95,10 +90,7 @@ export class LiquifyCPUManager {
|
||||
this.originalImageData.height
|
||||
);
|
||||
|
||||
this._initMesh(
|
||||
this.originalImageData.width,
|
||||
this.originalImageData.height
|
||||
);
|
||||
this._initMesh(this.originalImageData.width, this.originalImageData.height);
|
||||
this.initialized = true;
|
||||
return true;
|
||||
} catch (error) {
|
||||
@@ -268,13 +260,7 @@ export class LiquifyCPUManager {
|
||||
* @param {number} strength 强度
|
||||
* @param {boolean} isClockwise 是否顺时针旋转
|
||||
*/
|
||||
_applyEnhancedRotationDeformation(
|
||||
centerX,
|
||||
centerY,
|
||||
radius,
|
||||
strength,
|
||||
isClockwise
|
||||
) {
|
||||
_applyEnhancedRotationDeformation(centerX, centerY, radius, strength, isClockwise) {
|
||||
if (!this.currentImageData) return;
|
||||
|
||||
const data = this.currentImageData.data;
|
||||
@@ -287,11 +273,7 @@ export class LiquifyCPUManager {
|
||||
const timeFactor = Math.min(this.pressDuration / 1000, 5.0);
|
||||
const baseRotationSpeed = 0.02; // 使用与测试文件相同的速度
|
||||
const rotationAngle =
|
||||
(isClockwise ? 1 : -1) *
|
||||
baseRotationSpeed *
|
||||
pressure *
|
||||
power *
|
||||
(1.0 + timeFactor * 0.5);
|
||||
(isClockwise ? 1 : -1) * baseRotationSpeed * pressure * power * (1.0 + timeFactor * 0.5);
|
||||
|
||||
// 累积旋转角度 - 关键:这确保了持续旋转效果
|
||||
this.accumulatedRotation += rotationAngle;
|
||||
@@ -322,13 +304,7 @@ export class LiquifyCPUManager {
|
||||
const sourceY = centerY + Math.sin(newAngle) * distance;
|
||||
|
||||
// 双线性插值采样 - 确保像素连续性
|
||||
const color = this._bilinearSample(
|
||||
tempData,
|
||||
width,
|
||||
height,
|
||||
sourceX,
|
||||
sourceY
|
||||
);
|
||||
const color = this._bilinearSample(tempData, width, height, sourceX, sourceY);
|
||||
|
||||
if (color) {
|
||||
const targetIdx = (y * width + x) * 4;
|
||||
@@ -389,13 +365,7 @@ export class LiquifyCPUManager {
|
||||
const sourceY = centerY + dy * scale;
|
||||
|
||||
// 双线性插值采样
|
||||
const color = this._bilinearSample(
|
||||
tempData,
|
||||
width,
|
||||
height,
|
||||
sourceX,
|
||||
sourceY
|
||||
);
|
||||
const color = this._bilinearSample(tempData, width, height, sourceX, sourceY);
|
||||
|
||||
if (color) {
|
||||
const targetIdx = (y * width + x) * 4;
|
||||
@@ -461,13 +431,7 @@ export class LiquifyCPUManager {
|
||||
const sourceX = x - pushX;
|
||||
const sourceY = y - pushY;
|
||||
|
||||
const color = this._bilinearSample(
|
||||
tempData,
|
||||
width,
|
||||
height,
|
||||
sourceX,
|
||||
sourceY
|
||||
);
|
||||
const color = this._bilinearSample(tempData, width, height, sourceX, sourceY);
|
||||
|
||||
if (color) {
|
||||
const targetIdx = (y * width + x) * 4;
|
||||
@@ -504,13 +468,7 @@ export class LiquifyCPUManager {
|
||||
const sourceX = x - offsetX;
|
||||
const sourceY = y - offsetY;
|
||||
|
||||
const color = this._bilinearSample(
|
||||
tempData,
|
||||
width,
|
||||
height,
|
||||
sourceX,
|
||||
sourceY
|
||||
);
|
||||
const color = this._bilinearSample(tempData, width, height, sourceX, sourceY);
|
||||
|
||||
if (color) {
|
||||
const targetIdx = (y * width + x) * 4;
|
||||
@@ -561,7 +519,7 @@ export class LiquifyCPUManager {
|
||||
this._applyEnhancedPushDeformation(x, y, radius, strength);
|
||||
break;
|
||||
|
||||
default:
|
||||
default: {
|
||||
// 对于其他模式,使用原有的网格算法
|
||||
if (!this.mesh) return;
|
||||
|
||||
@@ -569,20 +527,14 @@ export class LiquifyCPUManager {
|
||||
const timeFactor = Math.min(this.pressDuration / 1000, 4.0);
|
||||
const finalStrength = baseStrength * (1.0 + timeFactor * 0.5);
|
||||
|
||||
this._applyDeformation(
|
||||
x,
|
||||
y,
|
||||
radius,
|
||||
finalStrength,
|
||||
mode,
|
||||
this.params.distortion
|
||||
);
|
||||
this._applyDeformation(x, y, radius, finalStrength, mode, this.params.distortion);
|
||||
|
||||
if (this.config.smoothingIterations > 0) {
|
||||
this._lightSmoothing();
|
||||
}
|
||||
|
||||
return this._applyMeshToImage();
|
||||
}
|
||||
}
|
||||
|
||||
// 对于像素算法,直接返回当前图像数据
|
||||
@@ -592,96 +544,96 @@ export class LiquifyCPUManager {
|
||||
/**
|
||||
* 应用液化变形 - 主要入口,集成增强算法
|
||||
*/
|
||||
applyDeformation(x, y) {
|
||||
if (!this.initialized || !this.originalImageData) {
|
||||
console.warn("液化管理器未初始化或缺少必要数据");
|
||||
return this.currentImageData;
|
||||
}
|
||||
// applyDeformation(x, y) {
|
||||
// if (!this.initialized || !this.originalImageData) {
|
||||
// console.warn("液化管理器未初始化或缺少必要数据");
|
||||
// return this.currentImageData;
|
||||
// }
|
||||
|
||||
// 更新鼠标位置
|
||||
this.currentMouseX = x;
|
||||
this.currentMouseY = y;
|
||||
// // 更新鼠标位置
|
||||
// this.currentMouseX = x;
|
||||
// this.currentMouseY = y;
|
||||
|
||||
// 计算拖拽参数
|
||||
const deltaX = this.currentMouseX - this.initialMouseX;
|
||||
const deltaY = this.currentMouseY - this.initialMouseY;
|
||||
this.dragDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
this.dragAngle = Math.atan2(deltaY, deltaX);
|
||||
// // 计算拖拽参数
|
||||
// const deltaX = this.currentMouseX - this.initialMouseX;
|
||||
// const deltaY = this.currentMouseY - this.initialMouseY;
|
||||
// this.dragDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
// this.dragAngle = Math.atan2(deltaY, deltaX);
|
||||
|
||||
// 获取当前参数
|
||||
const { size, pressure, power } = this.params;
|
||||
const mode = this.currentMode;
|
||||
const radius = size;
|
||||
const strength = pressure * power;
|
||||
// // 获取当前参数
|
||||
// const { size, pressure, power } = this.params;
|
||||
// const mode = this.currentMode;
|
||||
// const radius = size;
|
||||
// const strength = pressure * power;
|
||||
|
||||
// 根据模式选择算法
|
||||
const pixelModes = [
|
||||
this.modes.CLOCKWISE,
|
||||
this.modes.COUNTERCLOCKWISE,
|
||||
this.modes.PINCH,
|
||||
this.modes.EXPAND,
|
||||
this.modes.PUSH,
|
||||
];
|
||||
// // 根据模式选择算法
|
||||
// const pixelModes = [
|
||||
// this.modes.CLOCKWISE,
|
||||
// this.modes.COUNTERCLOCKWISE,
|
||||
// this.modes.PINCH,
|
||||
// this.modes.EXPAND,
|
||||
// this.modes.PUSH,
|
||||
// ];
|
||||
|
||||
if (pixelModes.includes(mode)) {
|
||||
// 使用增强的像素算法
|
||||
switch (mode) {
|
||||
case this.modes.CLOCKWISE:
|
||||
this._applyEnhancedRotationDeformation(x, y, radius, strength, false);
|
||||
break;
|
||||
case this.modes.COUNTERCLOCKWISE:
|
||||
this._applyEnhancedRotationDeformation(x, y, radius, strength, true);
|
||||
break;
|
||||
case this.modes.PINCH:
|
||||
this._applyEnhancedPinchDeformation(x, y, radius, strength, true);
|
||||
break;
|
||||
case this.modes.EXPAND:
|
||||
this._applyEnhancedPinchDeformation(x, y, radius, strength, false);
|
||||
break;
|
||||
case this.modes.PUSH:
|
||||
this._applyEnhancedPushDeformation(x, y, radius, strength);
|
||||
break;
|
||||
}
|
||||
// if (pixelModes.includes(mode)) {
|
||||
// // 使用增强的像素算法
|
||||
// switch (mode) {
|
||||
// case this.modes.CLOCKWISE:
|
||||
// this._applyEnhancedRotationDeformation(x, y, radius, strength, false);
|
||||
// break;
|
||||
// case this.modes.COUNTERCLOCKWISE:
|
||||
// this._applyEnhancedRotationDeformation(x, y, radius, strength, true);
|
||||
// break;
|
||||
// case this.modes.PINCH:
|
||||
// this._applyEnhancedPinchDeformation(x, y, radius, strength, true);
|
||||
// break;
|
||||
// case this.modes.EXPAND:
|
||||
// this._applyEnhancedPinchDeformation(x, y, radius, strength, false);
|
||||
// break;
|
||||
// case this.modes.PUSH:
|
||||
// this._applyEnhancedPushDeformation(x, y, radius, strength);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// 更新最后应用时间
|
||||
this.lastApplyTime = Date.now();
|
||||
this.isFirstApply = false;
|
||||
// // 更新最后应用时间
|
||||
// this.lastApplyTime = Date.now();
|
||||
// this.isFirstApply = false;
|
||||
|
||||
return this.currentImageData;
|
||||
} else {
|
||||
// 使用原有的网格算法处理其他模式
|
||||
if (!this.mesh) {
|
||||
console.warn("网格未初始化");
|
||||
return this.currentImageData;
|
||||
}
|
||||
// return this.currentImageData;
|
||||
// } else {
|
||||
// // 使用原有的网格算法处理其他模式
|
||||
// if (!this.mesh) {
|
||||
// console.warn("网格未初始化");
|
||||
// return this.currentImageData;
|
||||
// }
|
||||
|
||||
const finalStrength = (strength * this.config.maxStrength) / 100;
|
||||
// const finalStrength = (strength * this.config.maxStrength) / 100;
|
||||
|
||||
// 应用变形
|
||||
this._applyDeformation(
|
||||
x,
|
||||
y,
|
||||
radius,
|
||||
finalStrength,
|
||||
mode,
|
||||
this.params.distortion
|
||||
);
|
||||
// // 应用变形
|
||||
// this._applyDeformation(
|
||||
// x,
|
||||
// y,
|
||||
// radius,
|
||||
// finalStrength,
|
||||
// mode,
|
||||
// this.params.distortion,
|
||||
// );
|
||||
|
||||
// 平滑处理
|
||||
if (this.config.smoothingIterations > 0) {
|
||||
this._smoothMesh();
|
||||
}
|
||||
// // 平滑处理
|
||||
// if (this.config.smoothingIterations > 0) {
|
||||
// this._smoothMesh();
|
||||
// }
|
||||
|
||||
// 更新图像数据
|
||||
const result = this._applyMeshToImage();
|
||||
// // 更新图像数据
|
||||
// const result = this._applyMeshToImage();
|
||||
|
||||
// 更新最后应用时间
|
||||
this.lastApplyTime = Date.now();
|
||||
this.isFirstApply = false;
|
||||
// // 更新最后应用时间
|
||||
// this.lastApplyTime = Date.now();
|
||||
// this.isFirstApply = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// return result;
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* 双线性插值采样 - 用于像素级算法
|
||||
@@ -773,22 +725,14 @@ export class LiquifyCPUManager {
|
||||
|
||||
const baseDistortion = Math.max(distortion, 0.3);
|
||||
const timeFactor = Math.min(this.pressDuration / 1000, 2.0);
|
||||
const timeEnhancedDistortion =
|
||||
baseDistortion * (1.0 + timeFactor * 0.3);
|
||||
const timeEnhancedDistortion = baseDistortion * (1.0 + timeFactor * 0.3);
|
||||
|
||||
const wave1 =
|
||||
Math.sin(crystalAngle * 8 + this.pressDuration * 0.005) * 0.6;
|
||||
const wave2 =
|
||||
Math.cos(crystalAngle * 12 + this.pressDuration * 0.003) * 0.4;
|
||||
const waveAngle =
|
||||
crystalAngle + (wave1 + wave2) * timeEnhancedDistortion;
|
||||
const wave1 = Math.sin(crystalAngle * 8 + this.pressDuration * 0.005) * 0.6;
|
||||
const wave2 = Math.cos(crystalAngle * 12 + this.pressDuration * 0.003) * 0.4;
|
||||
const waveAngle = crystalAngle + (wave1 + wave2) * timeEnhancedDistortion;
|
||||
|
||||
const radialMod =
|
||||
1 +
|
||||
Math.sin(
|
||||
crystalRadius * Math.PI * 2 + this.pressDuration * 0.002
|
||||
) *
|
||||
0.3;
|
||||
1 + Math.sin(crystalRadius * Math.PI * 2 + this.pressDuration * 0.002) * 0.3;
|
||||
const modDistance = distance * radialMod;
|
||||
|
||||
const crystalX = x + Math.cos(waveAngle) * modDistance;
|
||||
@@ -809,8 +753,7 @@ export class LiquifyCPUManager {
|
||||
|
||||
const baseEdgeDistortion = Math.max(distortion, 0.5);
|
||||
const timeFactor = Math.min(this.pressDuration / 1000, 2.5);
|
||||
const timeEnhancedDistortion =
|
||||
baseEdgeDistortion * (1.0 + timeFactor * 0.4);
|
||||
const timeEnhancedDistortion = baseEdgeDistortion * (1.0 + timeFactor * 0.4);
|
||||
|
||||
const edgeWave =
|
||||
Math.sin(edgeRadius * Math.PI * 4 + this.pressDuration * 0.004) *
|
||||
@@ -887,11 +830,7 @@ export class LiquifyCPUManager {
|
||||
const points = this.mesh.deformedPoints;
|
||||
const tempPoints = points.map((p) => ({ x: p.x, y: p.y }));
|
||||
|
||||
for (
|
||||
let iteration = 0;
|
||||
iteration < this.config.smoothingIterations;
|
||||
iteration++
|
||||
) {
|
||||
for (let iteration = 0; iteration < this.config.smoothingIterations; iteration++) {
|
||||
for (let y = 1; y < rows; y++) {
|
||||
for (let x = 1; x < cols; x++) {
|
||||
const idx = y * (cols + 1) + x;
|
||||
@@ -996,19 +935,8 @@ export class LiquifyCPUManager {
|
||||
for (let x = 0; x < width; x += step) {
|
||||
const srcPos = this._mapPointBack(x, y);
|
||||
|
||||
if (
|
||||
srcPos.x >= 0 &&
|
||||
srcPos.x < width &&
|
||||
srcPos.y >= 0 &&
|
||||
srcPos.y < height
|
||||
) {
|
||||
const color = this._bilinearInterpolate(
|
||||
srcData,
|
||||
width,
|
||||
height,
|
||||
srcPos.x,
|
||||
srcPos.y
|
||||
);
|
||||
if (srcPos.x >= 0 && srcPos.x < width && srcPos.y >= 0 && srcPos.y < height) {
|
||||
const color = this._bilinearInterpolate(srcData, width, height, srcPos.x, srcPos.y);
|
||||
|
||||
// 如果使用步长采样,需要填充相邻像素
|
||||
for (let dy = 0; dy < step && y + dy < height; dy++) {
|
||||
@@ -1070,22 +998,14 @@ export class LiquifyCPUManager {
|
||||
// 根据推拉模式和拖拽距离动态调整强度
|
||||
let strength;
|
||||
if (mode === this.modes.PUSH) {
|
||||
const baseStrength =
|
||||
(pressure * power * this.config.maxStrength) / 100;
|
||||
const baseStrength = (pressure * power * this.config.maxStrength) / 100;
|
||||
const distanceFactor = Math.min(this.dragDistance / radius, 2.0);
|
||||
strength = baseStrength * distanceFactor * 0.3; // 批量处理时降低强度
|
||||
} else {
|
||||
strength = (pressure * power * this.config.maxStrength) / 100;
|
||||
}
|
||||
|
||||
this._applyDeformation(
|
||||
pos.x,
|
||||
pos.y,
|
||||
radius,
|
||||
strength,
|
||||
mode,
|
||||
distortion
|
||||
);
|
||||
this._applyDeformation(pos.x, pos.y, radius, strength, mode, distortion);
|
||||
});
|
||||
|
||||
// 结束拖拽操作
|
||||
@@ -1331,14 +1251,7 @@ export class LiquifyCPUManager {
|
||||
const finalStrength = (strength * this.config.maxStrength) / 100;
|
||||
|
||||
// 应用变形
|
||||
this._applyDeformation(
|
||||
x,
|
||||
y,
|
||||
radius,
|
||||
finalStrength,
|
||||
mode,
|
||||
this.params.distortion
|
||||
);
|
||||
this._applyDeformation(x, y, radius, finalStrength, mode, this.params.distortion);
|
||||
|
||||
// 平滑处理
|
||||
if (this.config.smoothingIterations > 0) {
|
||||
|
||||
Reference in New Issue
Block a user