添加编辑模式
This commit is contained in:
parent
d92cdedc57
commit
37158e7cb1
@ -32,6 +32,7 @@
|
||||
"fflate": "^0.8.2",
|
||||
"flatbush": "^3.3.0",
|
||||
"js-angusj-clipper": "^1.2.1",
|
||||
"pako": "^2.1.0",
|
||||
"pinia": "^3.0.2",
|
||||
"polylabel": "^1.1.0",
|
||||
"three": "npm:three-cf@^0.122.9",
|
||||
|
@ -23,6 +23,9 @@ importers:
|
||||
js-angusj-clipper:
|
||||
specifier: ^1.2.1
|
||||
version: 1.3.1
|
||||
pako:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
pinia:
|
||||
specifier: ^3.0.2
|
||||
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}
|
||||
hasBin: true
|
||||
|
||||
pako@2.1.0:
|
||||
resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
|
||||
|
||||
path-browserify@1.0.1:
|
||||
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
||||
|
||||
@ -1620,6 +1626,8 @@ snapshots:
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
|
||||
pako@2.1.0: {}
|
||||
|
||||
path-browserify@1.0.1: {}
|
||||
|
||||
path-parse@1.0.7: {}
|
||||
|
@ -27,7 +27,7 @@
|
||||
<h3>纹理选择(DEBUG)</h3>
|
||||
<label>纹理链接</label>
|
||||
<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>
|
||||
</div>
|
||||
<div class="adjust-section">
|
||||
@ -112,6 +112,7 @@ import CfFlex from "./CfFlex.vue";
|
||||
import { DirectoryId } from "../api/Request";
|
||||
import { IsNullOrWhitespace } from "../helpers/helper.string";
|
||||
import { DeflateAsync } from "../helpers/helper.compression";
|
||||
import { ToDeflatedBase64 } from "../helpers/helper.material";
|
||||
|
||||
export interface MaterialRequest {
|
||||
/** 材质名 */
|
||||
@ -136,7 +137,7 @@ const debugMode = ref(false);
|
||||
const { CurrGeometry, Geometries, Material } = storeToRefs(scene);
|
||||
const enableTexture = ref(Material.value.useMap);
|
||||
const _textureSrc = ref(props.textureSrc);
|
||||
const textureAdjustment = reactive<TextureAdjustment>({
|
||||
const textureAdjustment = ref<TextureAdjustment>({
|
||||
wrapS: 0,
|
||||
wrapT: 0,
|
||||
rotation: 0,
|
||||
@ -158,12 +159,12 @@ const materialInfo = reactive({
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
scene.ChangeTextureAsync(_textureSrc.value);
|
||||
scene.ChangeTextureFromUrlAsync(_textureSrc.value);
|
||||
})
|
||||
|
||||
watch(() => props.textureSrc, async (val) => {
|
||||
_textureSrc.value = val;
|
||||
await scene.ChangeTextureAsync(_textureSrc.value);
|
||||
await scene.ChangeTextureFromUrlAsync(_textureSrc.value);
|
||||
});
|
||||
|
||||
watch(model, async (val) => {
|
||||
@ -178,6 +179,19 @@ watch(textureAdjustment, async (val) => {
|
||||
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() {
|
||||
Material.value.matalness = model.metallic;
|
||||
Material.value.roughness = model.roughness;
|
||||
@ -188,7 +202,17 @@ async function UpdateMaterial() {
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -208,7 +232,7 @@ async function HandleUpload() {
|
||||
name: materialInfo.materialName,
|
||||
logo: await scene.GenerateMaterialLogoAsync(),
|
||||
// jsonString -> Deflate -> BinaryString -> Base64
|
||||
file: btoa(String.fromCharCode(...await DeflateAsync(await scene.SerializeMaterialAsync())))
|
||||
file: ToDeflatedBase64(await scene.SerializeMaterialAsync())
|
||||
};
|
||||
emits('submit', data);
|
||||
return data;
|
||||
|
@ -11,6 +11,7 @@ import { useScene } from '../stores/sceneStore';
|
||||
import CfFlex from './CfFlex.vue';
|
||||
import { GetConfig } from '../lib/libOutputConfig';
|
||||
import { useEvent } from '../stores/eventStore';
|
||||
import { FromDeflateBase64 } from '../helpers/helper.material';
|
||||
|
||||
const scene = useScene();
|
||||
const eventbus = useEvent();
|
||||
@ -21,10 +22,13 @@ const textureSrc = ref(config.textureSrc);
|
||||
|
||||
// 禁用右键菜单
|
||||
document.addEventListener('contextmenu', (e) => e.preventDefault());
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
scene.Initial(container.value);
|
||||
await HandleUpdateConfig();
|
||||
|
||||
eventbus.Subscribe('submit', HandleUpload);
|
||||
eventbus.Subscribe('update-texture', HandleChangeTexture);
|
||||
eventbus.Subscribe('update-config', HandleUpdateConfig)
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@ -41,6 +45,15 @@ function HandleChangeTexture() {
|
||||
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>
|
||||
|
||||
<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>) {
|
||||
ConfigureLibOutput(options);
|
||||
useEvent().Publish('update-config');
|
||||
}
|
||||
|
||||
/** 卸载已经挂载的DOM */
|
||||
@ -52,7 +53,7 @@ export async function SubmitRawAsync(options: { textureSrc: string }): Promise<{
|
||||
const virtualDom = document.createElement('div');
|
||||
virtualDom.style.display = 'none';
|
||||
scene.Initial(virtualDom);
|
||||
await scene.ChangeTextureAsync(options.textureSrc);
|
||||
await scene.ChangeTextureFromUrlAsync(options.textureSrc);
|
||||
var json = btoa(String.fromCharCode(...await DeflateAsync(await scene.SerializeMaterialAsync())));
|
||||
|
||||
scene.Dispose();
|
||||
|
@ -3,6 +3,7 @@ import type { MaterialRequest } from "../components/MaterialAdjuster.vue"
|
||||
|
||||
let _libOutputConfig = {
|
||||
textureSrc: "",
|
||||
file: undefined,
|
||||
submitCallback: undefined,
|
||||
cancelCallback: undefined,
|
||||
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 = {
|
||||
/** 材质贴图链接 */
|
||||
textureSrc: string,
|
||||
/** 材质预设数据,base64编码 */
|
||||
file?: string,
|
||||
/** 环境贴图链接(立方体贴图,按照顺序输入[右左上下前后]) */
|
||||
envTextureSrc: string[],
|
||||
/** 灰度环境贴图链接,输入格式与环境贴图一致 */
|
||||
|
@ -19,4 +19,4 @@ export const useEvent = defineStore('event', () => {
|
||||
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 { Texture } from "three";
|
||||
import { materialRenderer } from "../common/MaterialRenderer";
|
||||
import { MaterialOut } from "../common/MaterialSerializer";
|
||||
import { MaterialIn, MaterialOut } from "../common/MaterialSerializer";
|
||||
|
||||
const sceneSetup = () => {
|
||||
let _editor: MaterialEditor | undefined;
|
||||
@ -77,7 +77,7 @@ const sceneSetup = () => {
|
||||
Update();
|
||||
}
|
||||
|
||||
async function ChangeTextureAsync(url: string) {
|
||||
async function ChangeTextureFromUrlAsync(url: string) {
|
||||
const img = await LoadImageFromUrl(url);
|
||||
|
||||
// 关联贴图
|
||||
@ -97,25 +97,38 @@ const sceneSetup = () => {
|
||||
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() {
|
||||
const matJson = MaterialOut(Material.value as PhysicalMaterialRecord);
|
||||
console.log(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() {
|
||||
const blob = await materialRenderer.getBlob(Material.value.Material);
|
||||
return blob;
|
||||
@ -135,14 +148,15 @@ const sceneSetup = () => {
|
||||
|
||||
return {
|
||||
CurrGeometry,
|
||||
CurrTexture,
|
||||
Geometries,
|
||||
Material,
|
||||
Initial,
|
||||
Update,
|
||||
UpdateMaterialAsync,
|
||||
ChangeTextureAsync,
|
||||
UpdateTexture,
|
||||
ChangeTextureFromUrlAsync,
|
||||
SerializeMaterialAsync,
|
||||
ImportMaterialAsync,
|
||||
GenerateMaterialLogoAsync,
|
||||
Dispose
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user