feat: 裁剪组裁剪跟随选择组移动
This commit is contained in:
@@ -216,9 +216,7 @@ export class EnhancedLiquifyManager {
|
||||
// 计算图像大小
|
||||
const pixelCount = imageData.width * imageData.height;
|
||||
|
||||
console.log(
|
||||
`液化选择渲染器: 图像大小=${pixelCount}像素, WebGL可用=${this.isWebGLAvailable}`
|
||||
);
|
||||
console.log(`液化选择渲染器: 图像大小=${pixelCount}像素, WebGL可用=${this.isWebGLAvailable}`);
|
||||
|
||||
// 默认使用CPU渲染器
|
||||
this.activeRenderer = this.cpuRenderer;
|
||||
@@ -249,11 +247,7 @@ export class EnhancedLiquifyManager {
|
||||
this.activeRenderer = this.webglRenderer;
|
||||
this.renderMode = "webgl";
|
||||
} else {
|
||||
console.log(
|
||||
`液化功能: 使用CPU渲染模式${
|
||||
!this.isWebGLAvailable ? " (WebGL不可用)" : ""
|
||||
}`
|
||||
);
|
||||
console.log(`液化功能: 使用CPU渲染模式${!this.isWebGLAvailable ? " (WebGL不可用)" : ""}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,16 +312,11 @@ export class EnhancedLiquifyManager {
|
||||
this.params[param] = value;
|
||||
|
||||
// 同步更新当前渲染器 - 关键修复:确保参数正确传递
|
||||
if (
|
||||
this.activeRenderer &&
|
||||
typeof this.activeRenderer.setParam === "function"
|
||||
) {
|
||||
if (this.activeRenderer && typeof this.activeRenderer.setParam === "function") {
|
||||
console.log(`EnhancedLiquifyManager 设置参数: ${param}=${value}`);
|
||||
this.activeRenderer.setParam(param, value);
|
||||
} else {
|
||||
console.warn(
|
||||
`EnhancedLiquifyManager: 无法设置参数 ${param},渲染器未就绪`
|
||||
);
|
||||
console.warn(`EnhancedLiquifyManager: 无法设置参数 ${param},渲染器未就绪`);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -382,25 +371,17 @@ export class EnhancedLiquifyManager {
|
||||
* @param {Number} y 初始Y坐标
|
||||
*/
|
||||
startLiquifyOperation(x, y) {
|
||||
if (
|
||||
this.activeRenderer &&
|
||||
typeof this.activeRenderer.startDeformation === "function"
|
||||
) {
|
||||
if (this.activeRenderer && typeof this.activeRenderer.startDeformation === "function") {
|
||||
this.activeRenderer.startDeformation(x, y);
|
||||
}
|
||||
console.log(
|
||||
`开始液化操作,渲染模式=${this.renderMode}, 初始点: (${x}, ${y})`
|
||||
);
|
||||
console.log(`开始液化操作,渲染模式=${this.renderMode}, 初始点: (${x}, ${y})`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束液化操作
|
||||
*/
|
||||
endLiquifyOperation() {
|
||||
if (
|
||||
this.activeRenderer &&
|
||||
typeof this.activeRenderer.endDeformation === "function"
|
||||
) {
|
||||
if (this.activeRenderer && typeof this.activeRenderer.endDeformation === "function") {
|
||||
this.activeRenderer.endDeformation();
|
||||
}
|
||||
console.log(`结束液化操作,渲染模式=${this.renderMode}`);
|
||||
@@ -443,9 +424,7 @@ export class EnhancedLiquifyManager {
|
||||
|
||||
// 坐标边界检查
|
||||
if (x < 0 || x >= imageWidth || y < 0 || y >= imageHeight) {
|
||||
console.warn(
|
||||
`液化坐标超出图像范围: (${x}, ${y}), 图像尺寸: ${imageWidth}x${imageHeight}`
|
||||
);
|
||||
console.warn(`液化坐标超出图像范围: (${x}, ${y}), 图像尺寸: ${imageWidth}x${imageHeight}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -510,9 +489,7 @@ export class EnhancedLiquifyManager {
|
||||
console.log(
|
||||
`液化性能数据: 模式=${this.renderMode}, 平均耗时=${avgTime.toFixed(
|
||||
2
|
||||
)}ms, 图像尺寸=${this.originalImageData?.width}x${
|
||||
this.originalImageData?.height
|
||||
}`
|
||||
)}ms, 图像尺寸=${this.originalImageData?.width}x${this.originalImageData?.height}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -604,8 +581,7 @@ export class EnhancedLiquifyManager {
|
||||
const singleObject = objectsToCheck.length === 1;
|
||||
const isImage =
|
||||
singleObject &&
|
||||
(objectsToCheck[0].type === "image" ||
|
||||
objectsToCheck[0].type === "rasterized-layer");
|
||||
(objectsToCheck[0].type === "image" || objectsToCheck[0].type === "rasterized-layer");
|
||||
|
||||
// 检查是否为组
|
||||
const isGroup =
|
||||
@@ -655,19 +631,14 @@ export class EnhancedLiquifyManager {
|
||||
tempCanvas.height = fabricObject.height;
|
||||
const tempCtx = tempCanvas.getContext("2d");
|
||||
|
||||
console.log(
|
||||
`创建临时Canvas,尺寸: ${tempCanvas.width}x${tempCanvas.height}`
|
||||
);
|
||||
console.log(`创建临时Canvas,尺寸: ${tempCanvas.width}x${tempCanvas.height}`);
|
||||
|
||||
// 处理不同的图像源
|
||||
if (fabricObject._element) {
|
||||
console.log("使用 _element 绘制图像");
|
||||
|
||||
// 检查_element是否有效
|
||||
if (
|
||||
!fabricObject._element.complete &&
|
||||
fabricObject._element.tagName === "IMG"
|
||||
) {
|
||||
if (!fabricObject._element.complete && fabricObject._element.tagName === "IMG") {
|
||||
console.log("图像未加载完成,等待加载...");
|
||||
fabricObject._element.onload = () => {
|
||||
try {
|
||||
@@ -678,12 +649,7 @@ export class EnhancedLiquifyManager {
|
||||
fabricObject.width,
|
||||
fabricObject.height
|
||||
);
|
||||
const imageData = tempCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
console.log("✅ 图像加载完成后获取数据成功");
|
||||
resolve(imageData);
|
||||
} catch (error) {
|
||||
@@ -698,17 +664,8 @@ export class EnhancedLiquifyManager {
|
||||
}
|
||||
|
||||
// 直接绘制已加载的图像
|
||||
tempCtx.drawImage(
|
||||
fabricObject._element,
|
||||
0,
|
||||
0,
|
||||
fabricObject.width,
|
||||
fabricObject.height
|
||||
);
|
||||
} else if (
|
||||
fabricObject.getSrc &&
|
||||
typeof fabricObject.getSrc === "function"
|
||||
) {
|
||||
tempCtx.drawImage(fabricObject._element, 0, 0, fabricObject.width, fabricObject.height);
|
||||
} else if (fabricObject.getSrc && typeof fabricObject.getSrc === "function") {
|
||||
console.log("使用 getSrc() 方法获取图像源");
|
||||
|
||||
// 通过URL创建图像
|
||||
@@ -717,24 +674,11 @@ export class EnhancedLiquifyManager {
|
||||
|
||||
img.onload = () => {
|
||||
try {
|
||||
console.log(
|
||||
`图像加载成功,原始尺寸: ${img.naturalWidth}x${img.naturalHeight}`
|
||||
);
|
||||
console.log(`图像加载成功,原始尺寸: ${img.naturalWidth}x${img.naturalHeight}`);
|
||||
|
||||
tempCtx.drawImage(
|
||||
img,
|
||||
0,
|
||||
0,
|
||||
fabricObject.width,
|
||||
fabricObject.height
|
||||
);
|
||||
tempCtx.drawImage(img, 0, 0, fabricObject.width, fabricObject.height);
|
||||
|
||||
const imageData = tempCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
|
||||
console.log("✅ 通过URL获取图像数据成功");
|
||||
resolve(imageData);
|
||||
@@ -762,20 +706,9 @@ export class EnhancedLiquifyManager {
|
||||
|
||||
img.onload = () => {
|
||||
try {
|
||||
tempCtx.drawImage(
|
||||
img,
|
||||
0,
|
||||
0,
|
||||
fabricObject.width,
|
||||
fabricObject.height
|
||||
);
|
||||
tempCtx.drawImage(img, 0, 0, fabricObject.width, fabricObject.height);
|
||||
|
||||
const imageData = tempCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
|
||||
console.log("✅ 通过src属性获取图像数据成功");
|
||||
resolve(imageData);
|
||||
@@ -795,20 +728,13 @@ export class EnhancedLiquifyManager {
|
||||
return;
|
||||
} else {
|
||||
console.error("无法找到有效的图像源");
|
||||
reject(
|
||||
new Error("图像对象缺少有效的图像源(_element, getSrc, 或 src)")
|
||||
);
|
||||
reject(new Error("图像对象缺少有效的图像源(_element, getSrc, 或 src)"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果走到这里,说明使用了_element直接绘制
|
||||
try {
|
||||
const imageData = tempCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
tempCanvas.width,
|
||||
tempCanvas.height
|
||||
);
|
||||
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
|
||||
|
||||
console.log(
|
||||
`✅ 获取图像数据成功: 对象尺寸=${fabricObject.width}x${fabricObject.height}, ` +
|
||||
|
||||
@@ -178,10 +178,7 @@ export class HybridLiquifyManager {
|
||||
const timeFactor = Math.min(this.pressDuration / 1000, 5.0);
|
||||
const baseRotationSpeed = 0.015;
|
||||
const rotationAngle =
|
||||
(clockwise ? 1 : -1) *
|
||||
baseRotationSpeed *
|
||||
strength *
|
||||
(1.0 + timeFactor * 0.3);
|
||||
(clockwise ? 1 : -1) * baseRotationSpeed * strength * (1.0 + timeFactor * 0.3);
|
||||
|
||||
this.accumulatedRotation += rotationAngle;
|
||||
|
||||
@@ -209,13 +206,7 @@ export class HybridLiquifyManager {
|
||||
const sourceY = centerY + Math.sin(newAngle) * distance;
|
||||
|
||||
// 双线性插值采样
|
||||
const color = this._bilinearSample(
|
||||
srcData,
|
||||
width,
|
||||
height,
|
||||
sourceX,
|
||||
sourceY
|
||||
);
|
||||
const color = this._bilinearSample(srcData, width, height, sourceX, sourceY);
|
||||
|
||||
if (color) {
|
||||
const targetIdx = (y * width + x) * 4;
|
||||
@@ -232,16 +223,7 @@ export class HybridLiquifyManager {
|
||||
/**
|
||||
* 像素级水晶效果
|
||||
*/
|
||||
_applyPixelCrystal(
|
||||
srcData,
|
||||
dstData,
|
||||
width,
|
||||
height,
|
||||
centerX,
|
||||
centerY,
|
||||
radius,
|
||||
strength
|
||||
) {
|
||||
_applyPixelCrystal(srcData, dstData, width, height, centerX, centerY, radius, strength) {
|
||||
const timeFactor = Math.min(this.pressDuration / 1000, 3.0);
|
||||
const distortionStrength = strength * (1.0 + timeFactor * 0.5);
|
||||
|
||||
@@ -266,25 +248,16 @@ export class HybridLiquifyManager {
|
||||
// 多层波浪扭曲
|
||||
const wave1 = Math.sin(angle * 8 + this.pressDuration * 0.005) * 0.6;
|
||||
const wave2 = Math.cos(angle * 12 + this.pressDuration * 0.003) * 0.4;
|
||||
const waveAngle =
|
||||
angle + (wave1 + wave2) * distortionStrength * falloff;
|
||||
const waveAngle = angle + (wave1 + wave2) * distortionStrength * falloff;
|
||||
|
||||
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 sourceX = centerX + Math.cos(waveAngle) * modDistance;
|
||||
const sourceY = centerY + Math.sin(waveAngle) * modDistance;
|
||||
|
||||
const color = this._bilinearSample(
|
||||
srcData,
|
||||
width,
|
||||
height,
|
||||
sourceX,
|
||||
sourceY
|
||||
);
|
||||
const color = this._bilinearSample(srcData, width, height, sourceX, sourceY);
|
||||
|
||||
if (color) {
|
||||
const targetIdx = (y * width + x) * 4;
|
||||
@@ -311,16 +284,7 @@ export class HybridLiquifyManager {
|
||||
/**
|
||||
* 像素级边缘效果
|
||||
*/
|
||||
_applyPixelEdge(
|
||||
srcData,
|
||||
dstData,
|
||||
width,
|
||||
height,
|
||||
centerX,
|
||||
centerY,
|
||||
radius,
|
||||
strength
|
||||
) {
|
||||
_applyPixelEdge(srcData, dstData, width, height, centerX, centerY, radius, strength) {
|
||||
const timeFactor = Math.min(this.pressDuration / 1000, 2.5);
|
||||
const edgeStrength = strength * (1.0 + timeFactor * 0.4);
|
||||
|
||||
@@ -354,13 +318,7 @@ export class HybridLiquifyManager {
|
||||
const sourceX = x + offsetX;
|
||||
const sourceY = y + offsetY;
|
||||
|
||||
const color = this._bilinearSample(
|
||||
srcData,
|
||||
width,
|
||||
height,
|
||||
sourceX,
|
||||
sourceY
|
||||
);
|
||||
const color = this._bilinearSample(srcData, width, height, sourceX, sourceY);
|
||||
|
||||
if (color) {
|
||||
const targetIdx = (y * width + x) * 4;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -130,32 +130,18 @@ export class LiquifyManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`LiquifyManager.applyLiquify: 模式=${mode}, 坐标=(${x}, ${y}), 参数=`,
|
||||
params
|
||||
);
|
||||
console.log(`LiquifyManager.applyLiquify: 模式=${mode}, 坐标=(${x}, ${y}), 参数=`, params);
|
||||
|
||||
try {
|
||||
// 直接调用EnhancedLiquifyManager的applyLiquify方法
|
||||
// 避免重复设置参数,让EnhancedLiquifyManager处理参数设置
|
||||
const resultData = await this.enhancedManager.applyLiquify(
|
||||
targetObject,
|
||||
mode,
|
||||
params,
|
||||
x,
|
||||
y
|
||||
);
|
||||
const resultData = await this.enhancedManager.applyLiquify(targetObject, mode, params, x, y);
|
||||
|
||||
// 确保返回结果数据
|
||||
if (!resultData) {
|
||||
console.warn("液化变形没有返回结果数据");
|
||||
} else {
|
||||
console.log(
|
||||
"✅ 液化变形成功,返回图像数据尺寸:",
|
||||
resultData.width,
|
||||
"x",
|
||||
resultData.height
|
||||
);
|
||||
console.log("✅ 液化变形成功,返回图像数据尺寸:", resultData.width, "x", resultData.height);
|
||||
}
|
||||
|
||||
return resultData;
|
||||
|
||||
@@ -159,9 +159,7 @@ export class LiquifyRealTimeUpdater {
|
||||
// });
|
||||
// }
|
||||
} else {
|
||||
console.warn(
|
||||
"=================快速更新液化效果时,图像数据未变化,跳过更新"
|
||||
);
|
||||
console.warn("=================快速更新液化效果时,图像数据未变化,跳过更新");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("快速更新液化效果失败:", error);
|
||||
@@ -184,6 +182,8 @@ export class LiquifyRealTimeUpdater {
|
||||
*/
|
||||
async _fullUpdate(imageData) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 临时禁用画布自动渲染
|
||||
const oldRenderOnAddRemove = this.canvas.renderOnAddRemove;
|
||||
try {
|
||||
// 使用高质量canvas进行最终渲染
|
||||
this.highQualityCtx.putImageData(imageData, 0, 0);
|
||||
@@ -233,9 +233,6 @@ export class LiquifyRealTimeUpdater {
|
||||
selected: false,
|
||||
evented: originalObj.evented,
|
||||
});
|
||||
|
||||
// 临时禁用画布自动渲染
|
||||
const oldRenderOnAddRemove = this.canvas.renderOnAddRemove;
|
||||
this.canvas.renderOnAddRemove = false;
|
||||
|
||||
// 智能查找和替换canvas上的对象
|
||||
@@ -244,9 +241,7 @@ export class LiquifyRealTimeUpdater {
|
||||
|
||||
// 如果直接查找失败,尝试通过ID查找
|
||||
if (targetIndex === -1 && originalObjId) {
|
||||
targetIndex = allObjects.findIndex(
|
||||
(obj) => obj.id === originalObjId
|
||||
);
|
||||
targetIndex = allObjects.findIndex((obj) => obj.id === originalObjId);
|
||||
if (targetIndex !== -1) {
|
||||
console.log(`通过ID找到目标对象: ${originalObjId}`);
|
||||
// 更新目标对象引用
|
||||
@@ -256,9 +251,7 @@ export class LiquifyRealTimeUpdater {
|
||||
|
||||
// 如果通过ID查找仍然失败,尝试通过图层ID查找
|
||||
if (targetIndex === -1 && originalObjLayerId) {
|
||||
targetIndex = allObjects.findIndex(
|
||||
(obj) => obj.layerId === originalObjLayerId
|
||||
);
|
||||
targetIndex = allObjects.findIndex((obj) => obj.layerId === originalObjLayerId);
|
||||
if (targetIndex !== -1) {
|
||||
console.log(`通过图层ID找到目标对象: ${originalObjLayerId}`);
|
||||
// 更新目标对象引用
|
||||
@@ -284,9 +277,7 @@ export class LiquifyRealTimeUpdater {
|
||||
resolve(newImg);
|
||||
} else {
|
||||
// 如果在画布中找不到对象,可能对象已被移除或引用已更新
|
||||
console.warn(
|
||||
"在画布中找不到目标对象,可能已被其他操作移除或替换"
|
||||
);
|
||||
console.warn("在画布中找不到目标对象,可能已被其他操作移除或替换");
|
||||
|
||||
// 恢复自动渲染设置
|
||||
this.canvas.renderOnAddRemove = oldRenderOnAddRemove;
|
||||
@@ -333,24 +324,6 @@ export class LiquifyRealTimeUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理资源
|
||||
*/
|
||||
dispose() {
|
||||
this.targetObject = null;
|
||||
this.cachedDataURL = null;
|
||||
this.pendingImageData = null;
|
||||
this.updateQueue.length = 0;
|
||||
|
||||
// 清理临时canvas
|
||||
if (this.tempCanvas) {
|
||||
this.tempCanvas.width = 0;
|
||||
this.tempCanvas.height = 0;
|
||||
this.tempCanvas = null;
|
||||
this.tempCtx = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前目标对象
|
||||
* @returns {Object} 当前的fabric对象
|
||||
@@ -388,13 +361,6 @@ export class LiquifyRealTimeUpdater {
|
||||
console.log("✅ 恢复正常渲染模式");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前目标对象
|
||||
*/
|
||||
getTargetObject() {
|
||||
return this.targetObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置图像质量
|
||||
* @param {Number} quality 质量值 (0.1-1.0)
|
||||
@@ -416,6 +382,24 @@ export class LiquifyRealTimeUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 清理资源
|
||||
// */
|
||||
// dispose() {
|
||||
// this.targetObject = null;
|
||||
// this.cachedDataURL = null;
|
||||
// this.pendingImageData = null;
|
||||
// this.updateQueue.length = 0;
|
||||
|
||||
// // 清理临时canvas
|
||||
// if (this.tempCanvas) {
|
||||
// this.tempCanvas.width = 0;
|
||||
// this.tempCanvas.height = 0;
|
||||
// this.tempCanvas = null;
|
||||
// this.tempCtx = null;
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* 清理资源
|
||||
*/
|
||||
|
||||
@@ -30,10 +30,7 @@ export class LiquifyStateManager {
|
||||
// 设备性能检测
|
||||
this.devicePerformance = this._detectDevicePerformance();
|
||||
|
||||
console.log(
|
||||
"🎯 液化状态管理器已初始化,设备性能等级:",
|
||||
this.devicePerformance
|
||||
);
|
||||
console.log("🎯 液化状态管理器已初始化,设备性能等级:", this.devicePerformance);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,17 +126,10 @@ export class LiquifyStateManager {
|
||||
this.performanceMetrics.totalOperations++;
|
||||
this.performanceMetrics.totalTime += operationTime;
|
||||
this.performanceMetrics.averageTime =
|
||||
this.performanceMetrics.totalTime /
|
||||
this.performanceMetrics.totalOperations;
|
||||
this.performanceMetrics.totalTime / this.performanceMetrics.totalOperations;
|
||||
|
||||
this.performanceMetrics.maxTime = Math.max(
|
||||
this.performanceMetrics.maxTime,
|
||||
operationTime
|
||||
);
|
||||
this.performanceMetrics.minTime = Math.min(
|
||||
this.performanceMetrics.minTime,
|
||||
operationTime
|
||||
);
|
||||
this.performanceMetrics.maxTime = Math.max(this.performanceMetrics.maxTime, operationTime);
|
||||
this.performanceMetrics.minTime = Math.min(this.performanceMetrics.minTime, operationTime);
|
||||
this.performanceMetrics.lastOperationTime = operationTime;
|
||||
}
|
||||
|
||||
@@ -148,15 +138,8 @@ export class LiquifyStateManager {
|
||||
* @param {Object} metrics 性能指标对象
|
||||
*/
|
||||
recordOperationMetrics(metrics) {
|
||||
const {
|
||||
operationTime,
|
||||
operationType,
|
||||
mode,
|
||||
coordinates,
|
||||
imageSize,
|
||||
renderMode,
|
||||
isRealTime,
|
||||
} = metrics;
|
||||
const { operationTime, operationType, mode, coordinates, imageSize, renderMode, isRealTime } =
|
||||
metrics;
|
||||
|
||||
// 记录基础性能数据
|
||||
this.recordDeformation(operationTime);
|
||||
@@ -195,9 +178,7 @@ export class LiquifyStateManager {
|
||||
// 降低图像质量
|
||||
const currentQuality = this.realtimeUpdater.config.imageQuality || 1.0;
|
||||
if (currentQuality > 0.7) {
|
||||
this.realtimeUpdater.setImageQuality(
|
||||
Math.max(0.7, currentQuality - 0.1)
|
||||
);
|
||||
this.realtimeUpdater.setImageQuality(Math.max(0.7, currentQuality - 0.1));
|
||||
console.log("⚡ 自动降低图像质量以提升性能");
|
||||
}
|
||||
|
||||
@@ -215,9 +196,7 @@ export class LiquifyStateManager {
|
||||
if (operationTime < 20 && this.devicePerformance === "high") {
|
||||
const currentQuality = this.realtimeUpdater.config.imageQuality || 1.0;
|
||||
if (currentQuality < 1.0) {
|
||||
this.realtimeUpdater.setImageQuality(
|
||||
Math.min(1.0, currentQuality + 0.05)
|
||||
);
|
||||
this.realtimeUpdater.setImageQuality(Math.min(1.0, currentQuality + 0.05));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,8 +354,7 @@ export class LiquifyStateManager {
|
||||
// 恢复原始设置
|
||||
this.canvas.renderOnAddRemove = this._originalSettings.renderOnAddRemove;
|
||||
this.canvas.skipOffscreen = this._originalSettings.skipOffscreen;
|
||||
this.canvas.enableRetinaScaling =
|
||||
this._originalSettings.enableRetinaScaling;
|
||||
this.canvas.enableRetinaScaling = this._originalSettings.enableRetinaScaling;
|
||||
|
||||
this._originalSettings = null;
|
||||
}
|
||||
@@ -389,14 +367,8 @@ export class LiquifyStateManager {
|
||||
this.performanceMetrics.averageTime =
|
||||
this.performanceMetrics.totalTime / (this.operationCount + 1);
|
||||
|
||||
this.performanceMetrics.maxTime = Math.max(
|
||||
this.performanceMetrics.maxTime,
|
||||
operationTime
|
||||
);
|
||||
this.performanceMetrics.minTime = Math.min(
|
||||
this.performanceMetrics.minTime,
|
||||
operationTime
|
||||
);
|
||||
this.performanceMetrics.maxTime = Math.max(this.performanceMetrics.maxTime, operationTime);
|
||||
this.performanceMetrics.minTime = Math.min(this.performanceMetrics.minTime, operationTime);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,8 +61,7 @@ export class LiquifyWebGLManager {
|
||||
static isSupported() {
|
||||
try {
|
||||
const canvas = document.createElement("canvas");
|
||||
const gl =
|
||||
canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
||||
const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
||||
return !!gl;
|
||||
} catch (e) {
|
||||
return false;
|
||||
@@ -76,9 +75,7 @@ export class LiquifyWebGLManager {
|
||||
try {
|
||||
// 创建WebGL画布
|
||||
this.canvas = document.createElement("canvas");
|
||||
this.gl =
|
||||
this.canvas.getContext("webgl") ||
|
||||
this.canvas.getContext("experimental-webgl");
|
||||
this.gl = this.canvas.getContext("webgl") || this.canvas.getContext("experimental-webgl");
|
||||
|
||||
if (!this.gl) {
|
||||
throw new Error("WebGL不可用");
|
||||
@@ -200,10 +197,7 @@ export class LiquifyWebGLManager {
|
||||
}
|
||||
`;
|
||||
|
||||
this.program = this._createProgram(
|
||||
vertexShaderSource,
|
||||
fragmentShaderSource
|
||||
);
|
||||
this.program = this._createProgram(vertexShaderSource, fragmentShaderSource);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,10 +222,7 @@ export class LiquifyWebGLManager {
|
||||
_createProgram(vertexSource, fragmentSource) {
|
||||
const gl = this.gl;
|
||||
const vertexShader = this._createShader(gl.VERTEX_SHADER, vertexSource);
|
||||
const fragmentShader = this._createShader(
|
||||
gl.FRAGMENT_SHADER,
|
||||
fragmentSource
|
||||
);
|
||||
const fragmentShader = this._createShader(gl.FRAGMENT_SHADER, fragmentSource);
|
||||
|
||||
const program = gl.createProgram();
|
||||
gl.attachShader(program, vertexShader);
|
||||
@@ -267,9 +258,7 @@ export class LiquifyWebGLManager {
|
||||
*/
|
||||
_createMeshBuffer() {
|
||||
const gl = this.gl;
|
||||
const vertices = new Float32Array([
|
||||
-1, -1, 0, 0, 1, -1, 1, 0, -1, 1, 0, 1, 1, 1, 1, 1,
|
||||
]);
|
||||
const vertices = new Float32Array([-1, -1, 0, 0, 1, -1, 1, 0, -1, 1, 0, 1, 1, 1, 1, 1]);
|
||||
|
||||
this.meshBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.meshBuffer);
|
||||
@@ -427,12 +416,8 @@ export class LiquifyWebGLManager {
|
||||
}
|
||||
|
||||
// 计算拖拽向量(用于推拉模式)
|
||||
const dragX = this.isDragging
|
||||
? (x - this.initialMouseX) / this.canvas.width
|
||||
: 0;
|
||||
const dragY = this.isDragging
|
||||
? -(y - this.initialMouseY) / this.canvas.height
|
||||
: 0;
|
||||
const dragX = this.isDragging ? (x - this.initialMouseX) / this.canvas.width : 0;
|
||||
const dragY = this.isDragging ? -(y - this.initialMouseY) / this.canvas.height : 0;
|
||||
|
||||
// 获取模式索引
|
||||
const modeIndex = Object.values(this.modes).indexOf(this.currentMode);
|
||||
@@ -466,22 +451,13 @@ export class LiquifyWebGLManager {
|
||||
|
||||
// 读取结果并转换为ImageData
|
||||
const pixels = new Uint8Array(this.canvas.width * this.canvas.height * 4);
|
||||
gl.readPixels(
|
||||
0,
|
||||
0,
|
||||
this.canvas.width,
|
||||
this.canvas.height,
|
||||
gl.RGBA,
|
||||
gl.UNSIGNED_BYTE,
|
||||
pixels
|
||||
);
|
||||
gl.readPixels(0, 0, this.canvas.width, this.canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
||||
|
||||
// 翻转Y轴以匹配ImageData格式
|
||||
const flippedPixels = new Uint8ClampedArray(pixels.length);
|
||||
for (let y = 0; y < this.canvas.height; y++) {
|
||||
for (let x = 0; x < this.canvas.width; x++) {
|
||||
const srcIndex =
|
||||
((this.canvas.height - 1 - y) * this.canvas.width + x) * 4;
|
||||
const srcIndex = ((this.canvas.height - 1 - y) * this.canvas.width + x) * 4;
|
||||
const dstIndex = (y * this.canvas.width + x) * 4;
|
||||
flippedPixels[dstIndex] = pixels[srcIndex];
|
||||
flippedPixels[dstIndex + 1] = pixels[srcIndex + 1];
|
||||
@@ -503,16 +479,7 @@ export class LiquifyWebGLManager {
|
||||
|
||||
// 将原始纹理复制到当前纹理
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.currentTexture);
|
||||
gl.copyTexImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
0,
|
||||
gl.RGBA,
|
||||
0,
|
||||
0,
|
||||
this.canvas.width,
|
||||
this.canvas.height,
|
||||
0
|
||||
);
|
||||
gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, this.canvas.width, this.canvas.height, 0);
|
||||
|
||||
// 读取原始纹理数据
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
|
||||
@@ -525,21 +492,9 @@ export class LiquifyWebGLManager {
|
||||
);
|
||||
|
||||
const pixels = new Uint8Array(this.canvas.width * this.canvas.height * 4);
|
||||
gl.readPixels(
|
||||
0,
|
||||
0,
|
||||
this.canvas.width,
|
||||
this.canvas.height,
|
||||
gl.RGBA,
|
||||
gl.UNSIGNED_BYTE,
|
||||
pixels
|
||||
);
|
||||
gl.readPixels(0, 0, this.canvas.width, this.canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
||||
|
||||
return new ImageData(
|
||||
new Uint8ClampedArray(pixels),
|
||||
this.canvas.width,
|
||||
this.canvas.height
|
||||
);
|
||||
return new ImageData(new Uint8ClampedArray(pixels), this.canvas.width, this.canvas.height);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user