World.QueryAABB giving incorrect results in libgdx - scala

I'm trying to implement mouse selection for my game. When I QueryAABB it looks like it's treating objects much larger than they really are.
Here's what's going on in the image
The blue box is an actor containing a body that I'd like to select
The outline on the blue box is drawn by Box2DDebugRenderer
The mouse selects a region on the screen (white box), this is entirely graphical
The AABB is converted to meters and passed to QueryAABB
The callback was called for the blue box and turned it red
The green outline left behind is a separate body to check if my conversions were correct, this is not used for the actual selection process
It seems to be connected to my meter size, the larger it is, the more inaccurate the result is. At 1 meter = 1 pixel it works perfectly.
Meter conversions
val MetersToPixels = 160f
val PixelsToMeters = 1/MetersToPixels
def toMeters(n: Float) = n * PixelsToMeters
def toPixels(n: Float) = n * MetersToPixels
In the image I'm using MetersToPixels = 160f so the inaccuracy is more visible, but I really want MetersToPixels = 16f.
Relevant selection code
val x1 = selectPos.x
val y1 = selectPos.y
val x2 = getX
val y2 = getY + getHeight
val (l,r) =
if (x2 < x1)
(x2,x1)
else
(x1,x2)
val (b,t) =
if (y2 < y1)
(y2,y1)
else
(y1,y2)
world.QueryAABB(selectCallback, toMeters(l),toMeters(b), toMeters(r),toMeters(t))
This code is inside the act method of my CursorActor class. And selectPos represents the initial point where the use pressed down the left mouse button and getX and getY are Actor methods giving the current position. The next bit sorts them because they might be out of order. Then they are converted to meters because they are all in pixel units.
selectCallback: QueryCallback
override def reportFixture(fixture: Fixture): Boolean = {
fixture.getBody.getUserData match {
case selectable: Selectable =>
selected += selectable
true
case _ => true
}
}
Selectable is a trait that sets a boolean flag internally after the query which helps determines the color of the blue box. And selected is a mutable.HashSet[Selectable] defined inside of CursorActor.
Other things possibly worth noting
I'm new to libgdx and box2d.
The camera is scaled x2
My Box2DDebugRenderer uses the camera's combined matrix multiplied by MetersToPixels

From what I was able to gather, QueryAABB is naturally inaccurate for optimization. However, I've hit a roadblock with libgdx because it doesn't have any publicly visible function like b2testOverlap and from what I understand, there's no plan for there to be one any time soon.
I think my best solution would probably be to use jbox2d and pretend that libgdx's physics implementation doesn't exist.
Or as noone suggested I could add it to libgdx myself.
UPDATE
I decided to go with a simple solution of gathering the vertices from the fixture's shape and using com.badlogic.gdx.math.Intersector against the vertices of the selection. It works I guess. I may stop using QueryAABB all together if I decide to switch to using a sensor for the select box.

Related

Swift UIKit dynamics - Vary UIPushBehavior force magnitude by distance from center of source

Can someone suggest how I can vary the UIPushBehavior magnitude force by distance from source. To mirror the affect of the force of wind from a fan on another object. So the closer the object is to the fan the stronger the force.
if String(describing: identifier) == "fan1" {
self.push = UIPushBehavior(items: [self.object], mode: .instantaneous)
self.push.setAngle(.pi/4, magnitude: 1)
self.animator.addBehavior(self.push)
self.push.addItem(self.object)
}
Use a UIFieldBehaviour to create a linear gravitational field in the direction of the fan. Then you can specify a falloff:
var forceField: UIFieldBehaviour!
// ...
forceField = UIFieldBehavior.linearGravityField(direction: CGVector(dx: 1, dy: -5))
// example values for a "fan" on the bottom left blowing mostly upwards:
forceField.position = CGPoint(x: view.bounds.minX, y: view.bounds.maxY)
forceField.region = UIRegion(radius: 3000)
forceField.minimumRadius = 100
forceField.falloff = 5
forceField.strength = 10
forceField.addItem(view1)
forceField.addItem(view2)
animator.addBehavior(forceField)
Have fun playing around with these values!
Adding collision, another gravity behaviour, and a dynamic item behaviour to two views, we get the following effect:
That feels like a fan on the bottom left to me!
You can also choose a radial gravitational field positioned at where the fan is, if your fan is in a corner and blows "radially", but note that you should use a negative value for strength in that case to say that the field repels rather than attracts.

Confused about get_rays function in NeRF

I've been trying to understand NeRF. I finished reading the paper(Tancik) and watched some of the videos. I have been looking at some parts of the code. However, I can't quite wrap my head around what the get_rays function does in terms of the code. Could anybody just run through line-by-line about what each line in the the get_rays function is supposed to do?
def get_rays(H,W , focal, c2w): #c2w is pose
i, j = tf.meshgrid(tf.range(W, dtype=tf.float32), tf.range(H, dtype=tf.float32), indexing='xy')
dirs = tf.stack([(i-W*.5)/focal, -(j-H*.5)/focal, -tf.ones_like(i)], -1)
rays_d = tf.reduce_sum(dirs[..., np.newaxis, :] * c2w[:3,:3], -1)
rays_o = tf.broadcast_to(c2w[:3,-1], tf.shape(rays_d))
return rays_o, rays_d
It creates two lists, rays_o represents points where rays originate (camera centre) and rays_d represents direction vectors of each ray casting through the centre of every pixel of the camera. In this case, all values in the rays_o are the same because the function gets rays from a single camera.

