教程
- OpenGLES入门教程1-Tutorial01-GLKit
- OpenGLES入门教程2-Tutorial02-shader入门
- OpenGLES入门教程3-Tutorial03-三维变换
- OpenGLES入门教程4-Tutorial04-GLKit进阶
- OpenGLES进阶教程1-Tutorial05-地球月亮
这一次的的内容是光照。
概念准备
所谓的光照,是GPU为每个三角形的顶点进行光线计算,再把结果进行插值,得出每个片元的最终颜色。
OpenGL ES的灯光模拟包括:环境光、漫反射光、镜面反射光。
光线与几何图形相互作用的关键:计算出每个物体照射和发散出来多少光线。
光线计算依赖于表面法向量。法向量也是单位向量。
表面法向量可以通过平面内两个点的叉积(矢量积)来计算。
光线计算过程还包括材质、聚光灯效果、衰减因子等,但是GLKit简化了这一过程。
效果展示
核心思路
如下图,总共AI九个点,07八个面。E的z坐标是可变的,随着UISlider的数值由-1到0变化。
为了方便观察,绕X轴和Z轴旋转了一定角度。
灯光用GLKBaseEffect类。
具体细节
- 顶点
总共有9个顶点,具体坐标如下。前面为顶点坐标,后面为法线坐标。
static const SceneVertex vertexA = {{-0.5, 0.5, -0.5}, {0.0, 0.0, 1.0}};
static const SceneVertex vertexB = {{-0.5, 0.0, -0.5}, {0.0, 0.0, 1.0}};
static const SceneVertex vertexC = {{-0.5, -0.5, -0.5}, {0.0, 0.0, 1.0}};
static const SceneVertex vertexD = {{ 0.0, 0.5, -0.5}, {0.0, 0.0, 1.0}};
static const SceneVertex vertexE = {{ 0.0, 0.0, -0.5}, {0.0, 0.0, 1.0}};
static const SceneVertex vertexF = {{ 0.0, -0.5, -0.5}, {0.0, 0.0, 1.0}};
static const SceneVertex vertexG = {{ 0.5, 0.5, -0.5}, {0.0, 0.0, 1.0}};
static const SceneVertex vertexH = {{ 0.5, 0.0, -0.5}, {0.0, 0.0, 1.0}};
static const SceneVertex vertexI = {{ 0.5, -0.5, -0.5}, {0.0, 0.0, 1.0}};
重新缓存顶点数组
- 平面
SceneVertex是顶点的数据结构
SceneTriangle是平面(三角形)的数据结构
//顶点
typedef struct {
GLKVector3 position; //
GLKVector3 normal;
}
SceneVertex;
//三角形
typedef struct {
SceneVertex vertices[3];
}
SceneTriangle;
- 光源
配置漫反射光的颜色,还有光源的位置
self.baseEffect = [[GLKBaseEffect alloc] init];
self.baseEffect.light0.enabled = GL_TRUE;
self.baseEffect.light0.diffuseColor = GLKVector4Make(
0.7f, // Red
0.7f, // Green
0.7f, // Blue
1.0f);// Alpha
self.baseEffect.light0.position = GLKVector4Make(
1.0f,
1.0f,
0.5f,
0.0f);
self.extraEffect = [[GLKBaseEffect alloc] init];
self.extraEffect.useConstantColor = GL_TRUE;
- 变换
先旋转,后平移
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeRotation(GLKMathDegreesToRadians(-60.0f), 1.0f, 0.0f, 0.0f);
modelViewMatrix = GLKMatrix4Rotate(
modelViewMatrix,
GLKMathDegreesToRadians(-30.0f), 0.0f, 0.0f, 1.0f);
modelViewMatrix = GLKMatrix4Translate(
modelViewMatrix,
0.0f, 0.0f, 0.25f);
self.baseEffect.transform.modelviewMatrix = modelViewMatrix;
self.extraEffect.transform.modelviewMatrix = modelViewMatrix;
- 法线绘制
先设置光源颜色为绿色,画顶点法线
再设置光源颜色为黄色,画光源线
self.extraEffect.useConstantColor = GL_TRUE;
self.extraEffect.constantColor =
GLKVector4Make(0.0, 1.0, 0.0, 1.0);
[self.extraEffect prepareToDraw];
[self.extraBuffer drawArrayWithMode:GL_LINES
startVertexIndex:0
numberOfVertices:NUM_NORMAL_LINE_VERTS];
self.extraEffect.constantColor =
GLKVector4Make(1.0, 1.0, 0.0, 1.0);
[self.extraEffect prepareToDraw];
[self.extraBuffer drawArrayWithMode:GL_LINES
startVertexIndex:NUM_NORMAL_LINE_VERTS
numberOfVertices:(NUM_LINE_VERTS - NUM_NORMAL_LINE_VERTS)];
关键函数
- 求法向量函数
GLKVector3 SceneTriangleFaceNormal(const SceneTriangle triangle);
- 通过叉积求单位法向量函数
GLKVector3 SceneVector3UnitNormal(
const GLKVector3 vectorA,
const GLKVector3 vectorB)
总结
进阶教程不只是图形学知识的进阶,代码的规范也很重要,能避免一部分错误。
光照原理的内容可以参考这里,讲解非常详细,但是本次使用的GLKit,所以简化了许多。
附上源码