I have some problems on the display of my model with texture.
Everything works perfectly, however, I use a loop to repeat the texture to represent a floor 20 X 20 on the screen. My texture is repeated correctly. But I do not understand why all my textures generate a flicker ...
I noticed that images are superimposed on each other. I'm sure I checked my loop is coded correctly.
see screenshot:
my code (loop function generation ground):
//Function draw - ground land
private void draw_groundLand(Vector3 position_model_origin)
{
//example generation mode 4x4 cubes
int[,,] MatriceWorldCube = new int[1,2,2];
MatriceWorldCube[0, 0, 0] = 1;
MatriceWorldCube[0, 0, 1] = 1;
MatriceWorldCube[0, 1, 0] = 2;
MatriceWorldCube[0, 1, 1] = 1;
int height = MatriceWorldCube.GetLength(0);
int width = MatriceWorldCube.GetLength(1);
int length = MatriceWorldCube.GetLength(2);
Vector3 pos_reference = position_model_origin;
for (int thickness = 0; thickness < height; thickness ++)
{
for (int column = 0; column < width; column ++)
{
for (int line = 0; line < length ; line ++)
{
// Copy any parent transforms.
Matrix[] transforms = new Matrix[model_ground_land1.Bones.Count];
model_ground_land1.CopyAbsoluteBoneTransformsTo(transforms);
// Draw the model. A model can have multiple meshes, so loop.
foreach (ModelMesh mesh in model_ground_land1.Meshes)
{
// This is where the mesh orientation is set, as well
// as our camera and projection.
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.World = transforms[mesh.ParentBone.Index] *
Matrix.CreateRotationY(cubeGroundLand1_modelRotation) * Matrix.CreateTranslation(position_model_origin);
effect.View = View;
effect.Projection = Projection;
}
// Draw the mesh, using the effects set above.
mesh.Draw();
}
position_model_origin.X = (float)(line +1);
}
position_model_origin.X = pos_reference.X;
position_model_origin.Z = (float)(column +1);
}
position_model_origin.Z = pos_reference.Z;
position_model_origin.Y = (float)(thickness+1);
}
position_model_origin.Y = pos_reference.Y;
position_model_origin = pos_reference;
}
Thank you in advance for your help. I lose patience (over a whole weekend ^ ^)
It's Z-fighting. Z-buffer precision falling with distance so far objects have more "flickers" GPU can't figure out which polygon is on top because tail of the z-buffer value isn't precise enough to distinguish 2 almost equal values.
You have 6 ways to fix it:
Move geometry or do not display part that is below.
Use something like polygon offset in OpenGL
Use CPU z-sorting instead of z-buffer.
Use only one object with 2 textures instead of 2 objects + some shaders (i don't know what exactly you are trying to achieve)
Use larger z-buffer.
Move clip planes closer to each other it will increase precision.
Related
i have somewhat implemented marching cubes in unity/c# (you dont need to know unity to help me though) and i cant stop feeling like i have made a big mistake in my code because it is so slow. i am already running it on a separate thread but it just takes ages to complete. please help me optimize my code.
private void _UpdateChunk()
{
lock (this)
{
// clear the tri, vert and uv lists
ClearMeshData();
// Loop through each "cube" in the terrain.
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
for (int z = 0; z < width; z++)
{
// Create an array of floats representing each corner of a cube and get the value from our terrainMap.
float[] cube = new float[8];
float[] strengths = new float[8];
for (int i = 0; i < 8; i++)
{
Vector3Int corner = new Vector3Int(x, y, z) + gamedata.CornerTable[i];
cube[i] = terrainMap[corner.x, corner.y, corner.z].BlockType;
strengths[i] = terrainMap[corner.x, corner.y, corner.z].Strength;
}
// Pass the value into the MarchCube function.
MarchCube(new Vector3(x, y, z), cube, strengths);
}
}
}
}
}
void MarchCube(Vector3 position, float[] cube, float[] strengths)
{
// Get the configuration index of this cube.
int configIndex = GetCubeConfiguration(cube);
// If the configuration of this cube is 0 or 255 (completely inside the terrain or completely outside of it) we don't need to do anything.
if (configIndex == 0 || configIndex == 255)
return;
// Loop through the triangles. There are never more than 5 triangles to a cube and only three vertices to a triangle.
int edgeIndex = 0;
Vector3 vert1 = new Vector3();
Vector3 vert2 = new Vector3();
float vert1sample = 0;
float vert2sample = 0;
float lerp = 0;
int indice = 0;
for (int i = 0; i < 5; i++)
{
for (int p = 0; p < 3; p++)
{
// Get the current indice. We increment triangleIndex through each loop.
indice = gamedata.TriangleTable[configIndex, edgeIndex];
// If the current edgeIndex is -1, there are no more indices and we can exit the function.
if (indice == -1)
return;
// Get the vertices for the start and end of this edge.
vert1 = position + gamedata.EdgeTable[indice, 0];
vert2 = position + gamedata.EdgeTable[indice, 1];
vert1sample = strengths[gamedata.EdgeIndexTable[indice, 0]];
vert2sample = strengths[gamedata.EdgeIndexTable[indice, 1]];
// Get the midpoint of this edge.
lerp = Mathf.Abs(vert1sample) / (Mathf.Abs(vert2sample) + Mathf.Abs(vert1sample));
Vector3 vertPosition = Vector3.Lerp(vert1, vert2, lerp);
// Add to our vertices and triangles list and incremement the edgeIndex.
vertices.Add(vertPosition);
triangles.Add(vertices.Count - 1);
if (getChunkVoxel(vert1 + chunkPosition) != 0)
{
uvs.Add(new Vector2(getChunkVoxel(vert1 + chunkPosition) - 1, 0));
}
else
{
uvs.Add(new Vector2(getChunkVoxel(vert2 + chunkPosition) - 1, getChunkVoxel(vert2 + chunkPosition) - 1));
}
edgeIndex++;
}
}
}
int GetCubeConfiguration(float[] cube)
{
// Starting with a configuration of zero, loop through each point in the cube and check if it is below the terrain surface.
int configurationIndex = 0;
for (int i = 0; i < 8; i++)
{
// If it is, use bit-magic to the set the corresponding bit to 1. So if only the 3rd point in the cube was below
// the surface, the bit would look like 00100000, which represents the integer value 32.
if (cube[i] < terrainSurface)
configurationIndex |= 1 << i;
}
return configurationIndex;
}
it appears that this is the part that slows my game down, help would be appreciated
i already made it faster by changing terrainpoint from a class to a struct but it is still very slow.
One main reason it is slow is that there is a lot of allocations in the loop putting a lot of pressure on the garbadge collector. There is currently 11 allocation per "cube" in the terrain in _UpdateChunk and up to 17 in MarchCube (possibly even more if the expressions like position + gamedata.EdgeTable[indice, 0] allocates a new vector). This is not reasonable. Many allocation are not needed. For example cube and strengths can be preallocated once for all the cubes in the beginning of _UpdateChunk. You do not need to allocate the vector in the expression to compute corner: you can just compute the components separately manually (or you can possibly preallocate the vector and reset its component when needed). The same thing applies for the new Vector3(x, y, z) can can be preallocated and set in the loop. Such an algorithm is computationally intensive so you should get away any overhead like virtual method calls and allocations/GC -- only low-level arrays accesses and mathematical operations should remains.
Note that some computations can be optimized. For example GetCubeConfiguration can be modified so to be branchless. Mathf.Abs(vert1sample) can be precomputed so not to compute it twice (though the compiler may already do that). I am also wondering if the expression like vertices.Add are efficient but this is dependent of the type of container which is not provided here.
I am procedurally generating textures (in Unity3D using C#), each of which are bound to an Unlit/Texture Material attached to a plane with Offset 0, 0 and Tiling 1, 1. When I generate the textures, they work great with many resolutions and very poorly with others.
Here is what it looks like when it works:
And here is what it looks like when it doesn't:
I have messed around with the Texture2D() mipchain argument, the Apply() updateMipmaps argument, and filterMode types. None have been to any avail. Here is my code below:
// GENERATE AND APPLY TEXTURE
Texture2D texture = new Texture2D(width, height, TextureFormat.ARGB32, false); // width and height are integers
texture.filterMode = FilterMode.Point;
// 0 -> width/height
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
// 0 -> 1
float i = ((float)x / (float)width) * (float)width / (float)height;
float j = (float)y / (float)height;
bool open = ((Mathf.PerlinNoise((offset.x + i) * stretch, (offset.y + j) * stretch)) < clamp); // offset is a Vector2Int; stretch is a float; and clamp is a float
Color col = open ? empty : full; // empty and full are white and black, respectively
texture.SetPixel(x, y, col);
}
}
texture.Apply();
mat.SetTexture("_MainTex", texture);
What am I missing? Surely there's a way to make the sprite look normal. Another note is sometimes after initially generating the texture, the first time I regenerate the same texture after, it fixes some minor horizontal rendering issues. Any help would be greatly appreciated—thank you!
Im currently experimenting with Terrain trees but im stuck at manipulating their position. The following script as far as i know should work, it also transforms the position into local terrain coordinates yet nothing happens.
private void SetTrees()
{
var Trees_On_Terrain = Terrain.activeTerrain.terrainData.treeInstances;
for (int i = 0; i < Trees_On_Terrain.Length; i++)
{
Trees_On_Terrain[i].position = new Vector3(10f /
Terrain.activeTerrain.terrainData.heightmapResolution, 0f, 10f /
Terrain.activeTerrain.terrainData.heightmapResolution);
}
Terrain.activeTerrain.terrainData.SetTreeInstances(Trees_On_Terrain, true);
}
They are put into a near the (0,0,0) coordinate.
Please help!
The problem here is that you are dividing your x and y coordiantes with Terrain.activeTerrain.terrainData.heightmapResolution which is not correct.
Imagine your terrain heightmap resolution is 2049(power of two + 1), but your terrain dimension is 1250 * 500. You still gonna divide x and y by 2049 but you should rather by 1250 and 500.
You should use the sampled data
Terrain.activeTerrain.terrainData.heightmapWidthfor the x coordinate
Terrain.activeTerrain.terrainData.heightmapHeight for the y coordinate.
Corrected code snippet:
private void SetTrees()
{
var Trees_On_Terrain = Terrain.activeTerrain.terrainData.treeInstances;
for (int i = 0; i < Trees_On_Terrain.Length; i++)
{
Trees_On_Terrain[i].position = new Vector3(10f / Terrain.activeTerrain.terrainData.heightmapWidth, 0f, 10f / Terrain.activeTerrain.terrainData.heightmapHeight);
}
Terrain.activeTerrain.terrainData.SetTreeInstances(Trees_On_Terrain, true);
}
I want to find the 2D bounding box (BB) of the visible part of an Game-object in Unity3D.**
Thanks to having no reputation i cant post images, so here are links to Imgur:
Starting Point: Image
Showing the initial scene camera. For example i want to get the BB of the wheels of the passing car.
Goal: Image
Showing the quite small BB i want to get in an efficient way. The method used is very costly and i want to avoid it. Its works on a segmented version of the input picture, looking similar to this: Image.
Current Approach:
Image
This uses the bounds of all GameObjects (GO) tagged as wheels and calls a function similar like this:
Rect GetBoundingBox(GameObject go, Camera camera, float margin = 0f)
{
Rect rect = new Rect(-1f, -1f, -1f, -1f);
Vector3[] v; // Vertices
// Object is behind camera
if (camera.WorldToScreenPoint(go.GetComponentInChildren<Renderer>().bounds.center).z < 0)
return rect;
// get first mesh filter
v = go.GetComponentInChildren<MeshFilter>().mesh.vertices;
// maybe the game object hast no mesh yet... and is empty
if (v.Length < 1 || v == null)
return rect;
for (int i = 0; i < v.Length; i++)
{
//World space
v[i] = go.transform.TransformPoint(v[i]);
//GUI space
v[i] = camera.WorldToScreenPoint(v[i]);
v[i].y = Screen.height - v[i].y;
}
Vector3 min = v[0];
Vector3 max = v[0];
for (int i = 1; i < v.Length; i++)
{
min = Vector3.Min(min, v[i]);
max = Vector3.Max(max, v[i]);
}
//Construct a rect of the min and max positions and apply some margin
rect = Rect.MinMaxRect(min.x, min.y, max.x, max.y);
// apply optional margin
rect.xMin -= margin;
rect.xMax += margin;
rect.yMin -= margin;
rect.yMax += margin;
return rect;
}
Two problems appear.
Its getting all BB even if the GO is not visible by the camera.
Even if its visible, the boundaries are as large as the GO it self, not as the visible part.
I am very happy about every hint in a good direction!!
For interested people the background is the development of an application to generate/simulate labeled training data for an deep learning project.
This method that draws my tiles seems to be quite slow, Im not sure exactly whats wrong, it belive my culling method isnt working and is drawing stuff offscreen, but im not completeley sure. Here it is:
// Calculate the visible range of tiles.
int left = (int)Math.Floor(cameraPosition.X / 16);
int right = left + spriteBatch.GraphicsDevice.Viewport.Width / 16;
right = Math.Min(right, Width) + 1; // Width -1 originally - didn't look good as tiles drawn on screen
if (right > tiles.GetUpperBound(0))
right = tiles.GetUpperBound(0) + 1; // adding 1 to get the last right tile drawn
int top = (int)Math.Floor(cameraPosition.Y / 16);
int bottom = left + spriteBatch.GraphicsDevice.Viewport.Height/ 16;
bottom = Math.Min(bottom, Height) + 1; // Height -1 originally - didn't look good as tiles drawn on screen
if (bottom > tiles.GetUpperBound(1))
bottom = tiles.GetUpperBound(1) + 1; // adding 1 to get the last bottom tile drawn
// For each tile position
for (int y = top; y < bottom; ++y)
{
for (int x = left; x < right; ++x)
{
// If there is a visible tile in that position, draw it
if (tiles[x, y].BlockType.Name != "Blank")
{
Texture2D texture = tileContent["DirtBlock_" + getTileSetType(tiles,x,y)];
spriteBatch.Draw(texture, new Vector2(x * 16, y * 16), Color.White);
if (isMinimap)
spriteBatch.Draw(pixel, new Vector2(30+x, 30+y), Color.White);
}
}
}
GetTileSetTypes is a function to get what tiles are around it, for different textures, like DirtBlock_North, DirtBlock_Center, etc.
Tile content is just a class with my block textures.
Try changing SpriteBatch.Begin to defered and combining all of the tiles onto one texture.
See this GameDev question for info about why deferred is most likely the fastest option for you.
Also realize that every time you draw a new texture you have to take the old one out of the GPU and put the new one in. This process is called texture swapping and usually isn't an issue but you are swapping textures twice per tile which is likely to impact performance noticeably.
This can be fixed by combining multiple sprites onto one texture and using the source rectangle argument. This allows you to draw multiple sprites without a texture swap. There are a few OSS libraries for this. Sprite Sheet Packer is my personal favorite.
Unfortunantly without the project and a profiler I'm just guessing; however, these are the two biggest gotchas for rendering tilemaps I know of. I can't really see anything wrong from here. Below is the code I use to draw my tile maps and as you see its very similar to yours.
If all else fails I would suggest using a profiler to figure out which bits are running slowly.
//Init the holder
_holder = new Rectangle(0, 0, TileWidth, TileHeight);
//Figure out the min and max tile indices to draw
var minX = Math.Max((int)Math.Floor((float)worldArea.Left / TileWidth), 0);
var maxX = Math.Min((int)Math.Ceiling((float)worldArea.Right / TileWidth), Width);
var minY = Math.Max((int)Math.Floor((float)worldArea.Top / TileHeight), 0);
var maxY = Math.Min((int)Math.Ceiling((float)worldArea.Bottom / TileHeight), Height);
for (var y = minY; y < maxY; y++) {
for (var x = minX; x < maxX; x++) {
_holder.X = x * TileWidth;
_holder.Y = y * TileHeight;
var t = tileLayer[y * Width + x];
spriteBatch.Draw(
t.Texture,
_holder,
t.SourceRectangle,
Color.White,
0,
Vector2.Zero,
t.SpriteEffects,
0);
}
}