Я работаю над проектом Three.js, где у меня есть объект-сетка с нанесенной текстурой. Текстура представляет собой файл PNG размером 64x64.
Проблема: При изменении размеров объекта-сетки текстура растягивается по высоте и ширине, что искажает ее внешний вид. Я хочу, чтобы текстура сохраняла свои первоначальные размеры (64x64) независимо от размера сетки.
Когда сетка 64x64
Когда сетка имеет размер 16x07 (или любой другой, кроме NxN)
Я пытался изучить свойства текстуры и настройки материала в Three.js, но не смог найти способ сохранить фиксированные размеры текстуры при масштабировании сетки.
Как я могу предотвратить растяжение текстуры и сохранить ее исходный размер 64x64, когда размеры сетки изменяются в Three.js?
Вот как создается объект и материал меша
Создание Материала
function _createMaterial(url: string): THREE.MeshBasicMaterial {
let material = new THREE.MeshBasicMaterial();
this.loader.load(url, (texture) => {
texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.LinearMipMapLinearFilter;
material.setValues({ map: texture });
});
return material;
}
Создание MeshObject
this._meshObject = new Utils3.myTHREE.Mesh(geometry, material);
Вы можете попробовать использовать: non-indexed
геометрию и разделить сетку вручную, вы можете использовать собственный шейдер и создать сопоставленный шейдер для геометрии, вы можете попытаться вручную изменить UV
сопоставленной геометрии, вы можете попробовать использовать несколько материалов (пользовательские шейдер) по геометрии. Но все эти усилия будут бессмысленны, потому что если не изолировать текстуру от геометрии, она всегда будет зависеть от нее.
Примечание. После первоначального использования текстуры ее размеры, формат и Тип не может быть изменен...
Всегда будет растягиваться, повторяться и т. д. В принципе, это имеет смысл при отображении, не так ли?
На вашем месте я бы использовал DecalGeometry
в данном конкретном случае. Это позволяет независимо манипулировать двумя геометриями. Более того, судя по картинкам, которые вы показали, у меня это выглядит так, скажем так, как декаль.
const boxGeometry = new THREE.BoxGeometry(2, 2);
const loader = new THREE.TextureLoader();
const texture = loader.load('https://media.craiyon.com/2023-11-26/2ets6-v1SVGOdKAtPxmlMw.webp');
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true });
const mesh = new THREE.Mesh(boxGeometry, material);
scene.add(mesh);
const position = new THREE.Vector3(0,0,1);
const orientation = new THREE.Euler();
const size = new THREE.Vector3(1, 1 ,1);
const decalGeometry = new DecalGeometry(mesh, position, orientation, size);
const decalMaterial = new THREE.MeshBasicMaterial({ map: texture, polygonOffset: true, polygonOffsetFactor: -1 });
const decalMesh = new THREE.Mesh(decalGeometry, decalMaterial);
https://codepen.io/Lucas_Mas/full/VwOrYGR
ОБНОВЛЯТЬ
Спрайт — версия, в которой текстура всегда обращена к камере. Важно в 3D-контексте.
https://codepen.io/Lucas_Mas/full/wvbPrvW
Решение, предложенное Лукашом Д. Масталерцем, также имеет смысл, но в моем случае я отказался от текстурного подхода и использовал спрайты.
Создание спрайта:
private static _createSprite(url: string): THREE.Sprite {
let spriteMaterial: THREE.SpriteMaterial = null;
let sprite: THREE.Sprite = new THREE.Sprite(); // Initialize the sprite
this.loader.load(url, (texture) => {
// Create a sprite material with the loaded texture
spriteMaterial = new THREE.SpriteMaterial({ map: texture });
// Assign the material to the sprite
sprite.material = spriteMaterial;
// Set the dimensions of the sprite
sprite.scale.set(32, 32, 1);
// Indicate that the sprite needs an update
sprite.material.needsUpdate = true;
// this.render(); // Uncomment if you need to render the scene after loading the texture
});
// Return the sprite, even if the texture is not done loading
return sprite;
}
Линия,
// Set the dimensions of the sprite
sprite.scale.set(32, 32, 1);
играет важную роль в размещении изображения внутри объекта-сетки.
Вот конечный результат
Конечно, окончательное решение всегда за вами. Но имейте в виду, что спрайт всегда смотрит в сторону камеры. Это может иметь решающее значение в 3D-среде. Просто включите «Наклейку» на «Спрайт» в моей ручке, и вы поймете, о чем я говорю. Если это решение по-прежнему вам подходит… это хорошо. ;)
Я также пришел к тому же решению, но из-за некоторых специфических требований в моем случае использования я выбрал другой подход к использованию спрайтов. Тем не менее, спасибо за ваш вклад.