这一节为2D图形处理,展示如何去渲染基本几何(点,线,三角形),按 TAB可以切换图元显示

渲染器新增接口:

  void SoftRenderer::Render(const Vertex * varray, int vertexCount, const int * iarray, int primCount, int primType)
  {
    // 顶点处理
    mRasterizerVertexBuffer.resize(vertexCount);
    for (int i = 0; i < vertexCount; ++i)
    {
      _vertex_shader(&mRasterizerVertexBuffer[i], &varray[i]);
    }

    // 图元处理
    RasterizerVertex A, B, C, D;
    for (int i = 0; i < primCount; ++i)
    {
      if (primType == ePrimType::TRI_LIST)
      {
        if (iarray != NULL)
        {
          // 使用索引列表
          A = mRasterizerVertexBuffer[iarray[i * 3 + 0]];
          B = mRasterizerVertexBuffer[iarray[i * 3 + 1]];
          C = mRasterizerVertexBuffer[iarray[i * 3 + 2]];
        }
        else
        {
          // 使用顶点列表
          A = mRasterizerVertexBuffer[i * 3 + 0];
          B = mRasterizerVertexBuffer[i * 3 + 1];
          C = mRasterizerVertexBuffer[i * 3 + 2];
        }

        // 背面裁剪

        // 裁剪

        // 视口变换
        A.position.x /= A.position.w;
        A.position.y /= A.position.w;
        B.position.x /= B.position.w;
        B.position.y /= B.position.w;
        C.position.x /= C.position.w;
        C.position.y /= C.position.w;

        A.position.x = (A.position.x + 1) / 2 * mWidth;
        A.position.y = (1 - A.position.y) / 2 * mHeight;
        B.position.x = (B.position.x + 1) / 2 * mWidth;
        B.position.y = (1 - B.position.y) / 2 * mHeight;
        C.position.x = (C.position.x + 1) / 2 * mWidth;
        C.position.y = (1 - C.position.y) / 2 * mHeight;

        // 光栅化
        _rasterizeTri(&A, &B, &C);
      }
      else if (primType == ePrimType::LINE_LIST)
      {
        if (iarray != NULL)
        {
          // 使用索引列表
          A = mRasterizerVertexBuffer[iarray[i * 2 + 0]];
          B = mRasterizerVertexBuffer[iarray[i * 2 + 1]];
        }
        else
        {
          // 使用顶点列表
          A = mRasterizerVertexBuffer[i * 2 + 0];
          B = mRasterizerVertexBuffer[i * 2 + 1];
        }

        // 背面裁剪

        // 裁剪

        // 视口变换
        A.position.x /= A.position.w;
        A.position.y /= A.position.w;
        B.position.x /= B.position.w;
        B.position.y /= B.position.w;

        A.position.x = (A.position.x + 1) / 2 * mWidth;
        A.position.y = (1 - A.position.y) / 2 * mHeight;
        B.position.x = (B.position.x + 1) / 2 * mWidth;
        B.position.y = (1 - B.position.y) / 2 * mHeight;

        // 光栅化
        _rasterizeLine(&A, &B);
      }
      else if (primType == ePrimType::POINT_LIST)
      {
        if (iarray != NULL)
        {
          // 使用索引列表
          A = mRasterizerVertexBuffer[iarray[i]];
        }
        else
        {
          // 使用顶点列表
          A = mRasterizerVertexBuffer[i];
        }

        // 背面裁剪

        // 裁剪

        // 视口变换
        A.position.x /= A.position.w;
        A.position.y /= A.position.w;

        A.position.x = (A.position.x + 1) / 2 * mWidth;
        A.position.y = (1 - A.position.y) / 2 * mHeight;

        // 光栅化
        _rasterizePoint(&A);
      }
    }
  }

 

渲染点:

  void SoftRenderer::_rasterizePoint(const RasterizerVertex * PA)
  {
    RasterizerVertex v = *PA;

    int x = (int)v.position.x, y = (int)v.position.y;

    if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
    {
      _pixel_shader(&v);
      _output(x, y, &v);
    }
  }

 

