EGE光栅化三角形(无纹理)

说明:

这个demo效果很简单,可以直接用EGE的fillpoly相关函数实现,但他代表的意义不同:因为这是你自己画的,所以每一个像素点都为你所控制,能实现像素级的操作(这也是用EGE写3D的必须经过的历程),该项目下一步是实现。

效果图:

一部分在外面是为了测试裁剪

QQ截图20200312233429.png

性能:

实测开启优化后,每帧一个渐变三角形亦可稳定在60fps

代码:

如下,因为基本上都封装好了,大家完全可以直接拿DrawTrangle画。

建议留到高度熟悉EGE后详细阅读。

  1. #include <graphics.h>
  2. #include <algorithm>
  3. #include <cmath>
  4. #include <stdio.h>
  5. #include <map>
  6. using namespace std;
  7. //判断点v是否在[a,b]中
  8. //C#与JAVa的后遗症,EGEAPP
  9. namespace EA {
  10.  using namespace std;
  11. #define ct color_t
  12.  //几个全局变量
  13.  //屏幕buffer
  14.  color_t* wBuffer=nullptr;
  15.  //纹理buffer
  16.  color_t* tBuffer=nullptr;
  17.  //屏幕长宽
  18.  int W=0;
  19.  int H=0;
  20.  inline float F2I(float f) {
  21.   return floor(f);
  22.  }
  23.  //把浮点数位数强定为3位(担心爆精度
  24.  inline float F2F3(float f) {
  25.   return floor(f*1000.0f)/1000.0f;
  26.  }
  27.  template<class T>
  28.  inline bool IsCovered(T a,T b,T v) {
  29.   if(a>b) swap(a,b);
  30.   return (a<=v&&v<=b);
  31.  }
  32.  //数据类型
  33.  class Vertex2D {
  34.   public:
  35.    float x;
  36.    float y;
  37.    ct c;
  38.    inline Vertex2D() {
  39.     x=y=0.0f;
  40.     c=0;
  41.    }
  42.    inline Vertex2D(float _x,float _y,ct _c) {
  43.     x=_x,y=_y,c=_c;
  44.    }
  45.    inline void Format() {
  46.     x=EA::F2I(x);
  47.     y=EA::F2I(y);
  48.    }
  49.    inline VECTOR3D ToVec3D() {
  50.     return VECTOR3D(x,y,0);
  51.    }
  52.  };
  53.  typedef struct Vertex2D Ver2D;
  54.  //函数
  55.  //初始化绘图环境
  56.  void InitGraph(int w,int h) {
  57.   initgraph(w,h,0);
  58.   ege_enable_aa(1);
  59.   W=getwidth(),H=getheight();
  60.   wBuffer=getbuffer(NULL);
  61.  }
  62.  //颜色插值,0<=v<=1
  63.  inline ct ColorLerp(ct c1,ct c2,float v);
  64.  //2D顶点插值 
  65.  inline Ver2D V2DLerp(Ver2D v1,Ver2D v2,float t); 
  66.  //高速画点
  67.  inline void PutPixel_f(Ver2D v);
  68.  //高速画水平线
  69.  //这个会渐变
  70.  inline void DrawLine_f(float x1,float x2,float y,ct c1,ct c2);
  71.  //绘制简单三角,要求至少两个点y一样
  72.  inline void DrawSimpleTrangle(Ver2D v1,Ver2D v2,Ver2D v3);
  73.  //绘制复杂三角
  74.  inline void DrawTrangle(Ver2D v1,Ver2D v2,Ver2D v3);
  75. #undef ct
  76. }
  77. using EA::Ver2D;
  78. #define ct color_t
  79. //程序入口
  80. int main() {
  81.  EA::InitGraph(1000,600);
  82.  EA::DrawTrangle(Ver2D(0,EA::H/2,RED),Ver2D(EA::W/4,0,GREEN),Ver2D(EA::W/2,EA::H,BLUE));
  83.  delay_fps(60);
  84.  getch();
  85.  closegraph();
  86.  return 0;
  87. }
  88. ct EA::ColorLerp(ct c1,ct c2,float v) {
  89.  v=EA::F2F3(v);//可有可无,感觉没啥用
  90.  int r=EGEGET_R(c1)-EGEGET_R(c2);
  91.  int g=EGEGET_G(c1)-EGEGET_G(c2);
  92.  int b=EGEGET_B(c1)-EGEGET_B(c2);
  93.  r=r*v+EGEGET_R(c2);
  94.  g=g*v+EGEGET_G(c2);
  95.  b=b*v+EGEGET_B(c2);
  96.  return EGERGB(r,g,b);
  97. }
  98. void EA::PutPixel_f(Ver2D v) {
  99.  v.Format();
  100.  if(EA::IsCovered(0,W,int(v.x))&&EA::IsCovered(0,H,int(v.y))) {
  101.   wBuffer[int(v.x+v.y*W)]=v.c;
  102.  }
  103. }
  104. void EA::DrawLine_f(float x1,float x2,float y,ct c1,ct c2) {
  105.  if(x1>x2) swap(x1,x2);
  106.  x1=F2I(x1);
  107.  x2=F2I(x2);
  108.  y=F2I(y);
  109.  for(float i=x1; i<=x2; ++i) {
  110.   PutPixel_f(Vertex2D(i,y,ColorLerp(c1,c2,float((i-x1)/(x2-x1)))));
  111.  }
  112. }
  113. //v1.y==v2.y
  114. void EA::DrawSimpleTrangle(Ver2D v1,Ver2D v2,Ver2D v3) {
  115.  //Format
  116.  if(v2.y==v3.y&&v1.y!=v2.y) {
  117.   swap(v1,v2);
  118.   swap(v2,v3);
  119.  } else if(v1.y==v3.y&&v1.y!=v2.y) {
  120.   swap(v2,v3);
  121.  }
  122.  if(v1.x>v2.x) {
  123.   swap(v1,v2);
  124.  }
  125.  //解一次方程
  126.  float h=v3.y-v1.y;
  127.  float kL=(v3.x-v1.x)/h;
  128.  float kR=(v3.x-v2.x)/h;
  129.  float xL=0;
  130.  float xR=0;
  131.  ct c1=0,c2=0;
  132.  xL=v1.x;
  133.  xR=v2.x;
  134.  if(h>0) {
  135.   for(float i=v1.y; i<=v3.y; ++i) {
  136.    float percent=1.0f-(i-v1.y)/(v3.y-v1.y);
  137.    c1=EA::ColorLerp(v1.c,v3.c,percent);
  138.    c2=EA::ColorLerp(v2.c,v3.c,percent);
  139.    EA::DrawLine_f(xL,xR,i,c1,c2);
  140.    xL+=kL;
  141.    xR+=kR;
  142.   }
  143.  } else {
  144.   for(float i=v1.y; i>=v3.y; --i) {
  145.    float percent=(i-v3.y)/(v1.y-v3.y);
  146.    c1=EA::ColorLerp(v1.c,v3.c,percent);
  147.    c2=EA::ColorLerp(v2.c,v3.c,percent);
  148.    EA::DrawLine_f(xL,xR,i,c1,c2);
  149.    xL-=kL;
  150.    xR-=kR;
  151.   }
  152.  }
  153. }
  154. void EA::DrawTrangle(Ver2D v1,Ver2D v2,Ver2D v3) {
  155.  if(v1.y==v2.y||v1.y==v3.y||v2.y==v3.y) {
  156.   EA::DrawSimpleTrangle(v1,v2,v3);
  157.  } else {
  158.   //找出y中间的顶点,并放在v3的位置
  159.   if(v2.y<v1.y&&v1.y<v3.y) {
  160.    swap(v1,v3);
  161.   } else if(v1.y<v2.y&&v2.y<v3.y) {
  162.    swap(v2,v3);
  163.   }
  164.   //切成两半
  165.   float h=v1.y-v2.y;
  166.   float w=v1.x-v2.x;
  167.   Ver2D vm((w/h)*(v3.y-v2.y)+v2.x,v3.y,EA::ColorLerp(v2.c,v1.c,(v3.y-v2.y)/h));
  168.   swap(vm.c,v3.c);
  169.   //画他
  170.   DrawSimpleTrangle(v1,vm,v3);
  171.   DrawSimpleTrangle(v2,vm,v3);
  172.  }
  173. }
  174. #undef ct