Unity3D: Simultaneous Mesh update - unity3d

I'm facing a problem regarding the update of several meshes materials.
I'm developing a projection mapping app, currently I have 3 planes on my surface, each has 4 points that define their position in space (each point, named DestinationPoint is located at the edge of the plane's corners representing the mesh). By moving (manually, using the OnMouseDown() and OnMouseDrag() functions) each point, the mesh is updated accordingly so that each corner follows each of the point (the goal is matches a real world surface.)
So that I don't have to do this calibration each time, I'm saving the values (local position property) of these 12 points (3 planes * 4 points) in a XML file. The saving/loading process of the XML file is working just fine, all points are automatically moved to the positions previously saved in the XML file. The problem arises when Unity updates each mesh material, it is only updating ONE mesh.
For example, this is the saved scene, saved into a XML file, with 3 planes, each having 4 points represented by the white spheres.
This is the scene loaded from the XML file. The points are moved into the proper position, yet the mesh isn't updated.
The function that loads the XML file is the following:
void LoadScenario(){
filePath = Application.dataPath + "/XmlData/"+scenario+".xml";
XmlReader reader = XmlReader.Create(filePath);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
XmlNodeList Surfaces = xmlDoc.GetElementsByTagName("Surfaces");
/* XML file structure
*
* <Surfaces>
<ProjectionSurface1>
<DestinationPoints>
<DP0>
<Position>-8.28037,18.33852,10.06745</Position>
</DP0>
<DP1>
<Position>-31.55436,-3.485761,3.270439</Position>
</DP1>
<DP2>
<Position>38.00045,-1.380948,4.482903</Position>
</DP2>
<DP3>
<Position>30.65092,19.90506,10.96985</Position>
</DP3>
</DestinationPoints>
</ProjectionSurface1>
</Surfaces>
*/
for(int surface = 0; surface < Surfaces.Count; surface++){
// There is only 1 type of Surface, so only 1 node for now...
XmlNode NodeSurface = Surfaces.Item(surface);
// Get List of Projection Surfaces
XmlNodeList allProjSurfaces = NodeSurface.ChildNodes;
//Debug.Log("Number of Proj Surfaces = " + allProjSurfaces.Count);
for(int projSurf = 0 ; projSurf < allProjSurfaces.Count; projSurf++){
XmlNode nodeProjSurface = allProjSurfaces.Item(projSurf);
string activeProjSurfStr = nodeProjSurface.Name;
//Debug.Log("Projection Surface: " + nodeProjSurface.Name);
// Get the DestinationPoints node
XmlNode nodeDestPoints = nodeProjSurface.FirstChild;
// Get all DPs node list
XmlNodeList allDPs = nodeDestPoints.ChildNodes;
for(int dp = 0; dp < allDPs.Count; dp++){
XmlNode nodeDP = allDPs.Item(dp);
XmlNode nodePos = nodeDP.FirstChild;
string dpStr = nodeDP.Name;
Debug.Log("dpStr: " + dpStr);
string[] split_position = nodePos.InnerText.Split(',');
/*Debug.Log("ProjectionSurface : " + nodeProjSurface.Name +
" with " + nodeDP.Name +
" ,with PosX: " + float.Parse(split_position[0]) +
" ,with PosY: " + float.Parse(split_position[1]) +
" ,with PosZ: " + float.Parse(split_position[2]));*/
float xmlXPos = float.Parse(split_position[0]);
float xmlYPos = float.Parse(split_position[1]);
float xmlZPos = float.Parse(split_position[2]);
Vector3 xmlPosVec = new Vector3(xmlXPos, xmlYPos, xmlZPos);
List <GameObject> dpList = sleManager.listOfDestPoints;
int multiplier = destControl.ReturnModifier(projSurf+1);
dpList[dp+multiplier].transform.localPosition = xmlPosVec;
GameObject dpActiveObj = dpList[dp+multiplier].gameObject;
}
}
}
reader.Close();
// Test to force an update to all 3 projection surfaces meshes
GameObject dp0 = sleManager.listOfDestPoints[0];
GameObject dp4 = sleManager.listOfDestPoints[4];
GameObject dp8 = sleManager.listOfDestPoints[8];
destControl.Run(dp0);
Debug.Log("0");
destControl.Run(dp4);
destControl.Run(dp8);
}
}
The function Run(GameObj obj) that I'm using in the end has the main goal of updating the material properties of obj in the argument and is as follows:
public void Run(GameObject dpObj){
Debug.Log("Run com arg obj name: " + dpObj.gameObject.name);
manager.indexChanged = true;
string activeDPStr = dpObj.name;
string activeProjSurfStr = dpObj.transform.root.ToString();
manager.activeProjSurfObj = ReturnActiveProjSurf(dpObj);
manager.activePlaneObj = ReturnActivePlaneObj(manager.activeProjSurfObj);
string activePlaneStr = manager.activePlaneObj.name;
manager.activeProjSurf = int.Parse(activeProjSurfStr[17].ToString());
manager.modifier = ReturnModifier(manager.activeProjSurf);
manager.activeIndex = int.Parse(activeDPStr[2].ToString()) + manager.modifier;
manager.meshMaterial = manager.activePlaneObj.renderer.material;
}
The list "listOfDestPoints" contains all existing destination points. Keep in mind each plane has 4 points, so every 4 members in the list, the target plane changes.
Now, if I try to run do:
destControl.Run(dp0); // Updates Plane 1, works just fine.
But if I try:
destControl.Run(dp0);
destControl.Run(dp4); // Does not update Plane 1, only Plane 2.
p.s: Sorry about the wall of text!

