Ray Intersection doesn't work correctly - c#

Alright, So I have been working on a minecraft like builder, the idea is to be able to be able to quickly build huge structures, without mining etc. It's for the learning experience.
So now I'm stuck at an annoying point...
If I destroy a block from one side. It works correctly.
But once I move the camera to the other side, it goes all wrong.
So basically I'm stuck at this point and have no idea how to fix it.
I calculate the ray:
Ray getRay(MouseState mouseState)
{
Viewport vp = mainController.engine.graphics.GraphicsDevice.Viewport;
Vector3 nearPoint = new Vector3(mouseState.X, mouseState.Y, 0);
Vector3 farPoint = new Vector3(mouseState.X, mouseState.Y, 1);
nearPoint = vp.Unproject(nearPoint, camera.getProjectionMatrix(), camera.getViewMatrix(), Matrix.Identity);
farPoint = vp.Unproject(farPoint, camera.getProjectionMatrix(), camera.getViewMatrix(), Matrix.Identity);
Vector3 direction = Vector3.Normalize(farPoint - nearPoint);
return new Ray(nearPoint, direction);
}
And then just brute-check it with all the models' bounding boxes:
for (int y = world.settings.regionHeight - 1; y >= 0; y--)
{
gotblock = false;
for (int x = 0; x < world.settings.regionWidth; x++)
for (int z = 0; z < world.settings.regionLenght; z++)
{
f = ray.Intersects(block[x, y, z].boundingBox);
if (f != null)
{
if (f < lowestDistance && world.block[(int)position.X * world.settings.regionWidth + x, y, (int)position.Y * world.settings.regionLenght + z] != BlockTypes.none)
{
result = new intVector3((int)position.X * world.settings.regionWidth + x, y, (int)position.Y * world.settings.regionLenght + z);
gotblock = true;
}
}
}
if (gotblock)
break;
}
If you need any more information, just tell. Thanks in Advance.

The problem was that on check for lowest distance, the distance could have been counted by negative numbers in a ray. Therefore, I just needed to compare the absolute values of distance, instead of only positive ones.
Like so:
for (int y = world.settings.regionHeight - 1; y >= 0; y--)
{
gotblock = false;
for (int x = 0; x < world.settings.regionWidth; x++)
for (int z = 0; z < world.settings.regionLenght; z++)
{
f = ray.Intersects(block[x, y, z].boundingBox);
if (f != null)
{
f = Math.Abs((float)f);
if (f < lowestDistance && world.block[(int)position.X * world.settings.regionWidth + x, y, (int)position.Y * world.settings.regionLenght + z] != BlockTypes.none)
{
lowestDistance = (float)f;
result = new intVector3((int)position.X * world.settings.regionWidth + x, y, (int)position.Y * world.settings.regionLenght + z);
gotblock = true;
}
}
}
if (gotblock)
break;
}

Related

Add Trees to Terrain C# with TreeInstance

I try to add trees to my terrain with the following code:
// Create Trees
for (int x = 0; x < terrainData.heightmapWidth; x++)
{
for (int z = 0; z < terrainData.heightmapWidth; z++)
{
if (GetBiome(x, z) == "Grasland")
{
int r = UnityEngine.Random.Range(0, 500);
if (r == 0)
{
Terrain terrain = GetComponent<Terrain>();
TreeInstance treeTemp = new TreeInstance();
treeTemp.position = new Vector3(x, 0, z);
treeTemp.prototypeIndex = 0;
treeTemp.widthScale = 1f;
treeTemp.heightScale = 1f;
treeTemp.color = Color.white;
treeTemp.lightmapColor = Color.white;
terrain.AddTreeInstance(treeTemp);
terrain.Flush();
}
}
}
}
the function GetBiome() works correctly, i checked that by placing the trees as GameObjects and it worked fine.
Is there something missing that i didn't thought of?
Because there's not a single tree generated.
The tree i want to generate is set up under PaintTrees:
Please read my notes as comments below, I hope this explains and resolves the issue.
I have tested this in unity to confirm.
// Create Trees
//make these float otherwise your position math below is truncated
for (float x = 0; x < terrainData.heightmapWidth; x++)
{
//heightmapHeight not heightmapWidth
for (float z = 0; z < terrainData.heightmapHeight; z++)
{
Terrain terrain = GetComponent<Terrain>();
int r = UnityEngine.Random.Range(0, 500);
if (r == 0)
{
TreeInstance treeTemp = new TreeInstance
//position is local and expects value between 0 and 1
treeTemp.position = new Vector3(x / terrainData.heightmapWidth, 0, z / terrainData.heightmapHeight),
treeTemp.prototypeIndex = 0;
treeTemp.widthScale = 1f;
treeTemp.heightScale = 1f;
treeTemp.color = Color.white;
treeTemp.lightmapColor = Color.white;
terrain.AddTreeInstance(treeTemp);
terrain.Flush();
}
}
}
A bit late but, instead of
int r = UnityEngine.Random.Range(0, 500);
if (r == 0)
do
int r = UnityEngine.Random.Range(0, 500);
if (r >= 0 && <= 1)
to check for range. Because you're checking for a impossible number it will always come close but never 0 for example 0.000230...f you will need to Math floor it or check for range like I did