渲染线段(中心点算法):

  void SoftRenderer::_rasterizeLine(const RasterizerVertex * PA, const RasterizerVertex * PB)
  {
    if (PA->position.x > PB->position.x)
    std::swap(PA, PB);

    RasterizerVertex v;

    Int2 A = Int2((int)PA->position.x, (int)PA->position.y);
    Int2 B = Int2((int)PB->position.x, (int)PB->position.y);
    Int2 AB = B - A;

    if (AB.x > abs(AB.y))
    {
      float k = (float)AB.y / AB.x;
      int x = A.x, y = A.y;

      if (k > 0)
      {
        float e = -0.5f;

        for (int i = 0; i < AB.x; ++i)
        {
          x = x + 1;
          e = e + k;
          if (e > 0)
          {
            y = y + 1;
            e = e - 1.0f;
          }

          if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
          {
            float d = AB.x > 0 ? (float)i / AB.x : 1;

            RasterizerVertex::Lerp(v, *PA, *PB, d);

            _pixel_shader(&v);
            _output(x, y, &v);
          }
        }
      }
      else if (k == 0)
      {
        for (int i = 0; i < AB.x; ++i)
        {
          x = x + 1;

          if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
          {
            float d = AB.x > 0 ? (float)i / AB.x : 1;

            RasterizerVertex::Lerp(v, *PA, *PB, d);

            _pixel_shader(&v);
            _output(x, y, &v);
          }
        }
      }
      else
      {
        float e = -0.5f;

        for (int i = 0; i < AB.x; ++i)
        {
          x = x + 1;
          e = e - k;
          if (e > 0)
          {
            y = y - 1;
            e = e - 1.0f;
          }

          if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
          {
            float d = AB.x > 0 ? (float)i / AB.x : 1;

            RasterizerVertex::Lerp(v, *PA, *PB, d);

            _pixel_shader(&v);
            _output(x, y, &v);
          }
        }
      }
    }
    else
    {
      float k = (float)AB.x / AB.y;
      int x = A.x, y = A.y;

      if (k > 0)
      {
        float e = -0.5f;

        for (int i = 0; i < AB.y; ++i)
        {
          y = y + 1;
          e = e + k;
          if (e > 0)
          {
            x = x + 1;
            e = e - 1.0f;
          }

          if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
          {
            float d = AB.y > 0 ? (float)i / AB.y : 1;

            RasterizerVertex::Lerp(v, *PA, *PB, d);

            _pixel_shader(&v);
            _output(x, y, &v);
          }
        }
      }
      else if (k == 0)
      {
        if (AB.y > 0)
        {
          for (int i = 0; i < AB.y; ++i)
          {
            y = y + 1;

            if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
            {
              float d = AB.y > 0 ? (float)i / AB.y : 1;

              RasterizerVertex::Lerp(v, *PA, *PB, d);

              _pixel_shader(&v);
              _output(x, y, &v);
            }
          }
        }
        else
        {
          for (int i = 0; i < -AB.y; ++i)
          {
            y = y - 1;

            if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
            {
              float d = -AB.y > 0 ? (float)i / -AB.y : 1;

              RasterizerVertex::Lerp(v, *PA, *PB, d);

              _pixel_shader(&v);
              _output(x, y, &v);
            }
          }
        }
      }
      else
      {
        float e = -0.5f;

        for (int i = 0; i < -AB.y; ++i)
        {
          y = y - 1;
          e = e - k;
          if (e > 0)
          {
            x = x + 1;
            e = e - 1.0f;
          }

          if (x >= 0 && x < mWidth && y >= 0 && y <= mHeight)
          {
            float d = -AB.y > 0 ? (float)i / -AB.y : 1;

            RasterizerVertex::Lerp(v, *PA, *PB, d);

            _pixel_shader(&v);
            _output(x, y, &v);
          }
        }
      }
    }
  }

 

