How to compute bounding box/sphere across multiple meshes (C#) - c#

I load multiple meshs from .x files in different mesh variables.
Now I would like to calculate the bounding sphere across all the meshes I have loaded (and which are being displayed)
Please guide me how this could be achieved.
Can VertexBuffers be appended togather in one variable and the boundingSphere be computed using that? (if yes how are they vertexBuffers added togather)
Otherwise what alternative would you suggest!?
Thankx

Its surprisingly easy to do this:
You need to, firstly, average all your vertices. This gives you the center position.
This is done as follows in C++ (Sorry my C# is pretty rusty but it should give ya an idea):
D3DXVECTOR3 avgPos;
const rcpNum = 1.0f / (float)numVerts; // Do this here as divides are far more epxensive than multiplies.
int count = 0;
while( count < numVerts )
{
// Instead of adding everything up and then dividing by the number (which could lead
// to overflows) I'll divide by the number as I go along. The result is the same.
avgPos.x += vert[count].pos.x * rcpNum;
avgPos.y += vert[count].pos.y * rcpNum;
avgPos.z += vert[count].pos.z * rcpNum;
count++;
}
Now you need to go through every vert and work out which vert is the furthest away from the center point.
Something like this would work (in C++):
float maxSqDist = 0.0f;
int count = 0;
while( count < numVerts )
{
D3DXVECTOR3 diff = avgPos - vert[count].pos;
// Note we may as well use the square length as the sqrt is very expensive and the
// maximum square length will ALSO be the maximum length and yet we only need to
// do one sqrt this way :)
const float sqDist = D3DXVec3LengthSq( diff );
if ( sqDist > maxSqDist )
{
maxSqDist = sqDist;
}
count++;
}
const float radius = sqrtf( maxSqDist );
And you now have your center position (avgPos) and your radius (radius) and, thus, all the info you need to define a bounding sphere.

I have an idea, what I would do is that I would determine the center of every single mesh object, and then determine the center of the collection of mesh objects by using the aforementioned information ...

Related

finding unknown 4th point in arbitrary space programmatically

Problem:
I know the x and y of three arbitrary points on a 2d plane.
I know the vague distance from each point to the unknown, though I don't know the x y components.
I want to find the position of the 4th point.
The data is stored in a list >3 of type Data where
public class Data
{
double m_x, m_y, m_distance;
}
I've tried:
Walking the list, calculating the components of the distance, then adding the known x and y. I then calculated the average position of the predicted point from the 3 known points, but the accuracy was inconsistent.
foreach (var item in data_list)
{
var dx = item.m_x + item.m_distance * Math.Cos(item.m_distance);
var dy = item.m_y + item.m_distance * Math.Sin(item.m_distance);
out_list.Add(new Data { m_x = dx, m_y = dy });
}
foreach (var item in out_list)
{
__dx += item.m_x;
__dy += item.m_y;
}
__dx /= return_list.Count;
__dy /= return_list.Count;
Creating three circles at the known x and y, extending their radii equal to the distance component and checking intersection. The problem is that the distance varies since its rather imprecise, more like a suggestion.
Is there a simple, ok-performing, witty solution to this problem that I can't grasp?
I've thought of extending lines 360 degrees around each point and checking where three lines intersect, the shortest distance away from the origin, but I'm not entirely sure about the implementation.

Unity find objects within range of two angles and with a max length (pie slice)

I've been programming an ability for a Hack n Slash which needs to check Units within a pie slice (or inbetween two angles with max length). But I'm stuck on how to check whether an unit is within the arc.
Scenario (Not enough, rep for an image sorry im new)
I currently use Physics2D.OverlapSphere() to get all of the objects within the maximum range. I then loop through all of the found objects to see whether they are within the two angles I specify. Yet this has janky results, probably because angles don't like negative values and value above 360.
How could I make this work or is there a better way to do this?
I probably need to change the way I check whether the angle is within the bounds.
Thanks in advance guys! I might respond with some delay as I won't be at my laptop for a couple hours.
Here is the code snippet:
public static List<EntityBase> GetEntitiesInArc(Vector2 startPosition, float angle, float angularWidth, float radius)
{
var colliders = Physics2D.OverlapCircleAll(startPosition, radius, 1 << LayerMask.NameToLayer("Entity"));
var targetList = new List<EntityBase>();
var left = angle - angularWidth / 2f;
var right = angle + angularWidth / 2f;
foreach (var possibleTarget in colliders)
{
if (possibleTarget.GetComponent<EntityBase>())
{
var possibleTargetAngle = Vector2.Angle(startPosition, possibleTarget.transform.position);
if (possibleTargetAngle >= left && possibleTargetAngle <= right)
{
targetList.Add(possibleTarget.GetComponent<EntityBase>());
}
}
}
return targetList;
}
Vector2.Angle(startPosition, possibleTarget.transform.position);
This is wrong. Imagine a line from the scene origin (0,0) to startPosition and a line to the transform.position. Vector2.Angle is giving you the angle between those two lines, which is not what you want to measure.
What you actually want is to give GetEntitiesInArc a forward vector then get the vector from the origin to the target position (var directionToTarget = startPosition - possibleTarget.transform.position) and measure Vector2.Angle(forward, directionToTarget).

Moving mouse in direction and rate

I'm trying to create a simple mouse emulator controlled by a joystick's right thumbstick. I was trying to have the mouse move in the direction the stick pointed with a smooth gradient of pressure values dictating speed, but I've hit a number of snags when trying to do so.
The first is how to accurately translate the angle into accurate X and Y values. I can't find a way to implement the angle correctly. The way I have it, the diagonals are likely to move considerably faster than the cardinals.
I was thinking I need something like Math.Cos(angle) for the X values, and Math.Sin(angle) for the Y values to increment the mouse, but I can't think of a way to set it up.
The second, is smooth movement of the mouse, and this is probably the more important of the two. Since the SetPosition() function only works with integers, the rate at which pixels move over time seems very limited. The code I have is very basic, and only registers whole number values of 1-10. That not only creates small 'jumps' in acceleration, but limits diagonal movement as well.
The goal would to have something like 10 pixels-per-second, with the program running at 100hz, and each cycle outputting 0.1 pixel movement.
I'd imagine I might be able to keep track of the pixel 'decimals' for the X and Y values and add them to the axes when they build to whole numbers, but I'd imagine there's a more efficient way to do so and still not anger the SetPosition() function.
I feel like Vector2 objects should get this done, but I don't know how the angle would fit in.
Sample code:
//Poll Gamepad and Mouse. Update all variables.
public void updateData(){
padOne = GamePad.GetState(PlayerIndex.One, GamePadDeadZone.None);
mouse = Mouse.GetState();
currentStickRX = padOne.ThumbSticks.Right.X;
currentStickRY = padOne.ThumbSticks.Right.Y;
currentMouseX = mouse.X;
currentMouseY = mouse.Y;
angle = Math.Atan2(currentStickRY, currentStickRX);
vectorX = (int)( currentStickRX*10 );
vectorY = (int)( -currentStickRY*10 );
mouseMoveVector.X = vectorX;
mouseMoveVector.Y = vectorY;
magnitude = Math.Sqrt( Math.Pow( (currentStickRX - 0), 2 ) + Math.Pow( (currentStickRY - 0), 2 ) );
if (magnitude > 1){
magnitude = 1;
}
//Get values not in deadzone range and re-scale them from 0-1
if(magnitude >= deadZone){
activeRange = (magnitude - deadZone)/(1 - deadZone);
}
Console.WriteLine(); //Test Code
}
//Move mouse in in direction at specific rate.
public void moveMouse(){
if (magnitude > deadZone){
Mouse.SetPosition( (currentMouseX + vectorX), (currentMouseY + vectorY));
}
previousStickRX = currentStickRX;
previousStickRY = currentStickRY;
previousActiveRange = activeRange;
}
Note: I'm using all the xna frameworks.
Anyway, apologies if I'm explaining these things incorrectly. I haven't been able to find a good resource for this, and the vector examples I searched only move in integer increments and from point A to B.
Any help with any part of this is greatly appreciated.
I haven't tried it myself but from my point of view, you should normalize the pad axis after reading them, that way diagonals would move the same speed as cardinals. And for the second part, I would keep track of the mouse in floating variables, such as a Vector2 and do the cast (maybe rounding better) when setting the mouse position.
public void Start()
{
mousePosV2 = Mouse.GetState().Position.ToVector2();
}
public void Update(float dt)
{
Vector2 stickMovement = padOne.ThumbSticks.Right;
stickMovement.Normalize();
mousePosV2 += stickMovement*dt*desiredMouseSpeed;
/// clamp here values of mousePosV2 according to Screen Size
/// ...
Point roundedPos = new Point(Math.Round(mousePosV2.X), Math.Round(mousePosV2.Y));
Mouse.SetPosition(roundedPos.X, roundedPos.Y);
}

Xna Isometric point to click movement

I'm working on an isometric game (diamond grid) and I've stumbled across a minor problem regarding a character movement.
I'm using A* to find a path between 2 points and then I want to move my character from point A to point B going through all the tiles which form the path but I can't find a way to do this , I mean a simpler and accurate method.
So far I've scrapped this piece of code but it's kinda "rusty"
public void Destination(tile destination)
{
for (int i = 0; i < 8; i++)
{
if (AdjacentTile[i] == destination)
{
characterDirection = i;
}
}
animation.changeSpriteDirection(characterDirection); //After I found which adjacent tile is the next destination I change the character direction based on it's position (1 = North , 2 = Nort Est etc) .. so the Y of the Animation_sourceRectangle it's changed//
Vector2 Position;
Position.X = current_characterTile.X - destination.X;
Position.Y = current_characterTile.Y - destination.Y;
rotation = (float)Math.Atan2(-Position.X, Position.Y);
moveVector = (Vector2.Transform(new Vector2(0, -1), Matrix.CreateRotationZ(rotation))) * characterSpeed;
movingCommand = 1; // the character is supposed to be moving..
Move(); //this function moves the sprite until the *tile.i and tile.j* of the character is the same as tile.j and tile.i of the destination
//something like this
if ( characterTile.i == destination.i && characterTile.j == destination.j)
movingCommand = 0 //stop
else
character_Position += moveVector;
}
If anyone could give me a hint on what to do or help me I'll be very grateful.
Thank You.
Possibilities:
At each tile, determine the character's speed vector and also determine how much time it will take for the character to move to next tile. When that time elapses, immediately begin moving to the next tile. (This is what I implemented below.)
At each tile, determine the character's speed vector. Then, when the character is sufficiently close to the next tile (say, the difference between their X and Y coordinates is less than 2 pixels?), snap it to the tile and begin moving to the next tile. This will causes artifacts and be in general less precise.
A solution:
Let's assume you already ran your pathfinding algorithm and found a linked list of a tiles that you must go through to arrive at target. Let's also assume those tiles cannot become blocked partway through the movement (it is simple to modify the algorithm if they can, though).
I usually do something like this to handle this problem:
Run the pathfinding algorithm, which returns a List, if a path
exists.
character.Path = theListThatAStarReturned;
character.beginMovingToTarget(character.Path[0]);
character.Path.RemoveAt(0);
The beginMovingToTarget() method will determine the velocity vector and also determine the the time needed to arrive at the tile. When the time is reached, we immediately go to the next tile, until the Path is empty. Let's call this time variable character.timeToArrival.
Update():
if (!character.Moving) return; // Or just don't execute the rest of this code.
character.position += character.speed * elapsedSeconds;
character.timeToArrival -= elapsedSeconds;
// Did the character arrive in a tile?
if (character.timeToArrival <= 0)
{
// This will ensure the character is precisely in the tile, not a few pixels veered off.
character.position = character.movingToTile.position;
if (character.Path.Count == 0)
{
character.Moving = false;
// We are at final destination.
}
else
{
character.beginMovingToTarget(character.Path[0]);
character.Path.RemoveAt(0);
}
}
And the beginMovingToTarget(targetTile) function:
this.movingToTile = targetTile;
Vector2 direction;
direction = targetTile.position - this.position;
this.timeToArrival = direction.Length() / this.speedPerSeconds;
direction.Normalize();
direction *= this.speedPerSeconds;
this.speed = direction;
// Here, you may also want to change the character's animation, if you want to, or you may do that directly in the Draw() method based on its speed vector.
Make sure the division is in floats, not integers.

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