Cg_OpenGL Lighting

2023-10-29 22:18
文章标签 opengl lighting cg

本文主要是介绍Cg_OpenGL Lighting,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

光照模型将采用广泛应用的phong模型,虽然这种模型在openGL的固定管线中已经实现了,但是学习该光照模型可以更加清楚的了解可编程渲染管线的流程。

 

首先要实现phong光照模型先要了解该模型中光照计算,关于phong模型光照计算的相关资料网上相当多,或者参考任何一本计算机图形学的相关书籍即可,这里只给出计算公式。

 

C = ambient + diffuse + specular

 

从公式中可以得出,物体顶点的最终颜色是由环境反射,漫反射和镜面反射三个成分来决定的。环境反射的计算公式为:

 

ambient = IaKa

 

其中,Ia是光的环境反射强度,Ka是物体材质的环境射系数。环境反射很简单,和光源、法线等等都没有关系,下面是只有环境反射的例子。

 

 

Fig1环境反射,Ia=(1.0, 1.0, 1.0)Ka=(0.15,0.15,0.0)

 

和环境反射相比,漫反射就稍微复杂一点,它和光源的位置和物体顶点的法线都有关系。漫反射的计算公式为:

 

diffuse = I­d­K(NL)

 

其中I­d­是光的漫反射强度,Kd是物体材质漫反射系数,NL表示法线N和入射光线L的内积。下面是只有面反射的例子。

 

 

Fig2漫反射,Id=(1.0, 1.0, 1.0)Kd=(1.0, 1.0 , 0.0)

 

最后是镜面反射,和漫反射相比,镜面反射又复杂了一点。它不仅和光源位置,物体顶点法线有关系,而且还和我们观看的位置有关系。镜面反射的计算公式为:

 

specular = IsKs(VR)­n

 

其中Is是光的镜面反射强度,Ks是物体材质的镜面反射系数,VR表示相机朝向向量V和反射光线R的内积,n表示该内积的n次幂。这里反射光线R可以通过公式

 

= 2(LN)N-L­

 

来得到。这里还可以使用half vector来计算,计算half vector要比计算反射向量R方便快速的多。

 

H=(L+V)/2

 

所以,镜面反射公式现在可以写成

 

specular = IsKs(NH)­n

 

下面是只有镜面反射的例子。

 

 

 

Fig3镜面反射,Is=(1.0, 1.0, 1.0)Ks=(1.0, 1.0 , 1.0,), n=32

通过上面的过程,分别计算出了物体每个顶点的环境反射,面反射和镜面反射。最后简单将这三个成分相加即可得到顶点最终的颜色。

 

C = IaKa + I­d­K(NL)IsKs(NH)­n

 

图fig4显示了这个相加的过程。

 

+

+

=

Fig4 phong光照

 

下面是vertex shader的代码。由于是基于vertex的光照,所以不需要fragment shader。

vertex脚本:

