Implemented model-index.json, Separated individual variants, Italicized scientific name, updated Frog Zoo
This commit is contained in:
@@ -13,6 +13,16 @@ const sizes = {
|
||||
}
|
||||
|
||||
|
||||
let loadData = null;
|
||||
|
||||
fetch('model-index.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
loadData = data;
|
||||
startApp();
|
||||
});
|
||||
|
||||
|
||||
//RENDERER
|
||||
const renderer = new THREE.WebGLRenderer({antialias:true});
|
||||
renderer.setSize( sizes.width, sizes.height );
|
||||
@@ -26,18 +36,14 @@ document.body.appendChild( renderer.domElement );
|
||||
|
||||
|
||||
//CAMERA
|
||||
const DEFAULT_CAMERA_POS = new THREE.Vector3(0, 0, 2); // Camera default position
|
||||
const DEFAULT_CAMERA_POS = new THREE.Vector3(-0.4, 0.5, 1.5); // Camera default position
|
||||
const DEFAULT_TARGET = new THREE.Vector3(0, 0, 0); // Camera default target
|
||||
|
||||
const camera = new THREE.PerspectiveCamera( 65, sizes.width / sizes.height, 0.1, 1000 );
|
||||
const camera = new THREE.PerspectiveCamera( 65, sizes.width / sizes.height, 0.001, 1000 );
|
||||
// Apply default position initially
|
||||
camera.position.copy(DEFAULT_CAMERA_POS);
|
||||
camera.lookAt(DEFAULT_TARGET);
|
||||
|
||||
// camera.position.x = 0;
|
||||
// camera.position.y = 0;
|
||||
// camera.position.z = 2;
|
||||
|
||||
const controls = new OrbitControls( camera, renderer.domElement );
|
||||
controls.enableDamping = true;
|
||||
controls.dampingFactor = 0.05; // Friction
|
||||
@@ -63,44 +69,26 @@ const loader = new GLTFLoader();
|
||||
let currentModel = null;
|
||||
|
||||
|
||||
// MODEL PATHS
|
||||
const modelPaths = {
|
||||
'[MBS-2351] Ansonia muelleri': 'models/MBS-2351 Ansonia muelleri.glb',
|
||||
'[MBS-2355] Platymantis corrugatus': 'models/MBS-2355 Platymantis corrugatus.glb',
|
||||
'[MBS-2357] Hylarana grandocula': 'models/MBS-2357 Hylarana grandocula.glb',
|
||||
'[MBS-2358] Sanguirana mearnsi': 'models/MBS-2358 Sanguirana mearnsi.glb',
|
||||
'[MBS-2362] Hoplobatrachus rugulosus': 'models/MBS-2362 Hoplobatrachus rugulosus.glb',
|
||||
'[MBS-2407] Staurois natator': 'models/MBS-2407 Staurois natator.glb',
|
||||
'[MBS-2408] Oreophryne anulata': 'models/MBS-2408 Oreophryne anulata.glb',
|
||||
'[MBS-2410] Platymantis guentheri': 'models/MBS-2410 Platymantis guentheri.glb',
|
||||
'[MBS-2415] Kaloula pulchra': 'models/MBS-2415 Kaloula pulchra.glb',
|
||||
'[MBS-2416] Rhinella marina': 'models/MBS-2416 Rhinella marina.glb',
|
||||
'Frog Zoo': 'models/-------- Frog Zoo.glb'
|
||||
};
|
||||
const params = {
|
||||
selectedModel: modelPaths['[MBS-2351] Ansonia muelleri'] // default selected option
|
||||
};
|
||||
|
||||
// UPDATE NAME FUNCTION
|
||||
function updateNameText(name) {
|
||||
const recordtitleElement = document.getElementById('recordnumbertext');
|
||||
const titleElement = document.getElementById('nametext');
|
||||
|
||||
//Record Number
|
||||
const recnumberstart = name.slice(7);
|
||||
const trimmedrecnumber = recnumberstart.slice(0,8);
|
||||
recordtitleElement.textContent = trimmedrecnumber;
|
||||
const recnumber = name.slice(0,11);
|
||||
recordtitleElement.textContent = recnumber;
|
||||
|
||||
//Scientific Name
|
||||
const trimmedstart = name.slice(16);
|
||||
const trimmedsciname = trimmedstart.slice(0, -4);
|
||||
titleElement.textContent = trimmedsciname;
|
||||
const trimmedstart = name.slice(11);
|
||||
titleElement.textContent = trimmedstart;
|
||||
titleElement.style.fontStyle = "italic"; //italicize scientific name
|
||||
}
|
||||
|
||||
|
||||
// LOAD MODEL FUNCTION
|
||||
function loadNewModel(url) {
|
||||
const gui = new GUI({ width: 425 }); //New UI
|
||||
|
||||
//Load Function
|
||||
function loadModel(modelPath) {
|
||||
if (currentModel) {
|
||||
scene.remove(currentModel);
|
||||
currentModel.traverse((child) => {
|
||||
@@ -115,44 +103,87 @@ function loadNewModel(url) {
|
||||
});
|
||||
currentModel = null;
|
||||
}
|
||||
console.log(`Loaded: ${modelPath}`);
|
||||
|
||||
//Load the new model
|
||||
loader.load(
|
||||
url,
|
||||
(glb) => {
|
||||
currentModel = glb.scene;
|
||||
scene.add(currentModel);
|
||||
loader.load(modelPath, (glb) => {
|
||||
currentModel = glb.scene;
|
||||
scene.add(glb.scene);
|
||||
});
|
||||
}
|
||||
function startApp() {
|
||||
// 1. Create an object to hold the currently selected values
|
||||
const modelsData = loadData;
|
||||
const params = {
|
||||
name: modelsData[0].name,
|
||||
variant: Object.keys(modelsData[0].variants)[0]
|
||||
};
|
||||
|
||||
// 2. Extract just the names for the first dropdown
|
||||
const modelNames = modelsData.map(item => item.name);
|
||||
|
||||
// 3. Add the Controllers
|
||||
const nameController = gui.add(params, 'name', modelNames).name('Model Name');
|
||||
|
||||
// Initialize the variants dropdown with the first model's options
|
||||
let variantOptions = Object.keys(modelsData[0].variants);
|
||||
let variantController = gui.add(params, 'variant', variantOptions).name('Variant');
|
||||
|
||||
// 4. Handle dynamic updates
|
||||
nameController.onChange((selectedName) => {
|
||||
const selectedModelData = modelsData.find(item => item.name === selectedName); // Find the data for the newly selected model
|
||||
const newVariants = Object.keys(selectedModelData.variants);
|
||||
|
||||
params.variant = newVariants[0]; // Update the param state to the first available variant of the new model
|
||||
|
||||
// Destroy the old variant dropdown and create a new one with updated options
|
||||
variantController.destroy();
|
||||
variantController = gui.add(params, 'variant', newVariants).name('Variant');
|
||||
|
||||
// Re-attach the onChange listener to the new dropdown
|
||||
attachVariantListener(variantController, selectedModelData);
|
||||
|
||||
//Load Model
|
||||
loadModel(selectedModelData.variants[params.variant]);
|
||||
|
||||
// Reset camera position and target
|
||||
resetcam();
|
||||
|
||||
//Call function to update name text
|
||||
updateNameText(selectedName);
|
||||
});
|
||||
|
||||
// Helper function to handle variant changes
|
||||
function attachVariantListener(controller, modelData) {
|
||||
controller.onChange((selectedVariant) => {
|
||||
const modelPath = modelData.variants[selectedVariant];
|
||||
|
||||
// Load Model
|
||||
loadModel(modelPath);
|
||||
});
|
||||
}
|
||||
|
||||
// Attach listener to the very first variant dropdown
|
||||
attachVariantListener(variantController, modelsData[0]);
|
||||
const initialModelPath = modelsData[0].variants[params.variant];
|
||||
|
||||
// Load default model right away
|
||||
loadModel(initialModelPath);
|
||||
updateNameText(modelsData[0].name);
|
||||
|
||||
// Reset camera transforms
|
||||
function resetcam(){
|
||||
camera.position.copy(DEFAULT_CAMERA_POS);
|
||||
if (controls) {
|
||||
controls.target.copy(DEFAULT_TARGET);
|
||||
controls.update();
|
||||
} else {
|
||||
camera.lookAt(DEFAULT_TARGET);
|
||||
}
|
||||
);
|
||||
|
||||
//Call function to update name text
|
||||
updateNameText(params.selectedModel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GUI
|
||||
const gui = new GUI({ width: 425 });
|
||||
gui.add(params, 'selectedModel', modelPaths)
|
||||
.name('Displayed Model:')
|
||||
.onChange((newUrl) => {
|
||||
loadNewModel(newUrl);
|
||||
|
||||
// Reset camera position and target
|
||||
camera.position.copy(DEFAULT_CAMERA_POS);
|
||||
if (controls) {
|
||||
controls.target.copy(DEFAULT_TARGET);
|
||||
controls.update();
|
||||
} else {
|
||||
camera.lookAt(DEFAULT_TARGET);
|
||||
}
|
||||
});
|
||||
|
||||
// Load the initial default model right away
|
||||
loadNewModel(params.selectedModel);
|
||||
|
||||
gui.domElement.style.right = '0px';
|
||||
|
||||
|
||||
//ENVIRONMENT
|
||||
const env_loader = new UltraHDRLoader();
|
||||
const env_texture = await env_loader.loadAsync( 'assets/studio_small_08_4k.jpg' );
|
||||
|
||||
Reference in New Issue
Block a user