how to limit CreateCell c# procedural grid generation unity

I am learning C# for unity and could use some pointers.
I am following catlikecoding hex map tutorial but I have modified the grid for my own means.
http://catlikecoding.com/unity/tutorials/hex-map-1/
My goal is to create a pyramid of squares procedurally starting from a 7 * 7 grid. I am using a prefab plane
How do I place a limit on The CreateCell looped function so that cells with the (x,y) coordinates are not created when they meet the following expression
x + y > n - 1 where n = grid size (for example (6,1) or (5,6)
I have gotten as far as creating a rhombus of planes with the undesired planes below the ground plane.
The script is as follows.
public class HexGrid : MonoBehaviour {
public int width = 7;
public int height = 7;
public int length = 1;
public SquareCell cellPrefab;
public Text cellLabelPrefab;
SquareCell[] cells;
Canvas gridCanvas;
void Awake () {
gridCanvas = GetComponentInChildren<Canvas>();
cells = new SquareCell[height * width * length];
for (int z = 0 ; z < height; z++) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < length; y++)
CreateCell(x, z, y);
}
}
}
void CreateCell(int x, int z, int y) {
Vector3 position;
position.x = x * 10f ;
position.y = ((y + 1) - (x + z)) * 10f + 60f;
position.z = z * 10f ;
Cell cell = Instantiate<Cell>(cellPrefab);
cell.transform.SetParent(transform, false);
cell.transform.localPosition = position;
Text label = Instantiate<Text>(cellLabelPrefab);
label.rectTransform.SetParent(gridCanvas.transform, false);
label.rectTransform.anchoredPosition =
new Vector2(position.x, position.z);
label.text = x.ToString() + "\n" + z.ToString();
}
}
Grid so far
A quick solution would be to add an if statement before the part of the code that creates a cell. In this case the method CreateCell(). That if statement should have your logic in code. You would also have to create two variables for the size to check. For example:
public int tempX;
public int tempY;
void Awake () {
gridCanvas = GetComponentInChildren<Canvas>();
cells = new SquareCell[height * width * length];
for (int z = 0 ; z < height; z++) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < length; y++)
{
if (x + y < (tempX + tempY) - 1)
{
CreateCell(x, z, y);
}
}
}
}
}

Array Shifting / Wrong Index / i = [x+y*size+z*size*size]

I have a simple question. How can I shift a linear array in 3 dimensions?​
It seems too work but in the X & Y axis i got an index problem.
The reson why I wanna do this is simple. I want to create a volumetric terrain with a chunk buffer, so i only have to recalulate values on the edges when the viewport is moving.
I have read an article about this system :
Essentially they provide a way to scroll a potentially infinite data
field through a fixed size multi-resolution cache.
So my pipline for the generation part would be:
When viewport moves get axis
Shift the axis
Generate some noise only for the new cells
Triangulate the new cells
Update all cell positions
Here are my other images:
http://forum.unity3d.com/threads/array-shifting-wrong-index-i-x-y-size-z-size-size.425448/#post-2751774
Nobody in the unity forums could answer my question...
public int size;
public float speed;
private byte[] volume;
private byte[] shifted;
public bool widthShift, heightShift, depthShift;
private int widthOffset = 0;
private int heightOffset = 0;
private int depthOffset = 0;
private float time = 0;
private int cube;
void Start()
{
volume = new byte[size * size * size];
shifted = new byte[size * size * size];
cube = size * size * size;
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for(int z = 0; z < size; z++)
volume[x + y * size + z * size * size] = (x == 0 || y == 0 || z == 0) ? (byte)1 : (byte)0;
}
void Update()
{
time += Time.fixedDeltaTime * speed;
if (time > 1)
{
time = 0;
widthOffset = (widthOffset >= size) ? 0 : widthOffset;
heightOffset = (heightOffset >= size) ? 0 : heightOffset;
depthOffset = (depthOffset >= size) ? 0 : depthOffset;
if (widthShift)
widthOffset++;
else
widthOffset = 0;
if (heightShift)
heightOffset++;
else
heightOffset = 0;
if (depthShift)
depthOffset++;
else
depthOffset = 0;
Shift(widthOffset, heightOffset, depthOffset);
}
}
void Shift(int xOff, int yOff, int zOff)
{
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for(int z = 0; z < size; z++)
{
int i = ((x + xOff) + (y + yOff) * size + (z + zOff) * size * size);
i = (i >= cube) ? (i - cube) : i;
shifted[x + y * size + z * size * size] = volume[i];
}
}
void OnDrawGizmos()
{
if(Application.isPlaying)
for(int x = 0; x < size; x++)
for(int y = 0; y < size; y++)
for(int z = 0; z < size; z++)
{
Gizmos.color = (shifted[x + y * size + z * size * size] == 1) ? new Color32(0, 255, 0, 255) : new Color32(255, 0, 0, 4);
Gizmos.DrawWireCube(new Vector3(x + 0.5f, y + 0.5f, z + 0.5f), new Vector3(0.95f, 0.95f, 0.95f));
}
}
Give it a try:
void Shift(int xOff, int yOff, int zOff)
{
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for(int z = 0; z < size; z++)
{
int nx = (x + xOff) % size;
int ny = (y + yOff) % size;
int nz = (z + zOff) % size;
int i = (nx + ny * size + nz * size * size);
shifted[x + y * size + z * size * size] = volume[i];
}
}

