如何在verilog中填写FPGA生成的圆圈用于合成和VGA输出



我想在640x480 VGA显示器上输出一个半径为100像素的移动红色圆圈。我一直纠结于如何制作和填充实际的圆圈。现在我看了一下令人麻木的Bresenham算法,但我无法使它们适合我的verilog代码。

我已经推测了我能做什么,但我不完全确定这是可能的。我知道圆的方程是(x-a)(x-a,y-b)(y-b)=r*r,其中(a,b)是原点。所以我想用RGB颜色填充这个圆圈,并将其从上向下移动,即在a=640/2 时从b=0移动到480

由于VGA从左到右输出像素,向下迭代,我猜我必须使用嵌套循环。我知道垂直运动的第一个循环是从0到480。这是我遇到问题的第二个循环。它从0到640,但我希望像素在到达(x,y)(沿圆的一点)时改变颜色,保持该颜色,然后在经过(x+k)后变回(其中k是水平弦)。

本质上,如果下面是我圆圈的水平弦:

_黑色。(x,y)___红色(k像素)_。(x+k,y)_黑色

reg [8:0] bally;//y coordinate of the center of circle
reg [8:0] rad;//radius 
always @ (posedge clk)
begin
for(VCount=0;VCount<=480;VCount++)
  for(HCount=0;HCount<=640;HCount++)
     if((HCount*HCount>=rad*rad-((VCount-bally)*(VCount-bally)) && HCount*HCount<=((10000-((VCount-bally)*(VCount-bally)))+k)))
        R<=1;
        G<=0;
        B<=0;
     end

我的问题是,如何用我已经拥有的变量来表示if条件中的k?我意识到这可能不是一个verilog问题,但可能是我在基础三角学方面失败了,但我真的对此感到困惑。请,如果我在尝试做这个循环时非常偏离(代码方面,逻辑方面,综合方面),一定要告诉我。如有任何帮助,我们将不胜感激。

我不确定嵌套的for循环会像你想象的那样表现,至少对于合成设计来说是这样。

我的建议是不要根据圆的参数方程来生成圆,我认为这是你想要做的。相反,如果圆总是相同的(即它的半径总是小于或等于100像素),请预先生成一个圆的位图,并将其作为一个大精灵存储在FPGA(块RAM)内存中。它不会占用你太多空间。精灵中的0位将转换为"透明",而1位则表示使用与精灵(圆圈)相关的颜色绘制此点。

这样,你绘制屏幕的代码(实际上是屏幕的活动部分)应该是这样的:

`define SPRLEN 256  // how many pixels in width and heigh the sprite will have.
`define SPRITECOLOR 3'b100;  // RED ball. (RGB, 1-bit per channel)
`define BGCOLOR 3'010;       // GREEN background
reg ballsprite[0:`SPRLEN*`SPRLEN-1]; // A matrix to hold your sprite.
reg [9:0] hcont, vcont; // horizontal and vertical counters for scanning a VGA picture
reg [8:0] ballx, bally; //coordinates of the left-top corner of the ball sprite
reg [7:0] coorx,coory;  //X,Y coordinates of the current sprite position to draw
initial begin  // read your sprite definition into memory. FPGA synthetizable.
  $readmemb ("mysprite.bin", ballsprite);
end
// process to obtain relative coordinates of the current screen position within the sprite 
always @* begin
  coorx = hcont+1-ballx;
  coory = vcont+1-bally;
end
// process to get the next dot from the sprite. We begin at ballx-1,bally-1 because
// there's one clock delay in getting the current sprite dot value.
always @(posedge clk) begin
  if (hcont>=ballx-1 && hcont<=ballx-1+`SPRLEN && vcont>=bally-1 && vcont<=bally-1+`SPRLEN)
    dot_from_ball <= ballsprite[{coory,coorx}];  // i.e. coory*256+coorx
  else
    dot_from_ball <= 1'b0;  // if scan trace is not under the boundaries of the sprite,
                            // then it's transparent color
end
// multiplexer to actually put an RGB value on screen
always @* begin
  if (hcont>=0 && hcont<640 && vcont>=0 && vcont<480) begin
    if (dot_from_ball)
      {R,G,B} = `SPRITECOLOR;
    else
      {R,G,B} = `BGCOLOR;
  end
  else
    {R,G,B} = 3'b000;  //if not into active area, mute RGB
end

由您为hcont和vcont生成适当的值,并根据这些计数器何时达到某些值来推断同步信号。

不久前,我做了类似的事情:在VGA屏幕上绘制一个移动的精灵。我用Handel C做的,但逻辑是一样的。你可以在这里看到:http://www.youtube.com/watch?v=wgDSzC-vGZ0

您不希望出现这样的循环。如果要动态生成圆(而不是使用位图),请在单独的过程中跟踪当前坐标(always块)。每个始终块将在VGA时钟的每一个刻度上运行,因此每次执行块时都有一个新的像素位置。

然后有另一个always块,它查看这些x和y坐标,并决定当前点是否在圆中。根据这个决定,您可以选择前景或背景颜色。同样,按顺序对每个像素进行一次操作。

棘手的部分是决定当前点是否在圆中。

如果这看起来有点太难开始,那就画一个正方形,因为它的方程非常简单。一旦你明白了这一点,并确切地了解了它是如何工作的以及为什么工作的,你就可以研究圆形(以及其他参数定义的形状)。要找到实时渲染这些形状的方法,在扫描图像时,您可能会发现术语"扫描线渲染"或"增量渲染"很有用。


仔细想想,这不是圆的标准方程的情况吗

x^2 + y^2 = r^2

可以表示为圆内返回点的不等式:

x^2 + y^2 < r^2

扩展以允许中心点的变化:

(x-xc)^2 + (y-yc)^2 < r^2

这意味着,对于每个像素,你从x和y中减去中心点,将它们平方,并与r^2进行比较。如果小于r^2,则绘制像素。

在老式的FPGA中,这将是一个很大的逻辑,但现在3个减法器和2个乘法器已经不算什么了(或者如果你以像素时钟的倍数操作,你可以以牺牲输入上的mux为代价共享乘法器)

相关内容

  • 没有找到相关文章

最新更新