my shader is ignoring my worldspace height

Im VERY new to shaders so bear with me. I have a mesh that I want to put a sand texture on below a worldspace position y of say 10 else it should be a grass texture. Apparantly it seems to be ignoring anything I put in and only selecting the grass texture. Something IS happening because my vert and tris count explodes with this function, compared to if I just return the same texture. I just dont see anything no matter what my sandStart value is
this is in my frag function:
if (input.positionWS.y < _SandStart) {
return tex2D(_MainTex, input.uv)* mainLight.shadowAttenuation;
} else {
return tex2D(_SandTex, input.uv) * mainLight.shadowAttenuation;
}
Is there also a way I can easily debug some of the values?
Please note that the OP figured out that their specific problem wasn't caused by the code in the question, but an error in their geometry function, this answer is only about the question "Is there a way to debug shader values" as this debugging method helped the OP find the problem
Debugging shader code can be quite a challenging task, depending on what it is you need to debug, and there are multiple approaches to it. Personally the approach I like best is using colours.
if we break it down there are three aspects in your code that could be faulty:
the value of input.positionWS.y
the if statement (input.positionWS.y < _SandStart)
Returning your texture return tex2D(_MainTex, input.uv)* mainLight.shadowAttenuation;
Lets walk down the list and test each individually.
checking if input.positionWS.y actually contains a value we expect it to contain. To do this we can set any of the RGB channels to its value, and just straight up returning that.
return float4(input.positionWS.y, 0, 0, 1);
Now if input.positionWS.y isn't a normalized value (a.k.a a value that ranges from 0 to 1) this is almost guaranteed to just return your texture as entirely red. To normalize it we divide the value by its max value, lets take max = 100 for the exmaple.
return float4(input.positionWS.y / 100, 0, 0, 1);
This should now make the texture full red at the top (where input.positionWS.y / 100 would be 1) and black at the bottom (where input.positionWS.y / 100 is zero), and a gradient from black to full red inbetween. (Note that since its a position in world space you may need to move the texture up/down to see the colour shift). If this doesn't happen, for example it always stays black or full red then your issue is most likely the input.positionWS.y.
The if statement. It could be that your statement (input.positionWS.y < _SandStart) always returns either true or false, meaning it'll never split. We can test this quite easily by commenting out the current return texture, and instead just return a flat colour like so:
if(input.positionWS.y < _SandStart)
{
return float4(1,0,0,1);
}
else
{
return float4(0,0,1,1);
}
if we tested the input.positionWS.y to be correct in step 1, and _SandStart is set correctly we should see the texture be divided in parts red (if true) and the other part blue (if false) (again since we're basing off world position we might need to change the material's height a bit to see it). If this division in colours doens't happen then the likely cause is that _SandStart isn't set properly, or to an incorrect value. (assuming this is a property you can inspect its value in the material editor)
if both of above steps yield the expected result then return tex2D(_MainTex, input.uv)* mainLight.shadowAttenuation; is possibly the culprit. To debug this we can return one of the textures without the if statement and shadowAttenuation, see if it applies the texture, and then return the other texture by changing which line is commented.
return tex2D(_MainTex, input.uv);
//return tex2D(_SandTex, input.uv);
If each of these textures gets applied properly seperately then it is unlikely that that was your cause, leaving either the shadowAttenutation (just add the multiplication to the above test) or something different altogether that isn't covered by the code in your question.
bonus round. If you got a shader property you want to debug you can actually do this from C# as well using the material.Get<type> function (the supported types can be found in the docs here, and include the array variants too, as well as both Get and Set). a small example:
Properties
{
_Foo ("Foo", Float) = 2
_Bar ("Bar", Color) = (1,1,1,1)
}
can be debugged from C# using
Material mat = getComponent<Material>();
Debug.LogFormat("_Foo value: {0}", mat.GetFloat("_Foo"); //prints 2
Debug.LogFormat("_Bar value: {0}", mat.GetFloat("_Bar"); //prints (1,1,1,1)

Grouping (without collision), adding and removing multiple bodies and polygons in pymunk?

I'm using code from the pymunk index_video to create a generic function that creates multiple cars which race each other and if they reach the right extreme of the screen, they are removed from Space and re-generated on the left extreme of the screen.
The problem is, that in the example code, each part of the car (chassis, pin joint, motor, wheels) is added to Space separately. I wanted to treat the entire car as a single body whose coordinates I can keep track of by storing the reference of the entire car body in a List and add or delete it to the Space easily.
Also, if the wheels are too close to the chassis, they collide with each other. I presume using a ShapeFilter can help avoid such collisions, but for that I need all parts of the car as a single body.
Please bear with me. I'm completely new to this jargon.
def car(space):
pos = Vec2d(100,200)
wheel_color = 52,219,119
shovel_color = 219,119,52
mass = 100
radius = 25
moment = pymunk.moment_for_circle(mass, 20, radius)
wheel1_b = pymunk.Body(mass, moment)
wheel1_s = pymunk.Circle(wheel1_b, radius)
wheel1_s.friction = 1.5
wheel1_s.color = wheel_color
space.add(wheel1_b, wheel1_s)
mass = 100
radius = 25
moment = pymunk.moment_for_circle(mass, 20, radius)
wheel2_b = pymunk.Body(mass, moment)
wheel2_s = pymunk.Circle(wheel2_b, radius)
wheel2_s.friction = 1.5
wheel2_s.color = wheel_color
space.add(wheel2_b, wheel2_s)
mass = 100
size = (50,30)
moment = pymunk.moment_for_box(mass, size)
chassi_b = pymunk.Body(mass, moment)
chassi_s = pymunk.Poly.create_box(chassi_b, size)
space.add(chassi_b, chassi_s)
vs = [(0,0),(25,45),(0,45)]
shovel_s = pymunk.Poly(chassi_b, vs, transform = pymunk.Transform(tx=85))
shovel_s.friction = 0.5
shovel_s.color = shovel_color
space.add(shovel_s)
wheel1_b.position = pos - (55,0)
wheel2_b.position = pos + (55,0)
chassi_b.position = pos + (0,-25)
space.add(
pymunk.PinJoint(wheel1_b, chassi_b, (0,0), (-25,-15)),
pymunk.PinJoint(wheel1_b, chassi_b, (0,0), (-25, 15)),
pymunk.PinJoint(wheel2_b, chassi_b, (0,0), (25,-15)),
pymunk.PinJoint(wheel2_b, chassi_b, (0,0), (25, 15))
)
speed = 4
space.add(
pymunk.SimpleMotor(wheel1_b, chassi_b, speed),
pymunk.SimpleMotor(wheel2_b, chassi_b, speed)
)
So this question is actually two questions.
A. How to make a "car object" that consists of multiple parts
There is no built in support for this, you have keep track of it yourself.
One way to do it is to create a car class that contains all the parts of the car. Something like this (not complete code, you need to fill in the full car)
class Car():
def __init__(self, pos):
self.wheel_body = pymunk.Body()
self.wheel_shape = pymunk.Circle()
self.chassi_body = pymunk.Body()
self.chassi_shape = pymunk.Poly()
self.motor = pymunk.SimpleMotor(wheel_body, chassi_body, 0)
def add_to_space(self, space)
space.add(self.wheel_body, self.wheel_shape, self.chassi_body, self.chassi_shape, self.motor)
def set_speed(self, speed)
self.motor.rate = speed
def car_position(self)
return self.chassi_body.position
B. How to make parts of the car to not collide with each other
This is quite straight forward, just as you already found the ShapeFilter is the way to go. For each "car", create a ShapeFilter and set a unique non-zero group on it. Then set that ShapeFilter as the filter property on each shape that makes up the car. It doesnt matter if the shapes belong to the same body or not, any shape with a ShapeFilter with a group set will not collide to other shapes with the same group set.

Compare value of property of all instances of class in python

I'm trying to write an object oriented program (as a learning exercise, I know there may be simpler ways to do it) in which beads bounce around a 2D plane bounded by a ring. Each bead is an object defined by a class ball. In setting the initial positions of the balls I need to check that no other ball has already been placed at the same x and y coordinates.
#Class for the beads
class ball:
NumbBalls = 0
#Constructor
def __init__(self,Beads):
self.ball = sphere(pos = vector(0,0,0), radius = radiusBall,color=color.red)
ball.NumbBalls += 1
self.ball.pos = self.createInitialPosition(Beads)
#Assign ball its initial position
def createInitialPosition(self,other):
#CODE to compare self.ball.pos and other.ball.pos which returns a unique position coordinate
#Main program
NumbBeads = 100
Beads = []#Create empty list for all the beads
#create balls in random initial positions
Beads = [ball(Beads) for item in range(NumbBeads)]
I can get this to work if I create two objects bead1 and bead2 and then pass bead1 and bead2 as arguments ie bead2 = ball(bead1) but how do I do this if I am generating a list of beads and want all of them to be compared with self. Hopefully that makes sense.
Perhaps rather than the approach you are currently taking, you should consider something along these lines (of course, with the necessary changes to your class definition/methods):
N = 100
initialPositions = []
while len(initialPositions) <= N:
newPosition = generateRandomPosition()
if newPosition in initialPositions:
pass
else:
initialPositions.append(newPosition)
ballList = [ ball(p) for p in initialPositions ]
In other words, generate a list of initial positions outside of the creation of your objects, and do whatever validation/restriction you need during that creation. Then just create your objects from that list. If N is really large, you might want to consider a dictionary (or a mutable set of some sort) instead of a list for initialPositions, to help speed up the membership testing, but it's still the same concept...