uniform float3 LightPosition; //光源位置
uniform float3 eyePosition;   //相机位置
uniform float3 I;              //光强度
uniform float3 Ka;             //环境光反射系数
uniform float3 Kd;             //漫反射系数
uniform float3 Ks;             //镜面反射系数
uniform float shininess;      //n幂次struct output
{float4 position : POSITION; float4 color     : COLOR; 
};output v_main( float4 position : POSITION,float3 normal   : NORMAL,uniform float4x4 MV, // 在相机坐标系中计算,所以要用到ModelView变换矩阵uniform float4x4 MVP // ModelViewProjection变换矩阵)
{output OUT;OUT.position = mul(MVP, position);float3 N = normalize(mul(MV, float4(normal,0.0)) ).xyz; //转换法线到相机坐标系float3 P = mul(MV, position).xyz; //转换物体顶点到相机坐标系float3 L = normalize(LightPosition - P);float NdotL = max(dot(N,L),0); //判断法线和入射光线的角度是否大于90度float3 ambient = Ka * I; //环境反射float3 diffuse = Kd * I * NdotL; //漫反射float3 V = normalize(eyePosition - P);float3 H = normalize(L+V); //half vectorfloat NdotH = pow(max(dot(N,H), 0), shininess);if(NdotL<=0) NdotH = 0.0;float3 specular = Ks*I*NdotH; //镜面反射float3 color = ambient + diffuse +specular; //所有成分相加OUT.color.xyz= color;OUT.color.w = 1.0;return OUT;
}


主程序:

#include <gl/glut.h>
#include <cg/cg.h>
#include <Cg/cgGL.h>
#include <stdio.h>
#include <Windows.h>int ww = 640, hh = 480;void render();
void reshape(int w, int h);static CGcontext   myCgContext;
static CGprofile   myCgVertexProfile;
static CGprogram   myCgVertexProgram;static const char *myProgramName = "Lighting CG";
static const char *myVertexProgramFileName = "CSDN_02v.cg";
static const char *myVertexProgramName = "v_main";CGparameter lp, ep, i, a, d, s, n;
//display FPS on the title of the window
static float lastTime   = 0.0f;
void displayFPS(){static float framesPerSecond    = 0.0f;       // This will store our fps// This will hold the time from the last framefloat currentTime = GetTickCount() * 0.001f;    if( currentTime - lastTime > 0.0f ){framesPerSecond = 1/(currentTime - lastTime);char strFrameRate[256];lastTime = currentTime;sprintf(strFrameRate, "Current Frames Per Second: %f", framesPerSecond);glutSetWindowTitle( strFrameRate);framesPerSecond = 0;}
}int main(int argc, char** argv)
{//【1】初始化部分glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);glutInitWindowSize(ww,hh);glutCreateWindow(myProgramName);//【2】构建shader运行环境;myCgContext = cgCreateContext();cgGLSetDebugMode(CG_FALSE);cgSetParameterSettingMode(myCgContext, CG_DEFERRED_PARAMETER_SETTING);myCgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);cgGLSetOptimalOptions(myCgVertexProfile);myCgVertexProgram =cgCreateProgramFromFile(myCgContext,              /* Cg runtime context */CG_SOURCE,                /* Program in human-readable form */myVertexProgramFileName,  /* Name of file containing program */myCgVertexProfile,        /* Profile: OpenGL ARB vertex program */myVertexProgramName,      /* Entry function name */NULL);                    /* No extra compiler options */cgGLLoadProgram(myCgVertexProgram);//【3】将shader载入,并运行glutDisplayFunc(render);glutReshapeFunc(reshape);glEnable(GL_DEPTH_TEST);glutMainLoop();return 0;
}void reshape(int w, int h)
{glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(45, (float)w/(float)h, 0.1, 100);glViewport(0,0,w,h);ww = w;hh = h;
}void render()
{displayFPS();//【3.1】gl视图变换glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glClearColor(.0f, .0f, .2f, 1.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(.0,.0,5.0, .0,.0,.0, .0,1.0,.0);static float angle;glRotatef(angle, 0.0,1.0,0.0);//【3.2】把程序与当前API状态绑定起来;cgGLBindProgram(myCgVertexProgram);cgGLEnableProfile(myCgVertexProfile);//将ModelViewProjection矩阵传入shaderCGparameter mvp = cgGetNamedParameter(myCgVertexProgram, "MVP");cgGLSetStateMatrixParameter(mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);CGparameter mv = cgGetNamedParameter(myCgVertexProgram, "MV");cgGLSetStateMatrixParameter(mv, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY);//注意传参的方法☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
	lp = cgGetNamedParameter(myCgVertexProgram, "LightPosition");ep = cgGetNamedParameter(myCgVertexProgram, "eyePosition");i = cgGetNamedParameter(myCgVertexProgram, "I");a = cgGetNamedParameter(myCgVertexProgram, "Ka");d = cgGetNamedParameter(myCgVertexProgram, "Kd");s = cgGetNamedParameter(myCgVertexProgram, "Ks");n = cgGetNamedParameter(myCgVertexProgram, "shininess");cgSetParameter3f(lp,1.0,1.0,1.0);cgSetParameter3f(ep,0,0.5,0);cgSetParameter3f(i ,1.0, 1.0, 1.0);cgSetParameter3f(a ,0.15,0.15, 0.0);cgSetParameter3f(d ,1.0, 1.0 , 0.0);cgSetParameter3f(s ,1.0, 1.0 , 1.0);cgSetParameter1f(n ,32);glutSolidTorus(0.3,1.0,30,30);cgGLDisableProfile(myCgVertexProfile);angle += 0.5;if(angle >=360) angle = 0.0f;glutSwapBuffers();glutPostRedisplay();
}



由于是基于vertex的光照,虽然采用gouraud shading要比flat shading效果好的多,但是和phong shading的效果相差很大。这里大家要注意的是,phong modelphong shading的区别。上一篇教程所讲的光照模型叫phong model,而这篇教程要介绍的一种着色方法叫phong shading,必须要使用shader才能实现。下面的图中对比了采用flat shadinggouraud shadingphong shading技术渲染的一个圆环。

  

Flat shading

Gouraud shading

Phong shading


Cg来实现基于pixel lighingphong shading光照就容易多了。绝大部分的Cg shader代码都是一样的,主要的改变就是这次不是在vertex shader里光照,而是在fragment shader里计算光照。所以整个vertex shader的代码很简单,将要渲染的物体的顶点位置,顶点法线传入fragment shader就是vertex shader的全部工作。整个vertex shader的代码如下。

  

上面的代码的输出结构体中有三个成员。Position是传入的物体的顶点,该顶点将用ModelViewProjection矩阵转换成剪裁坐标系中的坐标供光栅化使用。一旦将坐标转换后,我们就无法在fragment shader中使用物体的顶点坐标了。由于要在fragmentshader中计算光照,所以我们要将物体的顶点位置,顶点法线都传入到fragment shader中。这里物体转换前的顶点和法线分别使用了语义TEXCOORD0TEXCOORD1,代表将它们作为纹理坐标后传入fragment shader。这样GPU会把顶点和法线信息当做纹理坐标来处理,在贴图的时候,GPU会根据纹理自动插值计算每个像素对应的颜色,而现在GPU插值计算出来的就是每个像素对应的坐标和法线信息了。有了这些数据就可以进行phong shading的计算了。光照计算的公式和方法和上一个教程介绍的一模一样。

vertex脚本:

struct output
{float4 position  : POSITION;    float3 objectPos : TEXCOORD0;   float3 normal     : TEXCOORD1;
};output v_main( float4 position : POSITION,float3 normal   : NORMAL,uniform float4x4 MV,uniform float4x4 MVP)
{output OUT;OUT.position = mul(MVP, position);OUT.objectPos = mul(MV, position).xyz;OUT.normal = mul(MV, float4(normal,0.0)).xyz;return OUT;
}


fragment脚本:

uniform float3 LightPosition;
uniform float3 eyePosition;
uniform float3 I;
uniform float3 Ka;
uniform float3 Kd;
uniform float3 Ks;
uniform float shininess;struct input{float3 objectPos: TEXCOORD0;   float3 normal   : TEXCOORD1;
};struct output{float4 color     : COLOR;
};output f_main( in input IN )
{output OUT;float3 N = normalize(IN.normal);float3 P = IN.objectPos;float3 L = normalize(LightPosition - P);float NdotL = max(dot(N,L),0);float3 ambient = Ka * I;float3 diffuse = Kd * I * NdotL;float3 V = normalize(eyePosition - P);float3 H = normalize(L+V);float NdotH = pow(max(dot(N,H), 0), shininess);if(NdotL<=0)NdotH = 0.0;float3 specular = Ks*I*NdotH;float3 color = ambient + diffuse + specular;OUT.color.xyz= color;OUT.color.w = 1.0;return OUT;
}


主程序:

#include <gl/glut.h>
#include <cg/cg.h>
#include <Cg/cgGL.h>
#include <stdio.h>
#include <Windows.h>int ww = 640, hh = 480;void render();
void reshape(int w, int h);static CGcontext   myCgContext;
static CGprofile   myCgVertexProfile;
static CGprofile   myCgFragmentProfile;
static CGprogram   myCgVertexProgram;
static CGprogram   myCgFragmentProgram;static const char *myProgramName = "Lighting CG2";
static const char *myVertexProgramFileName = "CSDN_03v.cg";
static const char *myVertexProgramName = "v_main";
static const char *myFragmentProgramFileName = "CSDN_03f.cg";
static const char *myFragmentProgramName = "f_main";CGparameter lp, ep, i, a, d, s, n;
//display FPS on the title of the windowvoid displayFPS(){static float lastTime   = 0.0f;static float framesPerSecond    = 0.0f;       // This will store our fps// This will hold the time from the last framefloat currentTime = GetTickCount() * 0.001f;    if( currentTime - lastTime > 0.0f ){framesPerSecond = 1/(currentTime - lastTime);char strFrameRate[256];lastTime = currentTime;sprintf(strFrameRate, "Current Frames Per Second: %f", framesPerSecond);glutSetWindowTitle( strFrameRate);framesPerSecond = 0;}
}int main(int argc, char** argv)
{//【1】初始化部分glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);glutInitWindowSize(ww,hh);glutCreateWindow(myProgramName);//【2】构建shader运行环境;myCgContext = cgCreateContext();cgGLSetDebugMode(CG_FALSE);cgSetParameterSettingMode(myCgContext, CG_DEFERRED_PARAMETER_SETTING);myCgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);cgGLSetOptimalOptions(myCgVertexProfile);myCgVertexProgram =cgCreateProgramFromFile(myCgContext,              /* Cg runtime context */CG_SOURCE,                /* Program in human-readable form */myVertexProgramFileName,  /* Name of file containing program */myCgVertexProfile,        /* Profile: OpenGL ARB vertex program */myVertexProgramName,      /* Entry function name */NULL);                    /* No extra compiler options */cgGLLoadProgram(myCgVertexProgram);myCgFragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);cgGLSetOptimalOptions(myCgFragmentProfile);myCgFragmentProgram =cgCreateProgramFromFile(myCgContext,                /* Cg runtime context */CG_SOURCE,                  /* Program in human-readable form */myFragmentProgramFileName,  /* Name of file containing program */myCgFragmentProfile,        /* Profile: OpenGL ARB vertex program */myFragmentProgramName,      /* Entry function name */NULL);                      /* No extra compiler options */cgGLLoadProgram(myCgFragmentProgram);//【3】将shader载入,并运行glutDisplayFunc(render);glutReshapeFunc(reshape);glEnable(GL_DEPTH_TEST);glutMainLoop();return 0;
}void reshape(int w, int h)
{glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(45, (float)w/(float)h, 0.1, 100);glViewport(0,0,w,h);ww = w;hh = h;
}void render()
{displayFPS();//【3.1】gl视图变换glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glClearColor(.0f, .0f, .2f, 1.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(.0,.0,5.0, .0,.0,.0, .0,1.0,.0);static float angle;glRotatef(angle, 0.0,1.0,0.0);//【3.2】把程序与当前API状态绑定起来;cgGLBindProgram(myCgVertexProgram);cgGLEnableProfile(myCgVertexProfile);cgGLBindProgram(myCgFragmentProgram);cgGLEnableProfile(myCgFragmentProfile);//将ModelViewProjection矩阵传入shaderCGparameter mvp = cgGetNamedParameter(myCgVertexProgram, "MVP");cgGLSetStateMatrixParameter(mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);CGparameter mv = cgGetNamedParameter(myCgVertexProgram, "MV");cgGLSetStateMatrixParameter(mv, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY);//传参的方法lp = cgGetNamedParameter(myCgFragmentProgram, "LightPosition");ep = cgGetNamedParameter(myCgFragmentProgram, "eyePosition");i = cgGetNamedParameter(myCgFragmentProgram, "I");a = cgGetNamedParameter(myCgFragmentProgram, "Ka");d = cgGetNamedParameter(myCgFragmentProgram, "Kd");s = cgGetNamedParameter(myCgFragmentProgram, "Ks");n = cgGetNamedParameter(myCgFragmentProgram, "shininess");cgSetParameter3f(lp,1.0,1.0,1.0);cgSetParameter3f(ep,0,0.5,0);cgSetParameter3f(i ,1.0, 1.0, 1.0);cgSetParameter3f(a ,0.15,0.15, 0.0);cgSetParameter3f(d ,1.0, 1.0 , 0.0);cgSetParameter3f(s ,1.0, 1.0 , 1.0);cgSetParameter1f(n ,32);glutSolidTorus(0.3,1.0,30,30);cgGLDisableProfile(myCgVertexProfile);cgGLDisableProfile(myCgFragmentProfile);angle += 0.5;if(angle >=360) angle = 0.0f;glutSwapBuffers();glutPostRedisplay();
}


