Three.js - Updating texture on plane - three.js

I'm trying to make a terrain editor. So I have a plane with multiple materials on it, which I initialize like so:
var materials = [];
var grasstexture = THREE.ImageUtils.loadTexture('Img/grass.png', {}, function() { });
var rocktexture = THREE.ImageUtils.loadTexture('Img/rock.png', {}, function() { });
materials.push(new THREE.MeshPhongMaterial({color: 0xffffff, map: grasstexture}));
materials.push(new THREE.MeshPhongMaterial({color: 0xffffff, map: rocktexture}));
// Plane
this.geometry.materials = materials;
for(var i = 0; i < this.geometry.faces.length; i++)
{
this.geometry.faces[i].materialIndex = 0;
}
this.geometry.dynamic = true;
this.mesh = new THREE.Mesh( this.geometry, new THREE.MeshFaceMaterial( ) );
this.mesh.receiveShadow = true;
The result is a square plane stripped with the two textures.
Now, I can't seem to update the materialIndex for each vertex during the runtime. I have tried:
face.materialIndex = 1;
for(var i = 0; i < geo.materials.length; i++){
geo.materials[i].needsUpdate = true;
}
for(var i = 0; i < this.geometry.faces.length; i++)
{
geo.faces[i].materialIndex = 0;
}
for(var i = 0; i < geo.materials.length; i++){
geo.materials[i].needsUpdate = true;
}
this.mesh.needsUpdate = true;
this.mesh.material.needsUpdate = true;
geo.verticesNeedUpdate = true;
geo.normalsNeedUpdate = true;
geo.colorsNeedUpdate = true;
geo.computeFaceNormals();
geo.computeVertexNormals();
geo.computeCentroids();
geo.computeTangents() ;
And every other 'materialIndex' and 'needsUpdate' variable in Three.js I was able to find, but still nothing happens. How do I force an update on the material indices?

You can't. materialIndex is only used in the first render to partition the geometry into chunks, with each chunk having the same material. Also, you cannot re-partition the chunks.
What you can do, however, is change a material in the materials array.
materials[ 0 ] = new THREE.MeshBasicMaterial();
You do not need to set any needsUpdate flags to true after doing so, either.
An alternate thing you can do is give each face it's own material from the start, and then, for example, just change a material's texture.
mesh.geometry.materials[ 0 ].map = texture;
texture.needsUpdate = true;

Related

Three.js - previous lines become invisible after cloning

I'm attempting to duplicate an array of lines, but when I do, the previous ones somehow become dark or invisible. The previous lines can still be accessed with all their properties and I tested them also having the correct location. I shift both sets of lines, and the previous ones are not visible. Does anyone know what the problem could be?
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var lines = []
currentIndex = 0;
addLines()
duplicateLines(0)
var lineColorGradientList = [
0x100FFF,
0x0F76FF,
0x0FE0FF,
0x0FFFB3,
0x0FFF4A,
0x3DFF0F,
0xA7FF0F,
0xFFED0F
]
function addLines(){
var linesArray = []
for(i=0; i<8; ++i){
var geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(0, 0, 2),
new THREE.Vector3(3, 0, 0));
var color = lineColorGradientList[i]
var material = new THREE.LineBasicMaterial({
color: color
});
var line = new THREE.Line( geometry, material );
line.geometry.verticesNeedUpdate = true;
line.material.needsUpdate = true
linesArray.push(line)
}
linesArray.forEach(function(line) {
line.frustumCulled = false;
scene.add(line);
});
lines.push(linesArray)
}
function duplicateLines(selectedIndex){
currentIndex += 1
var linesArray = []
for(i=0; i<8; ++i){
var line = lines[selectedIndex][i].clone()
line.geometry.verticesNeedUpdate = true;
line.material.needsUpdate = true
linesArray.push(line)
}
lines.push(linesArray)
lines[currentIndex].forEach(function(line) {
line.frustumCulled = false;
scene.add(line);
});
}
You also need to clone the geometry in order for it to work.
My corrected duplicateLinesFunction:
function duplicateLines(selectedIndex){
currentIndex += 1
var linesArray = []
for(i=0; i<8; ++i){
var line = lines[selectedIndex][i].clone()
line.geometry = lines[selectedIndex][i].geometry.clone()
line.geometry.verticesNeedUpdate = true;
line.material = lines[selectedIndex][i].material.clone()
line.material.needsUpdate = true
linesArray.push(line)
}
lines.push(linesArray)
lines[currentIndex].forEach(function(line) {
line.frustumCulled = false;
scene.add(line);
});
}

