Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
horriblePencilist
Oct 18, 2012

It's a Dirt Devil!
Get it?
I'm currently working on a 3D-engine that uses Binary Space Partitioning like Doom built from scratch. The idea is that I start with the basics, and work my way up to include color indexing, multithreading, dynamic lighting etc, but as for now I'm stuck on the perspective transformation. I dug up this useful stackexchange answer which covers the necessary steps to get the coordinates, but unfortunately I can't quite grasp the concept of homogenous coordinates.
Right now I'm getting the coordinates relative to the camera's position and rotation (just along the z-axis, since you're just looking left and right for now) which works for a map-feature, but I'm unsure what to do afterwards. What is the w-component for the 3D-coordinates supposed to be? And how is the camera-coordinate system supposed to be oriented, should z be orthogonal to the projection plane? I tried following the instructions assuming w is 1 and the ground being the xy-plane, but the resulting vector ended up being infinity.
Here's my code - pardon the mess, I started with Processing because it's quick but I'm planning on switching to some form of C because Processing is severely lacking.

code:
PVector screenTransform(PVector point){
  PVector sPoint = point.copy().sub(position);
  float tX = cos(rotation)*sPoint.x+sin(rotation)*sPoint.y;
  float tY = -sin(rotation)*sPoint.x+cos(rotation)*sPoint.y;
  float w = sPoint.z;
  sPoint.x = tX*fov*width/height;
  sPoint.y = tY*fov;
  sPoint.z = (far+near)*sPoint.z/(far-near)+(2*near*far)/(near-far);
  println(sPoint);
  float u = (sPoint.x*width)/(2*w);
  float v = (sPoint.y*height)/(2*w);
  return new PVector(u, v);
}

Adbot
ADBOT LOVES YOU

horriblePencilist
Oct 18, 2012

It's a Dirt Devil!
Get it?

Doc Block posted:

I'm not really qualified to comment on your math code, but you should definitely be wary of allocating a new vector every projection. Also, use matrix math instead if at all possible.

Typically, in world space the X and Z axes are horizontal, while the Y axis is vertical. Some very early 3D engines like Quake had X & Y being horizontal and Z being vertical, and 2.5D engines like Doom had only X & Y axes (both horizontal). In screen space (sometimes called eye space), X is horizontal, Y is vertical, and Z is into/out of the screen.

The sloppy code is mostly on Processing, it can't do Matrix math - hence my desire to switch languages. I suspected that Z was supposed to be the distance from the viewer, and after some adjusting, it now seems to work properly (save for the incorrect vertex order when viewing the wall from the back, but that was expected). Here's what the correct math looks like:

code:
PVector screenTransform(PVector point){
  point.sub(position);
  float tX = cos(rotation)*point.x+sin(rotation)*point.y;
  float tY = -sin(rotation)*point.x+cos(rotation)*point.y;
  point.x = tY*fov*width/height;
  point.y = point.z*fov;
  point.z = (far+near)*tX/(far-near)+(2*near*far)/(near-far);
  float u = (point.x*width)/(2*tX);
  float v = (point.y*height)/(2*tX);
  return new PVector(u, v);
}
I still don't really understand the need for four-dimensional coordinates, though.

Edit: I noticed I never actually linked to the afformentioned stackexchange post. Here it is. I must admit it had me confused for a while because I've never seen column-major matrices before.

horriblePencilist fucked around with this message at 14:04 on Aug 1, 2017

horriblePencilist
Oct 18, 2012

It's a Dirt Devil!
Get it?
^^ Thanks for the links, I'll check them out.

Doc Block posted:

Well, if nothing else you need the w coordinate to make the vertex have 4 elements so it can be multiplied against a 4x4 matrix. The real purpose of the w coord IIRC is that it gets used to do the perspective divide. Set it to 1.0 in your vertex data and then don't worry about it.

Any language that can do arrays of floats can do matrix math, you just have to write the code yourself. For C and C++, people either write their own math libraries for vectors and matrices or use something like GLM.

Why not use a 3x4 matrix? Does it use up less resources or something?

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply