封面来源:链接

简介

Long Long Ago,在知乎上看了叶大的“一百行以下有哪些给力代码“和“用C语言绘制心形”的回答,可谓是我图形学的开始之一,最近才好好理解完了后者思路和实现,自己做了个球体版的。然后便看一幅幅图片就这样神奇地画出来...

大概的功能就是:

  • 输出一些字符到(黑糊糊的)控制台,模拟一个圆/球的视觉效果;
  • 生成一幅ppm格式的图像文件;
  • 加入考虑高光、光照角度变化等因素生成动画帧序列等等。

接下来依次简要介绍它们的原理与效果,代码地址见文末。

平面圆形

首先,从简单的开始,这一切的根本都是源于一个方程:

没错,高中的姿势,这是笛卡尔坐标系下的圆形方程,圆心在原点(0,0),半径为1。把一个坐标(x,y)带入方程f(x)之后,如果f值等于0,那么这个坐标点在圆上,如小于0就在圆内,反之在圆外。

于是,可以把控制台窗口的行和列作为XY轴,窗口中每一个位置即可以用一个坐标(行序号,列序号)表示,然后将用循环把坐标一个个代入方程,判断,小于等于0就输出一个符号(如'@'),大于0就输出一个空格,并在相应位置换行。这样你就有个圆啦。

控制台输出:基本2D圆形

判断控制台坐标属不属于圆的这个过程,对应在图形学中叫做光栅化(rasterization);计算一个坐标控制台坐标该绘制什么符号的过程叫Pixel Operation(像素操作);二者合起来也叫光栅化...

【细节不看区域】

/* 这里面比较妙的是,控制台本来就是自上而下、从左到右依次输出到屏幕的,相当于遍历了坐标平面,程序使用的坐标——也就是带入方程计算的坐标——并不是实际上的控制台的当前所在行数和列数,而是按照规定转换了下再代入方程计算的,这种转换是类似于把(第2行,第14列)的位置坐标转为(-1.2 , 0.3)坐标的过程,这发生在两个for循环中,for循环的步长也决定了图案的“分辨率”,结合代码就一目了然了。*/

平面圆形Plus

接下来是一个变体:Level-Set版的圆。就是有点等值线的味道,从平面圆方程可知,从边缘越往圆心走,f值从0变到-1,所以进一步把圆内部分按f值划分为若干个区域,着以不同符号。不多说效果如下。

控制台输出:2D圆形Plus

3D球体

到了关键了,从2D到了3D,类似地有3D球体方程:

变量多了1个,增加了深度信息,开始变得那么一点点复杂了,数学也多起来了~~。但是始终记住,我们眼睛看到的东西都是图像,是二维的,显示到屏幕上的东西也是二维的。我们要找到二维图像上各像素的RGB数值。

【明暗处理模型】

我们以所以能看到物体,是因为有光的存在,物体反射/发出了光进入了眼睛。图形学中有一个基本的朗伯(Lambert)明暗处理模型,即遵从朗伯余弦定理:

物体表面的颜色c 与 此表面法线n和光线入射方向l的夹角的余弦 成比例。

直观理解是光线越是垂直与平面射入,这个平面颜色越亮,反之越暗,物体表面的颜色可以理解为RGB三个分量的值,值越大越明亮,值越小越黑暗。如果余弦值为负。具体细节可以参考图形学教材等。既然提到了方向,在XYZ坐标系中,方向可以用一个向量来表示,要求两个向量夹角的余弦值,可以简单让两个向量做点乘除以他们各自的模。

so,要确定图片一个点的颜色(的明暗程度),关键就是得到光线方向向量和图形在该点的法向量,再进一步求他们的余弦值。第一个:光线的方向是不变的,并且是我们人为给定的,这里让光线向量l从左上方射向中心点屏幕里,即在本例右手坐标系中l=(-1,1,1) (为什么是右手坐标系见代码里h函数及注释);第二个:球体的法线向量也很直观,球心在原点的球体,其上的点(x,y,z)的法线n=(x,y,z),不用像心形那样用有限差分法求法向量,因此画球体比画心形要简单些。

【思路】

对控制台每个坐标点按照平面案例中的规定转换为相应值后,代入f进行判断,由于只有x和y两个变量,所以还差一个代表深度z的变量,先把z设置为0进行计算,如果f>0即在点在球体外,输出代表空白的符号(空格);如果f<=0在球体内,就计算下在当前x和y位置上,球体表面的z是多少,在同一个位置上有正面和背面2个深度,我们取靠近我们这一侧看得见的深度z。到这儿法向量和光线向量都有了,这个点的余弦值cos<n·l>=(-x+y+z),余弦值在 [-1,1]之间。再根据不同的余弦值填充不同符号,这样你就有个球啦...

和前面有点像对不对~前面是根据f值填充不同符号,这里是根据不同余弦值~

