Archive

Archive for the ‘图形编程’ Category

多平台下录屏方式

November 16th, 2015 No comments

随便记录下,想得起来的多少写多少:

Windows:
GDI 全屏:fullscreen desktop BitBlt 速度是 20ms / 帧
GDI 窗口:Win7+可以录制游戏和非游戏,XP以前只能录制普通界面,截不到游戏窗口
DirectDraw 全屏:full screen primary surface 异步到 offscreen-surface XP下闪电速度 1ms / 帧
D3D9: render target -> offscreen surface XP下 16ms Win7 下 10ms
D3D Hook: Hook Device::Present -> 保存 StateBlock -> 截屏 -> 恢复 StateBlock 极速!

Linux:
framebuffer: 打开 /dev/fb0 映射到内存,直接读里面内容,部分显卡驱动启用硬件加速绘图后,framebuffer会被跳过,直接调用 framebuffer 导致读取出来的东西为空。

Android:
framebuffer: 需要 root 权限才能访问 framebuffer
RootView: 取得 root view 然后得到 drawing cache 然后保存,兼容性好,慢。
OpenGL:直接 glReadPixel 保险,但是会卡到应用。
OpenGL FBO: 更改渲染的 FBO ,让渲染到纹理,从纹理取下来,还行,速度还好。
screenshot: SurfaceComposerClient::getBuiltInDisplay Android 4.0 以后,性能不错。
native buffer: ANativeWindowBuffer -> GraphicBuffer -> 映射读取, 性能不错

iOS:
OpenGL: 直接 glReadPixel 同 Android,同样会卡到应用
OpenGL FBO: 渲染到 FBO,读取下来,还行。

大部分方法可以用 Hook 的方式注入到目标程序,或者系统 API,在不需要目标程序改一行代码的情况下实现功能。

Categories: 图形编程 Tags:

如何写一个软件渲染器?

August 10th, 2015 15 comments

实现个简单的固定渲染管线软渲染器不算复杂,差不多700行代码就可以搞定了。之所以很多人用 D3D用的很熟,写软渲染却坑坑洼洼,主要是现在大部分讲图形的书,讲到透视投影时就是分析一下透视变换矩阵如何生成,顶点如何计算就跳到其他讲模型或者光照的部分了。

因为今天基本上是直接用 D3D 或者 OGL,真正光栅化的部分不了解也不影响使用,所以大部分教材都直接跳过了一大段,摄像机坐标系如何转换?三角形如何生成?CVV边缘如何检测?四维坐标如何裁剪?边缘及步长如何计算?扫描线该如何绘制?透视纹理映射具体代码该怎么写?framebuffer zbuffer 到底该怎么用?z-test 到底是该 test z 还是 w 还是 1/z 还是 1/w ?这些都没讲。

早年培训学生时候,我花两天时间写的一个 DEMO,今天拿出来重新调整注释一下,性能和功能当然比不过高大上的软件渲染器。但一般来讲,工程类项目代码不容易阅读,太多边界情况和太多细节优化容易让初学者迷失,这个 mini3d 的项目不做任何优化,主要目的就是为了突出主干:

源代码:skywind3000/mini3d · GitHub
可执行:http://www.skywind.me/mw/images/c/c8/Mini3d.7z

操作方式:左右键旋转,前后键前进后退,空格键切换模式,ESC退出。

 

特性介绍:

  • 单个文件:源代码只有一个 mini3d.c,单个文件实现所有内容,阅读容易。
  • 独立编译:没有任何第三方库依赖,没有复杂的工程目录。
  • 模型标准:标准 D3D 坐标模型,左手系 + WORLD/VIEW/PROJECTION 三矩阵
  • 实现裁剪:简单 CVV 裁剪
  • 纹理支持:最大支持 1024 x 1024 的纹理
  • 深度缓存:使用深度缓存判断图像前后
  • 边缘计算:精确的多边形边缘覆盖计算
  • 透视贴图:透视纹理映射以及透视色彩填充
  • 实现精简:渲染部分只有 700行, 模块清晰,主干突出。
  • 详细注释:主要代码详细注释

