Как дублировать одну 3D модель несколько раз на странице?
Есть одна 3D модель, в будущем её нужно будет дублировать много раз, но ТЕКСТУРА будет меняться. При попытке дублировать <.script> ничего не работает.
Как можно это реализовать? 3D модель сделана через Three.js

<script>
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(10, window.innerWidth / window.innerHeight, 0.1, 50);
camera.position.z = 20;
camera.position.y = 1.5;
camera.position.x = 0;
renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
renderer.setClearColor(0x000000, 0);
renderer.setSize(200, 300);
renderer.domElement.setAttribute("id", "Minecraft3D0bj");
document.getElementsByClassName('skin_one')[0].insertBefore(renderer.domElement, document.getElementsByClassName('skin_one')[0].firstChild);
var light = new THREE.HemisphereLight(0xFFFFFF, 0xFFFFFF, 1.41);
scene.add(light);
let loader = new THREE.GLTFLoader();
let obj = null;
loader.load('/Стив.gltf', function (gltf) {
obj = gltf;
obj.scene.scale.set(4.5, 1.5, 4.5);
scene.add(obj.scene);
});
function animate() {
requestAnimationFrame(animate);
if (obj)
obj.scene.rotation.y += 0.020;
renderer.render(scene, camera);
}
animate();
</script>
body {
height: inherit;
margin: 0 auto;
padding: 0 auto;
width: var(--layout-width);
height: var(--header-height);
--layout-width: 95%;
height: 100%;
background: rgb(26, 26, 26);
flex-direction: row;
display: flex;
}
.block {
display: flex;
width: 200px;
height: 300px;
margin: 15px;
justify-content: center;
align-items: center;
}
.block .skin {
display: flex;
position: absolute;
justify-content: center;
align-items: center;
width: 200px;
height: 300px;
background: rgb(30, 30, 30);
background: linear-gradient( 140deg, rgba(30, 30, 30, 0.294) 0%, rgba(17, 17, 17, 0.5) 100% );
border: 2.1px solid rgb(70, 70, 70);
border-radius: 10px;
-webkit-box-shadow: 0px 2px 6px 3px #00000065;
box-shadow: 0px 2px 6px 3px #0000004f;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r123/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/GLTFLoader.js "></script>
</head>
<body>
<div class="block">
<div class="skin">
</div>
</div>
<div class="block_two">
<div class="skin_two">
</div>
</div>
</body>
</html>
Ответы (1 шт):
Автор решения: Хацкер
→ Ссылка
Вот упрощенная выдержка кода из моего проекта:
<script>
models = {
build:{//модели без скелетной анимации
home:{
'href':'home.glb',
'name':'home',
'status':'not loaded',
'model':undefined,
'count':'0'
},
},
units:{//модели с использованием скелетной анимации - их чуточку сложнее копировать
human:{
'href':'human.glb',
'name':'human',
'status':'not loaded',
'model':undefined,
'count':'0'
},
},
}
function loadModel(type, name){
loader.load('models/'+models[type][name].href, function(gltf){
models[type][name].status = 'loaded';
if(type == 'build'){
models[type][name].model = gltf.scene.children[0];// здесь,
//сохраняется непосредственно НЕ сцена 3d объекта, а его Mesh потомок, в
//противном случае используемый мной метод копирования объекта может ругаться
//- требовать Mesh объект для клонирования. у сцены объекта могут быть
//несколько потомков, зачастую это свой собственный источник света, проверить
//под каким индексом идет Mesh вашего объекта можете с помощью консоли
// console.log(gltf.scene);
gltf.scene.children[0].name = models[type][name].name;
}
else if(type == 'units'{ //здесь же, наоборот,
//копируется весь файл, это необходимо для сохранения скелетных анимаций
models[type][name].model = gltf;
gltf.scene.name = models[type][name].name;
}
});
}
function startLoader(){
for(var type in models){
for(var name in models[type]){
if(models[type][name].status == 'not loaded') loadModel(type, name);
}
}
}
startLoader();
function addBuild(type, name){
var newBuild = models[type][name].model.clone();
models[type][name].count += 1;
var newName = models[type][name].name + models[type][name].count;
newBuild.name = newName;
scene.add(newBuild);
}
$('#addBuild').click(function(){//не знаю используете ли вы jQury...
//я привязал эти события к клику, для того чтобы они не сработали ДО того,
//как все модели будут загружены, но вы можете воспользоваться
//менеджером загрузок THREE.JS
addBuild('build', 'home');
});
//до смены непосредственно текстуры объекта я еще не дошел (не приходилось пока),
//но думаю принцип такой же (клонировать, изменить, присвоить) как в примере ниже:
function changeMaterial(el){//смена материала build
var cloned = el.material.clone();
cloned.emissive.setRGB(255, 100, 100); //например
cloned.emissiveIntensity = 0.002; //степень наложения к примеру
el.material = cloned;
}
$('#changeMaterial').click(function(){
//тут код зависит от того, в каком моменте вашего кода необходимо изменить
//объект и каким способом вы получаете его (его имя),к примеру, мы знаем
//имя объекта - 'home2'
var el = scene.getObjectByName('home2')
changeMaterial(el);
});
function addUnit(type, name){
//как я говорил, для копирования юнитов со скелетной анимацией понадобится
//модуль SkeletonUtils
var unit = models[type][name].model.scene;
var newunit = THREE.SkeletonUtils.clone(unit);
// как подключать миксер анимаций - расписывать не буду, так как это уже
//выходит за рамки вопроса и займет еще не мало строк кода и времени.
scene.add(newunit);
}
</script>
непосредственно у меня в проекте всё работает, надеюсь собирая выдержку нигде не допустил критической ошибки, но думаю пример поможет решить вашу проблему.