【余弦值的修正】

有些面的法向量与光夹角大于90°时,按这个方式这些面就不显示,因为cos为负值的,但我们是实际上是能看见的,因为程序只加入了1个方向的光,而现实中的光是充满各个方向的,为避免这个现象,对cos进行wrapped diffuse修正,使其值在背面到正面的范围是 [0, 1],而不是[-1,1]。修正公式:cos'=cos*0.5+0.5

控制台输出:3D圆球

/* 为了表述方便,上面的XYZ方向和代码实现的有出入,代码里的深度是Y方向表示的,右手坐标系。*/

3D球体-图像输出

ppm图像格式

这是一种简单的图像格式,无压缩使用方便,能够直接控制精确到某一个像素的RGB值,适合用作图形学这种练习项目。建立一个文件,写入简单的文件头,然后依次写入每一行的RGB值,最后保存为ppm后缀格式,图片就这样生成了。可以用photoshop打开查看,我是用的2345看图王也可以。

【思路】

基本同前,不同的只有两个地方。

一、由于从控制台上0转到图片上时,控制台的行列和图片的宽高像素的转换规则不同了点,这部分反映在两个for循环处。

二、控制台版是根据修正后的余弦值填充不同符号;图片版是根据修正后的余弦值向文件写入不同的rgb强度值。在这个例子中rgb分量相同,即球体“固有色”是白色。控制台版填充空格时换在这里是填充背景色。

图片输出-球体

3D球体-光照动画图像序列

这个也比较简单了,之前所用的光线方向向量l=(-1,1,1)一直不变,于是可以一次次改变光线向量,一次次输出图像,就可以模拟光照方向改变时的情形啦。

例如l=(cosT,sinT,1) ,T是随"时间"不断变化的角度。也可以自己发挥乱改~下面的效果图我改变了球体固有色和背景色~以及后半时间段Z值

图片序列输出-球体

动图戳此 → github链接,破乎居然不支持gif动图...

控制台动画(for windows)

原理同上,这次回到控制台,调用了windows控制台的API,进行擦除、定位、输出的功能。

实现了光照动画和心跳状动画,这个毕竟参照的画心形,直接拿过来用...

不多解释,直接上图。

控制台动画-球体光照
控制台动画-球体心跳

图片是对控制台录屏后做成gif后分解得到的。

gif动图戳此 → 光照 ,心跳

一些效果 · 高光、卡通渲染…

目前的场景里只有一个光源,我们假设球体的高光是就它产生的(其实也可以由别的方向的光产生,心形中shadertoy中的例子就是,为了视觉更好看,高光光光源的方向有一点点位置偏差。)

上面我们画的是物体在光照下的漫反射颜色,加入高光就是在原有漫反射的颜色基础上加入一个高光颜色(常见的是白色日光)进行合成。

高光的实现方法也简单,还是在求得的余弦值上做文章,高光是产生在哪里?可以认为,光线越是垂直射入一个面,那个面高光越强;我们只关注法向量和光线向量平行的那些面,即余弦值越接近于0。 筛选出我们想要的这些面后,按照接近程度,按照余弦值的大小比例(具体来说是1-cos)来加入高光颜色分量。对一个红球加入高光的效果如下图左。

图片输出-带高光的球体

可以看到,受高光影响的面太多了,显得有点假,现实中高光通常集中在一小块区域。应该降低余弦值的影响范围,由于余弦值在[0,1]之间,可以通过对余弦值进行乘方操作以减小其值(类似Phong光照模型)。右图是取cos^64的结果,可以看到,高光区域明显小很多,也要符合现实一点。

更新:卡通渲染,原理也比较简单就不介绍了。见源码。

卡通渲染

源码在此

工程放在github上,代码文件都在sphere.c里面,这里还有一个介绍,里面有程序运行方法。

几句结语

到这里差不多介绍完了。还想说的是:

  • 以前的意识是学图形学好像都是要装个什么opengl,d3d之类的库,等费劲倒腾安装完之后,又陷入各种各样的接口里面,看了milo先生的各种回答和文章后才眼前一亮,只靠一个记事本和一个gcc编译器就能直击图形学的知识,还体会到了数学之美_(:з」∠)_,成本和门槛大大降低了。大佬指路就是不一样,opengl之类的是属于图形学中实时渲染这一块,图形学的很多知识,基础知识是不一定需要这些工具库才可以学的。
  • ppm图像格式确实简单,通俗易懂,以前不知道,在学校那会还曾研究过JPG图像格式,早知道有个ppm格式的就好了:)

细节还有欠缺,有空再修改,谢谢阅读。