截图效果

颜色填充

image

 

透视纹理映射

image

Read more…

Categories: 图形编程, 编程技术 Tags:

游戏中角色变色如何实现?

June 13th, 2015 No comments

来自知乎问题:http://www.zhihu.com/question/31133351 

游戏中的惯用做法叫:调色盘色彩旋转

image

1. 调色盘里能变色的颜色总是固定几个位置
2. 让需要变色的位置的 RGB转换成 HSV,然后旋转 H分量旋转一定角度
3. 重新将 HSV转换为 RGB保存回调色盘

image

在 HSV 色彩空间中,旋转 H 分量

主要是旋转 H分量,S/V分量也可以微调,但是变色是以旋转 H为主。题主两张图片的八神,除了调色盘前面几个皮肤颜色不参与变色外,后面的衣服整体都参与了色彩旋转:

Read more…

Categories: 图形编程 Tags: ,

还原被摄像机透视的纹理

May 20th, 2015 No comments

有人问如何还原被透视纹理?给你一张照片,还原照片上四个点所组成的平面的纹理该怎么做?我们可以从数学上推导一下,为了和三维图形的透视纹理映射对照,我们称照片上四个点在照片上的位置为“屏幕坐标”,那么可以发现:

空间中,三维坐标(x,y,z)和纹理坐标(u, v)承线性关系。根据该问题描述,可以理解为已知四个点的屏幕投影坐标(xi,yi),和对应纹理坐标(u,v),求整个纹理坐标系到屏幕坐标系的反向映射过程,即根据(u,v)求解(xi,yi)。

1. 按照纹理隐射的原理,同平面纹理坐标与空间坐标存在线性关系,设 a1-a12为常数,有:

a1 * x +  a2 * y +  a3 * z +  a4 = u ... 线性关系
a5 * x +  a6 * y +  a7 * z +  a8 = v ... 线性关系
a9 * x + a10 * y + a11 * z + a12 = 0 ... 平面方程

2. 求解上面的方程组,可以得到类似下面的关系,其中b1-b9为常数:

x = b1 * u + b2 * v + b3  
y = b4 * u + b5 * v + b6 
z = b7 * u + b8 * v + b9 

常数 b1-b9如果展开,就是9个关于a1-a12的等式,太长了,这里不展开,有兴趣可以自己求解。

3. 屏幕上投影坐标一般是:

           x
xi = D1 * --- + C1
           z
       
           x
yi = D2 * --- + C2
           z

因为同样一个透视投影矩阵下,能隐射成屏幕上同样形状纹理的平面,在空间中存在无穷多个,而且还存在不同透视投影矩阵下,同样屏幕投影的平面存在更多无穷多个。这里我们不用去求解每个平面,直接设置 D1 = D2 = 1 且 C1 = C2 = 0 有:

      x
xi = ---
      z
       
      x
yi = ---
      z

Read more…

Categories: 图形编程 Tags:

计算机图形算法中的光滑边缘算法经历了那些变迁?

April 26th, 2015 No comments

主要有四种方法:

1. wupixel:wu xiaolin提出的最早的绘制直线和圆的平滑方法,优点是简单快速,缺点是只有一个方向的像素偏移被考虑了,效果普通,而且只能绘制1个像素宽度的直线,超过一个像素后,两个端点就会非常不自然。

image

2. supersampling:解析度扩大数倍绘制,四个或者多个像素合并平滑成一个像素,优点是效果好,缺点是计算量大,多用于显卡加速,cpu基本没发做,显卡负担也大:

image
当然小范围的ss可以用来改进界面字体效果,如windows字体长宽扩大两倍绘制后再平滑down sample成小尺寸,四个像素点均匀合并成一个像素点,会好看很多。