渲染三角形(扫描线算法):

    void SoftRenderer::_rasterizeTri(const RasterizerVertex * PA, const RasterizerVertex * PB, const RasterizerVertex * PC)
    {
      int _width = mWidth, _height = mHeight;

      // 确保点A是最上面的点
      if (PA->position.y > PB->position.y)
      std::swap(PA, PB);
      if (PA->position.y > PC->position.y)
      std::swap(PA, PC);

      // 确保B在C的左边
      if (PB->position.x > PC->position.x)
      std::swap(PB, PC);

      Int2 A = Int2((int)PA->position.x, (int)PA->position.y);
      Int2 B = Int2((int)PB->position.x, (int)PB->position.y);
      Int2 C = Int2((int)PC->position.x, (int)PC->position.y);
      Int2 AB = B - A, AC = C - A;

      RasterizerVertex v1, v2, v;

      if (B.y > C.y)
      {
        // 三角形类型1 (B.y < C.y)
        //    A*
        //
        //      *C
        // B*
        //

        // 画上半部分
        int cy = A.y, ey = C.y;
        cy = std::max(cy, 0);
        ey = std::min(ey, _height);

        while (cy < ey)
        {
          float kab = AB.y > 0 ? (float)(cy - A.y) / (float)AB.y : 1;
          float kac = AC.y > 0 ? (float)(cy - A.y) / (float)AC.y : 1;

          int x1 = (int)(A.x + AB.x * kab);
          int x2 = (int)(A.x + AC.x * kac);

          RasterizerVertex::Lerp(v1, *PA, *PB, kab);
          RasterizerVertex::Lerp(v2, *PA, *PC, kac);

          if (x1 > x2)
          {
            std::swap(x1, x2);
            std::swap(v1, v2);
          }

          int sx = std::max(x1, 0);
          int ex = std::min(x2, _width);

          for (int x = sx; x < ex; x += 1)
          {
            float k = (x2 - x1) > 0 ? (float)(x - x1) / (float)(x2 - x1) : 1;

            RasterizerVertex::Lerp(v, v1, v2, k);

            _pixel_shader(&v);
            _output(x, cy, &v);
          }

          cy += 1;
        }

        // 画下半部分
        Int2 CB = Int2(B.x - C.x, B.y - C.y);
        ey = std::min(B.y, _height);

        while (cy < ey)
        {
          float kab = AB.y > 0 ? (float)(cy - A.y) / (float)AB.y : 1;
          float kcb = CB.y > 0 ? (float)(cy - C.y) / (float)CB.y : 1;

          int x1 = (int)(A.x + AB.x * kab);
          int x2 = (int)(C.x + CB.x * kcb);

          RasterizerVertex::Lerp(v1, *PA, *PB, kab);
          RasterizerVertex::Lerp(v2, *PC, *PB, kcb);

          if (x1 > x2)
          {
            std::swap(x1, x2);
            std::swap(v1, v2);
          }

          int sx = std::max(x1, 0);
          int ex = std::min(x2, _width);

          for (int x = sx; x < ex; x += 1)
          {
            float k = (x2 - x1) > 0 ? (float)(x - x1) / (float)(x2 - x1) : 1;

            RasterizerVertex::Lerp(v, v1, v2, k);

            _pixel_shader(&v);
            _output(x, cy, &v);
          }

          cy += 1;
        }
      }
      else
      {
        // 三角形类型2 (B在C上面)
        //     A*
        //
        //  B*
        //        *C
        //

        // 画上半部分
        int cy = A.y, ey = B.y;
        cy = std::max(cy, 0);
        ey = std::min(ey, _height);

        while (cy < ey)
        {
          float kab = AB.y > 0 ? (float)(cy - A.y) / (float)AB.y : 1;
          float kac = AC.y > 0 ? (float)(cy - A.y) / (float)AC.y : 1;

          int x1 = (int)(A.x + AB.x * kab);
          int x2 = (int)(A.x + AC.x * kac);

          RasterizerVertex::Lerp(v1, *PA, *PB, kab);
          RasterizerVertex::Lerp(v2, *PA, *PC, kac);

          if (x1 > x2)
          {
            std::swap(x1, x2);
            std::swap(v1, v2);
          }

          int sx = std::max(x1, 0);
          int ex = std::min(x2, _width);

          for (int x = sx; x < ex; x += 1)
          {
            float k = (x2 - x1) > 0 ? (float)(x - x1) / (float)(x2 - x1) : 1;

            RasterizerVertex::Lerp(v, v1, v2, k);

            _pixel_shader(&v);
            _output(x, cy, &v);
          }

          cy += 1;
        }

        // 画下半部分
        Int2 BC = Int2(C.x - B.x, C.y - B.y);
        ey = std::min(C.y, _height);

        while (cy < ey)
        {
          float kbc = BC.y > 0 ? (float)(cy - B.y) / (float)BC.y : 1;
          float kac = AC.y > 0 ? (float)(cy - A.y) / (float)AC.y : 1;

          int x1 = (int)(B.x + BC.x * kbc);
          int x2 = (int)(A.x + AC.x * kac);

          RasterizerVertex::Lerp(v1, *PB, *PC, kbc);
          RasterizerVertex::Lerp(v2, *PA, *PC, kac);

          if (x1 > x2)
          {
            std::swap(x1, x2);
            std::swap(v1, v2);
          }

          int sx = std::max(x1, 0);
          int ex = std::min(x2, _width);

          for (int x = sx; x < ex; x += 1)
          {
            float k = (x2 - x1) > 0 ? (float)(x - x1) / (float)(x2 - x1) : 1;

            RasterizerVertex::Lerp(v, v1, v2, k);

            _pixel_shader(&v);
            _output(x, cy, &v);
          }

          cy += 1;
        }
      }
    }

 

 

 