phong model结果1:                                                                                                    phong shading结果2:

                                             


这篇关于Cg_OpenGL Lighting的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/303702

相关文章

OPENGL顶点数组, glDrawArrays,glDrawElements

顶点数组, glDrawArrays,glDrawElements  前两天接触OpenGL ES的时候发现里面没有了熟悉的glBegin(), glEnd(),glVertex3f()函数,取而代之的是glDrawArrays()。有问题问google,终于找到答案:因为OpenGL ES是针对嵌入式设备这些对性能要求比较高的平台,因此把很多影响性能的函数都去掉了,上述的几个函数都被移除了。接

OpenGL ES学习总结:基础知识简介

什么是OpenGL ES? OpenGL ES (为OpenGL for Embedded System的缩写) 为适用于嵌入式系统的一个免费二维和三维图形库。 为桌面版本OpenGL 的一个子集。 OpenGL ES管道(Pipeline) OpenGL ES 1.x 的工序是固定的,称为Fix-Function Pipeline,可以想象一个带有很多控制开关的机器,尽管加工

OpenGL雾(fog)

使用fog步骤: 1. enable. glEnable(GL_FOG); // 使用雾气 2. 设置雾气颜色。glFogfv(GL_FOG_COLOR, fogColor); 3. 设置雾气的模式. glFogi(GL_FOG_MODE, GL_EXP); // 还可以选择GL_EXP2或GL_LINEAR 4. 设置雾的密度. glFogf(GL_FOG_DENSITY, 0