画个球啊(上)——纯C语言绘制圆球相关推荐

  1. matlab 画qq图,科学网—[转载]R语言绘制QQ图 - 刘朋的博文

    R语言绘制QQ图 实例1: #############加载数据 data R R=apply(R,2,as.numeric) #R语言将字符串矩阵转化为数值型矩阵,apply()函数里面的第2个值,如 ...

  2. java看不起c语言,为什么我感觉Java比C语言难呢?总觉得逻辑上没有C语言好理解。比如各种继承介面。包之间的关系。...

    为什么我感觉Java比C语言难呢?总觉得逻辑上没有C语言好理解.比如各种继承介面.包之间的关系.以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我 ...

  3. JS是世界上最好的语言—— 使用Electron开发桌面应用(一)

    Electron 可以让你使用纯 JavaScript 调用丰富的原生(操作系统) APIs 来创造桌面应用. 你可以把它看作一个专注于桌面应用的 Node. js 的变体,而不是 Web 服务器. ...

  4. java的开源项目哪里找,我想参加开源项目的开发,请问在网上去哪找这样的项目? 纯C语言的(非C++或JAVA)...

    我想参加开源项目的开发,请问在网上去哪找这样的项目? 纯C语言的(非C++或JAVA)以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起 ...

  5. linux c语言 电子相册,纯C语言开发(电子相册).doc

    纯C语言开发(电子相册) PAGE PAGE 4 毕 业 论 文 课 题:(C语言)电子相册 摘要:对于java,.net,C++等一些面向对象的语言来说,结合相应的开发工具做出一个电子相册并非难事, ...

  6. c语言实现协议层层消息,纯C语言实现面向对象分析与示例分享.pdf

    纯C语言实现面向对象分析与示例分享 采用 语言实现的关键是如何运用 语言本身的特性来实现多态.继承面.封装的面向对 C C 象的特征最近给出了例子,大家可以参考使用 , C语言的对象化模型 面向对象的 ...

  7. c语言坦克大战程序设计,用纯C语言实现坦克大战

    好久没给大家看有意思的C语言实现的代码了,今天给大家分享一个C语言实现坦克大战的游戏源码,依旧是纯C语言,点c文件,但是是在TC的环境下,运行效果截图如下: 上下左右控制方向,空格为发射炮弹,还带声音 ...

  8. 我用纯C语言开发的中英文混合分词服务器3.0正式发布,词库190多万词,每秒切分5万+,同时提供 c、java、C#、delphi、js调用范例

    我用纯C语言开发的中英文混合分词服务器3.0正式发布,词库190多万词,每秒切分5万+,同时提供 c.java.C#.delphi.js调用范例 百万商业圈中英文混合分词服务器3.0正式发布, 绝对稳 ...

  9. 纯C语言实战-打字游戏

    纯C语言的打字游戏 学了那么长时间C语言了,每天写出来的代码都是一个小黑框,也没写过好玩的东西,突然有了一个想法,能不能写一个C语言的小游戏呢?然后百度了半天,游戏很多,但是大多数都需要引入其他的库来 ...

最新文章

  1. Oracle Advanced Security:Column Encryption Overhead
  2. 苹果正和激光雷达供应商谈判,自动驾驶硬件一把手:辞职,去看星辰大海
  3. 表的插入、更新、删除、合并操作_16_ 删除表中所有记录
  4. [Trie] Luogu P2992 [USACO08DEC]秘密消息Secret Message
  5. Silverlight WCF RIA服务(十三)数据 3
  6. JAVA 函数式接口存在
  7. 这个计算机到底是咋入门的(1.0)胡学友修改版
  8. 如何使用vsCode+Icarus verilog+GTKwave编写并仿真verilog
  9. 程序人生 | 春风得意马蹄疾,一日看尽长安花
  10. php密钥,php – 唯一的密钥生成
  11. oracle11g memory_target,oracle11g要求在操作系统层设定共享内存/dev/shm,且大于MEMORY_TARGET...
  12. virsh 保护命令 virtual protect rebase
  13. 大力哥谈 DALI - DALI 调光电源怎么用
  14. 通俗易懂了解50个IT专业术语
  15. Flutter下MVVM——Bloc的探索
  16. 输入三个城市名,按照升序显示
  17. 用Python基础创建一个简单的注册登录系统
  18. SBM模型测算代码,matlab,可算 sbm,超效率sbm,非期望sbm,非期望超效率sbm
  19. SIM800_基本指令调试笔记
  20. 初识fastAdmin表格列表的功能

热门文章

  1. 【数据分析师八大能力】
  2. 再别康桥-----双语版
  3. 动态规划入门到熟悉,看不懂来打我啊
  4. 人工智能-seaborn单双多变量绘图、两案例:NBA球员数据分析、北京租房数据统
  5. 一次圆通快递的亲身体验,不满意。
  6. FFMpeg框架代码阅读(转)
  7. Elasticsearch安装拼音插件结合IK中文分词+拼音(在线+离线)
  8. VMware Tools 其实很重要
  9. iOS开发逆向之应用重签名(下)
  10. Android LOG系统原理剖析