fix(model3d): preserve textures with qiniu storage
This commit is contained in:
parent
cd1639b4d7
commit
a3e3938f7b
@ -14,6 +14,11 @@ const ALLOWED_MODEL_HOST_DOMAINS = [
|
||||
"worldlabs.ai",
|
||||
"s3.1080p.hk",
|
||||
"img.yydd.ai",
|
||||
"yybb.top",
|
||||
"qiniucs.com",
|
||||
"qiniudn.com",
|
||||
"clouddn.com",
|
||||
"qbox.me",
|
||||
"blob.vercel-storage.com",
|
||||
"aliyuncs.com",
|
||||
"amazonaws.com",
|
||||
|
||||
@ -300,6 +300,7 @@ function configureMaterialTextures(
|
||||
|
||||
function cloneSceneWithIndependentMaterials(scene: Object3D) {
|
||||
const clonedScene = scene.clone(true);
|
||||
const clonedTextures = new Map<THREE.Texture, THREE.Texture>();
|
||||
|
||||
clonedScene.traverse((node) => {
|
||||
if (!isMesh(node)) return;
|
||||
@ -309,6 +310,24 @@ function cloneSceneWithIndependentMaterials(scene: Object3D) {
|
||||
: [node.material];
|
||||
const clonedMaterials = sourceMaterials.map((material) => {
|
||||
const clonedMaterial = material.clone();
|
||||
const sourceMaterialRecord = material as any;
|
||||
const clonedMaterialRecord = clonedMaterial as any;
|
||||
|
||||
for (const key of MATERIAL_TEXTURE_KEYS) {
|
||||
const sourceTexture = sourceMaterialRecord[key];
|
||||
if (!sourceTexture?.isTexture) continue;
|
||||
|
||||
const typedSourceTexture = sourceTexture as THREE.Texture;
|
||||
let clonedTexture = clonedTextures.get(typedSourceTexture);
|
||||
if (!clonedTexture) {
|
||||
const newTexture = typedSourceTexture.clone();
|
||||
newTexture.needsUpdate = true;
|
||||
clonedTextures.set(typedSourceTexture, newTexture);
|
||||
clonedTexture = newTexture;
|
||||
}
|
||||
clonedMaterialRecord[key] = clonedTexture;
|
||||
}
|
||||
|
||||
configureMaterialTextures(clonedMaterial, node.geometry);
|
||||
return clonedMaterial;
|
||||
});
|
||||
@ -407,12 +426,20 @@ function ModelScene({
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
const disposedTextures = new Set<THREE.Texture>();
|
||||
scene.traverse((node) => {
|
||||
if (!isMesh(node)) return;
|
||||
const materials = Array.isArray(node.material)
|
||||
? node.material
|
||||
: [node.material];
|
||||
for (const material of materials) {
|
||||
const materialRecord = material as any;
|
||||
for (const key of MATERIAL_TEXTURE_KEYS) {
|
||||
const texture = materialRecord[key];
|
||||
if (!texture?.isTexture || disposedTextures.has(texture)) continue;
|
||||
disposedTextures.add(texture);
|
||||
texture.dispose();
|
||||
}
|
||||
material.dispose();
|
||||
}
|
||||
});
|
||||
@ -437,7 +464,7 @@ function ModelScene({
|
||||
|
||||
return (
|
||||
<group rotation={modelRotation || [0, 0, 0]}>
|
||||
<primitive object={scene} scale={1} />
|
||||
<primitive dispose={null} object={scene} scale={1} />
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
@ -7,6 +7,11 @@ const PROXY_HOST_KEYWORDS = [
|
||||
"marble",
|
||||
"s3.1080p.hk",
|
||||
"img.yydd.ai",
|
||||
"yybb.top",
|
||||
"qiniucs.com",
|
||||
"qiniudn.com",
|
||||
"clouddn.com",
|
||||
"qbox.me",
|
||||
"blob.vercel-storage.com",
|
||||
"aliyuncs.com",
|
||||
"amazonaws.com",
|
||||
|
||||
@ -28,11 +28,32 @@ test.describe("3D workspace and Style Pro regressions", () => {
|
||||
|
||||
expect(viewer).toContain("cloneSceneWithIndependentMaterials");
|
||||
expect(viewer).toContain("const clonedMaterial = material.clone()");
|
||||
expect(viewer).toContain("typedSourceTexture.clone()");
|
||||
expect(viewer).toContain("clonedMaterialRecord[key] = clonedTexture");
|
||||
expect(viewer).toContain("disposedTextures.add(texture)");
|
||||
expect(viewer).toContain("texture.dispose()");
|
||||
expect(viewer).toContain("<primitive dispose={null}");
|
||||
expect(viewer).toContain(
|
||||
"configureMaterialTextures(clonedMaterial, node.geometry)"
|
||||
);
|
||||
});
|
||||
|
||||
test("loads Qiniu-hosted GLB assets through the authenticated same-origin proxy", () => {
|
||||
const assetUrl = readSource("lib/canvas/three-asset-url.ts");
|
||||
const proxy = readSource("app/api/canvas/3d/model-proxy/route.ts");
|
||||
|
||||
for (const host of [
|
||||
"yybb.top",
|
||||
"qiniucs.com",
|
||||
"qiniudn.com",
|
||||
"clouddn.com",
|
||||
"qbox.me",
|
||||
]) {
|
||||
expect(assetUrl).toContain(`\"${host}\"`);
|
||||
expect(proxy).toContain(`\"${host}\"`);
|
||||
}
|
||||
});
|
||||
|
||||
test("uses the same hidden-model access rule in Style Pro as canvas", () => {
|
||||
const route = readSource("app/api/style-pro/model-options/route.ts");
|
||||
const canvasModelsRoute = readSource("app/(chat)/api/models/route.ts");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user