opengl纹理操作

我们在前一课中,学习了简单的像素操作,这意味着我们可以使用各种各样的BMP文件来丰富程序的显示效果,于是我们的OpenGL图形程序也不再像以前总是只显示几个多边形那样单调了。——但是这还不够。虽然我们可以将像素数据按照矩形进行缩小和放大,但是还不足以满足我们的要求。例如要将一幅世界地图绘制到一个球体表面,只使用glPixelZoom这样的函数来进行缩放显然是不够的。OpenGL纹理映射功能支持将

OpenGL ES 2.0渲染管线

http://codingnow.cn/opengles/1504.html Opengl es 2.0实现了可编程的图形管线,比起1.x的固定管线要复杂和灵活很多,由两部分规范组成:Opengl es 2.0 API规范和Opengl es着色语言规范。下图是Opengl es 2.0渲染管线,阴影部分是opengl es 2.0的可编程阶段。   1. 顶点着色器(Vert

【UVA】11400-Lighting System Design(动态规划)

这道题感觉状态式不是很好推。。。 WA了好几次是因为排序的时候出问题了。 这道题出在线性结构里了,先说一下最长上升子序列吧。 dp[i]代表了以array[i]结尾的时候,最长子序列长度。 推导的时候,以起点递增的顺序进行推导。 #include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#i

