Suppose I have 10 objects and I want for each object to be given a texture picked for me randomly out of a pool of 10 textures. How do I go about that for this mesh object?
for(var int = 0; int <= 10 ; int++)
{ var loader = new THREE.TextureLoader();
var testMat = new THREE.MeshPhongMaterial({ map: loader.load('images/image1') });
var testGeo = new THREE.SphereGeometry(50, 50, 50);
testSphere = new THREE.Mesh(testGeo, testMat);
testSphere.position.set(distance, 100, 100);
scene.add(testSphere); }
Assuming all of your texture-images are named in a numeric/sequential manner, you could do:
...
var testMat = new THREE.MeshPhongMaterial({ map: loader.load('images/image' + THREE.Math.randInt(1, 10) ) });
...
If not, then you'd make a list of filenames in a manner similar to this, and choose a random value from the list:
var texturesList = [
'images/image1',
'images/some-other-image',
'images/yet-another-image',
...
'images/10th-image'
];
...
...
var randIndex = THREE.Math.randInt(0, texturesList.length - 1);
var randTexture = loader.load(texturesList[randIndex]);
var testMat = new THREE.MeshPhongMaterial({ map: randTexture });
...
Related
I'm looking for a way to store and reload the decals that produced in This example ( source-code), so when a user "paints" a new splatter - he could save it and later on - reloads it.
I've tried many ways but unfortunately none of them seems to work.
My approach was to save the position, rotation and scale and then build them like this :
function loadLeePerrySmith(callback) {
var loader = new THREE.JSONLoader();
loader.load('assets/LeePerrySmith.js', function (geometry) {
geometry.verticesNeedUpdate = true;
geometry.elementsNeedUpdate = true;
geometry.morphTargetsNeedUpdate = true;
geometry.uvsNeedUpdate = true;
geometry.normalsNeedUpdate = true;
geometry.colorsNeedUpdate = true;
geometry.tangentsNeedUpdate = true;
var material = new THREE.MeshPhongMaterial({
map: THREE.ImageUtils.loadTexture('assets/Map-COL.jpg'),
specularMap: THREE.ImageUtils.loadTexture('assets/Map-SPEC.jpg'),
normalMap: THREE.ImageUtils.loadTexture('assets/Map-NOR.jpg'),
shininess: 10
});
mesh = new THREE.Mesh(geometry, material);
// ALL FOLLOWING VECTORS SHOULD COME FROM D.B
var pos = new THREE.Vector3(0.18564199509178245, 23.11243036463454, 21.79273328636014);
var rot = new THREE.Vector3(-0.24357513937426453, -0.07708039421506024, 4.358263365975027);
var some = new THREE.Vector3(20.694949486021706, 20.694949486021706, 20.694949486021706);
var check = new THREE.Vector3(1, 1, 1);
var m = new THREE.Mesh(new THREE.DecalGeometry(mesh, pos, rot, some, check), decalMaterial);
scene.add(mesh);
decals.push(m);
scene.add(m);
mesh.scale.set(10, 10, 10);
});
}
Adding a simple timeOut did the trick
setTimeout(function(){
let m = new THREE.Mesh(new DecalGeometry(mesh, pos, rot,
size), decalMateria2);
decals.push(m);
scene.add(m);
},100)
I want to create a simple app in three.js
For this app, I need to subtract two meshes and I have found that ThreeCSG can do this. But somehow I don't get the expected result.
I have copied the code from an example, but even this doesn't work properly.
Trying some other function like the union. But instead of merging two meshes into one it removes it.
link to ThreeCSG: https://github.com/chandlerprall/ThreeCSG/blob/master/ThreeCSG.js
result that I get when subtracting
result that I get when I use union
var materialNormal = new THREE.MeshNormalMaterial( { side: THREE.DoubleSide } );
var diceCube = new THREE.Mesh( new THREE.BoxGeometry(10,10,10), materialNormal);
diceCube.position.x = 0;
diceCube.position.y = 5;
diceCube.position.z = 0;
diceCube.geometry.computeFaceNormals();
diceCube.geometry.computeVertexNormals();
var cubeBSP = new ThreeBSP(diceCube);
var sphereGeometry = new THREE.SphereGeometry(7.5,16,8);
var sphereMesh = new THREE.Mesh(sphereGeometry, materialNormal);
sphereMesh.scale.x = 0.17;
sphereMesh.scale.y = 0.17;
sphereMesh.scale.z = 0.17;
//coords of the spheres
var xPositions = [ 0, 3 ]; // coordinates for xPositions of sphereMesh
var yPositions = [ 10, 10 ];
var zPositions = [ 0, 0 ];
var diceDots = new THREE.Geometry();
for(var i = 0; i < xPositions.length; i++){
sphereMesh.position.x = xPositions[i];
sphereMesh.position.y = yPositions[i];
sphereMesh.position.z = zPositions[i];
sphereMesh.updateMatrix();
diceDots.merge( sphereMesh.geometry, sphereMesh.matrix );
}
var material = new THREE.MeshPhongMaterial( { color: 0xffaa00 });
var dotsMesh = new THREE.Mesh(diceDots);
dotsMesh.geometry.computeFaceNormals();
dotsMesh.geometry.computeVertexNormals();
var dotsBSP = new ThreeBSP(dotsMesh);
var resultBSP = cubeBSP.subtract(dotsBSP);
result = resultBSP.toMesh(material);
scene.add(result);
I have found a solution.
The threeCSG I used was corrupted this one works exactly how it must be done.
Link to working ThreeCSG: https://github.com/oathihs/ThreeCSG/blob/master/dist/THREE.CSG.js
I've got a sprite and i'm trying to make the texture repeat over and over.
I think I have the right settings but it doesn't seem to be doing what I expect, am I doing something wrong?
Here's my result:
And this is my code:
var bgTexture = new THREE.TextureLoader().load('/bg.png');
var spriteMaterial = new THREE.SpriteMaterial({ map: bgTexture });
spriteMaterial.wrapS = spriteMaterial.wrapT = THREE.RepeatWrapping;
spriteMaterial.map.offset.set( 0, 0 );
spriteMaterial.map.repeat.set( 10, 1 );
var sprite = new THREE.Sprite(spriteMaterial);
sprite.position.y = 0;
sprite.position.y = 0;
sprite.scale.x = 10;
sprite.scale.y = 1;
this.scene.add(sprite);
The properties .wrapS and .wrapT have to be set to the Texture rather than the SpriteMaterial:
spriteMaterial.wrapS = spriteMaterial.wrapT = THREE.RepeatWrapping;
spriteMaterial.map.wrapS = spriteMaterial.map.wrapT = THREE.RepeatWrapping;
I want to create a Pine using 2 meshes, 1 for the trunk and another one for the bush, this what I've done:
var pine_geometry = new THREE.Geometry();
var pine_texture_1 = THREE.ImageUtils.loadTexture('./res/textures/4.jpg');
var pine_geometry_1 = new THREE.CylinderGeometry(25, 25, 50, 6);
var pine_material_1 = new THREE.MeshBasicMaterial({
map : pine_texture_1
});
var pine_1 = new THREE.Mesh(pine_geometry_1);
pine_1.position.x = x;
pine_1.position.y = y + 25;
pine_1.position.z = z;
pine_1.updateMatrix();
pine_geometry.merge(pine_1.geometry, pine_1.matrix);
var pine_texture_2 = THREE.ImageUtils.loadTexture('./res/textures/5.jpg');
var pine_geometry_2 = new THREE.CylinderGeometry(0, 70, 250, 8);
var pine_material_2 = new THREE.MeshBasicMaterial({
map : pine_texture_2
});
var pine_2 = new THREE.Mesh(pine_geometry_2);
pine_2.position.x = x;
pine_2.position.y = y + 175;
pine_2.position.z = z;
pine_2.updateMatrix();
pine_geometry.merge(pine_2.geometry, pine_2.matrix);
var pine = new THREE.Mesh(pine_geometry, new THREE.MeshFaceMaterial([pine_material_1, pine_material_2]));
pine.geometry.computeFaceNormals();
pine.geometry.computeVertexNormals();
Game.scene.add(pine);
The Pine is correctly positioned as I want, however, the whole merged shape only uses 1 material instead of the 2 (the whole shape is covered by the 1st) and I want that each mesh has it's respective material when mergin both.
What I'm doing wrong? any idea?
After a long research I discovered that I was missing an extra parameter for the method 'merge' from the Geometry object, the last parameter is the index of the material that the mesh must have from the materials array, ex: 0 -> first material in 'materials' array... and so on.
So, my final piece of code looks like:
pine_geometry.merge(pine_1.geometry, pine_1.matrix, 0);
var pine_texture_2 = THREE.ImageUtils.loadTexture('./res/textures/5.jpg');
var pine_geometry_2 = new THREE.CylinderGeometry(0, 70, 250, 8);
var pine_material_2 = new THREE.MeshBasicMaterial({
map : pine_texture_2
});
var pine_2 = new THREE.Mesh(pine_geometry_2);
pine_2.position.x = x;
pine_2.position.y = y + 175;
pine_2.position.z = z;
pine_2.updateMatrix();
pine_geometry.merge(pine_2.geometry, pine_2.matrix, 1);
(Note the last numbers I add to each merge).
However, I want to clarify that this practice only works when we are dealing with various geometries that are from the same type, in this case, we're merging two CylinderGeometry, but if we wanted to merge for example a Cylinder with a Box AND add the MeshFaceMaterial, it wouldn't be recognized properly and the console will throw us 'Cannot read property map/attributes from undefined', nevertheless we can still merge both geometries but not providing multiple materials (that's a terrible mistake I made).
Hope this helps to anyone.
Here's a general function to merge meshes with materials, You can also specify if you want it to return it as a buffer geometry.
function _mergeMeshes(meshes, toBufferGeometry) {
var finalGeometry,
materials = [],
mergedGeometry = new THREE.Geometry(),
mergeMaterial,
mergedMesh;
meshes.forEach(function(mesh, index) {
mesh.updateMatrix();
mesh.geometry.faces.forEach(function(face) {face.materialIndex = 0;});
mergedGeometry.merge(mesh.geometry, mesh.matrix, index);
materials.push(mesh.material);
});
mergedGeometry.groupsNeedUpdate = true;
mergeMaterial = new THREE.MeshFaceMaterial(materials);
if (toBufferGeometry) {
finalGeometry = new THREE.BufferGeometry().fromGeometry(mergedGeometry);
} else {
finalGeometry = mergedGeometry;
}
mergedMesh = new THREE.Mesh(finalGeometry, mergeMaterial);
mergedMesh.geometry.computeFaceNormals();
mergedMesh.geometry.computeVertexNormals();
return mergedMesh;
}
var mergedMesh = _mergeMeshes([trunkMesh, treeTopMesh], true);
Three js ver67
Current code something like this -
var materials = [];
var totalGeom = new THREE.Geometry();
var cubeMat;
for (var i = 0; i < dataSetArray.length; i++) {
var ptColor = dataSetArray[i].color;
var value = dataSetArray[i].value;
var position = latLongToVector3(dataSetArray[i].y, dataSetArray[i].x, 600, 1);
var cubeGeom = new THREE.BoxGeometry(5, 5, 1 + value / 20);
cubeMat = new THREE.MeshLambertMaterial({
color: new THREE.Color(ptColor),
opacity: 0.6
});
materials.push(cubeMat);
// cubeGeom.updateMatrix();
var cubeMesh = new THREE.Mesh(cubeGeom, cubeMat);
cubeMesh.position = position;
cubeMesh.lookAt(scene.position);
// totalGeom.merge(cubeMesh.geometry, cubeMesh.geometry.matrix);
//THREE.GeometryUtils.setMaterialIndex(cubeMesh.geometry, i);
THREE.GeometryUtils.merge(totalGeom, cubeMesh);
}
var total = new THREE.Mesh(totalGeom, new THREE.MeshFaceMaterial(materials));
scene.add(total);
However I get the message
DEPRECATED: GeometryUtils's .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.
in chrome dev tools.
When I try something like -
totalGeom.merge(cubeMesh.geometry, cubeMesh.geometry.matrix);
instead of THREE.GeometryUtils.merge(totalGeom, cubeMesh); I get exceptions.
How will I do the above merge? Please help.
Note: This answer applies to legacy versions of three.js.
Do this:
cubeMesh.updateMatrix();
totalGeom.merge( cubeMesh.geometry, cubeMesh.matrix );
For a further understanding, see the source code of THREE.Geometry.merge().
three.js r.69