fix(falukant): use nearest lower age model fallback
Some checks failed
Deploy to production / deploy (push) Has been cancelled
Some checks failed
Deploy to production / deploy (push) Has been cancelled
This commit is contained in:
@@ -27,15 +27,12 @@ import { getApiBaseURL } from '@/utils/axios.js';
|
|||||||
/** Backend-Route: GET /api/models/3d/falukant/characters/:filename (Proxy mit Draco-Optimierung) */
|
/** Backend-Route: GET /api/models/3d/falukant/characters/:filename (Proxy mit Draco-Optimierung) */
|
||||||
const MODELS_API_PATH = '/api/models/3d/falukant/characters';
|
const MODELS_API_PATH = '/api/models/3d/falukant/characters';
|
||||||
const OPTIMIZED_MODEL_SUFFIX = '_opt.glb';
|
const OPTIMIZED_MODEL_SUFFIX = '_opt.glb';
|
||||||
// Optional: zusätzliche Namenskonventionen, die vor dem Standardpfad ausprobiert werden.
|
// Only concrete age models are used. If an exact age is not available, choose
|
||||||
// Hier werden mögliche Alternativ-Dateinamen aufgeführt, die für bestimmte Altersstufen
|
// the nearest lower one instead of the generic gender/age-group fallback.
|
||||||
// (z.B. weibliche Modelle für 1-4 Jahre) existieren könnten. Trage hier die tatsächlichen
|
const AVAILABLE_MODEL_AGES = Object.freeze({
|
||||||
// Dateinamen ein, falls dein Backend solche Varianten enthält.
|
female: Object.freeze([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 25, 30, 40, 50, 60]),
|
||||||
const AGE_ALTERNATIVE_SUFFIXES = [
|
male: Object.freeze([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 25, 30, 40, 50, 60]),
|
||||||
'_alt.glb',
|
});
|
||||||
'_special.glb',
|
|
||||||
'_v2.glb'
|
|
||||||
];
|
|
||||||
|
|
||||||
// Per-age camera offsets applied after auto-fit. Values are additive (meters).
|
// Per-age camera offsets applied after auto-fit. Values are additive (meters).
|
||||||
// Set `y` to raise/lower the camera, `z` to move it closer/further.
|
// Set `y` to raise/lower the camera, `z` to move it closer/further.
|
||||||
@@ -196,18 +193,6 @@ export default {
|
|||||||
if (age <= 17) return 'teen';
|
if (age <= 17) return 'teen';
|
||||||
return 'adult';
|
return 'adult';
|
||||||
},
|
},
|
||||||
modelPath() {
|
|
||||||
const base = getApiBaseURL();
|
|
||||||
const prefix = base ? `${base}${MODELS_API_PATH}` : MODELS_API_PATH;
|
|
||||||
return `${prefix}/${this.actualGender}_${this.ageGroup}.glb`;
|
|
||||||
},
|
|
||||||
exactAgeModelPath() {
|
|
||||||
// Pfad für genaues Alter (z.B. female_1y.glb für Alter 1)
|
|
||||||
const age = this.actualAge;
|
|
||||||
const base = getApiBaseURL();
|
|
||||||
const prefix = base ? `${base}${MODELS_API_PATH}` : MODELS_API_PATH;
|
|
||||||
return `${prefix}/${this.actualGender}_${age}y.glb`;
|
|
||||||
},
|
|
||||||
fallbackImageSrc() {
|
fallbackImageSrc() {
|
||||||
return this.actualGender === 'female'
|
return this.actualGender === 'female'
|
||||||
? '/images/mascot/mascot_female.png'
|
? '/images/mascot/mascot_female.png'
|
||||||
@@ -219,7 +204,7 @@ export default {
|
|||||||
if (this.is3DDisabled) return;
|
if (this.is3DDisabled) return;
|
||||||
await this.loadModel();
|
await this.loadModel();
|
||||||
},
|
},
|
||||||
async ageGroup() {
|
async actualAge() {
|
||||||
if (this.is3DDisabled) return;
|
if (this.is3DDisabled) return;
|
||||||
await this.loadModel();
|
await this.loadModel();
|
||||||
}
|
}
|
||||||
@@ -454,35 +439,14 @@ export default {
|
|||||||
const base = getApiBaseURL();
|
const base = getApiBaseURL();
|
||||||
const prefix = base ? `${base}${MODELS_API_PATH}` : MODELS_API_PATH;
|
const prefix = base ? `${base}${MODELS_API_PATH}` : MODELS_API_PATH;
|
||||||
|
|
||||||
// Fallback-Hierarchie:
|
|
||||||
// Standard:
|
|
||||||
// 1. Exaktes Altersmodell
|
|
||||||
// 2. Altersbereich
|
|
||||||
// 3. Basis-Modell
|
|
||||||
// Lightweight:
|
|
||||||
// 1. Altersbereich
|
|
||||||
// 2. Basis-Modell
|
|
||||||
const exactAgePath = this.toOptimizedModelPath(this.exactAgeModelPath);
|
|
||||||
const ageGroupPath = this.toOptimizedModelPath(this.modelPath);
|
|
||||||
const fallbackPath = `${prefix}/${this.actualGender}${OPTIMIZED_MODEL_SUFFIX}`;
|
|
||||||
|
|
||||||
// Build a list of candidate paths. For every age and gender we first try
|
|
||||||
// possible alternate filenames for the exact-age model (e.g. female_1y_alt.glb),
|
|
||||||
// then the exact-age file, then the age-group file, and finally the base gender
|
|
||||||
// fallback. This makes the age-specific model the primary source and the
|
|
||||||
// age-group only a later fallback.
|
|
||||||
const candidates = [];
|
|
||||||
const modelAge = this.actualAge;
|
const modelAge = this.actualAge;
|
||||||
|
const availableAges = AVAILABLE_MODEL_AGES[this.actualGender] || [];
|
||||||
// Try exact-age variants with configured suffixes first (works for any gender/age)
|
const candidateAges = availableAges
|
||||||
for (const sfx of AGE_ALTERNATIVE_SUFFIXES) {
|
.filter((age) => age <= modelAge)
|
||||||
candidates.push(this.toOptimizedModelPath(`${prefix}/${this.actualGender}_${modelAge}y${sfx}`));
|
.sort((left, right) => right - left);
|
||||||
}
|
const candidates = candidateAges.map((age) =>
|
||||||
|
`${prefix}/${this.actualGender}_${age}y${OPTIMIZED_MODEL_SUFFIX}`
|
||||||
// Standard preference order: exact age, age group, fallback
|
);
|
||||||
candidates.push(exactAgePath);
|
|
||||||
candidates.push(ageGroupPath);
|
|
||||||
candidates.push(fallbackPath);
|
|
||||||
|
|
||||||
let gltf;
|
let gltf;
|
||||||
try {
|
try {
|
||||||
@@ -505,10 +469,8 @@ export default {
|
|||||||
// store for debug overlay
|
// store for debug overlay
|
||||||
this.debugInfo.modelPath = chosenPath;
|
this.debugInfo.modelPath = chosenPath;
|
||||||
// determine modelType
|
// determine modelType
|
||||||
if (chosenPath === exactAgePath) this.debugInfo.modelType = 'exactAge';
|
const chosenAge = candidateAges[candidates.indexOf(chosenPath)];
|
||||||
else if (chosenPath === ageGroupPath) this.debugInfo.modelType = 'ageGroup';
|
this.debugInfo.modelType = chosenAge === modelAge ? 'exactAge' : 'nearestLowerAge';
|
||||||
else if (chosenPath === fallbackPath) this.debugInfo.modelType = 'fallback';
|
|
||||||
else this.debugInfo.modelType = 'alternate';
|
|
||||||
} finally {
|
} finally {
|
||||||
dracoLoader.dispose();
|
dracoLoader.dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user