《黑神话:悟空》专题合集MOD/修改器/壁纸/音乐/CG剧情

《黑神话:悟空》专题合集」 链接:https://pan.quark.cn/s/d67857f4e308 包含内容: 《黑神话:悟空》MOD合集 《黑神话:悟空》修改器(风灵月影) 《黑神话:悟空》壁纸合集 《黑神话:悟空》3小时CG完整剧情合集 4K120帧最高画质!国语 简中字幕 附:4K 结尾动画合集 ​​​国语 简中字幕 《黑神话:悟空》主题曲 《黑神话

OpenGL/GLUT实践:流体模拟——数值解法求解Navier-Stokes方程模拟二维流体(电子科技大学信软图形与动画Ⅱ实验)

源码见GitHub:A-UESTCer-s-Code 文章目录 1 实现效果2 实现过程2.1 流体模拟实现2.1.1 网格结构2.1.2 数据结构2.1.3 程序结构1) 更新速度场2) 更新密度值 2.1.4 实现效果 2.2 颜色设置2.2.1 颜色绘制2.2.2 颜色交互2.2.3 实现效果 2.3 障碍设置2.3.1 障碍定义2.3.2 障碍边界条件判定2.3.3 障碍实现2.3.

OpenGL——着色器画一个点

一、 绘制 在窗口中间画一个像素点: #include <GL/glew.h>#include <GLFW/glfw3.h>#include <iostream>using namespace std;#define numVAOs 1GLuint renderingProgram;GLuint vao[numVAOs];GLuintcreateShaderProgram (){c

试用GLFW并创建OpenGL和DX的环境

介绍GLFW GLFW官网:https://www.glfw.org/ GLFW is an Open Source, multi-platform library for OpenGL, OpenGL ES and Vulkan development on the desktop. It provides a simple API for creating windows, contex