c语言 实体光照模型原理,光照模型与面绘制算法(计算机图形学)

1.光照

光源分为点光源与无穷远光源,区别在于无穷远光源只在一个方向上照明场景。

光照需要设置光源位置、颜色和光照范围(一个光照向量和该向量开始的角度范围,通常用光照单位向量和物体单位向量的数量积来判断是否在范围内(其实就是cos角的值或符号来判断))。

光强衰减分为距离衰减(纵向,衰减因子1/d太小,1/d^2太大,一般用1/(二次多项式)来作为衰减因子)和角强度衰减(横向,圆锥体光照,光方向向量的光强最强,偏离这个方向向量则开始衰减,直至看不到光)。

2.基本光照模型

光照模型:计算某一点的光强度的模型。

基本光照模型中的发光体一般限于点光源。

a.环境光

在空间中近似均匀分布,即在任何位置、任何方向上强度一样。(但物体表面所呈现的亮度不一定都一样,因为这还取决于物体表面环境光的反射系数(反射光决定了物体呈现的颜色))。

缺点:虽然不同物体具有不同的亮度,但是同一物体表面的亮度是一个恒定值,没有明暗的自然过渡。

b.漫反射

粗糙、无光泽物体(黑板)表面对光的反射(和环境光一样,是看光强和材质的漫反射系数强度的)。

0818b9ca8b590ca3270a3433284dd417.png

上图说明单位面积所接受的光照强度还与角度有关,cosθ*漫反射光照强度*材质漫反射系数(cosθ的计算可有点光源的单位方向向量和物体表面的单位方向向量数量积得出)。

缺点:对于许多物体,使用漫反射+环境光反射计算光强是可以的,但是对于金属等,还需要镜面反射

c.镜面反射

光滑物体表面对光的反射

0818b9ca8b590ca3270a3433284dd417.png

观察者只能在反射方向上才能看到反射光,偏离了该方向则看不到反射光。

镜面也不是绝对光滑的,会出现散射现象。因此Is=Ip*Ks*(cosθ)^Ns;其中Ip是光照强度,Ks是镜面反射系数,Ns是镜面反射参数(它与镜面的毛糙程度有关,因为镜面粗糙所以反射角不一定完全等于入射角,所以才会有这个反射参数)。

d.Phong光照明模型

就是综合考虑以上三个光对物体的影响,强度计算也就是上面几个光强的叠加。

e.考虑上光的衰减

还可以在各个光照模型上乘上光的衰减因子,使之更加真实

0818b9ca8b590ca3270a3433284dd417.png

2.透明、雾气、半色调模式和抖动技术

透明:材质透明就会产生折射问题,折射了一部分的光,则该表面的反射光强度就得重新调整了(整个光强-折射的光强)

雾气:从效果来看就是在光照上加个衰减函数

半色调模式

a.运用原理(但这显然会降低分辨率,用10个点来模拟一个点的强度)

当输出设备的光强度范围较小时,可以将多个像素单元组合起来表示一种强度值,从而使得可以得到的强度数增加(因为当我们观察一个包含几个像素的小区域时,眼睛往往通过取整或将细节取平均而得到一个总体的强度效果)。

0818b9ca8b590ca3270a3433284dd417.png

对于只有黑白两种强度的输出设备,它是这样来表示不同的灰度的:比较暗的地方3*3的矩形小方块里就多打几个黑点,比较亮的地方在3*3的矩形小方块里少打几个黑点。

强度模拟1~10:

0818b9ca8b590ca3270a3433284dd417.png 抖动技术:

抖动技术的效果是在整个图像上增加噪音以柔化强度边界

3.多边形绘制算法

a.均匀着色

方法:任取多边形上一点,利用光照明方程计算出它的颜色,用这个颜色填充整个多边形

适用场合:光源在无穷远处;视点在无穷远处;多边形是物体表面的精确表示

缺点:产生的图形效果不好。相邻两个多边形的法向量方向不同,计算出来的颜色也不同,因此造成整个物体表面的颜色过渡不光滑

b.光滑着色

a.Gourand着色方法

基本思想:在每个多边形顶点处计算颜色,然后在各个多边形内部进行线性插值,得到多边形内部个点颜色。

步骤:

1.计算多边形的单位法向量

2.计算多边形顶点的单位法向量(计算方法:与该顶点相邻的所有多边形的法向量平均值近似作为该顶点的近似法向量)

3.利用光照明方程计算顶点光强(颜色)

4.对多边形顶点光强(颜色)进行双线性插值,获得多边形内部各点的光强(颜色)

插值:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

a.线性插值(插边界上的点)

0818b9ca8b590ca3270a3433284dd417.png

b.双线性插值(插内部点)

0818b9ca8b590ca3270a3433284dd417.png

先用线性插值计算出边上的点的光照强度,在用边上的点计算出内部的点的光照强度。

c.增量算法

对于线性插值来讲,扫描线y递增一个单位变为y+1,增量(以I4为例)是:△I = ( I1 - I2 ) / ( y1 - y2 );则 Iy+1 = Iy + △I。

对于双线性插值来讲,△I = ( I4 - I5 ) / ( x4 - x5 )。

优点:能有效显示漫反射曲面,计算量小

缺点:高光有时会异常;当对曲面采用不同的多边形进行分割会产生不同的效果(法向量不同了);会造成该表面出现过亮或过暗的条纹(解决方案:Phong着色方法)。

b.Phong着色方法

基本思想:通过多边形顶点的法向量进行插值,获得其内部个点的法向量,又称为法向量插值着色方法。

