combining several iterations of same object in different location using .add() or .merge() - merge

I am trying to make a coil with several small loops. I have a custom function to create a single helix for each loop, and at first I was calling that within a for loop several hundred times, but it was taking too long to render and slowed down the scene.
I tried the merge function several different ways to no avail, so I'm now simply trying to combine two meshes by using the .add command. Here is my process:
(1) add the helix mesh to the total mesh
(2) move the position of the helix mesh
(3) try to add it again so that the total mesh will include both helixes
Only the second (moved) helix shows up when I say scene.add(createCoil()); in my init() function though. How do I add, or merge, several differently positioned helices into one object, geometry, mesh, or whatever, without calling a function to create a new Geometry for every iteration of the for loop?
Here is the code (I took the for loop out just to try one iteration):
function createCoil(){
var geometry = new THREE.TorusGeometry( 11, 0.5, 16, 100 );
var material = new THREE.MeshBasicMaterial( { color: 0x017FFF } );
mesh = new THREE.Mesh( geometry, material );
var clockwise = false;
var radius = 10;
var height = 3.4;
var arc = 1;
var radialSegments = 24;
var tubularSegments = 2;
var tube = 0.1;
var bottom = new THREE.Vector3();
bottom.set(radius, -height / 2, 0);
mesh2 = createHelix(clockwise, radius, height, arc, radialSegments, tubularSegments, tube, material, bottom);
mesh2.position.set(1,1,1);
mesh.add(mesh2);
for(i=1;i<=50;i++){
mesh2.position.y=3.4*i;
mesh.add(mesh2);
}
return mesh;
}
createHelix(...) creates a new THREE.Geometry. I have also tried this and the merge function with the helix being a THREE.Object3D
Please don't point to an answer that includes
THREE.GeometryUtils.merge(geometry, otherGeometry);
(...it's obsolete)
Used another link that was helpful, but I can only (1) change the position of a mesh (not geometry), and (2) only merge geometries (not meshes), within the for loop.
How do I get 500 loops of a coil into a scene without a terrible frame rate?
Please and Thanks!

Use the matrix4 toolset for translation (and rotation if you want), then merge your geometrys:
var geometry = new THREE.TorusGeometry( 11, 0.5, 16, 100 );
var mergeGeometry = new THREE.Geometry();
var matrix = new THREE.Matrix4();
for( i = 1; i <= 50; i++ ) {
matrix.makeTranslation( 0, 3.4 * i, 0 );
mergeGeometry.merge( geometry, matrix );
}
var mesh = new THREE.Mesh( mergeGeo, material );

Related

Optimizing Unity mesh generation | Faster than SetVertexBufferData/ SetIndexBufferData

I’m trying to squeeze every bit of performance out of some voxel mesh generation, and it takes about 1.1ms per chunk at the moment (average measurements):
~0.04ms for vertex, normal, and triangle index calculation in a burst job
~0.61ms for the SetVertexBufferData call
~0.45ms for SetIndexBufferData call
Is there a better way to update a mesh than this? Maybe one that works inside a burst job? I know 1.1ms is pretty fast but I can't help but feel like I'm missing out on performance when the actual data generation is an order of magnitude faster.
Here's what I have:
// Input heightmap
// arr is an int[] created from perlin noise
NativeArray<int> heights = new NativeArray<int>(arr, Allocator.TempJob);
int numVerts = heights.Length * 20;
// VData is the struct: { float3 Vert; float3 Norm; }
NativeArray<VData> verts = new NativeArray<VData>(numVerts, Allocator.TempJob);
// Triangle indices
NativeArray<ushort> tris = new NativeArray<ushort>(heights.Length * 30, Allocator.TempJob);
// create Verts, Tris, and Norms in IJob
Job job = new Job
{
Heights = heights,
Verts = verts,
Tris = tris
};
// Calculate the values
job.Schedule().Complete();
int indices = heights.Length * 30;
Mesh mesh = new Mesh();
mesh.SetVertexBufferParams(numVerts,
new VertexAttributeDescriptor(VertexAttribute.Position),
new VertexAttributeDescriptor(VertexAttribute.Normal)
);
// slow
mesh.SetVertexBufferData(verts, 0, 0, numVerts, 0, MeshUpdateFlags.DontValidateIndices);
mesh.SetIndexBufferParams(indices, IndexFormat.UInt16);
// also slow
mesh.SetIndexBufferData(tris, 0, 0, indices, MeshUpdateFlags.DontValidateIndices);
mesh.SetSubMesh(0, new SubMeshDescriptor(0, indices));
If you have any alternatives or if you see any ways I could improve this, I'm all ears!

How can i Draw Lines in Monogame?

I just started learning monogame a couple of days ago and I was wondering how I can draw a line from a Start Vector2 and an End Vector2 with a specific line thickness?
Should I use a one pixel image to draw it onto the screen and then use a Bresenham's line algorithm to find there positions, or is there a more optimized and less complicated method to do this using monogames built in functions?
One way is to create a Texture2D with a width that is the distance between the two Vector2s and a height that is the desired width. Then you apply a rotation to the texture when you draw it.
Here is an example (as a SpriteBatch extension method):
public static void DrawLineBetween(
this SpriteBatch spriteBatch,
Vector2 startPos,
Vector2 endPos,
int thickness,
Color color)
{
// Create a texture as wide as the distance between two points and as high as
// the desired thickness of the line.
var distance = (int)Vector2.Distance(startPos, endPos);
var texture = new Texture2D(spriteBatch.GraphicsDevice, distance, thickness);
// Fill texture with given color.
var data = new Color[distance * thickness];
for (int i = 0; i < data.Length; i++)
{
data[i] = color;
}
texture.SetData(data);
// Rotate about the beginning middle of the line.
var rotation = (float)Math.Atan2(endPos.Y - startPos.Y, endPos.X - startPos.X);
var origin = new Vector2(0, thickness / 2);
spriteBatch.Draw(
texture,
startPos,
null,
Color.White,
rotation,
origin,
1.0f,
SpriteEffects.None,
1.0f);
}
Example of use:
var startPos = new Vector2(0, 0);
var endPos = new Vector2(800, 480);
_spriteBatch.DrawLineBetween(startPos, endPos, 12, Color.White);
How it looks:
It's not a perfect solution. You'll want to modify it if you want to draw connected lines with different angles without any visible seams. Also not sure about the performance.
I use a library I found. It draws a number of 2D primitives, like lines, boxes, etc. Really easy to use. Called "C3.MonoGame.Primitives2D", it can be found here:
https://github.com/z2oh/C3.MonoGame.Primitives2D
Here's a screenshot of a demo I wrote using many of its methods:
It's just one file of around 500 lines. If you don't like Git or using libraries, you can just copy & paste it into your project.

Box2D emulation on flutter painfully slow

I am re-writing a game a made using easlejs with Box2Dweb to flutter's flame engine with the dart port of box2d. My problem is that the objects are move really really slow. Gravity setting seems to progress in a linear fashion.
I read about scale factors etc... just don't know how to link it all. The World class does not have that,
can someone show me an example of how to setup the initial screen to box2d world ratios?
I get the screenSize using flames resize override I want to use that to set the scale or whatever works.
The examples in GitHub never seem to use that and even when I download then and run them... again painfully slow falling bodies.
A simple screen with a circle or a Square falling (correctly) will be appreciated.
Here's how I instantiate the code. (I need the object to be 80x80 pixels)
class MyGame extends Game with TapDetector {
MyGame() : _world = Box2D.World.withGravity(Box2D.Vector2(0, 10)) {
_world.setAllowSleep(true);
spawnBlocks();
}
void createSquare(int index, double w, double h, double x, double y) {
int randomNumber = random.nextInt(letters.length);
var bodyDef = Box2D.BodyDef();
bodyDef.type = Box2D.BodyType.DYNAMIC;
bodyDef.position = Box2D.Vector2(x - 5, y);
bodyDef.angle = 0;
dynamicBody = _world.createBody(bodyDef);
dynamicBody.userData = letters[randomNumber];
var boxShape = Box2D.PolygonShape();
boxShape.setAsBox(w / 2, h / 2, Box2D.Vector2(w / 2, -h * 2), 0);
var boxFixtureDef = Box2D.FixtureDef();
boxFixtureDef.shape = boxShape;
boxFixtureDef.density = 0;
boxFixtureDef.restitution = 0;
boxFixtureDef.friction = 1;
dynamicBody.createFixtureFromFixtureDef(boxFixtureDef);
blocks.add(dynamicBody);
}
spawnBlocks() {
for (var i = 0; i < 8; i++) {
createSquare(
i, blockWidth, blockHeight, blockWidth * i + 18, -100 * i.toDouble());
}
}
}
It doesn't matter how high I set the gravity, the body still falls at the same speed.
Even when they hit the floor they bounce very slowly, I have used the body.setTransform to increase the position.y etc but it just seems to move right through the static body(floor).
Since the density of your square is 0 it is not affected by gravity, try to set it to something higher and see if the objects are more affected.
Don't use the body.setTransform if you don't really need to, since it will break the physics set up in the world.
Did you try this example?
https://github.com/flame-engine/flame/tree/master/doc/examples/box2d/contact_callbacks
And don't forget to add the scale argument to your world, otherwise you'll hit the speed limits quite fast since you'll be so zoomed out.
I'm the maintainer of box2d for flame (now Forge2D), if you have more questions you can join the box2d channel on our discord and I'll try to help you.

How can I find all the lakes in a region (bounded by polgon) in earth engine?

The problem statement is that a region of interest is given.
I need to find all the lakes in a polygon bounded region using the NDWI index for water bodies, which are at a height of more than 1500m. Then display the changes in the area of lake's surface water starting from the year 1984 till 2018 on a 2-year interval in a table like structure in Google Earth Engine. I have used Landsat 5 and 7 data.
I have created the following code:
Earth Engine Code
Now I need to display the results in the polygon marked region in a table sort of structure in the following format:-
Rows - (Lake 1, Lake 2, Lake 3... Lake n)
Columns - (Surface Area in 1984, Surface Area in 1986, ....2018)
How should I go about doing it?
I answer this question in regard of the code posted in the comments, hopefully the question is updated with the code posted in the comments.
Filtering: ok.
Just a comment, I wouldn't name an image collection variable with name img, it's just confusing to me, but variables names are up to you.
var mf = ee.Filter.calendarRange(10, 12, 'month');
var img1 = ee.ImageCollection(l5
.filterDate('1984-01-01','1999-12-31')
.filterBounds(roi)
.filter(mf));
var img2 = ee.ImageCollection(l7
.filterDate('2000-01-01','2018-12-31')
.filterBounds(roi)
.filter(mf));
add NDWI: This is your code:
var addNDWI = function(image){
var ndwi = image.normalizedDifference(['B2', 'B4']).rename('NDWI');
var ndwiMask = ndwi.gte(0.3);
return image.addBands(ndwi);
};
var image1 = img1.map(addNDWI);
var image2 = img2.map(addNDWI);
you are not saving ndwiMask, so you won't be able to use it outside of this function. Again, I wouldn't name them image as they are not images but image collections.
elevation mask: you have to select the elevation band:
var elevMask = elevation.select('elevation').gt(1500)
This mask image will have ones where elevation is greater than 1500 and zeros where not.
applying masks: in this part you have to remember that Earth Engine uses functional programming, so objects are not mutable, this means that you cannot update the state of an object using a method, you have to catch the output of the method you are calling. Here you need ndwi mask, so you have to compute it with NDWI band.
var mask = function(image){
var ndwiMask = image.select('NDWI').gt(0.3)
var ndwi_masked = image.updateMask(ndwiMask);
return ndwi_masked.updateMask(elevMask);
};
var maskedImg = image1.map(mask); // ImageCollection!
var maskedImg2 = image2.map(mask); // ImageCollection!
Visualizing: As the results are ImageCollection, when you add it to the map EE makes a mosaic and that is what you would see. Keep that in mind for further processing.
var ndwiViz = {bands: ['NDWI'], min: 0.5, max: 1, palette: ['00FFFF', '0000FF']};
Map.addLayer(maskedImg, ndwiViz, 'Landsat 5 masked collection');

How can I see the inside of a cylinder in Unity?

I place my camera inside of a cylinder but I am not able to see it. All I can see is the outside of it. What should I do?
I found out! You have to add a material to the cylinder, then select Shader/Legacy Shaders/Particles/Alpha Blended.
Instead of using double sided materials (which will render twice) you can just flip your mesh (aka invert normals).
Inverting normals is performed by taking the triangles array which contains indexes of vertexes that the mesh is referring to when renderig triangles.
A simplest code that does it looks kind of like this:
[RequireComponent(typeof(MeshFilter))]
public class MeshInverter : MonoBehaviour
{
void Start()
{
var meshFilter = GetComponent<MeshFilter>();
var triss = meshFilter.sharedMesh.triangles;
var normals=meshFilter.sharedMesh.normals;
for (int i=0;i<normals.Length;i++)
normals[i]=-normals[i];
for (int i = 0; i < triss.Length / 3; i++)
{
int temp = triss[i * 3 + 1];
triss[i * 3 + 1] = triss[i * 3];
triss[i * 3] = temp;
}
Mesh mesh=Instantiate(meshFilter.sharedMesh);
mesh.triangles=triss;
mesh.normals=normals;
meshFilter.mesh=mesh;
}
}
It will make the inside of the capsule visible in play mode