Animating Three.js vertices

I'm trying to animate individual vertices from a collada model.
The vertices ARE animating fine once but then they don't animate anymore.
1: Load my collada
// name obj
var orgVerts = false;
var desVerts = false;
var material = new THREE.MeshBasicMaterial({ color:0x1e5679, wireframe:true });
var loader = new THREE.ColladaLoader();
var nameModel = false;
loader.options.convertUpAxis = true;
loader.load( '3d/name.dae', function ( collada ) {
nameModel = collada.scene.children[0].children[0];
nameModel.material = material;
nameModel.geometry.dynamic = true;
nameModel.position.set(0,0,0);//x,z,y- if you think in blender dimensions ;)
nameModel.scale.x = .0035;
nameModel.scale.y = .0035;
nameModel.scale.z = .0035;
scene.add(nameModel);
orgVerts = nameModel.geometry.vertices; // make a backup of all verts
genVerts(); // create a new array of random verts
});
2: in my render function
var render = function () {
requestAnimationFrame(render);
// do stuff
if(nameModel){
if(window.globalCurrentSlide != 0){
for(var r=0; r < nameModel.geometry.vertices.length; r++){
var vert = desVerts[r]; // loop through all the destination verts
nameModel.geometry.vertices[r].x = nameModel.geometry.vertices[r].x - (nameModel.geometry.vertices[r].x - vert.x)/20;
nameModel.geometry.vertices[r].y = nameModel.geometry.vertices[r].y - (nameModel.geometry.vertices[r].y - vert.y)/20;
nameModel.geometry.vertices[r].z = nameModel.geometry.vertices[r].z - (nameModel.geometry.vertices[r].z - vert.z)/20;
}
}else{
for(var t=0; t < nameModel.geometry.vertices.length; t++){
var vert2 = orgVerts[t]; // loop through all the original verts
nameModel.geometry.vertices[t].x = nameModel.geometry.vertices[t].x - (nameModel.geometry.vertices[t].x - vert2.x)/20;
nameModel.geometry.vertices[t].y = nameModel.geometry.vertices[t].y - (nameModel.geometry.vertices[t].y - vert2.y)/20;
nameModel.geometry.vertices[t].z = nameModel.geometry.vertices[t].z - (nameModel.geometry.vertices[t].z - vert2.z)/20;
}
}
nameModel.geometry.verticesNeedUpdate = true;
nameModel.rotation.y += .005;
}
renderer.render( scene, camera );
}
window.globalCurrentSlide is set to 0 to start with and everything is fine. if I change window.globalCurrentSlide to 1, all the vertices animate correctly... BUT when I change window.globalCurrentSlide back to 0 the vertices don't animate back to their original positions. I've debugged heaps and can 100% say that BOTH desVerts and orgVerts don't change and they are correct. Any ideas? It's driving me nuts.
PS: I know the code could be condensed, I'm just playing ATM
The answer was that my orgVerts was just a reference NOT a clone. use:
var geometry = nameModel.geometry.clone();
orgVerts = geometry.vertices;

Texture mapping from one Face4 to two Face3 on Three.js