Just solved it with:
yield return new WaitForSeconds(.25f);
Inside the LoadScenario() function. Seems For cycle was faster than the update function so only the last member of the For cycle was truly updated.

Related

Macro for multiple images analysis in the calculator plus

I have a set of images in a folder which their names are: 2 days.bmp 3 days.bmp ..... 28 days.bmp. Also, I have a folder with the background images exactly with the same names. I want to use the calculator plus and divide each image to its relevant background. I want to save time and do that at the same time instead of doing it for each image one by one. Is there any idea how can I do that? I have written a macro but it didn't work for me.
macro "Batch calculate images [1]" {
LocationOfFiles = getDirectory("Select Folder");
LocationOfbackgrounds = getDirectory("Select Folder of backgrounds");
LocationOfSave = getDirectory("Select Save Location");
setBatchMode(true);
FileList = getFileList(LocationOfFiles);
NumberOfFiles = FileList.length;
for (i=0; i<NumberOfFiles; i+=1) {
FileName = FileList[i];
pathtofile1 = LocationOfFiles+FileName;
open(pathtofile1);
name1 = getTitle();
pathtofile2 = LocationOfbackgrounds+FileName;
open(pathtofile2);
name2 = getTitle();
run("Calculator Plus", "i1="+name1+" i2="+name2+" operation=[Divide: i2 = (i1/i2) x k1 + k2] k1=255 k2=0 create");
selectWindow("Result");
SaveName = replace(name, ".bmp", "_backgroud subtracted.jpg");
saveAs("BMP", LocationOfSave+SaveName);
selectWindow(BackgroundImage);
close("\\Others");

How to set specific angle between 2 game objects in unity

SCENARIO
I am creating an app where I have to show chemical bonding between atoms(which are game objects). I am using Leap motion hands for spawning and making atoms collide to form molecules. Now the bond between atoms are made using cylinder game objects.
Also when bond(cylinder) is spawned correctly it is joined to atoms' game objects using fixed joints.
All these things are working correctly and as intended.
PROBLEM:
As one atom can form bond with multiple atoms so I want to maintain a certain angle between each bonded atoms.(for eg. in chemistry CH4 molecule's atoms are separated by around 105 degrees).
So I want to achieve the same effect in my app too by separating each atom in molecule by certain angle.
What I currently have only create molecule properly but doesn't have anything to separate according to angle.
This is what I am doing currently.
private IEnumerator SetAtomPosition(Transform atomOne, Transform atomTwo, Transform cylinder)
{
cylinder.gameObject.GetComponent<Rigidbody>().isKinematic = true;
while (Vector3.Distance(atomOne.position, atomTwo.position) > atomDistance)
{
atomTwo.position = Vector3.MoveTowards(atomTwo.position, atomOne.position, Time.deltaTime * 0.1f);
yield return 0;
}
while (Vector3.Distance(atomOne.position, atomTwo.position) < atomDistance)
{
atomTwo.position = Vector3.MoveTowards(atomTwo.position, -atomTwo.forward * 1000f, Time.deltaTime * 0.1f);
yield return 0;
}
cylinder.transform.position = (atomTwo.position - atomOne.position) / 2.0f + atomOne.position;
cylinder.transform.rotation = Quaternion.FromToRotation(Vector3.up, atomTwo.position - atomOne.position);
#region JoinAtoms
cylinder.gameObject.AddComponent<FixedJoint>();
cylinder.gameObject.AddComponent<FixedJoint>();
var cylinderJoints = cylinder.GetComponents<FixedJoint>();
cylinderJoints[0].connectedBody = atomOne.GetComponent<Rigidbody>();
atomOne.GetComponent<Atom>().joint = cylinderJoints[0];
//cylinderJoints[0].breakForce = breakForce;
cylinderJoints[1].connectedBody = atomTwo.GetComponent<Rigidbody>();
atomTwo.GetComponent<Atom>().joint = cylinderJoints[1];
KinematicToggle(cylinder.gameObject);
cylinder.GetComponent<Rigidbody>().mass = 10f;
#endregion
yield return null;
}
And this is what it looks like currently
I want those 4 white spheres to be aligned around black sphere(Carbon atom).
What I want is something similar to this image.

Sand 3D Printer Slicing Issue

For my doctoral thesis I am building a 3D printer based loosely off of one from the University of Twente:
http://pwdr.github.io/
So far, everything has gone relatively smoothly. The hardware part took longer than expected, but the electronics frighten me a little bit. I can sucessfully jog all the motors and, mechanically, everything does what is supposed to do.
However, now that I am working on the software side, I am getting headaches.
The Pwder people wrote a code that uses Processing to take an .STL file and slice it into layers. Upon running the code, a Processing GUI opens where I can load a model. The model loads fine (I'm using the Utah Teapot) and shows that it will take 149 layers.
Upon hitting "convert" the program is supposed to take the .STL file and slice it into layers, followed by writing a text file that I can then upload to an SD card. The printer will then print directly from the SD card.
However, when I hit "convert" I get an "Array Index Out of Bounds" error. I'm not quite sure what this means.. can anyone enlighten me?
The code can be found below, along with a picture of the error.
Thank you.
// Convert the graphical output of the sliced STL into a printable binary format.
// The bytes are read by the Arduino firmware
PrintWriter output, outputUpper;
int loc;
int LTR = 0;
int lowernozzles = 8;
int uppernozzles = 4;
int nozzles = lowernozzles+uppernozzles;
int printXcoordinate = 120+280; // Left margin 120
int printYcoordinate = 30+190; // Top margin 30
int printWidth = 120; // Total image width 650
int printHeight = 120; // Total image height 480
int layer_size = printWidth * printHeight/nozzles * 2;
void convertModel() {
// Create config file for the printer, trailing comma for convenience
output = createWriter("PWDR/PWDRCONF.TXT"); output.print(printWidth+","+printHeight/nozzles+","+maxSlices+","+inkSaturation+ ",");
output.flush();
output.close();
int index = 0;
byte[] print_data = new byte[layer_size * 2];
// Steps of 12 nozzles in Y direction
for (int y = printYcoordinate; y < printYcoordinate+printHeight; y=y+nozzles ) {
// Set a variable to know wheter we're moving LTR of RTL
LTR++;
// Step in X direction
for (int x = 0; x < printWidth; x++) {
// Clear the temp strings
String[] LowerStr = {""};
String LowerStr2 = "";
String[] UpperStr = {""};
String UpperStr2 = "";
// For every step in Y direction, sample the 12 nozzles
for ( int i=0; i<nozzles; i++) {
// Calculate the location in the pixel array, use total window width!
// Use the LTR to determine the direction
if (LTR % 2 == 1){
loc = printXcoordinate + printWidth - x + (y+i) * width;
} else {
loc = printXcoordinate + x + (y+i) * width;
}
if (brightness(pixels[loc]) < 100) {
// Write a zero when the pixel is white (or should be white, as the preview is inverted)
if (i<uppernozzles) {
UpperStr = append(UpperStr, "0");
} else {
LowerStr = append(LowerStr, "0");
}
} else {
// Write a one when the pixel is black
if (i<uppernozzles) {
UpperStr = append(UpperStr, "1");
} else {
LowerStr = append(LowerStr, "1");
}
}
}
LowerStr2 = join(LowerStr, "");
print_data[index] = byte(unbinary(LowerStr2));
index++;
UpperStr2 = join(UpperStr, "");
print_data[index] = byte(unbinary(UpperStr2));
index++;
}
}
if (sliceNumber >= 1 && sliceNumber < 10){
String DEST_FILE = "PWDR/PWDR000"+sliceNumber+".DAT";
File dataFile = sketchFile(DEST_FILE);
if (dataFile.exists()){
dataFile.delete();
}
saveBytes(DEST_FILE, print_data); // Savebytes directly causes bug under Windows
} else if (sliceNumber >= 10 && sliceNumber < 100){
String DEST_FILE = "PWDR/PWDR00"+sliceNumber+".DAT";
File dataFile = sketchFile(DEST_FILE);
if (dataFile.exists()){
dataFile.delete();
}
saveBytes(DEST_FILE, print_data); // Savebytes directly causes bug under Windows
} else if (sliceNumber >= 100 && sliceNumber < 1000){
String DEST_FILE = "PWDR/PWDR0"+sliceNumber+".DAT";
File dataFile = sketchFile(DEST_FILE);
if (dataFile.exists()){
dataFile.delete();
}
saveBytes(DEST_FILE, print_data); // Savebytes directly causes bug under Windows
} else if (sliceNumber >= 1000) {
String DEST_FILE = "PWDR/PWDR"+sliceNumber+".DAT";
File dataFile = sketchFile(DEST_FILE);
if (dataFile.exists()){
dataFile.delete();
}
saveBytes(DEST_FILE, print_data); // Savebytes directly causes bug under Windows
}
sliceNumber++;
println(sliceNumber);
}
What's happening is that print_data is smaller than index. (For example, if index is 123, but print_data only has 122 elements.)
Size of print_data is layer_size * 2 or printWidth * printHeight/nozzles * 4 or 4800
Max size of index is printHeight/nozzles * 2 * printWidth or 20*120 or 2400.
This seems alright, so I probably missed something, and it appears to be placing data in element 4800, which is weird. I suggest a bunch of print statements to get the size of print_data and the index.

Merging geometries using a WebWorker?

Anyone know if it's possible to merge a set of cube geometries in a web worker and pass it back to the main thread? Was thinking this could reduce the lag when merging large amounts of cubes.
Does Three.JS work okay in a web worker, and if it does, would it be possible (and faster) to do this? Not sure if passing the geometry back would take just as long as merging it normally.
At the moment I'm using a timed for loop to reduce the lag:
// This array is populated by the server and contains the chunk position and data (which I do nothing with yet).
var sectionData = data.secData;
var section = 0;
var tick = function() {
var start = new Date().getTime();
for (; section < sectionData.length && (new Date().getTime()) - start < 1; section++) {
var sectionXPos = sectionData[section][0] * 10;
var sectionZPos = sectionData[section][1] * 10;
var combinedGeometry = new THREE.Geometry();
for (var layer = 0; layer < 1; layer++) { // Only 1 layer because of the lag...
for (var x = 0; x < 10; x++) {
for (var z = 0; z < 10; z++) {
blockMesh.position.set(x-4.5, layer-.5, z-4.5);
blockMesh.updateMatrix();
THREE.GeometryUtils.merge(combinedGeometry, blockMesh);
}
}
}
var sectionMesh = new THREE.Mesh(combinedGeometry, grassBlockMat);
sectionMesh.position.set(sectionXPos, 0, sectionZPos);
sectionMesh.matrixAutoUpdate = false;
sectionMesh.updateMatrix();
scene.add(sectionMesh);
}
if (section < sectionData.length) {
setTimeout(tick, 25);
}
};
setTimeout(tick, 25);
Using Three.JS rev59-dev.
Merged cubes make up the terrain in chunks, and at the moment (due to the lag) each chunk only has 1 layer.
Any tips would be appreciated! Thanks.
THREE.JS will not work in a web worker, however you can copy those parts of the library that you need to work both in the main thread and in your web worker.
Your first problem will be that you cannot send the geometry object itself back to the main thread.
Since the web worker onmessage variable passing works only by sending copies of JSON (not javascript objects) or references to ArrayBuffers, you would have to decode the geometry down to each float, pack it in an ArrayBuffer, and send a reference back to the main thread.
Note those are called transferable objects and once sent, they are cleared in the webworker / main thread from which they came.
See here for more details:
http://www.html5rocks.com/en/tutorials/workers/basics/
https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers
Here is an example of packing position vertices into an array for a physics type system:
//length * 3 axes * 4 bytes per vertex
var posBuffer = new Float32Array(new ArrayBuffer(len * 3 * 4));
//in a loop
//... do hard work
posBuffer[i * 3] = pos.x; //pos is a threejs vector
posBuffer[i * 3 + 1] = pos.y;
posBuffer[i * 3 + 2] = pos.z;
//after loop send buffer to main thread
self.postMessage({posBuffer:posBuffer}, [posBuffer.buffer]);
I copied the THREE.JS vector class inside my web worker and cut out all the methods I didn't need to keep it nice and lean.
FYI it's not slow and for something like n-body collisions it works well.
The main thread sends a command to the web worker telling it to run the update and then listens for the response. Kind of like a producer consumer model in regular threading.

Particle ID and retrieving multiple IDs in Three.js

I am trying to create particles with three.js, currently as a particle system.
The goal of the project is to create particles, with defined positions and unique IDs, and add an option to select multiple particles and retrieve their IDs.
I did some research, but found only ways to detect the position of a mouse-click.
So, I'm looking for the following information:
First: Is there an option to assign IDs to single particles (as simple as a number)?
Second: Is there a way to select multiple particles and view their IDs in a (popup) window?
Thanks for your Help!
PS: I found, that you can assign IDs to THREE.ParticleDOMMaterial (I don't know, what this function does!?) and THREE.ParticleBasicMaterial (Assign an ID to the material, but not to the particle itself).
All Object3D instances have a unique id in three.js by default and Particle inherits that. Also Object3D has a name property, if that helps.
Here's a little snippet which illustrates naming particles:
for ( var i = 0; i < 100; i++ ) {
particle = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: Math.random() * 0x808008 + 0x808080, program: program } ) );
particle.name = "particle"+i;
particle.position.x = Math.random() * 2000 - 1000;
particle.position.y = Math.random() * 2000 - 1000;
particle.position.z = Math.random() * 2000 - 1000;
particle.scale.x = particle.scale.y = Math.random() * 10 + 5;
group.add( particle );
}
and here's an example of a mouse down event handler which prints the name and id of the clicked particle in the console:
function onDocumentMouseDown( event ) {
event.preventDefault();
var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
var intersects = ray.intersectScene( scene );
if ( intersects.length > 0 ) {
console.log("you clicked particle named '" + intersects[0].object.name + "' with id: " + intersects[0].object.id);
}
}
Goodluck!