代码之家  ›  专栏  ›  技术社区  ›  user8780062

将精灵添加到Pygame光线投射引擎

  •  0
  • user8780062  · 技术社区  · 7 年前

    我目前正在使用pygame光线投射引擎pyray( https://github.com/oscr/PyRay/blob/master/pyray.py ),我想问一些问题:

    1) 如何添加一个不是a细胞的精灵,就像Wolfenstein 3D中的敌人?

    2) 你如何制作墙壁图像,而不是色块?

    1 回复  |  直到 7 年前
        1
  •  0
  •   Spektre    7 年前
    1. 纹理

      第一次看到 Ray Casting with different height size

      您需要的是更改引擎的扫描线渲染以使用纹理。这个 C++ 以上链接中的代码仅供初学者使用(请查找 // render scan line perspective correct texture mapping .

      这就是它的样子(在我将其实现到我链接的前一个代码之后)

      void Doom3D::draw_scanline(int sx,int sy0,int sy1,int sz0,int sz1,int symin,int tx0,int ty0,int tx1,int ty1,DWORD li)
          {
          //
          union { DWORD dd; BYTE db[4]; } cc;
          int Txs=txs*tn;
          if (sz0==sz1)   // affine texture mapping (front side of walls)
              {
              int sy,tx,ty,ktx,kty,dtx,dty,ctx,cty,dsy;
                     dsy=sy1-sy0; if (dsy<0)                        dsy=-dsy;
              ktx=0; dtx=tx1-tx0; if (dtx>0) ktx=+1; else { ktx=-1; dtx=-dtx; } tx=tx0; ctx=0;
              kty=0; dty=ty1-ty0; if (dty>0) kty=+1; else { kty=-1; dty=-dty; } ty=ty0; cty=0;
              if (dsy) for (sy=sy0;sy>=sy1;sy--)
                  {
                  if ((sy>=0)&&(sy<sys)&&(sy<=symin))
                   if ((tx>=0)&&(tx<Txs)&&(ty>=0)&&(ty<tys))
                      {
                      cc.dd=ptxr[ty][tx];
                      cc.db[0]=DWORD((DWORD(cc.db[0])*li)>>8);
                      cc.db[1]=DWORD((DWORD(cc.db[1])*li)>>8);
                      cc.db[2]=DWORD((DWORD(cc.db[2])*li)>>8);
                      pscr[sy][sx]=cc.dd;
                      }
                  for (ctx+=dtx;ctx>=dsy;) { ctx-=dsy; tx+=ktx; }
                  for (cty+=dty;cty>=dsy;) { cty-=dsy; ty+=kty; }
                  }
              }
          else{           // perspective correct mapping (floor, top side of walls, ceiling)
              int sy,tx,ty,dsy,dtx,dty,_n,n,dn;
              int a,b,_z0,_z1;
              const int acc=15;
              dsy=sy1-sy0; n=abs(dsy); dn=n;
              dtx=tx1-tx0; n=abs(dtx); if (dn<n) dn=n;
              dty=ty1-ty0; n=abs(dty); if (dn<n) dn=n;
              if (sz0==0) return; _z0=(1<<acc)/sz0;
              if (sz1==0) return; _z1=(1<<acc)/sz1;
              if (dn) for (n=0;n<=dn;n++)
                  {
                  sy=sy0+((n*dsy)/dn);
                  tx=tx0+((n*dtx)/dn);
                  ty=ty0+((n*dty)/dn);
                  // perspective correction (https://en.wikipedia.org/wiki/Texture_mapping)
                  _n=dn-n;
                  a=(_n*tx0*_z0) + (n*tx1*_z1);
                  b=(_n    *_z0) + (n    *_z1); tx=a/b;
                  a=(_n*ty0*_z0) + (n*ty1*_z1);
                  b=(_n    *_z0) + (n    *_z1); ty=a/b;
                  if ((sy>=0)&&(sy<sys)&&(sy<=symin))
                   if ((tx>=0)&&(tx<Txs)&&(ty>=0)&&(ty<tys))
                      {
                      cc.dd=ptxr[ty][tx];
                      cc.db[0]=DWORD((DWORD(cc.db[0])*li)>>8);
                      cc.db[1]=DWORD((DWORD(cc.db[1])*li)>>8);
                      cc.db[2]=DWORD((DWORD(cc.db[2])*li)>>8);
                      pscr[sy][sx]=cc.dd;
                      }
                  }
              }
          }
      

      这个 sx,sy0,sy1 屏幕是否与扫描线协调 tx0,ty0,tx1,ty1 是纹理坐标和 l0,l1 是与摄像机的距离。 li 只是光的强度。纹理坐标是每个网格单元命中坐标的分数部分。使用的纹理是atlas,因此x坐标也对使用的纹理进行编码。

      除此之外,您还应该添加mip贴图(使用接近投影单元大小的纹理分辨率),以避免在移动或旋转时远处墙上的像素闪烁。。。

    2. 对于每个对象,计算其相对于玩家的极位。所以你会有角度(相对于视图方向)和距离。你可以计算屏幕 x 直接从角度和屏幕 y0,y1 从远处看。由此,只需渲染每个扫描线+/-计算位置周围的精灵宽度。你不需要为精灵绘制透视正确的纹理贴图,因为它们总是垂直于播放器。。。

      此处需要计算: Theory behind Wolfenstein-style 3D rendering