添加编辑模式
This commit is contained in:
parent
d92cdedc57
commit
37158e7cb1
@ -32,6 +32,7 @@
|
|||||||
"fflate": "^0.8.2",
|
"fflate": "^0.8.2",
|
||||||
"flatbush": "^3.3.0",
|
"flatbush": "^3.3.0",
|
||||||
"js-angusj-clipper": "^1.2.1",
|
"js-angusj-clipper": "^1.2.1",
|
||||||
|
"pako": "^2.1.0",
|
||||||
"pinia": "^3.0.2",
|
"pinia": "^3.0.2",
|
||||||
"polylabel": "^1.1.0",
|
"polylabel": "^1.1.0",
|
||||||
"three": "npm:three-cf@^0.122.9",
|
"three": "npm:three-cf@^0.122.9",
|
||||||
|
@ -23,6 +23,9 @@ importers:
|
|||||||
js-angusj-clipper:
|
js-angusj-clipper:
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.3.1
|
version: 1.3.1
|
||||||
|
pako:
|
||||||
|
specifier: ^2.1.0
|
||||||
|
version: 2.1.0
|
||||||
pinia:
|
pinia:
|
||||||
specifier: ^3.0.2
|
specifier: ^3.0.2
|
||||||
version: 3.0.2(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))
|
version: 3.0.2(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))
|
||||||
@ -703,6 +706,9 @@ packages:
|
|||||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
pako@2.1.0:
|
||||||
|
resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
|
||||||
|
|
||||||
path-browserify@1.0.1:
|
path-browserify@1.0.1:
|
||||||
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
||||||
|
|
||||||
@ -1620,6 +1626,8 @@ snapshots:
|
|||||||
|
|
||||||
nanoid@3.3.11: {}
|
nanoid@3.3.11: {}
|
||||||
|
|
||||||
|
pako@2.1.0: {}
|
||||||
|
|
||||||
path-browserify@1.0.1: {}
|
path-browserify@1.0.1: {}
|
||||||
|
|
||||||
path-parse@1.0.7: {}
|
path-parse@1.0.7: {}
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<h3>纹理选择(DEBUG)</h3>
|
<h3>纹理选择(DEBUG)</h3>
|
||||||
<label>纹理链接</label>
|
<label>纹理链接</label>
|
||||||
<input v-model.trim="_textureSrc" type="text" placeholder="在此键入纹理图像的URL..." />
|
<input v-model.trim="_textureSrc" type="text" placeholder="在此键入纹理图像的URL..." />
|
||||||
<button class="btn-primary" @click="scene.ChangeTextureAsync(_textureSrc)"
|
<button class="btn-primary" @click="scene.ChangeTextureFromUrlAsync(_textureSrc)"
|
||||||
style="margin-left: 1em;">应用</button>
|
style="margin-left: 1em;">应用</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="adjust-section">
|
<div class="adjust-section">
|
||||||
@ -112,6 +112,7 @@ import CfFlex from "./CfFlex.vue";
|
|||||||
import { DirectoryId } from "../api/Request";
|
import { DirectoryId } from "../api/Request";
|
||||||
import { IsNullOrWhitespace } from "../helpers/helper.string";
|
import { IsNullOrWhitespace } from "../helpers/helper.string";
|
||||||
import { DeflateAsync } from "../helpers/helper.compression";
|
import { DeflateAsync } from "../helpers/helper.compression";
|
||||||
|
import { ToDeflatedBase64 } from "../helpers/helper.material";
|
||||||
|
|
||||||
export interface MaterialRequest {
|
export interface MaterialRequest {
|
||||||
/** 材质名 */
|
/** 材质名 */
|
||||||
@ -136,7 +137,7 @@ const debugMode = ref(false);
|
|||||||
const { CurrGeometry, Geometries, Material } = storeToRefs(scene);
|
const { CurrGeometry, Geometries, Material } = storeToRefs(scene);
|
||||||
const enableTexture = ref(Material.value.useMap);
|
const enableTexture = ref(Material.value.useMap);
|
||||||
const _textureSrc = ref(props.textureSrc);
|
const _textureSrc = ref(props.textureSrc);
|
||||||
const textureAdjustment = reactive<TextureAdjustment>({
|
const textureAdjustment = ref<TextureAdjustment>({
|
||||||
wrapS: 0,
|
wrapS: 0,
|
||||||
wrapT: 0,
|
wrapT: 0,
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
@ -158,12 +159,12 @@ const materialInfo = reactive({
|
|||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
scene.ChangeTextureAsync(_textureSrc.value);
|
scene.ChangeTextureFromUrlAsync(_textureSrc.value);
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => props.textureSrc, async (val) => {
|
watch(() => props.textureSrc, async (val) => {
|
||||||
_textureSrc.value = val;
|
_textureSrc.value = val;
|
||||||
await scene.ChangeTextureAsync(_textureSrc.value);
|
await scene.ChangeTextureFromUrlAsync(_textureSrc.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(model, async (val) => {
|
watch(model, async (val) => {
|
||||||
@ -178,6 +179,19 @@ watch(textureAdjustment, async (val) => {
|
|||||||
UpdateTexture();
|
UpdateTexture();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 监听纹理更新
|
||||||
|
watch(() => scene.CurrTexture, (val) => {
|
||||||
|
textureAdjustment.value = {
|
||||||
|
wrapS: val.wrapS,
|
||||||
|
wrapT: val.wrapT,
|
||||||
|
rotation: val.rotation,
|
||||||
|
repeatX: val.repeat.x,
|
||||||
|
repeatY: val.repeat.y,
|
||||||
|
moveX: val.offset.x,
|
||||||
|
moveY: val.offset.y
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
async function UpdateMaterial() {
|
async function UpdateMaterial() {
|
||||||
Material.value.matalness = model.metallic;
|
Material.value.matalness = model.metallic;
|
||||||
Material.value.roughness = model.roughness;
|
Material.value.roughness = model.roughness;
|
||||||
@ -188,7 +202,17 @@ async function UpdateMaterial() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function UpdateTexture() {
|
function UpdateTexture() {
|
||||||
scene.UpdateTexture(textureAdjustment);
|
const texture = scene.CurrTexture;
|
||||||
|
const val = textureAdjustment.value;
|
||||||
|
texture.wrapS = val.wrapS;
|
||||||
|
texture.wrapT = val.wrapT;
|
||||||
|
texture.anisotropy = 16;
|
||||||
|
texture.rotation = val.rotation;
|
||||||
|
texture.repeat.set(val.repeatX, val.repeatY);
|
||||||
|
texture.offset.set(val.moveX, val.moveY);
|
||||||
|
texture.needsUpdate = true;
|
||||||
|
|
||||||
|
scene.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function EnableTexture(enable: boolean) {
|
async function EnableTexture(enable: boolean) {
|
||||||
@ -208,7 +232,7 @@ async function HandleUpload() {
|
|||||||
name: materialInfo.materialName,
|
name: materialInfo.materialName,
|
||||||
logo: await scene.GenerateMaterialLogoAsync(),
|
logo: await scene.GenerateMaterialLogoAsync(),
|
||||||
// jsonString -> Deflate -> BinaryString -> Base64
|
// jsonString -> Deflate -> BinaryString -> Base64
|
||||||
file: btoa(String.fromCharCode(...await DeflateAsync(await scene.SerializeMaterialAsync())))
|
file: ToDeflatedBase64(await scene.SerializeMaterialAsync())
|
||||||
};
|
};
|
||||||
emits('submit', data);
|
emits('submit', data);
|
||||||
return data;
|
return data;
|
||||||
|
@ -11,6 +11,7 @@ import { useScene } from '../stores/sceneStore';
|
|||||||
import CfFlex from './CfFlex.vue';
|
import CfFlex from './CfFlex.vue';
|
||||||
import { GetConfig } from '../lib/libOutputConfig';
|
import { GetConfig } from '../lib/libOutputConfig';
|
||||||
import { useEvent } from '../stores/eventStore';
|
import { useEvent } from '../stores/eventStore';
|
||||||
|
import { FromDeflateBase64 } from '../helpers/helper.material';
|
||||||
|
|
||||||
const scene = useScene();
|
const scene = useScene();
|
||||||
const eventbus = useEvent();
|
const eventbus = useEvent();
|
||||||
@ -21,10 +22,13 @@ const textureSrc = ref(config.textureSrc);
|
|||||||
|
|
||||||
// 禁用右键菜单
|
// 禁用右键菜单
|
||||||
document.addEventListener('contextmenu', (e) => e.preventDefault());
|
document.addEventListener('contextmenu', (e) => e.preventDefault());
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
scene.Initial(container.value);
|
scene.Initial(container.value);
|
||||||
|
await HandleUpdateConfig();
|
||||||
|
|
||||||
eventbus.Subscribe('submit', HandleUpload);
|
eventbus.Subscribe('submit', HandleUpload);
|
||||||
eventbus.Subscribe('update-texture', HandleChangeTexture);
|
eventbus.Subscribe('update-texture', HandleChangeTexture);
|
||||||
|
eventbus.Subscribe('update-config', HandleUpdateConfig)
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
@ -41,6 +45,15 @@ function HandleChangeTexture() {
|
|||||||
textureSrc.value = config.textureSrc;
|
textureSrc.value = config.textureSrc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function HandleUpdateConfig() {
|
||||||
|
if (config.file && config.file.length > 0) {
|
||||||
|
console.log("base64", config.file);
|
||||||
|
const json = FromDeflateBase64(config.file);
|
||||||
|
await scene.ImportMaterialAsync(json);
|
||||||
|
}
|
||||||
|
textureSrc.value = config.textureSrc;
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
15
src/helpers/helper.material.ts
Normal file
15
src/helpers/helper.material.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import Pako from "pako";
|
||||||
|
import { Decompress, DecompressAsync, Deflate, DeflateAsync, StrToU8, U8ToStr } from "./helper.compression";
|
||||||
|
|
||||||
|
export function ToDeflatedBase64(materialJson: string)
|
||||||
|
{
|
||||||
|
return btoa(String.fromCharCode(...Deflate(materialJson)))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function FromDeflateBase64(base64: string) {
|
||||||
|
let binaryString = atob(base64);
|
||||||
|
console.log("Bin", binaryString);
|
||||||
|
let data = Pako.inflate(binaryString as any, { to: "string" });
|
||||||
|
console.log("data", data);
|
||||||
|
return data;
|
||||||
|
}
|
@ -27,6 +27,7 @@ export function Mount(element: Element, options: Partial<LibOutputConfig>) {
|
|||||||
/** 对程序配置进行更改 */
|
/** 对程序配置进行更改 */
|
||||||
export function Configure(options: Partial<LibOutputConfig>) {
|
export function Configure(options: Partial<LibOutputConfig>) {
|
||||||
ConfigureLibOutput(options);
|
ConfigureLibOutput(options);
|
||||||
|
useEvent().Publish('update-config');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 卸载已经挂载的DOM */
|
/** 卸载已经挂载的DOM */
|
||||||
@ -52,7 +53,7 @@ export async function SubmitRawAsync(options: { textureSrc: string }): Promise<{
|
|||||||
const virtualDom = document.createElement('div');
|
const virtualDom = document.createElement('div');
|
||||||
virtualDom.style.display = 'none';
|
virtualDom.style.display = 'none';
|
||||||
scene.Initial(virtualDom);
|
scene.Initial(virtualDom);
|
||||||
await scene.ChangeTextureAsync(options.textureSrc);
|
await scene.ChangeTextureFromUrlAsync(options.textureSrc);
|
||||||
var json = btoa(String.fromCharCode(...await DeflateAsync(await scene.SerializeMaterialAsync())));
|
var json = btoa(String.fromCharCode(...await DeflateAsync(await scene.SerializeMaterialAsync())));
|
||||||
|
|
||||||
scene.Dispose();
|
scene.Dispose();
|
||||||
|
@ -3,6 +3,7 @@ import type { MaterialRequest } from "../components/MaterialAdjuster.vue"
|
|||||||
|
|
||||||
let _libOutputConfig = {
|
let _libOutputConfig = {
|
||||||
textureSrc: "",
|
textureSrc: "",
|
||||||
|
file: undefined,
|
||||||
submitCallback: undefined,
|
submitCallback: undefined,
|
||||||
cancelCallback: undefined,
|
cancelCallback: undefined,
|
||||||
envTextureSrc: ['./right.webp', './left.webp', './top.webp', './bottom.webp', './front.webp', './back.webp'],
|
envTextureSrc: ['./right.webp', './left.webp', './top.webp', './bottom.webp', './front.webp', './back.webp'],
|
||||||
@ -19,6 +20,8 @@ export function ConfigureLibOutput(config: Partial<LibOutputConfig>) {
|
|||||||
export type LibOutputConfig = {
|
export type LibOutputConfig = {
|
||||||
/** 材质贴图链接 */
|
/** 材质贴图链接 */
|
||||||
textureSrc: string,
|
textureSrc: string,
|
||||||
|
/** 材质预设数据,base64编码 */
|
||||||
|
file?: string,
|
||||||
/** 环境贴图链接(立方体贴图,按照顺序输入[右左上下前后]) */
|
/** 环境贴图链接(立方体贴图,按照顺序输入[右左上下前后]) */
|
||||||
envTextureSrc: string[],
|
envTextureSrc: string[],
|
||||||
/** 灰度环境贴图链接,输入格式与环境贴图一致 */
|
/** 灰度环境贴图链接,输入格式与环境贴图一致 */
|
||||||
|
@ -19,4 +19,4 @@ export const useEvent = defineStore('event', () => {
|
|||||||
return { Subscribe, Publish, Unsubscribe };
|
return { Subscribe, Publish, Unsubscribe };
|
||||||
});
|
});
|
||||||
|
|
||||||
export type EventNames = 'submit' | 'update-texture';
|
export type EventNames = 'submit' | 'update-texture' | 'update-config';
|
@ -5,7 +5,7 @@ import { Database, ObjectId, PhysicalMaterialRecord, TextureTableRecord } from "
|
|||||||
import { LoadImageFromUrl } from "../helpers/helper.imageLoader";
|
import { LoadImageFromUrl } from "../helpers/helper.imageLoader";
|
||||||
import { Texture } from "three";
|
import { Texture } from "three";
|
||||||
import { materialRenderer } from "../common/MaterialRenderer";
|
import { materialRenderer } from "../common/MaterialRenderer";
|
||||||
import { MaterialOut } from "../common/MaterialSerializer";
|
import { MaterialIn, MaterialOut } from "../common/MaterialSerializer";
|
||||||
|
|
||||||
const sceneSetup = () => {
|
const sceneSetup = () => {
|
||||||
let _editor: MaterialEditor | undefined;
|
let _editor: MaterialEditor | undefined;
|
||||||
@ -77,7 +77,7 @@ const sceneSetup = () => {
|
|||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ChangeTextureAsync(url: string) {
|
async function ChangeTextureFromUrlAsync(url: string) {
|
||||||
const img = await LoadImageFromUrl(url);
|
const img = await LoadImageFromUrl(url);
|
||||||
|
|
||||||
// 关联贴图
|
// 关联贴图
|
||||||
@ -97,25 +97,38 @@ const sceneSetup = () => {
|
|||||||
await UpdateMaterialAsync();
|
await UpdateMaterialAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
function UpdateTexture(adjustment: TextureAdjustment) {
|
|
||||||
const texture = _currTexture.value;
|
|
||||||
texture.wrapS = adjustment.wrapS;
|
|
||||||
texture.wrapT = adjustment.wrapT;
|
|
||||||
texture.anisotropy = 16;
|
|
||||||
texture.rotation = adjustment.rotation;
|
|
||||||
texture.repeat.set(adjustment.repeatX, adjustment.repeatY);
|
|
||||||
texture.offset.set(adjustment.moveX, adjustment.moveY);
|
|
||||||
texture.needsUpdate = true;
|
|
||||||
|
|
||||||
Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function SerializeMaterialAsync() {
|
async function SerializeMaterialAsync() {
|
||||||
const matJson = MaterialOut(Material.value as PhysicalMaterialRecord);
|
const matJson = MaterialOut(Material.value as PhysicalMaterialRecord);
|
||||||
console.log(matJson);
|
console.log(matJson);
|
||||||
return matJson;
|
return matJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function ApplyTextureAsync(textureRecord: TextureTableRecord)
|
||||||
|
{
|
||||||
|
if (!textureRecord.imageUrl) {
|
||||||
|
alert("该纹理无效");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定纹理
|
||||||
|
let newTexture = textureRecord.Clone() as TextureTableRecord;
|
||||||
|
newTexture.Owner = undefined;
|
||||||
|
newTexture.Name = _database.TextureTable.AllocateName();
|
||||||
|
_database.TextureTable.Add(newTexture);
|
||||||
|
|
||||||
|
// 替换map
|
||||||
|
Material.value.map = newTexture.Id;
|
||||||
|
|
||||||
|
await UpdateMaterialAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ImportMaterialAsync(materialJson: string) {
|
||||||
|
const material = MaterialIn(JSON.parse(materialJson));
|
||||||
|
Material.value = material;
|
||||||
|
_editor.setMaterial(material);
|
||||||
|
await UpdateMaterialAsync();
|
||||||
|
}
|
||||||
|
|
||||||
async function GenerateMaterialLogoAsync() {
|
async function GenerateMaterialLogoAsync() {
|
||||||
const blob = await materialRenderer.getBlob(Material.value.Material);
|
const blob = await materialRenderer.getBlob(Material.value.Material);
|
||||||
return blob;
|
return blob;
|
||||||
@ -135,14 +148,15 @@ const sceneSetup = () => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
CurrGeometry,
|
CurrGeometry,
|
||||||
|
CurrTexture,
|
||||||
Geometries,
|
Geometries,
|
||||||
Material,
|
Material,
|
||||||
Initial,
|
Initial,
|
||||||
Update,
|
Update,
|
||||||
UpdateMaterialAsync,
|
UpdateMaterialAsync,
|
||||||
ChangeTextureAsync,
|
ChangeTextureFromUrlAsync,
|
||||||
UpdateTexture,
|
|
||||||
SerializeMaterialAsync,
|
SerializeMaterialAsync,
|
||||||
|
ImportMaterialAsync,
|
||||||
GenerateMaterialLogoAsync,
|
GenerateMaterialLogoAsync,
|
||||||
Dispose
|
Dispose
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user