aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortslil clingman <>2021-09-05 18:03:56 -0400
committertslil clingman <>2021-09-05 19:36:00 -0400
commit1c4874c9f2855ee776bf8d5c35aef3d245c0519d (patch)
tree7478157a9a0841542eb01bd3c5937f07ad39e687 /src
parentb1086c978996e522f133b4c6bdc59c95016eec0a (diff)
I don't understand this, but it works ...
For whatever reason, we /can/ compensate for the TERRIBLE linear interpolation hacks on direction (and so distance) computations for the walls and floors. We do this by scaling the otherwise exact and correct computations for the perp_distance and centre of an object by the magic number FOV_SCALE = 2 * tan(FOV / 2) Why? Who knows. This is a little frustrating, because it means i don't understand some part of the rendering process.
Diffstat (limited to 'src')
-rw-r--r--src/raycast.zig33
1 files changed, 20 insertions, 13 deletions
diff --git a/src/raycast.zig b/src/raycast.zig
index 20597e9..1f1fd7f 100644
--- a/src/raycast.zig
+++ b/src/raycast.zig
@@ -54,7 +54,8 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type {
const PlanePixels = PlaneWidth * PlaneHeight;
// given the desired width of the image, how far away must
// the projection plane be from the camera?
- const PlaneDist = PlaneWidth / (2 * std.math.tan(FOV / 2));
+ const FOV_SCALE = 2 * std.math.tan(FOV / 2);
+ const PlaneDist = PlaneWidth / FOV_SCALE;
// standing still at the given location, looking in direction ang,
pub fn new(pos_x: f32, pos_y: f32, ang: f32) !@This() {
@@ -131,25 +132,34 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type {
for (map.objects.items) |obj| {
const ox = obj.pos_x - self.pos_x;
const oy = obj.pos_y - self.pos_y;
- // we compute the two coordinates of rotating by -self.ang, the
+
+ // We compute the two coordinates of rotating by -self.ang, the
// first of which gives the perpendicular distance to the plane
// of projection, and the second of which gives the
// (unprojected) centre of the object.
const perp_distance = self_cos * ox + self_sin * oy;
const centre = self_sin * ox - self_cos * oy;
+
+ // NOTE: in the below we have applied the magic scaling factor
+ // of FOV_SCALE. I don't understand how this compensates for the
+ // linear interpolation incorrectness we do elsewhere, but
+ // somehow it scales the *correct* values we compute above into
+ // whatever agrees with the wall and floor rendering voodoo.
+
+ // This quantity is independent of FOV_SCALE because it enters
+ // both via centre and perp_distance
const proj_centre = PlaneWidth / 2 + PlaneDist * centre / perp_distance;
- const width = PlaneDist * obj.width / perp_distance;
+ // Here's the magic adjustment
+ const scaled_perp_distance = FOV_SCALE * perp_distance;
+ const width = PlaneDist * obj.width / scaled_perp_distance;
const left = proj_centre - width / 2;
// TODO: prune before this?
if (left + width < 0 or left >= PlaneWidth) continue;
- // TODO: Here's another fudge factor. I think this is something
- // like the floors and walls aren't actually distance correct,
- // so we have to toy with these exact calculations to fix it.
- const height = PlaneDist * obj.height / perp_distance;
- const top = PlaneHeight / 2 + PlaneDist * (obj.height + 0.2 - self.height) / perp_distance;
+ const height = PlaneDist * obj.height / scaled_perp_distance;
+ const top = PlaneHeight / 2 + PlaneDist * (obj.height - self.height) / scaled_perp_distance;
// TODO: likewise?
if (top < 0 or top - height >= PlaneHeight) continue;
@@ -166,12 +176,9 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type {
tex_frac += tex_frac_step;
}) {
var bottom = std.math.min(top, PlaneHeight);
- while (bottom > 0 and bottom > top - height) : (bottom -= 1) {
+ while (bottom >= 0 and bottom >= top - height) : (bottom -= 1) {
const index = @intCast(usize, col * @floatToInt(i32, PlaneHeight) + @floatToInt(i32, bottom));
- // TODO: what is this fudge factor? Is this again
- // because distances aren't actually correct in the
- // z_buffer but they are in this computation?
- if (self.z_buffer.get(index) < perp_distance + 1) {
+ if (self.z_buffer.get(index) < scaled_perp_distance) {
bottom += 1;
break;
}