程序逻辑:

  virtual void OnInit(int w, int h)
  {
    mRenderer = new SoftRenderer(mWnd, w, h);

    // 创建正方形
    Vertex * vb = mQuad;
    vb[0].position = Float3(-1, +1, 0) * 0.5f;
    vb[1].position = Float3(+1, +1, 0) * 0.5f;
    vb[2].position = Float3(-1, -1, 0) * 0.5f;
    vb[3].position = Float3(+1, -1, 0) * 0.5f;
    vb[0].color = Float4(1, 0, 0, 1);
    vb[1].color = Float4(1, 0, 0, 1);
    vb[2].color = Float4(0, 1, 0, 1);
    vb[3].color = Float4(0, 1, 0, 1);

    // 三角形列表
    int * ib = mTriList;
    {
      *ib++ = 0, *ib++ = 1, *ib++ = 2;
      *ib++ = 2, *ib++ = 1, *ib++ = 3;
    }

    // 线列表
    ib = mLineList;
    {
      *ib++ = 0, *ib++ = 1;
      *ib++ = 1, *ib++ = 3;
      *ib++ = 3, *ib++ = 2;
      *ib++ = 2, *ib++ = 0;
    }

    // 点列表直接使用顶点的列表,不用额外定义

    //
    mPrimType = ePrimType::TRI_LIST;
  }

  virtual void OnUpdate()
  {
    mRenderer->Begin();

    // 清屏
    mRenderer->Clear(Float3(0, 0, 0), 1);

    // 随着时间旋转
    Mat4 form;
    form.MakeRotation(Float3(0, 0, 1), PI * mTime * 0.3f);

    Vertex * vb = mQuad;
    vb[0].position = Float3(-1, +1, 0) * 0.5f;
    vb[1].position = Float3(+1, +1, 0) * 0.5f;
    vb[2].position = Float3(-1, -1, 0) * 0.5f;
    vb[3].position = Float3(+1, -1, 0) * 0.5f;

    mQuad[0].position.TransformA(form);
    mQuad[1].position.TransformA(form);
    mQuad[2].position.TransformA(form);
    mQuad[3].position.TransformA(form);

    // 保持纵横比
    float aspect = (float)mHeight / mWidth;
    vb[0].position *= Float3(aspect, 1, 0);
    vb[1].position *= Float3(aspect, 1, 0);
    vb[2].position *= Float3(aspect, 1, 0);
    vb[3].position *= Float3(aspect, 1, 0);

    // 渲染图元
    switch (mPrimType)
    {
    case ePrimType::TRI_LIST:
      mRenderer->Render(vb, 4, mTriList, 2, ePrimType::TRI_LIST);
      break;

    case ePrimType::LINE_LIST:
      mRenderer->Render(vb, 4, mLineList, 4, ePrimType::LINE_LIST);
      break;

    case ePrimType::POINT_LIST:
      mRenderer->Render(vb, 4, NULL, 4, ePrimType::POINT_LIST);
      break;
    }

    mRenderer->End();

    // 提交
    mRenderer->Present();
  }

 

总结:

  例程最重要部分是渲染流程(Render函数的处理流程)和三种图元的渲染算法(3个_rasterizeX函数),对于跟深入的了解可以看下基础计算机图形书籍。

posted on 2017-04-17 14:04  devil86  阅读(60)  评论(0)    收藏  举报