Why does CombineMesh delete parts of my mesh? - c#

I'm working on creating a building generator, and am trying to combine all walls of the building into a single mesh. The building itself is made of quite a lot of individual gameobjects, all parented under one gameobject. In play mode, the constructed building looks like this.
I can export the gameobjects as a prefab just fine.
The issue arises when I attempt to combine everything to a single mesh. It shows like this, with a great deal of vertices appearing to be missing. I've already considered that I could be running up against the vertice limit, but even after raising that limit, the issue remains unresolved. Recalculating the normals hasn't helped, either. Code below.
MeshFilter[] filters = building.GetComponentsInChildren<MeshFilter>();
Mesh finalMesh = new Mesh();
finalMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
Debug.Log("Filters " + filters.Length);
CombineInstance[] combiners = new CombineInstance[filters.Length];
for (int i = 0; i < filters.Length; i++)
{
Debug.Log(filters[i].gameObject.name);
combiners[i].subMeshIndex = 0;
combiners[i].mesh = filters[i].sharedMesh;
combiners[i].transform = filters[i].transform.localToWorldMatrix;
}
finalMesh.CombineMeshes(combiners);
finalMesh.RecalculateNormals();
building.AddComponent<MeshFilter>();
building.GetComponent<MeshFilter>().sharedMesh = finalMesh;
string localPath2 = buildingFolderPath + "/Building.asset";
AssetDatabase.CreateAsset(finalMesh, localPath2);
GameObject finalBuilding = PrefabUtility.SaveAsPrefabAsset(building, localPath);
I have no clue what could be happening. I've considered that it could be automatically removing intersecting polygons (unsure if that's even a factor with CombineMesh(), the documentation doesn't say anything about it) but even changing the gameobjects involved to very small sizes, to the point where intersection would be impossible, hasn't helped a bit.
A possible clue is that the mesh is only displaying T-junction walls, which are the largest of the walls. Could there be a connection between size and this issue?
As it stands, I've exhausted all of my possible ideas. What could be going on here? For reference, the models in question are simple blender models, more or less just planes, exported in fbx with read/write enabled.
EDIT: As suggested by shingo, I have counted the vertices in the building using the following code.
MeshFilter[] filters = building.GetComponentsInChildren<MeshFilter>();
Mesh finalMesh = new Mesh();
finalMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
CombineInstance[] combiners = new CombineInstance[filters.Length];
long count = 0;
for (int i = 0; i < filters.Length; i++)
{
combiners[i].subMeshIndex = 0;
combiners[i].mesh = filters[i].sharedMesh;
combiners[i].transform = filters[i].transform.localToWorldMatrix;
count += filters[i].sharedMesh.vertexCount;
}
Debug.Log("Final count is " + count);
In one experimental example, the final count given by the code was 39174 vertices, while the vertices recorded in the inspector of the corresponding mesh counted 28372. So there's a significant disparity, meaning that the vertices are actually being deleted, instead of just not displaying properly.

Related

Confused on Clipper in C#