I am playing with Three.js. I am working on a project that uses an old version of Three.js. I'm trying to replace the old library with the new one (r71). Everything is going well except the texture mapping.
In the old project we use the Face4 which is deprecated and have been removed in the newest version of Three.js. So I have created two Face3 instead of just one Face4. Now the question is: how can I make one texture to cover both Face3 as they were like a single Face4?
Old pseudo-code using Face4
numberOfFaces = 10;
function createMyGeometry(){
var geometry = new THREE.Geometry();
...
for (var i = 0; i < numberOfFaces; i++) {
var face = new THREE.Face4(v1.index, v2.index, v3.index, v4.index, [v1.clone(), v2.clone(), v3.clone(), v4.clone()]);
face.centroid.add(v1).add(v2).add(v3).add(v4).divideScalar(4);
face.normal = face.centroid.clone().normalize();
face.materialIndex = matIdx;
geometry.faces.push(face);
geometry.faceVertexUvs[0].push([uv1.clone(), uv2.clone(), uv3.clone(), uv4.clone()]);
}
...
return geometry;
}
for (var i = 0; i < numberOfFaces; i++) {
var texture = THREE.ImageUtils.loadTexture("MyImage"+ i + '.jpg');
var material = new THREE.MeshBasicMaterial();
material.map = texture;
material.side = THREE.FrontSide;
materials.push(material);
}
materials = new THREE.MeshFaceMaterial(materials);
myGeometry = new THREE.Mesh(createMyGeometry(), materials);
scene.add(myGeometry);
Pseudo-code using Face3
numberOfFaces = 10;
function createMyGeometry(){
var geometry = new THREE.Geometry();
...
for (var i = 0; i < numberOfFaces; i++) {
var face1 = new THREE.Face3(v1.index, v2.index, v3.index, [v1.clone(), v2.clone(), v3.clone()]);
var face2 = new THREE.Face3(v1.index, v3.index, v4.index, [v1.clone(), v3.clone(), v4.clone()]);
face1.materialIndex = matIdx;
face2.materialIndex = matIdx;
geometry.faces.push(face1);
geometry.faces.push(face2);
geometry.faceVertexUvs[0].push([uv1.clone(), uv2.clone(), uv3.clone(), uv4.clone()]);
}
...
return geometry;
}
for (var i = 0; i < numberOfFaces; i++) {
var texture = THREE.ImageUtils.loadTexture("MyImage"+ i + '.jpg');
var material = new THREE.MeshBasicMaterial();
material.map = texture;
material.side = THREE.FrontSide;
materials.push(material);
}
materials = new THREE.MeshFaceMaterial(materials);
myGeometry = new THREE.Mesh(createMyGeometry(), materials);
scene.add(myGeometry);
You should just do the same thing with vertex uvs as with vertices.
For example:
geometry.faceVertexUvs[0].push([uv1.clone(), uv2.clone(), uv3.clone()]);
geometry.faceVertexUvs[0].push([uv1.clone(), uv3.clone(), uv4.clone()]);

BufferGeometry : Vertex Colors changed, but not updated visually

while using Three.js i met a problem connected with vertexes colors.
I created BufferGeometry , which consists of squares made by 2 triangles.
var geometry = new THREE.BufferGeometry();
// filling positions and colors
geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.addAttribute('color', new THREE.BufferAttribute(colors, 3));
var material = new THREE.MeshPhongMaterial(
{
side: THREE.OneSide, vertexColors: THREE.VertexColors
});
GridFloor = new THREE.Mesh(geometry, material);
GridFloor.rotation.x = Math.PI / 2;
GridFloor.geometry.dynamic = true;
GridFloor.geometry.__dirtyColors = true;
scene.add(GridFloor);
Everything works fine, until i change vertex colors. I am changing them , trying to update , but nothing happens...
var newColor = new THREE.Color(0xff0000);
var colors = GridFloor.geometry.attributes.color.array;
for (var i = 0, j = 0; i < 4; i++, j += 3) {
var index = INTERSECTED.indices[i % 3] * 3;
colors[index] = newColor.r;
colors[index + 1] = newColor.g;
colors[index + 2] = newColor.b;
}
GridFloor.geometry.colorsNeedUpdate = true;
INTERSECTED.colorsNeedUpdate = true;
Thank you for your help.
Here is how you set the needsUpdate flag for BufferGeometry.
bufferGeometry.attributes.attributeName.needsUpdate = true;
three.js r.68

three.js: texture on shapegeometry

I'm working with three.js and I have a plane shape. This shape should get a texture. Below you can see how I try this. The problem is, that the texture is only shown in two stripes at two edges of the shape. If I take higher values for texture.repeat this stripes get thinner.
I know there is a related topic here Three.JS Is it possible to render a texture on shapeGeometry?, but I can't understand how that could help me.
//Draw Floorshape
var points_floor = [];
points_floor.push(new THREE.Vector2(edges[edges.length-1][edges[3].length-1][0], edges[edges.length-1][edges[3].length-1][1]));
for (var i = 0; i < edges.length; i++) {
for (var j = 0; j < edges[i].length; j++) {
points_floor.push(new THREE.Vector2(edges[i][j][0], edges[i][j][1]));
}
}
var shape_floor = new THREE.Shape(points_floor);
var floorGeometry = new THREE.ShapeGeometry(shape_floor);
var texture = new THREE.ImageUtils.loadTexture("./img/tileable_wood_texture_by_ftIsis_Stock.jpg");
texture.repeat.set(0.1, 0.1);
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
var materialFloor = new THREE.MeshBasicMaterial({
map : texture,
side : THREE.DoubleSide
});
var floor = new THREE.Mesh(floorGeometry, materialFloor);
floor.overdraw = true;

Resources