Getting vertices and indices from a List<Vector3>

I am trying to achieve drawing triangles from a list of Vector3 Elements.
Previously I have used a heightmap to create vertices and indices however this worked out well because it was a rectangle in a 2d array but not a list.
How would I go about (or modify) my existing code to deal with a list instead of a 2d array.
My existing code for Vertices:
public VertexPositionNormalTexture[] getVerticies(float[,] heightData)
{
VertexPositionNormalTexture[] vertices = new VertexPositionNormalTexture[terrainLength * terrainWidth];
for (int y = 0; y < terrainLength; y++)
{
for (int x = 0; x < terrainWidth; x++)
{
// position the vertices so that the heightfield is centered
// around x=0,z=0
vertices[x + y * terrainWidth].Position.X = terrainScale * (x - ((terrainWidth - 1) / 2.0f));
vertices[x + y * terrainWidth].Position.Z = terrainScale * (y - ((terrainLength - 1) / 2.0f));
vertices[x + y * terrainWidth].Position.Y = (heightData[x, y] - 1);
vertices[x + y * terrainWidth].TextureCoordinate.X = (float)x / terrainScale;
vertices[x + y * terrainWidth].TextureCoordinate.Y = (float)y / terrainScale;
}
}
return vertices;
}
Here is the code for indices:
public int[] getIndicies()
{
int counter = 0;
int [] indices = new int[(terrainWidth - 1) * (terrainLength - 1) * 6];
for (int y = 0; y < terrainLength - 1; y++)
{
for (int x = 0; x < terrainWidth - 1; x++)
{
int lowerLeft = x + y * terrainWidth;
int lowerRight = (x + 1) + y * terrainWidth;
int topLeft = x + (y + 1) * terrainWidth;
int topRight = (x + 1) + (y + 1) * terrainWidth;
indices[counter++] = topLeft;
indices[counter++] = lowerRight;
indices[counter++] = lowerLeft;
indices[counter++] = topLeft;
indices[counter++] = topRight;
indices[counter++] = lowerRight;
}
}
return indices;
}
You'd be looking at List<List<float> or whichever type you're working with here.
Syntax might change slightly.

Getting the height and width of a polygon on a certain plane

I'm currently using the following to apply a texture to a polygon formed by TriangleList
public static VertexPositionColorTexture[] TextureMapping(VertexPositionColorTexture[] vertices, float xScale, float yScale)
{
bool initialized = false;
float x, y;
float lX = 0, hX = 0, lY = 0, hY = 0;
for (int i = 0; i < vertices.Length; i++)
{
x = vertices[i].Position.X;
y = vertices[i].Position.Y;
if (!initialized)
{
hX = x;
lX = x;
hX = y;
hY = y;
initialized = true;
}
else
{
if (x > hX)
{
hX = x;
}
else if (x < lX)
{
lX = x;
}
if (y > hY)
{
hY = y;
}
else if (y < lY)
{
lY = y;
}
}
}
float width = (Math.Abs(lX) + Math.Abs(hX)) / xScale;
float height = (Math.Abs(lY) + Math.Abs(hY)) / yScale;
for (int i = 0; i < vertices.Length; i++)
{
vertices[i].TextureCoordinate.X = vertices[i].Position.X / width;
vertices[i].TextureCoordinate.Y = vertices[i].Position.Y / height;
}
return vertices;
This currently works fine for a polygon that has points that all have Z=0 (example: (0,0,0) (0,10,0) (10,10,0) (10,0,0)) but doesn't work for any that are rotated or not flat along the z (example (0,0,0) (0,0,10) (0,10,10) (0,10,0)). The only solution I have come with is to get the plane that the polygon lies on (it will always be flat) and somehow rotate or translate the vertices in the above method to flatten it to the xy line to allow for the correct height and width to be determined. Anyone point me in the right direction, or suggest something else?
Solved this myself by re-writing and rotating the polygon to the z plane.

Categories

Resources