I'm creating a 2D game in Unity which has procedurally placed tiles. I want to simplify the collision geometry using Angus Johnson's Clipper library (specifically the union function), but I'm running into an issue with the library returning empty solutions and I'm not sure why.
For reference, here are the Polygon Colliders I've been using to test.
And here is a simplified version of the function I'm using to combine the geometry:
List<List<Vector2>> unitedPolygons = new List<List<Vector2>>();
Clipper clipper = new Clipper();
Paths solution = new Paths();
ClipperOffset offset = new ClipperOffset();
//Use a scaling factor for floats and convert the Polygon Colliders' points to Clipper's desired format
int scalingFactor = 10000;
for (int i = 0; i < polygons.Count; i++)
{
Path allPolygonsPath = new Path(polygons[i].points.Length);
for (int j = 0; j < polygons[i].points.Length; j++)
{
allPolygonsPath.Add(new IntPoint(Mathf.Floor(polygons[i].points[j].x * scalingFactor), Mathf.Floor(polygons[i].points[j].y * scalingFactor)));
}
bool succeeded = clipper.AddPath(allPolygonsPath, PolyType.ptSubject, true);
}
//Execute the union
bool success = clipper.Execute(ClipType.ctUnion, solution);
Debug.Log("Polygons after union: " + solution.Count);
//Offset the polygons
offset.AddPaths(solution, JoinType.jtMiter, EndType.etClosedPolygon);
offset.Execute(ref solution, 5f);
//Convert back to a format Unity can use
foreach (Path path in solution)
{
List<Vector2> unitedPolygon = new List<Vector2>();
foreach (IntPoint point in path)
{
unitedPolygon.Add(new Vector2(point.X / (float)scalingFactor, point.Y / (float)scalingFactor));
}
unitedPolygons.Add(unitedPolygon);
}
return unitedPolygons;
What I've discovered through debugging is that the first Execute (for the union) is returning an empty solution. I've figured out that the "BuildResult" function in the "Clipper" class is indeed running, and "m_PolyOuts" has data in it, but the "Pts" property of the "OutRec"s in that list are all null. I can't figure out where this happens or if they were ever set in the first place.
I'm convinced this is proper behavior and I'm just using the library wrong, but I can't find any documentation or examples explaining what I need to change to make the union succeed.
Thanks.
EDIT: I've narrowed it down a bit more. During "ExecuteInteral" in the Clipper class, the "Pts" lists aren't null until the "FixupOutPolygon" function is run. After that, all of the lists are null. "JoinCommonEdges" also makes a couple of the lists null, but not all of them.
I've been working on my own game project as well and stumbled upon similar problem with Clipper. What worked for me in this case was instead of writing this:
clipper.Execute(ClipType.ctUnion, solution);
... I specified PolyFillType for Execute method:
clipper.Execute(ClipType.ctUnion, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
I'm not sure why it worked for me but I think it's due to the fact that some Paths can share common edges so with the default pftEvenOdd filling rule it gets cut out.

Unity 2D array tile map

I am new to Unity as well as C#. Yet, I am trying to make a simple 2D platform game where I made a prefab of an object called Block. What I want to be able to do is to create an array tile map with 0s and 1s where the 1s are blocks and 0s are nothing. Also, I don't want the tile map to be random. I want the blocks to be instantiated from another object called GameController. A perfect example of what I would like to achieve is something like this.
But I don't really know how to do this with an array. I want to keep things simple since I am trying to learn how unity and c# work. Any help would be appreciated.
So you can use some assets from the asset store( for example: https://www.assetstore.unity3d.com/en/#!/list/2965-procedural-generation) This is a pretty hard challange. I would recomand this video: https://www.youtube.com/watch?v=k1pWpYEt2UE , but the closest one to what you want to achieve is this one: https://www.youtube.com/watch?v=gIUVRYViG_g
Hope it helped.
You can make a 2 dimensional array, e.g. int[40, 100] and loop through it twice, and if the number in the array is one, multiply your position in the array by the length or width of your block respectively. For example:
int[,] positions = new int[40,100];
for (int i = 0; i < 41; i++) {
for (int j = 0; j < 100; j++) {
if (positions[i,j] = 1) {
GameObject temp = Instantiate(block, new Vector3(j * blockWidth, i * blockHeight, 0), Quaternion.identity) as GameObject;
}
}
}
It would take a long while to set all of the coordinates for an array this large, but you could loop through with parameters, or just do it the hard way if it is smaller. Otherwise, I would just try doing it without a script.

Applying gravity to a 2D array in XNA game

I am working on a game somewhat similar to Tetris. I have arrived at a roadblock when it comes to handling the gravity logic. (I'm working in XNA if it's at all relevant)
Without wasting your time by going into details I essentially have a 2D array. There are 4 types of pieces: empty(0), blue(1), green(2), red(3) and yellow(4).
In this game it will be possible to form NxM solid blocks of the same color. This is the part which makes the logic messy. I hope it doesn't sound too vague for now but I will show an example and show my progress so far.
int[,] example = new int[5,5]
{
{ 0,0,1,0,4 },
{ 0,2,2,0,0 },
{ 0,2,2,2,0 },
{ 0,0,0,3,0 },
{ 1,2,2,0,0 }
};
Let's say that this is the board state right now. As you can see there is a 2x2 of 2's(greens) and some pieces floating in mid-air. My plan is to play an animation of those pieces falling down until the place underneath is occupied, update all solids. I was trying to fix this and it worked fine if I was just looking at gravity for single 1x1 pieces. When it came to handling 2x2's and bigger blocks it became a big mess and I just got stuck.
My attempt at this was to have a List to keep track of all blocks that are on the gameboard, this would be updated every time the gravity update method was called.
int[,] board = new int[6, 6];
bool[,] isBlock = new bool[board.GetLength(0), board.GetLength(1)];
List<int[]> blocks = new List<int[]>();
List<int[]> toplayAnimation = new List<int[]>();
for (int x = 0; x < board.GetLength(0); x++)
{
for (int y = 0; y < board.GetLength(1) - 1; y++)
{
if ((isBlock[x, y] == false) && (board[x, y + 1] == 0) && (board[x, y] != 0))
{
}
}
}
If we look at the example the result should be that the board is updated and an animation is played of the pieces falling down it should look like this:
int[,] example = new int[5,5]
{
{ 0,0,0,0,0 },
{ 0,0,1,0,0 },
{ 0,2,2,0,0 },
{ 0,2,2,2,0 },
{ 1,2,2,3,4 }
};
So I basically have the question, what approach do you suggest I take when tackling this problem? I was thinking of having two separate 2D arrays for blocks and single pieces and comparing them two in the loop. I have been stuck on this for a little over two weeks now and I couldn't seem to find any help in already existing threads. Hope I explained everything well, thanks in advance!
I think you should have a look here:
http://farseerphysics.codeplex.com/
Like this you will not have the pain to rebuild an entire engine from scratch :)
There lot more:
https://gamedev.stackexchange.com/questions/318/what-are-some-known-2d-3d-physics-engines-for-xna

Civilization 1 like tilemap generation

Okay so, I have looked at a lot of question from people like my self who are beginners in programming. And most of the time their questions are hard to answer or understand what the question really is. I will do my best to be as specific as possible about my problems so the above mentioned doesn't happen.
First off I have been following the tutorials over at http://xnagpa.net/xna4rpg.php. And my tile engine is based off the one that Jamie McMahon makes in his rpg tutorial series. Just so you know what the general structure of my tile engine is like.
Secondly I will try to explain what I'm trying to do inside the tile engine. I recently found an article about how the original Civilization generated their maps. http://forums.civfanatics.com/showthread.php?t=498630
And I rather like this approach to generating a "world" style map if you will. ie: oceans, continents, islands ect. So I decided to try to take this and implement it into my tile engine. It works for the most part. The parts that I added to the tile engine are supposed to randomly pick a location in the specified map layer (y,x) and then from that location generate a chunk of land(or tiles) and then replace the tiles in the map layer with the tiles created in the chunk of land. (ill show the code in a minute) and then do that for a desired amount of either number of landmasses(chunks) or continue creating chunks of land until the number of land tiles is equal to a desired amount of land tiles.
My Problem:
My program does what its supposed to (as mentioned above) except it only ever makes one landmass.(Chunk of land tiles) It does everything else just fine but it for some reason will not make more than one landmass. Now I suspect that it actually is making the other landmasses but somehow the way the tile engine is set up to display map layers is causing the landmass's to be covered up with water. Maybe its a layering issue. But It shouldn't be because the landmass's are all part of the same layer. So I'm completely baffled as to why its doing this.
public void GenerateLandChunks(MapLayer layer)
{
Tile tile = new Tile(0, 3);
Random random = new Random();
int x = random.Next(8, layer.Width - 10);
int y = random.Next(10, layer.Height - 20);
int length = random.Next(10, 70);
for (int i = 0; i < length; i++)
{
if (length != 0 && x > 8 || x < layer.Width - 10 && y > 10 || y < layer.Height - 20)
{
layer.SetTile(y, x, tile);
layer.SetTile(y, x + 1, tile);
layer.SetTile(y + 1, x, tile);
}
x = random.Next(x - 1, x + 2);
y = random.Next(y - 1, y + 2);
}
}
This is my method for generating the actual chunks it does what I want it to. (ABOVE)
MapLayer randomLayer = new MapLayer(100, 100);
for (int y = 0; y < randomLayer.Height; y++)
{
for (int x = 0; x < randomLayer.Width; x++)
{
Tile tile = new Tile(1, 3);
randomLayer.SetTile(x, y, tile);
}
}
int landMasses = 5;
for (int i = 0; i < landMasses; i++)
{
randomLayer.GenerateLandChunks(randomLayer);
}
This is where I create the map layer. I initially set the entire map to water tiles(tile (1,3)) then I tell it to generate 5 landmasses.
It seems like this should work. And it does but like I said only for the first one. It doesn't display the other 4 land masses.
My Question:
Is there anything you can see here that I'm doing wrong in order to accomplish what I'm trying to do?
If you need more of the code to understand whats going on let me know and ill post what ever you need. And like I said everything other than what I have posted is the exact same as it is in Jamie McMahon's tile engine.
I'm sorry if I have come off as unclear or if my question is hard to answer. I tried to make it as straight forward as possible. Thank you for your time.
So much text for such a simple answer. The problem is that a new Random object is generated every time, and so the "random" values are the same every time. That is how random number generators work, the numbers are not actually random, but "pseudorandom", and if you use the same random function and the same seed you will get the same progression of seemingly random numbers.
Default Random constructor seeds the generator with some value based on time, but if two generators are created with very small time period then that time value will be the same.
Move the Random object outside the function, so that it is used for all random generations, or move the loop inside (but Random outside the loop).

What's wrong with my soft-shadow code?

I'm trying to write a simple raytracer as a hobby project and it's all working fine now, except I can't get soft-shadows to work at all. My idea of soft-shadows is that the lightsource is considered to have a location and a radius. To do a shadow test on this light I take the point where the primary ray hit an object in the scene and cast an n-amount of rays towards the lightsource where each new ray has a random component to every axis, where the random component varies between -radius and radius.
If such a ray hits an object in the scene, I increment a hitcounter (if a ray hits multiple objects, it still only increments with one). If it makes it to the lightsource without collisions, I add the distance of the primary ray's intersect point to the lightsource's center to a variable.
When n samples have been taken, I calculate the ratio of rays that have collided and multiply the color of the light by this ratio (so a light with color 1000,1000,1000 will become 500,500,500 with a ratio of 0.5, where half the rays have collided). Then I calculate the average distance to the lightsource by dividing the distance variable of earlier by the amount of non-colliding rays. I return that variable and the function exits.
The problem is: it doesn't work. Not quite at least. What it looks like can be seen here. You can see it sort of resembles soft-shadows, if you squint real hard.
I don't get it, am I making some sort of fundamental flaw here, or is it something tiny? I'm fairly sure the problem is in this method, because when I count the number of partially lit pixels produced directly by this method, there are only about 250, when there should be a lot more. And when you look closely at the picture, you can see there's some partially lit pixels, suggesting the rest of the code processes the partially lit pixels just fine.
Here's the actual light for soft-shadows class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyFirstRayTracer
{
public class AreaLight : ILight
{
private const int _radius = 5;
private const int _samples = 16;
public Color Color { get; set; }
public Vector Location { get; set; }
#region ILight Members
public float GetLightingInformation(Vector point, ISceneObject[] scene, out Color color)
{
int intersectCount = 0;
float distance = -1;
for(int i = 0; i < _samples; i++)
{
bool intersects = false;
float rand = 0;
rand = _radius - (float)(new Random().NextDouble()*(2*_radius));
foreach (ISceneObject obj in scene)
{
Vector iPoint;
Vector loc = new Vector(Location.X + rand, Location.Y + rand, Location.Z + rand);
if (!obj.Intersect(new Ray(point, loc), out iPoint))
{
distance += (Location - point).SqLength;
}
else
{
intersects = true;
distance -= (Location - point).SqLength;
}
}
if (intersects)
intersectCount++;
}
float factor = 1-((float)intersectCount/_samples);
color = new Color(factor*Color.R, factor*Color.G, factor*Color.B);
return (float)Math.Sqrt(distance / (_samples - intersectCount));
}
#endregion
}
}
minor point but is this the best use of the random class..
for(int i = 0; i < _samples; i++)
{
bool intersects = false;
float rand = 0;
rand = _radius - (float)(new Random().NextDouble()*(2*_radius));
should this not be..
var rnd = new Random()
for(int i = 0; i < _samples; i++)
{
bool intersects = false;
float rand = 0;
rand = _radius - (float)(rnd.NextDouble()*(2*_radius));
Try generating a different "rand" for each component of "loc". As is, your jittered points all lie on a line.
You actually generate the point on the line on a line with direction (1, 1, 1). Is the lightsource really linear?
Also, I can barely see anything in your example. Could you make your camera nearer the to-be shadow and not pointing from the direction of the light?
See, this is why I come to this site :)
Every axis has its own random now, and it looks a lot better. It's still a little weird looking, increasing the number of samples helps though. It now looks like this.
Do you know a more efficient way to reduce the pattern-forming?
The biggest help though: not instantiating Random for every sample. It seriously tripled my rendering speed with soft shadows! I never knew that Random was so costly to instantiate. Wow.
Thanks a lot.
In your response you asked for an improved way to make soft shadows. An improvement could be, instead of randomizing all the rays from the same point, to give each ray a different offset on all axes to effectively give them a seperate little window to randomize in. This should result in a more even distribution. I don't know if that was clear but another way to describe it is as a grid which is perpendicular to the shadow ray. Each tile in the grid contains one of the n shadow rays but the location in the grid is random. Here you can find a part of a tutorial which describes how this can be used for soft shadows.

Categories

Resources