image

3. 覆盖面积计算:通过计算多边形覆盖了矩形点阵面积的百分比来计算 Alpha,多用于软件渲染,字体绘制,如高质量图形库如AGG,采用直接子像素的绘制方式来避免supersampling的性能浪费,并达到更好效果。缺点是过于复杂不如supersampling 那样简单直接,不容易的用gpu实现。

image

比如我五年前做的一个玩具图形库:skywind3000/pixellib · GitHub
就是用覆盖面积计算方式来平滑边缘。

4. clear type:采用子像素并考虑lcd的rgb分布,利用lcd上rgb的排列规则模拟更高的解析度,缺点是过分依赖lcd排列,以及主要是x方向的抗锯齿:

image

编辑于 2015-04-26

Categories: 图形编程 Tags: ,

使用 GlowFilter实现字体沟边与发光

April 19th, 2013 5 comments

如果你正在使用 Flash,那么实现下面一个字体效果是一件十分简单的事情:

image

textfield.filters = [ new GlowFilter(0, 1, 2, 2, 10) ];

这样就可以了,接着把字体设置成宋体12号,颜色是0xffff99,就成了。

image

如果要实现上面类似QQ面板的发光效果,也只需要一行:

textfield.filters = [ new GlowFilter(0xffffffff, 1, 6, 6, 0.9) ];

看起来这个 GlowFilter是无所不能呀,那么如果你在使用C++的话,如何用C++来实现一个Glow效果呢?

而且如果你正在使用3D引擎的话,如何用GPU来实现上面的效果呢?详细见下文:

Read more…

Categories: 图形编程 Tags:

Windows字体为什么那么难看?

September 6th, 2011 No comments

1)很多字库比如宋体,12号以下都是点阵字体。

2)GDI太老了,只有5级灰度,而且AA是横向的,Y轴方向没有AA。

3)雅黑又不能通用,且小字号时高低不平。

 

改进:

1)字体SuperSample。

2)勾边。

image_thumb8

image_thumb13

image_thumb15

image_thumb17

Categories: 图形编程, 编程技术 Tags:

美术资源超级压缩方法

August 7th, 2011 1 comment

如何在质量下降不大的情况下降低一倍的占用?如何让臃肿的美术资源压缩再压缩?

 

JPEG->WDP/WEBP

 

大部分项目都陆续废掉了JPEG,而最好的代替品是微软的HD Photo,wdp格式,在PSNR差不多的情况下,wdp能比JPEG小一倍多。

(wdp的encoder/decoder不好找的话,我这里有一份微软的库)

观察下面的演示图片不要缩放PDF,用100%显示才看得清楚差别

image

image

JPEG 16.18 KB,可以看出脸部方块已经很严重,头发等高频部分已经看不清楚,帽子和墙面质量损失严重,而下面这张WDP文件(HDPHOTO,XnView可以转换)只有13.85KB大小,质量却比JPEG好很多。(通常情况下峰值信噪比差不多的话,WDP能够小一倍):

压缩比从强到弱依次是:WDP>WEBP>JPEG2000>JPEG。因此换用WDP格式能缩小不少资源。

 

PNG->WEBP

非界面元素,仅仅是为了使用ARGB32的资源,可以用webp的带alpha有损格式代替,能节省不少。

 

实时纹理压缩

PS Vita里面已经大范围用到了实时纹理压缩方法,DXT格式存储纹理仅仅是为了方便显卡,但是它的地压缩率却害苦了硬盘。废除DXT格式,用wdp格式或者webp格式有损保存图片(不要用JPEG了,JPEG太差)。运行时动态载入并且动态生成dxt格式再载入显卡。如此在质量微弱损失的情况下,可以至少获得4-5倍的空间节省。

PS Vita使用的动态生成dxt的库叫:

Read more…

Categories: 图形编程 Tags:
Wordpress Social Share Plugin powered by Ultimatelysocial