|
算法描像素法的不足
算法描像素法指的是程序根据预先给出的半径、起始角度、结束角度,通过特定算法计算出圆孤要经过的像素,然后填色这些像素从而画出圆弧。下图是使用了中点圆算法画出10个同心圆弧,从左到右这些圆弧的半径遂个增一。
图中使用白色画圆弧,但它们中间有不少像素出现背景色,原因是算法算出的像素没包括它们。
当然有比中点圆更好的算法,或许能使得画满10宽度内的所有像素。——即使能被画满,以算法描像素画圆弧还有个问题,它描画时采用的是纯色,一旦使用纯色,基本就不能避免掉边界会出现锯齿,导致不美观。
综上所述,用算法描像素法画圆弧存在两个问题,1)当要画的圆弧宽度大于1时,圆弧中可能出现漏画的像素;2)由于是纯色填充,边界会出锯齿。
圆环素材+弧外像素变透明
该方法是让美工事先画出包含了希望中圆弧的圆环,要开始画了,程序计算出属于圆环、但不属于圆弧的弧外像素,把这些像素填成全透明,从而间接画出圆弧。用这方法会直接面临的一个问题,如何找出弧外像素。
第一种是用算法是去找。例如还是用以上的中点圆算法,但这种方法就会碰上个问题,“当要画的圆弧宽度大于1时,圆弧中可能出现漏画的像素”,计算弧外像素也可能出现漏计算。
第二种是抛开画弧算法,使用看去简单的逻辑。
一、分析圆环图像,收集出所有不是全透明的像素。制做素材时要求把图中像素分为两类:环中像素是不透明或半透明,环外像素全透明。在分析时,代码用自定义的tarc_pixel存储每个像素。
- struct tarc_pixel
- {
- unsigned short x;
- unsigned short y;
- unsigned short degree;
- };
复制代码
x、y是像素在素材中的坐标,degree是该像素在此圆环中角度。以下是计算角度的公式,在不同象限公式略有不同,总的逻辑是基于x、y,用反正切计算出角度。(circle_calculate_pixels、circle_draw_arc函数来自Rose项目中的<src>/librose/sdl_utils.cpp)
- tarc_pixel* circle_calculate_pixels(surface& surf, int* valid_pixels)
- {
- const int diameter = surf->w;
- surface_lock lock(surf);
- ......
- // circle_valid_pixels是圆环图面中的不透明和半透明像素数
- int at = 0;
- circle_pixels = (tarc_pixel*)malloc(circle_valid_pixels * sizeof(tarc_pixel));
- const int originx = diameter / 2;
- const int originy = originx;
- int diffx, diffy;
- for (int row = 0; row < diameter; row ++) {
- for (int col = 0; col < diameter; row ++) {
- if (beg[row * diameter + col] >> 24) {
- tarc_pixel* pixel = circle_pixels + at;
- pixel->x = col;
- pixel->y = row;
- if (col >= originx && row < originy) {
- // 第一象限
- diffx = col - originx;
- diffy = originy - row;
- pixel->degree = atan(1.0 * diffx / diffy) * 180 / M_PI;
- } else {
- // 其它象限
- ......
- }
- at ++;
- }
- }
- }
- ......
- }
复制代码
二、根据起、始角度把弧外像素置为透明
- void circle_draw_arc(surface& surf, tarc_pixel* circle_pixels, const int circle_valid_pixels, int start, int stop, Uint32 erase_col)
- {
- // surf是圆环素材图面
- const int diameter = surf->w;
- surface_lock lock(surf);
- Uint32* beg = lock.pixels();
- for (int at = 0; at < circle_valid_pixels; at ++) {
- const tarc_pixel& coor = circle_pixels[at];
- if (start < stop) {
- if (!(pixel.degree >= start && pixel.degree <= stop)) {
- beg[coor.y * diameter + coor.x] = erase_col;
- }
- } else {
- if (pixel.degree < start && pixel.degree > stop) {
- beg[coor.y * diameter + coor.x] = erase_col;
- }
- }
- }
- 到此生成的surf就是希望中的圆弧图面
- ...
- }
复制代码 |
|