I've been working on adding a line-of-sight/ray-tracing system to my 3d block-world game. I've tried several different methods and they all work fairly well. At the moment I'm using something similar to what Bukkit uses.
Essentially, using the point of origin (the player location, plus the extra height for the "eye" of the camera), and the current
pitch, I'm looking for every block that the line of sight would pass through.
For the most part it works - however, the "ray" is always slightly off, by roughly half a block or so. What I mean is, as I slowly move my cursor left/right or up/down, the block I'm actually focusing on doesn't "highlight" (for testing, I set it to snow) until the cursor is roughly to the middle. This offset varies a bit based on my angle to the block.
It seems like when my cursor is on the left 50% of a block, the block to the left highlights. The top 50% of the block, the block above highlights. Same for right/bottom 50%s.
I'm trying to understand where this discrepancy is coming from. I've been tweaking and toying with code based on the assumption that one of the following is the issue:
- The "eye" offset or the player's location are wrong. I'm using the same y offset the camera uses and as far as I can tell from collision, the standing location of the player is accurate
- The ray somehow needs adjusted yaw/pitch values? I don't see how, those yaw/pitch values are used for the camera. They should describe the exact direction the ray needs
- The "normalization" code for the vector is wrong. I've found essentially same code in multiple examples, and it seems like it doesn't round/cast values, so I shouldn't be losing anything
I'm looking for advise on:
- What values are the most likely cause for a half-block offset?
- or, how do I fix?
The player's camera is set like this:
GL11.glLoadIdentity(); GL11.glRotatef(pitch, 1.0f, 0, 0); GL11.glRotatef(360.0f - yaw, 0, 1.0f, 0); GL11.glTranslatef(-position.x, -position.y - EYE_HEIGHT, -position.z);
The "direction" vector is normalized like this:
Vector vector = new Vector(0,0,0); vector.setY( (float)-Math.sin(Math.toRadians(pitch)) ); float v = (float)Math.cos(Math.toRadians(pitch) ); vector.setX( (float)(Math.sin(Math.toRadians(yaw))*-v) ); vector.setZ( (float)(Math.cos(Math.toRadians(yaw))*v) );
And the player's location is essentially just a `Vector3f.
I've found several alternate methods of calculating the right info here on gamedev, but the code I have is so close it doesn't seem worth ditching. Though I will if needed, lol.