深度画布功能

This commit is contained in:
lzp
2026-03-11 15:34:56 +08:00
parent 5e063f919d
commit c87ed70e7c
46 changed files with 12646 additions and 224 deletions

View File

@@ -0,0 +1,617 @@
/**
* 材质预设管理器
* 负责管理所有材质预设,包括内置预设和用户自定义预设
*/
export class TexturePresetManager {
constructor() {
// 内置材质预设
this.builtInTextures = [];
// 用户自定义材质
this.customTextures = [];
// 材质分类
this.categories = new Map();
// 材质缓存
this.textureCache = new Map();
// 事件监听器
this.listeners = {
textureAdded: [],
textureRemoved: [],
textureUpdated: [],
};
// 初始化内置材质
this._initBuiltInTextures();
}
/**
* 初始化内置材质预设
* @private
*/
_initBuiltInTextures() {
// 基于项目中的texture文件夹内容创建预设
const textureList = [
// 基础纹理
{
id: "texture0",
name: "纸质纹理",
category: "基础纹理",
path: "/src/assets/texture/texture0.webp",
},
{
id: "texture1",
name: "粗糙表面",
category: "基础纹理",
path: "/src/assets/texture/texture1.webp",
},
{
id: "texture2",
name: "细腻纹理",
category: "基础纹理",
path: "/src/assets/texture/texture2.webp",
},
{
id: "texture3",
name: "颗粒质感",
category: "基础纹理",
path: "/src/assets/texture/texture3.webp",
},
{
id: "texture4",
name: "布料纹理",
category: "基础纹理",
path: "/src/assets/texture/texture4.webp",
},
{
id: "texture5",
name: "木质纹理",
category: "自然纹理",
path: "/src/assets/texture/texture5.webp",
},
{
id: "texture6",
name: "石材纹理",
category: "自然纹理",
path: "/src/assets/texture/texture6.webp",
},
{
id: "texture7",
name: "金属质感",
category: "金属纹理",
path: "/src/assets/texture/texture7.webp",
},
{
id: "texture8",
name: "皮革纹理",
category: "自然纹理",
path: "/src/assets/texture/texture8.webp",
},
{
id: "texture9",
name: "水彩纸质",
category: "艺术纹理",
path: "/src/assets/texture/texture9.webp",
},
{
id: "texture10",
name: "画布纹理",
category: "艺术纹理",
path: "/src/assets/texture/texture10.webp",
},
{
id: "texture11",
name: "沙砾质感",
category: "自然纹理",
path: "/src/assets/texture/texture11.webp",
},
{
id: "texture12",
name: "水波纹理",
category: "自然纹理",
path: "/src/assets/texture/texture12.webp",
},
{
id: "texture13",
name: "云朵纹理",
category: "自然纹理",
path: "/src/assets/texture/texture13.webp",
},
{
id: "texture14",
name: "火焰纹理",
category: "特效纹理",
path: "/src/assets/texture/texture14.webp",
},
{
id: "texture15",
name: "烟雾效果",
category: "特效纹理",
path: "/src/assets/texture/texture15.webp",
},
{
id: "texture16",
name: "星空纹理",
category: "特效纹理",
path: "/src/assets/texture/texture16.webp",
},
{
id: "texture17",
name: "大理石纹",
category: "石材纹理",
path: "/src/assets/texture/texture17.webp",
},
{
id: "texture18",
name: "花岗岩纹",
category: "石材纹理",
path: "/src/assets/texture/texture18.webp",
},
{
id: "texture19",
name: "竹纹理",
category: "自然纹理",
path: "/src/assets/texture/texture19.webp",
},
{
id: "texture20",
name: "抽象图案",
category: "艺术纹理",
path: "/src/assets/texture/texture20.webp",
},
];
// 添加内置材质
textureList.forEach((texture) => {
this.builtInTextures.push({
id: texture.id,
name: texture.name,
category: texture.category,
path: texture.path,
type: "builtin",
preview: texture.path, // 使用原图作为预览
description: `内置${texture.category} - ${texture.name}`,
tags: [texture.category.replace("纹理", ""), "内置"],
created: new Date().toISOString(),
// 默认属性
defaultSettings: {
scale: 1,
opacity: 1,
repeat: "repeat",
angle: 0,
},
});
// 添加到分类
if (!this.categories.has(texture.category)) {
this.categories.set(texture.category, []);
}
this.categories.get(texture.category).push(texture.id);
});
}
/**
* 获取所有材质(内置 + 自定义)
* @returns {Array} 材质数组
*/
getAllTextures() {
return [...this.builtInTextures, ...this.customTextures];
}
/**
* 根据ID获取材质
* @param {String} textureId 材质ID
* @returns {Object|null} 材质对象
*/
getTextureById(textureId) {
return this.getAllTextures().find((texture) => texture.id === textureId) || null;
}
/**
* 根据分类获取材质
* @param {String} category 分类名称
* @returns {Array} 材质数组
*/
getTexturesByCategory(category) {
return this.getAllTextures().filter((texture) => texture.category === category);
}
/**
* 获取所有分类
* @returns {Array} 分类名称数组
*/
getCategories() {
const categories = new Set();
this.getAllTextures().forEach((texture) => {
categories.add(texture.category);
});
return Array.from(categories);
}
/**
* 添加自定义材质
* @param {Object} textureData 材质数据
* @returns {String} 材质ID
*/
addCustomTexture(textureData) {
const textureId =
textureData.id || `custom_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const texture = {
id: textureId,
name: textureData.name || "自定义材质",
category: textureData.category || "自定义材质",
path: textureData.path || textureData.dataUrl,
type: "custom",
preview: textureData.preview || textureData.path || textureData.dataUrl,
description: textureData.description || "用户自定义材质",
tags: textureData.tags || ["自定义"],
created: new Date().toISOString(),
defaultSettings: {
scale: textureData.scale || 1,
opacity: textureData.opacity || 1,
repeat: textureData.repeat || "repeat",
angle: textureData.angle || 0,
...textureData.defaultSettings,
},
// 保存原始文件信息
file: textureData.file || null,
dataUrl: textureData.dataUrl || null,
};
this.customTextures.push(texture);
// 添加到分类
if (!this.categories.has(texture.category)) {
this.categories.set(texture.category, []);
}
this.categories.get(texture.category).push(textureId);
// 触发事件
this._triggerEvent("textureAdded", texture);
return textureId;
}
/**
* 删除自定义材质
* @param {String} textureId 材质ID
* @returns {Boolean} 是否删除成功
*/
removeCustomTexture(textureId) {
const index = this.customTextures.findIndex((texture) => texture.id === textureId);
if (index === -1) {
return false;
}
const texture = this.customTextures[index];
// 只能删除自定义材质
if (texture.type !== "custom") {
console.warn("不能删除内置材质");
return false;
}
this.customTextures.splice(index, 1);
// 从分类中移除
if (this.categories.has(texture.category)) {
const categoryTextures = this.categories.get(texture.category);
const categoryIndex = categoryTextures.indexOf(textureId);
if (categoryIndex !== -1) {
categoryTextures.splice(categoryIndex, 1);
}
// 如果分类为空且不是内置分类,删除分类
if (categoryTextures.length === 0 && texture.category === "自定义材质") {
this.categories.delete(texture.category);
}
}
// 清除缓存
this.textureCache.delete(textureId);
// 触发事件
this._triggerEvent("textureRemoved", texture);
return true;
}
/**
* 更新材质信息
* @param {String} textureId 材质ID
* @param {Object} updates 更新数据
* @returns {Boolean} 是否更新成功
*/
updateTexture(textureId, updates) {
const texture = this.getTextureById(textureId);
if (!texture || texture.type === "builtin") {
return false;
}
// 更新材质属性
Object.assign(texture, updates);
// 触发事件
this._triggerEvent("textureUpdated", texture);
return true;
}
/**
* 获取材质预览URL
* @param {Object} texture 材质对象
* @returns {String} 预览URL
*/
getTexturePreviewUrl(texture) {
if (!texture) return null;
// 如果有预览图,使用预览图
if (texture.preview) {
return texture.preview;
}
// 否则使用原图
return texture.path || texture.dataUrl;
}
/**
* 加载材质图像
* @param {String} textureId 材质ID
* @returns {Promise<HTMLImageElement>} 图像对象
*/
loadTextureImage(textureId) {
return new Promise((resolve, reject) => {
// 检查缓存
if (this.textureCache.has(textureId)) {
resolve(this.textureCache.get(textureId));
return;
}
const texture = this.getTextureById(textureId);
if (!texture) {
reject(new Error(`材质 ${textureId} 不存在`));
return;
}
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = () => {
// 缓存图像
this.textureCache.set(textureId, img);
resolve(img);
};
img.onerror = () => {
reject(new Error(`材质 ${textureId} 加载失败`));
};
img.src = texture.path || texture.dataUrl;
});
}
/**
* 搜索材质
* @param {String} query 搜索关键词
* @returns {Array} 匹配的材质数组
*/
searchTextures(query) {
if (!query) return this.getAllTextures();
const searchTerm = query.toLowerCase();
return this.getAllTextures().filter((texture) => {
return (
texture.name.toLowerCase().includes(searchTerm) ||
texture.category.toLowerCase().includes(searchTerm) ||
texture.description.toLowerCase().includes(searchTerm) ||
texture.tags.some((tag) => tag.toLowerCase().includes(searchTerm))
);
});
}
/**
* 保存自定义材质到本地存储
*/
saveCustomTexturesToStorage() {
try {
const customTexturesData = this.customTextures.map((texture) => ({
...texture,
// 不保存file对象到localStorage
file: null,
}));
localStorage.setItem("canvasEditor_customTextures", JSON.stringify(customTexturesData));
} catch (error) {
console.error("保存自定义材质失败:", error);
}
}
/**
* 从本地存储加载自定义材质
*/
loadCustomTexturesFromStorage() {
try {
const stored = localStorage.getItem("canvasEditor_customTextures");
if (stored) {
const customTexturesData = JSON.parse(stored);
this.customTextures = customTexturesData;
// 重建分类索引
this.customTextures.forEach((texture) => {
if (!this.categories.has(texture.category)) {
this.categories.set(texture.category, []);
}
if (!this.categories.get(texture.category).includes(texture.id)) {
this.categories.get(texture.category).push(texture.id);
}
});
}
} catch (error) {
console.error("加载自定义材质失败:", error);
this.customTextures = [];
}
}
/**
* 创建材质预设
* @param {String} name 预设名称
* @param {Object} settings 材质设置
* @returns {String} 预设ID
*/
createTexturePreset(name, settings) {
const presetId = `preset_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const preset = {
id: presetId,
name: name,
type: "preset",
category: "材质预设",
created: new Date().toISOString(),
settings: {
textureId: settings.textureId,
scale: settings.scale || 1,
opacity: settings.opacity || 1,
repeat: settings.repeat || "repeat",
angle: settings.angle || 0,
brushSize: settings.brushSize || 5,
brushOpacity: settings.brushOpacity || 1,
brushColor: settings.brushColor || "#000000",
},
};
this.customTextures.push(preset);
this._triggerEvent("textureAdded", preset);
return presetId;
}
/**
* 应用材质预设
* @param {String} presetId 预设ID
* @returns {Object|null} 预设设置
*/
applyTexturePreset(presetId) {
const preset = this.getTextureById(presetId);
if (!preset || preset.type !== "preset") {
return null;
}
return preset.settings;
}
/**
* 添加事件监听器
* @param {String} event 事件名称
* @param {Function} callback 回调函数
*/
addEventListener(event, callback) {
if (this.listeners[event]) {
this.listeners[event].push(callback);
}
}
/**
* 移除事件监听器
* @param {String} event 事件名称
* @param {Function} callback 回调函数
*/
removeEventListener(event, callback) {
if (this.listeners[event]) {
const index = this.listeners[event].indexOf(callback);
if (index !== -1) {
this.listeners[event].splice(index, 1);
}
}
}
/**
* 触发事件
* @param {String} event 事件名称
* @param {*} data 事件数据
* @private
*/
_triggerEvent(event, data) {
if (this.listeners[event]) {
this.listeners[event].forEach((callback) => {
try {
callback(data);
} catch (error) {
console.error(`执行 ${event} 事件监听器出错:`, error);
}
});
}
}
/**
* 清除所有缓存
*/
clearCache() {
this.textureCache.clear();
}
/**
* 获取统计信息
* @returns {Object} 统计信息
*/
getStats() {
return {
builtInCount: this.builtInTextures.length,
customCount: this.customTextures.length,
totalCount: this.getAllTextures().length,
categoriesCount: this.getCategories().length,
cacheSize: this.textureCache.size,
};
}
/**
* 验证纹理文件
* @param {File} file 要验证的文件
* @returns {Boolean} 是否为有效的纹理文件
*/
validateTextureFile(file) {
if (!file) {
console.warn("文件不存在");
return false;
}
// 检查文件类型
if (!file.type.startsWith("image/")) {
console.warn("文件类型无效,必须是图片文件");
return false;
}
// 检查文件大小(限制为 10MB
const maxSize = 10 * 1024 * 1024; // 10MB
if (file.size > maxSize) {
console.warn("文件大小超过限制10MB");
return false;
}
// 检查支持的图片格式
const supportedTypes = [
"image/jpeg",
"image/jpg",
"image/png",
"image/webp",
"image/svg+xml",
"image/bmp",
"image/gif",
];
if (!supportedTypes.includes(file.type)) {
console.warn("不支持的图片格式");
return false;
}
return true;
}
}
// 创建单例实例
const texturePresetManager = new TexturePresetManager();
// 导出单例
export default texturePresetManager;