第二十节—光照计算2
2020-10-16 本文已影响0人
L_Ares
本文为L_Ares个人写作,如需转载请表明原文出处。
上一节已经学习过了光照的种类,特性,关于光照材质的属性,以及光照的计算公式,本节将通过GLKBaseEffect
来实现光照效果。
当然,GLKBaseEffect是不需要我们来自己写光照计算的shader代码的。GLSL才需要。
光照的效果图如图1.0所示。
1.0.png从图1.0中可以得到的信息是这个图形需要8个三角形精灵来完成绘制。
那么确认了三角形的数量以后,来确认一下各顶点的位置。如图1.1所示:
1.1.pngE点就是可以升高降低的三角形锥的顶点。
另外,本文用到的第三方的Utils
将在文章末尾放入。
直接上代码
//
// ViewController.m
// 07光照金字塔
//
// Created by EasonLi on 2020/10/15.
//
#import "ViewController.h"
#import "AGLKVertexAttribArrayBuffer.h"
#import "sceneUtil.h"
@interface ViewController ()
//图形上下文
@property (nonatomic, strong) EAGLContext *mContext;
//GLKBaseEffect绘制对象,苹果封装的用于简便shader操作的类
@property (nonatomic, strong) GLKBaseEffect *mBaseEffect;
//顶点缓冲区的第三方工具类
@property (nonatomic, strong) AGLKVertexAttribArrayBuffer *mVertexBuffer;
//三角锥的锥顶点的高度
@property (nonatomic, assign) GLfloat centreVertexHeight;
@end
@implementation ViewController
{
//三角形数组
SceneTriangle triangles[NUM_FACES];
}
#pragma mark - Controller生命周期
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpES];
[self setUpBaseEffect];
[self setUpVertex];
[self setUpBuffer];
// Do any additional setup after loading the view.
}
#pragma mark - 设置OpenGL ES的基本环境
- (void)setUpES
{
//1. 创建图形上下文
self.mContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
//2. 设置GLKView
GLKView *glkView = (GLKView *)self.view;
glkView.context = self.mContext;
glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
glkView.drawableDepthFormat = GLKViewDrawableDepthFormat24;
//3. 设置当前的图形上下文
[EAGLContext setCurrentContext:self.mContext];
}
#pragma mark - 设置GLKBaseEffect
- (void)setUpBaseEffect
{
//1. 初始化GLKBaseEffect对象并给到属性
self.mBaseEffect = [[GLKBaseEffect alloc] init];
//2. 即然要使用光照,那么就要把GLKBaseEffect中的light的enable设置成可用
// 用到几个光源就可以开启几个
self.mBaseEffect.light0.enabled = GL_TRUE;
//3. 设置光源的属性
// (1). 首先设置光源在世界坐标系中的位置[-1,1]区间自己选择
self.mBaseEffect.light0.position = GLKVector4Make(-1.f, 1.f, 0.5f, 0.f);
// (2). 然后设置光源的漫反射颜色。也可以设置镜面或者环境颜色,自己随意
self.mBaseEffect.light0.diffuseColor = GLKVector4Make(0.8f, 0.8f, 0.8f, 1.f);
//4. 最好把图形稍微做一些变换,不然图形初始都是以坐标系原点为基准的,观察起来不舒服
// 可以把这段代码去掉,就知道为什么要变换了
[self rotateGraph];
}
#pragma mark - 设置顶点相关
- (void)setUpVertex
{
//设置三角形数组中每个三角形的顶点坐标和法线坐标
triangles[0] = SceneTriangleMake(vertexA, vertexB, vertexD);
triangles[1] = SceneTriangleMake(vertexB, vertexC, vertexF);
triangles[2] = SceneTriangleMake(vertexD, vertexB, vertexE);
triangles[3] = SceneTriangleMake(vertexB, vertexF, vertexE);
triangles[4] = SceneTriangleMake(vertexD, vertexE, vertexH);
triangles[5] = SceneTriangleMake(vertexE, vertexF, vertexH);
triangles[6] = SceneTriangleMake(vertexG, vertexD, vertexH);
triangles[7] = SceneTriangleMake(vertexH, vertexF, vertexI);
}
#pragma mark - 设置缓冲区
- (void)setUpBuffer
{
//初始化顶点缓冲区
self.mVertexBuffer = [[AGLKVertexAttribArrayBuffer alloc] initWithAttribStride:sizeof(SceneVertex) numberOfVertices:sizeof(triangles)/sizeof(SceneVertex) bytes:triangles usage:GL_DYNAMIC_DRAW];
self.centreVertexHeight = 0.f;
}
#pragma mark - 设置GLKView的代理
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
//设置清屏颜色
glClearColor(0.3f, 0.3f, 0.3f, 1.f);
//清空缓冲区
glClear(GL_COLOR_BUFFER_BIT);
//准备绘制
[self.mBaseEffect prepareToDraw];
//准备绘制顶点数据
[self.mVertexBuffer prepareToDrawWithAttrib:GLKVertexAttribPosition numberOfCoordinates:3 attribOffset:offsetof(SceneVertex, position) shouldEnable:YES];
//准备绘制光照数据
[self.mVertexBuffer prepareToDrawWithAttrib:GLKVertexAttribNormal numberOfCoordinates:3 attribOffset:offsetof(SceneVertex, normal) shouldEnable:YES];
//绘制
[self.mVertexBuffer drawArrayWithMode:GL_TRIANGLES startVertexIndex:0 numberOfVertices:sizeof(triangles)/sizeof(SceneVertex)];
}
#pragma mark - 其余封装方法
//设置一下初始的模型视图矩阵,发生一下变换
- (void)rotateGraph
{
//创建一个4 * 4矩阵,矩阵围绕任意矢量旋转
//旋转是负的度数是因为OpenGL ES是右手系,而且从轴正方向一侧向原点看逆时针旋转为正
//顺时针旋转为负,按照习惯,还是负的比较容易看到锥顶,度数自己随意
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeRotation(GLKMathDegreesToRadians(-60.f), 1.f, 0.f, 0.f);
//跟上面同理,绕Z轴旋转一个负角度,因为我们并没有开启正背面剔除,有一块可能会重叠
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(-30.f), 0.f, 0.f, 1.f);
//设置baseEffect的模型视图矩阵
self.mBaseEffect.transform.modelviewMatrix = modelViewMatrix;
}
/**
更新法向量
如果你需要把顶点的位置发生变化,那么法向量一定也是随着改变的,为了光照的效果
就需要随着顶点数据的变化,更新法向量
*/
- (void)updateNormals
{
//更新每个顶点的法向量
SceneTrianglesUpdateFaceNormals(triangles);
//重新更新VBO中的顶点数据
[self.mVertexBuffer reinitWithAttribStride:sizeof(SceneVertex) numberOfVertices:sizeof(triangles)/sizeof(SceneVertex) bytes:triangles];
}
#pragma mark - 重写centreVertexHeight属性的setter方法
- (void)setCentreVertexHeight:(GLfloat)centreVertexHeight
{
_centreVertexHeight = centreVertexHeight;
//更新锥顶的那个顶点的z值,以达到改变高度的情况
SceneVertex nVertexE = vertexE;
nVertexE.position.z = _centreVertexHeight;
//重新把顶点改变完的三角形放回到三角形数组中
triangles[2] = SceneTriangleMake(vertexD, vertexB, nVertexE);
triangles[3] = SceneTriangleMake(nVertexE, vertexB, vertexF);
triangles[4] = SceneTriangleMake(vertexD, nVertexE, vertexH);
triangles[5] = SceneTriangleMake(nVertexE, vertexF, vertexH);
//更新法向量
[self updateNormals];
}
#pragma mark - UISlider的滑动事件,改变中心点的高度
- (IBAction)clickSlider:(id)sender {
NSLog(@"sliderValue : %f",((UISlider *)sender).value);
self.centreVertexHeight = ((UISlider *)sender).value;
}
@end
执行效果如图1.2所示 :
1.2.png另附工具类文件。
提取码 : 7jh0
里面添加了详细的注释。