OpenGL ES

第二十节—光照计算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.png

E点就是可以升高降低的三角形锥的顶点。

另外,本文用到的第三方的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

里面添加了详细的注释。

上一篇 下一篇

猜你喜欢

热点阅读