步骤:

1.计算多边形单位法向量

2.计算多边形顶点单位法向量

3.对多边形顶点法向量进行双线性插值,获得内部各点的法向量

4.利用光照明方程计算多边形内部各点的颜色

法向量线性(双线性)插值方法和着色的插值方法大致是一样的,只不过此处算的是法向量,而不是颜色值

法向量增量算法和着色的增量算法也是大致相同的,只是此处计算的法向量的值

优点:比Gouraud方法更加真实,体现在高光区域的扩散,产生正确的高光区域

缺点:计算量太大;处理某些多边形分割的曲面时,效果可能还不如Gouraud算法好

4.光线跟踪方法

a.本节参考

http://blog.csdn.net/ryfdizuo/article/details/6252776

http://wenku.baidu.com/view/1aebb91aa8114431b90dd8e2.html?re=view&pn=51

http://www.cnblogs.com/daniagger/archive/2012/05/27/2520254.html

b.原理

由于从光源发出的光线有无穷多条,使得直接从光源出发对光线进行跟踪变得非常困难。实际上,从光源发出的光线只有少数经由场景的反射和透射(折射)后到达观察者的眼中。为此标准光线跟踪算法采用逆向跟踪技术完成整个场景的绘制。

c.光线跟踪思路

从视点出发,通过图像平面上每个像素中心向场景发出一条光线,光线的起点为视点,方向为像素中心和视点连线单位向量。光线与离视点最近的场景物体表面交点有三种可能:

当前交点所在的物体表面为理想漫射面,跟踪结束。

当前交点所在的物体表面为理想镜面,光线沿其镜面发射方向继续跟踪。

当前交点所在的物体表面为规则透射面,光线沿其规则透射方向继续跟踪。

0818b9ca8b590ca3270a3433284dd417.png

d.步骤伪码

//设置视点,投影平面以及窗口参数

//for(窗口内每一条扫描线)

//{

//for(扫描线上的每一个像素点)

//{

//确定从视点指向像素中心的光线ray

//像素的颜色=RayTracing(ray,1);

//}

//}

//Color RayTracing(Ray ray,int depth)

//{

//求ray与物体表面最近的交点P;

//if(有交点)

//{

//用局部光照模型计算环境光Ic;

//color=Ic;

//if(depth

//{

//计算ray的反射光线;

//Is=RayTracing(反射光线,depth+1);

// if(物体是透明的)

//{

//计算ray的透射光线;

//It=RayTracing(透射光线,depth+1);

//}

//color=Ic+Is+It;

//}

// }

//else

//{

//color=背景色;

//}

//return color;

//}

e.优缺点

优点:能够方便的产生阴影,模拟镜面反射与折射现象。

缺点:计算量大,每条光线都要与场景中的物体进行求交、计算光照模型。

f.光线跟踪的反走样

0818b9ca8b590ca3270a3433284dd417.png

1.对每一个像素的角点计算光线跟踪的光强

2.比较像素四个角点的光强,确定要进行细分的像素

3.对细分后新增的角点计算光线跟踪的光强。然后,重复2,3步骤,直到各角点的光强比较接近为止

4.加权平均求出投影平面上各像素点的光强

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基本光照模型算法通常包括漫反射、镜面反射和环境光三个部分。下面是一个简单的示例程序,使用C语言和OpenGL实现了基本光照模型算法。 ```c #include <GL/glut.h> #include <math.h> // 光源位置 GLfloat light_position[] = { 1.0f, 1.0f, 1.0f, 0.0f }; // 材质属性 GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f }; GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat mat_shininess[] = { 100.0f }; // 物体位置 GLfloat object_pos[] = { 0.0f, 0.0f, 0.0f }; void init(void) { // 设置光源位置 glLightfv(GL_LIGHT0, GL_POSITION, light_position); // 设置材质属性 glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); // 启用光照 glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // 启用深度测试 glEnable(GL_DEPTH_TEST); } void display(void) { // 清空缓冲区 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 设置物体位置 glPushMatrix(); glTranslatef(object_pos[0], object_pos[1], object_pos[2]); // 绘制物体 glutSolidSphere(1.0, 20, 20); glPopMatrix(); // 刷新显示 glutSwapBuffers(); } void reshape(int w, int h) { // 设置视口大小 glViewport(0, 0, (GLsizei)w, (GLsizei)h); // 设置投影矩阵 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, (GLdouble)w / (GLdouble)h, 1.0, 100.0); // 设置模型视图矩阵 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 'w': object_pos[2] -= 0.1; break; case 's': object_pos[2] += 0.1; break; case 'a': object_pos[0] -= 0.1; break; case 'd': object_pos[0] += 0.1; break; case 'q': object_pos[1] -= 0.1; break; case 'e': object_pos[1] += 0.1; break; } glutPostRedisplay(); } int main(int argc, char **argv) { // 初始化 GLUT glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(400, 400); glutInitWindowPosition(100, 100); glutCreateWindow("Basic Lighting"); // 初始化 init(); // 设置回调函数 glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); // 进入主循环 glutMainLoop(); return 0; } ``` 这个示例程序使用了OpenGL的固定管线,其中`init()`函数设置了光源位置和材质属性,并启用了光照和深度测试。`display()`函数绘制了一个球体,`reshape()`函数设置了投影矩阵和模型视图矩阵,`keyboard()`函数处理键盘事件。在主函数中,我们使用了GLUT库初始化窗口并设置回调函数,然后进入主循环。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值