dinsdag 16 april 2019

Correcting "Pseudo 3D Planes aka MODE7"

The formula David uses in his Programming Pseudo 3D Planes aka MODE7 (C++) is not correct.
He uses:

   for (int y = 0; y < ScreenHeight() / 2; y++)
   {
      float fSampleDepth = (float)y / ((float)ScreenHeight() / 2.0f);
      float fStartX = (fFarX1 - fNearX1) / (fSampleDepth) + fNearX1;
      float fStartY = (fFarY1 - fNearY1) / (fSampleDepth) + fNearY1;
      float fEndX = (fFarX2 - fNearX2) / (fSampleDepth) + fNearX2;
      float fEndY = (fFarY2 - fNearY2) / (fSampleDepth) + fNearY2;

      for (int x = 0; x < ScreenWidth(); x++)
      {
      ...

In the comments a guy named JohnnyCrash pointed out that David does not draw the Frustum, but from infinity till the far plane. Also he doesn't expect to see weird curvature when you change the near plane.

There is a fellow dutchman who wrote a very nice explanation about mode7. Read it.
Which will result in the correct way of drawing:

float space_y = 100.0f;
float scale_y = 200.0f;
int horizon = 40; 
for (int y = 0; y < Graphics::ScreenHalfDIMy; y++) {
 float distance = space_y * scale_y / (y + horizon);

 float fStartX = fWorldX + (cosf(fWorldAngle + fFoVHalf) * distance);
 float fStartY = fWorldY - (sinf(fWorldAngle + fFoVHalf) * distance);
 float fEndX = fWorldX + (cosf(fWorldAngle - fFoVHalf) * distance);
 float fEndY = fWorldY - (sinf(fWorldAngle - fFoVHalf) * distance);

 for (int x = 0; x < Graphics::ScreenDIMx; x++) {
  float fSampleWidth = (float)x / (float)Graphics::ScreenDIMx;
  float fSampleX = fStartX + ((fEndX - fStartX) * fSampleWidth);
  float fSampleY = fStartY + ((fEndY - fStartY) * fSampleWidth);

  Uint32 pixelColor = racetrackARGB.GetPixel(fSampleX, fSampleY);
  screenARGB.SetPixel(x, y, pixelColor);
 }
}

Which results in the following screenshot, which draws the 3d mode7 at the top and the 2d with frustum at the bottom:

5 opmerkingen:

  1. Hi Reno, I tried your example but it still doesn't work, how to calculate space_y and scale_y?

    BeantwoordenVerwijderen
    Reacties
    1. The screengrab is taking from the code that is posted, so it works.
      The space_y is the "height". A value close to zero will put you on the ground. A big value high in the air. The scale_y is a number that defines how every "y" is translated to screenpixels. You see in the code that the distance is a division of 20000/(y+40).

      Verwijderen
    2. You can download my code from:
      http://www.vergeestelijking.nl/_nietweg/Mode7_20211128.zip

      Verwijderen
  2. I wanted to understand what exactly the variables "space_y" and "scale_y" would be...

    BeantwoordenVerwijderen
  3. The screengrab is taking from the code that is posted, so it works.
    The space_y is the "height". A value close to zero will put you on the ground. A big value high in the air. The scale_y is a number that defines how every "y" is translated to screenpixels. You see in the code that the distance is a division of 20000/(y+40).

    You can download the code from:
    http://www.vergeestelijking.nl/_nietweg/Mode7_20211128.zip

    BeantwoordenVerwijderen