Reputation: 21612
Is it possible to load texture to specific faces of PlaneGeometry
object? What I want to do is to map separate texture to specific 2 triangles of PlaneGeometry
object.
Here is some example that color each 2 trianles of PlaneGeometry
object with some color and it works:
<!DOCTYPE html>
<html lang="en">
<head>
<title>title</title>
<meta charset="utf-8">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
<script>
var camera, scene, renderer, geometry, material, mesh;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 500;
scene.add(camera);
// geometry
var thumbnail_width = 32;
var thumbnail_height = 32;
var width_segments = 10;
var height_segments = 10;
var plane_geometry_width = width_segments * thumbnail_width;
var plane_geometry_height = height_segments * thumbnail_height;
var geometry = new THREE.PlaneGeometry(plane_geometry_width, plane_geometry_height, width_segments, height_segments); // faces.length = widthSegments*heightSegments*2
//Draw grid with static colors
// materials
var materials = [];
materials.push(new THREE.MeshBasicMaterial({
color: 0xff0000, side:THREE.DoubleSide
}));
materials.push(new THREE.MeshBasicMaterial({
color: 0x00ff00, side:THREE.DoubleSide
}));
materials.push(new THREE.MeshBasicMaterial({
color: 0x0000ff, side:THREE.DoubleSide
}));
// Add materialIndex to face
var l = geometry.faces.length / 2;
for (var i = 0; i < l; i++) {
var j = 2 * i;
geometry.faces[j].materialIndex = i % 3;
geometry.faces[j + 1].materialIndex = i % 3;
}
// mesh
mesh = new THREE.Mesh(geometry, materials);
scene.add(mesh);
// WebGL renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
renderer.render(scene, camera);
}
</script>
</body>
However when I try to map texture the same way, it maps to all triangles, which is not what I want:
<!DOCTYPE html>
<html lang="en">
<head>
<title>title</title>
<meta charset="utf-8">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
<script>
var camera, scene, renderer, geometry, material, mesh;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 500;
scene.add(camera);
// geometry
var thumbnail_width = 32;
var thumbnail_height = 32;
var width_segments = 10;
var height_segments = 10;
var plane_geometry_width = width_segments * thumbnail_width;
var plane_geometry_height = height_segments * thumbnail_height;
var geometry = new THREE.PlaneGeometry(plane_geometry_width, plane_geometry_height, width_segments, height_segments); // faces.length = widthSegments*heightSegments*2
var texture = new THREE.TextureLoader().load("image_small/item_1.png")
var materials = [];
materials.push(new THREE.MeshBasicMaterial({map : texture, side: THREE.DoubleSide}));
materials.push(new THREE.MeshBasicMaterial({color: 0xff0000, side:THREE.DoubleSide}));
materials.push(new THREE.MeshBasicMaterial({color: 0x00ff00, side:THREE.DoubleSide}));
// Add materialIndex to face
var l = geometry.faces.length / 2;
for (var i = 0; i < l; i++) {
var j = 2 * i;
geometry.faces[j].materialIndex = i % 3;
geometry.faces[j + 1].materialIndex = i % 3;
}
// mesh
mesh = new THREE.Mesh(geometry, materials);
scene.add(mesh);
// WebGL renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
renderer.render(scene, camera);
}
</script>
</body>
UPDATE:
Part of code for 2nd solution suggested by @WestLangley
var texture = new THREE.TextureLoader().load("image_small/item_1.png")
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 10, 10 );
var materials = [];
materials.push(new THREE.MeshBasicMaterial({map : texture, side: THREE.DoubleSide}));
materials.push(new THREE.MeshBasicMaterial({color: 0xff0000, side:THREE.DoubleSide}));
materials.push(new THREE.MeshBasicMaterial({color: 0x00ff00, side:THREE.DoubleSide}));
// Add materialIndex to face
var l = geometry.faces.length / 2;
for (var i = 0; i < l; i++) {
var j = 2 * i;
geometry.faces[j].materialIndex = i % 3;
geometry.faces[j + 1].materialIndex = i % 3;
}
geometry.sortFacesByMaterialIndex();
// Mesh
mesh = new THREE.Mesh(geometry, materials);
scene.add(mesh);
// WebGL renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
UPDATE2:
var texture = new THREE.TextureLoader().load("image_small/item_1.png")
texture.flipY = true
var materials = [];
materials.push(new THREE.MeshBasicMaterial({map : texture, side: THREE.DoubleSide}));
for (var i = 0; i < geometry.faces.length; i++) {
geometry.faces[i].materialIndex = 0;
}
var uvs = geometry.faceVertexUvs[ 0 ]; // widthSegments*heightSegments*2
//UV
// (0,1) (1,1)
// (0,0) (1,0)
// For THREE.PlaneGeometry, UV ( 0, 0 ) is located at the bottom left, and ( 1, 1 ) the top right.
for (var i = 0; i < uvs.length; i++) {
if(i % 2 == 0)
{
// (0,1)[2] x
// (0,0)[1] (1,0)[3]
uvs[i][0].x = 0.0;
uvs[i][0].y = 0.0;
uvs[i][1].x = 0.0;
uvs[i][1].y = 1.0;
uvs[i][2].x = 1.0;
uvs[i][2].y = 0.0;
}
else
{
// (0,1)[1] (1,1)[2]
// x (1,0)[3]
uvs[i][0].x = 0.0;
uvs[i][0].y = 1.0;
uvs[i][1].x = 1.0;
uvs[i][1].y = 1.0;
uvs[i][2].x = 1.0;
uvs[i][2].y = 0.0;
}
}
var mesh = new THREE.Mesh(geometry, materials);
scene.add(mesh);
// WebGL renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
Upvotes: 1
Views: 1563
Reputation: 104783
You have two options.
One is to change the UVs of your geometry so each square has UVs that range from ( 0, 0 ) lower-left to ( 1, 1 ) upper-right.
The other solution is to just set the repeat
of your texture:
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 10, 10 );
BTW, type renderer.info
into the console, and you will see you are generating 100 draw calls.
Add the following to your code after you set the material indices:
geometry.sortFacesByMaterialIndex();
You should now see just 3 draw calls.
three.js r.89
Upvotes: 4