How can i manipulate every object im creating? Three.js - javascript

Im creating a scene using three.js and im adding 3 spheres to it. Then im trying to switching all spheres created from wireframe to non-wireframe material. I not using scene.traverse() because i have more objects on my scene and i only want to switch the spheres, but with this code i can only switch one sphere. How can i get to every sphere? Any help? Thanks!
var numSpheres = 3;
function createSphere (x, y, z){
sphere = new THREE.Object3D();
material = new THREE.MeshBasicMaterial({ color: 0XFFA500, wireframe: true});
geometry = new THREE.SphereGeometry (2, 8, 8);
mesh = new THREE.Mesh(geometry, material);
sphere.add(mesh);
sphere.position.set(x, y, z);
scene.add(sphere);
}
createSpheres(numSpheres){
for(i = 1; i <= numSpheres; i++){
var randomnumber1 = Math.floor(Math.random() * (29.5 - -29.5 + 1)) + -29.5;
var randomnumber2 = Math.floor(Math.random() * (29.5 - -29.5 + 1)) + -29.5;
createSphere(randomnumber1, 3, randomnumber2);
}
}
function onKeyDown(e){
case 65:
case 97:
sphere.traverse(function (node){
if(node instanceof THREE.mesh) {
node.material.wireframe = !node.material.wireframe;
}
});

As #prisoner849 suggested, put your objects you want to manipulate in an array or map (as #prisoner849 suggested). This way, you avoid the test instanceof THREE.Mesh and you only manipulate the objects you want to manipulate.
var numSpheres = 3;
var spheresMap = {}; // OR
var spheresArray = [];
function createSphere (x, y, z){
var sphere = new THREE.Object3D();
material = new THREE.MeshBasicMaterial({ color: 0XFFA500, wireframe: true});
geometry = new THREE.SphereGeometry (2, 8, 8);
mesh = new THREE.Mesh(geometry, material);
sphere.add(mesh);
sphere.position.set(x, y, z);
scene.add(sphere);
spheresMap[sphere.id] = sphere; // OR
spheresArray.push(sphere);
}
createSpheres(numSpheres){
for(i = 1; i <= numSpheres; i++){
var randomnumber1 = Math.floor(Math.random() * (29.5 - -29.5 + 1)) + -29.5;
var randomnumber2 = Math.floor(Math.random() * (29.5 - -29.5 + 1)) + -29.5;
createSphere(randomnumber1, 3, randomnumber2);
}
}
function onKeyDown(e){
case 65:
case 97:
for (var key in spheresMap) {
spheresMap[key].material.wireframe = !spheresMap[key].material.wireframe;
}
// OR
for (var i=0; i<spheresArray.length; i++) {
spheresArray[i].material.wireframe = !spheresArray[i].material.wireframe;
}
}

If You can reach your spheres one by one in the future, most relative is array in object:
function createSphere (x, y, z){
var sphere= new THREE.Mesh(new THREE.SphereGeometry (2, 8, 8), new THREE.MeshBasicMaterial({ color: 0XFFA500, wireframe: true}));
scene.add(sphere);
sphere.position.set(x, y, z);
return sphere;
}
mySpheres = {};
mySpheres.models = [];
mySpheres.materials = [];
for(i = 1; i <= 3; i++){
var randomnumber1 = Math.floor(Math.random() * (29.5 - -29.5 + 1)) + -29.5;
var randomnumber2 = Math.floor(Math.random() * (29.5 - -29.5 + 1)) + -29.5;
var obj = createSphere(randomnumber1, 3, randomnumber2); //
var id = obj.id; // or whartever (redone,barrack,donald,george)
mySpheres.models[id] = obj;
mySpheres.materials.push(obj.material);
}
//after that you can do
mySpheres.models['donald'].translateX(10);
//or
mySpheres.models['george'].material.opacity = 0.5;
//or
mySpheres.materials.forEach(function(m) {
m.opacity = 0.5;
});

Related

How do I target children of a "for" loop which creates a mesh, outside of the loop

I'm trying to target every mesh created by one loop inside an another.
I have a loop inside another loop, a first that creates these spheres radially, inside another repeating these rows by incrementing the number of spheres each time the circle of sphere is growing.
I tried to increment a variable to have a continual number (1,2,3,4,5…) even if the loop start again, because the idea is to add each sound of my php array to each mesh that created, but I don't know if I need to do it inside the loop, or how to do it outside the loop?
var mathpi = Math.PI/180;
var startRadians = startAngle + mathpi;
var arraysamples = <?php echo json_encode($samples);?>;
var rangee = Math.round((Object.keys(arraysamples).length) / 5);
var incrementAngle = 360/totalson;
var incrementRadians = incrementAngle * mathpi;
var totalson = 5;
var yp = 30;
for ( var n = 0; n < rangee; n ++) {
for ( var i = 0; i < totalson; i ++ ) {
var object = new THREE.Mesh( sphere, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );
var xp = centerX + Math.sin(startRadians) * radius;
var zp = centerZ + Math.cos(startRadians) * radius;
object.position.z = xp;
object.position.x = zp;
object.position.y = yp;
nomsample ++;
scene.add( object );
startRadians += incrementRadians;
}
totalson = totalson + 3;
var nomsample = totalson + 2;
radius = radius + 100;
startAngle = startAngle + 150;
var startRadians = startAngle + mathpi;
var incrementAngle = 360/totalson;
var incrementRadians = incrementAngle * mathpi;
if (yp > 59) {
yp = yp - 30;
} else {
yp = yp + 30;
}
}
and the idea is to have something like :
for ( var i = 0; i < arraysamples.length ; i ++ ) {
var sound[i] = new THREE.PositionalAudio(listener);
audioLoader.load('sounds/'arraysamples[1]'', function (buffer) {
sound[i].setBuffer(buffer);
sound[i].setRefDistance(20);
sound[i].play();
sound[i].setLoop(true);
sound[i].setVolume(1);
});
object.add(sound[i]);
}
I just expect to add every sound of the array distribute to one mesh, with no several mesh with the same sound. I really hope I'm clear.
Thank you for taking time to read my problem and I apologize in advance if the problem seems simple.

How to detect what side of a cube is clicked

Right now, I am trying to make a navigational menu, but to do this, I need to detect what side is clicked by the user. Is there any way to do this with raycasting, or if not, any other way?
Here is my code if you need it:
CodePen Link
The short version is here
var geometry = new THREE.BoxGeometry(200, 200, 200);
var material = new THREE.MeshLambertMaterial(
{
color: 65535,
morphTargets: true
});
for (var i = 0; i < 8; i++)
{
var vertices = [];
for (var v = 0; v < geometry.vertices.length; v++)
{
vertices.push(geometry.vertices[v].clone());
if (v === i)
{
vertices[vertices.length - 1].x *= 2;
vertices[vertices.length - 1].y *= 2;
vertices[vertices.length - 1].z *= 2
}
}
geometry.morphTargets.push(
{
name: "target" + i,
vertices: vertices
})
}
mesh = new THREE.Mesh(geometry, material);
mesh.position.y = 0;
scene.add(mesh);
scene.background = new THREE.Color(15790320);
var params = {
influence1: 1,
influence2: 1,
influence3: 1,
influence4: 1,
influence5: 1,
influence6: 1,
influence7: 1,
influence8: 1
};
var geometry = new THREE.PlaneBufferGeometry(5e3, 5e3);
geometry.rotateX(-Math.PI / 2);
var material = new THREE.MeshBasicMaterial(
{
color: 975132,
overdraw: .5
});
onMouseDown(event) {
this.mouse.x = (event.pageX / window.innerWidth) * 2 - 1;
this.mouse.y = -(event.pageY / window.innerHeight) * 2 + 1;
this.raycaster.setFromCamera(this.mouse, this.camera);
let intersectCube = this.raycaster.intersectObjects( Cube , true );
}
Make a raycaster on your mouse and check for intersections with the Cube or its faces

Planes trimmed by mesh three.js

I have a mesh, which should represent a "building" and I want to add planes every 3 units (different floor levels) and trim them with the mesh faces, so they appear only inside the mesh.
How do I do that? I can't figure it out and the mesh is quite complex for me to define the plane to normally cover only the inside.
var program = new Program(reset, step)
function reset() {
scene.clear()
scene.add(new THREE.GridHelper(100, 1))
}
function step() {
}
program.startup()
// the points group
var spGroup;
// the mesh
var hullMesh;
generatePoints();
render();
function generatePoints() {
// add 10 random spheres
var points = [];
for (var i = 0; i < 50; i++) {
var x = Math.random() * (80 - 1) + 1 //Math.random() * (max - min) + min
var y = Math.random() * (80 - 1) + 1
var z = Math.random() * (80 - 1) + 1
points.push(new THREE.Vector3(x, y, z));
}
spGroup = new THREE.Object3D();
var material = new THREE.MeshBasicMaterial({
color: 0xff0000,
transparent: false
});
points.forEach(function(point) {
var spGeom = new THREE.SphereGeometry(0.5);
var spMesh = new THREE.Mesh(spGeom, material);
spMesh.position.copy(point);
spGroup.add(spMesh);
});
// add the points as a group to the scene
scene.add(spGroup);
// use the same points to create a convexgeometry
var hullGeometry = new THREE.ConvexGeometry(points);
hullMesh = createMesh(hullGeometry);
scene.add(hullMesh);
}
function createMesh(geom) {
// assign two materials
var meshMaterial = new THREE.MeshBasicMaterial({
color: 0x00ff00,
transparent: true,
opacity: 0.2
});
meshMaterial.side = THREE.DoubleSide;
var wireFrameMat = new THREE.MeshBasicMaterial();
wireFrameMat.wireframe = true;
// create a multimaterial
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial, wireFrameMat]);
return mesh;
}

Three.js render white part of plain geometry

I'm trying to turn this plainGeometry, into this (sort of mask).
This code works: (to sum-up, create two materials, divide the plane to segments and decide for each one which material is it with MeshFaceMaterial)
Button.onClick(function () {
var obj = editor.selected;
var material = obj.material;
var tex = material.map;
var objHeight = obj.geometry.parameters.height;
var objWidth = obj.geometry.parameters.width;
var texHeight = tex.image.height;
var texWidth = tex.image.width;
var geometry = new THREE.PlaneGeometry(objWidth, objHeight, objWidth, objHeight);
var facesNum = objHeight * objWidth * 2;
var facesX = objWidth * 2;
var facesInX = texWidth * 2;
var materials = [];
materials.push(material);
materials.push(new THREE.MeshBasicMaterial({ }));
for (var i = 0; i < facesNum; i++) {
if ((i % facesX >= objWidth - texWidth) &&
(i % facesX <= (facesInX + objWidth - texWidth - 1)) &&
(i <= (texHeight * objWidth * 2) - 1)) {
geometry.faces[i].materialIndex = 0;
}
else {
geometry.faces[i].materialIndex = 1;
}
}
obj.geometry = geometry;
obj.material = new THREE.MeshFaceMaterial(materials);
editor.signals.materialChanged.dispatch(obj);
});
But I'm wondering if there is a simpler way to go. Any suggestions?
Another way to do this is to use an alpha channel on your texture. You can do this with Gimp or Photoshop.
You then duplicate the mesh and push it just a tad out the axis with polygonOffsetFactor on the material. Apply the background material to the first mesh, and the foreground material with the texture with alpha to the second.
See this fiddle alphaTest. (you may need to disable cross-domain access security so the texture can load in this fiddle, chrome will allow this if you run it with the --disable-web-security flag)
The advantage to this method is that the image can be of any shape and location, and doesn't need to fit into a geometry face.
Another way, if the geometry you were using is complicated, is to use Three.DecalGeometry to cut a mesh piece out and use it shifted a bit with polygonOffsetFactor on the material. See the three.js decals example for this.
Source for the example fiddle is below:
var renderer;
var pointLight;
var scene;
var plane1;
var plane2;
function addPlane()
{
var material1 = new THREE.MeshPhongMaterial({ color: 0xFFFFFF });
var material2;
var loader = new THREE.TextureLoader();
loader.load('http://i.imgur.com/ETdl4De.png',
function ( texture ) {
var material2 = new THREE.MeshPhongMaterial({
color: 0xFFFFFF,
map: texture,
alphaTest: 0.7,
polygonOffset: true,
polygonOffsetFactor: - 4,
});
var geometry1 = new THREE.PlaneGeometry(12, 12, 12, 12);
var geometry2 = geometry1.clone();
plane1 = new THREE.Mesh(geometry1,material1);
plane2 = new THREE.Mesh(geometry2,material2);
scene.add(plane2);
scene.add(plane1);
}
);
}
(function() {
'use strict';
scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 10000);
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
addPlane();
camera.position.z = 52;
pointLight = new THREE.DirectionalLight(0xffffff,1);
pointLight.position.x = 11;
pointLight.position.y = 5;
pointLight.position.z = 25;
scene.add(pointLight);
var reqAnimFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame;
var render = function() {
reqAnimFrame(render);
renderer.render(scene, camera);
};
render();
}());
this did it, eventually:
var obj = editor.selected;
var tex = obj.material.map.;
var materials = [];
materials.push(new THREE.MeshBasicMaterial({ map: tex }));
materials.push(new THREE.MeshBasicMaterial({}));
var material = new THREE.MeshFaceMaterial(materials);
var objHeight = obj.geometry.parameters.height;
var objWidth = obj.geometry.parameters.width;
var texHeight = tex.image.height;
var texWidth = tex.image.width;
tex.repeat = new THREE.Vector2(3, 3);
tex.offset = new THREE.Vector2(0, 0);
var geometry = new THREE.PlaneGeometry(objWidth, objHeight, 3, 3);
var v = geometry.vertices;
var facesNum = geometry.faces.length;
v[1] = new THREE.Vector3(-texWidth / 2, objHeight / 2, 0);
v[2] = new THREE.Vector3(texWidth / 2, objHeight / 2, 0);
v[5] = new THREE.Vector3(-texWidth / 2, (objHeight / 2) - texHeight, 0);
v[6] = new THREE.Vector3(texWidth / 2, (objHeight / 2) - texHeight, 0);
v[9] = v[13];
v[10] = v[14];
v[4] = v[8] = v[12];
v[7] = v[11] = v[15];
for (var i = 0; i < facesNum; i++) {
if (i !== 2 && i !== 3) geometry.faces[i].materialIndex = 1;
}
obj.material = material;
obj.geometry = geometry;
editor.signals.materialChanged.dispatch(obj);

three.js r74 BufferGeometry Sphere Instead of Squares

I have the following code:
var geometry = new THREE.BufferGeometry(4, 4, 4);
var length = parsedData.length;
var positions = new Float32Array(length * 3);
var colors = new Float32Array(length * 3);
var color = new THREE.Color();
var i = 0;
for (i; i < length * 3; i += 3) {
var index = Math.floor(i / 3);
positions[i] = parsedData[index].vector.x;
positions[i + 1] = parsedData[index].vector.y;
positions[i + 2] = parsedData[index].vector.z;
color.setHex(parsedData[index].color);
colors[i] = color.r;
colors[i + 1] = color.g;
colors[i + 2] = color.b;
}
geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.addAttribute('color', new THREE.BufferAttribute(colors, 3));
var material = new THREE.PointsMaterial({vertexColors: THREE.VertexColors});
var particleSystem = new THREE.Points(geometry, material);
scene.add(particleSystem);
render();
Which will render cubes quickly and fine, but I need spheres. Could anyone explain to me how that works with Revision 74? I have found this question, however it isn't working anymore.
Thanks!

Categories

Resources