shji
数据类型
整型(有符号/无符号)
浮点数(单精度)
布尔值
向量类型/矩阵类型
bool bDone = false
int value =1;
unint vale = 21u
float value = 2.1
向量/分量类型
vec2,vec3,vec4 2分量 3 分量 4 分量复电向量
ivec2 ivec3 ivec4 2 分量 3 分量 4分量整型向量
uvec2 uvec3 uvec4 2分量 3 分量 4分量无符号整型向量
bvec2 bvec3 b各处 2分量 3分量 4 分量bool型向量
向量使用
// 声明4分量的float向量
vec4 value
vec4 v1 = vec4(1,2,3,4)
vec4 v2 = vec4(0,0,0,0)
3.向量运算
v1 = v2 + v3;
vec4 v4 = v1;
v1 += vec4(10,10,10,10)
v1 *- 5;
// 获取向量中的元素 通过下标
v1.x =3.0
v1.y = 4.0
v1.z = 4.0
v1.w = 4.0
v1.xy = vec2(3,5)
v1.xyz = vec3(1,2,3)
获取向量元素可通过r,g,b,a获取向量中元素
v2.r = 1.0f;
v2= vec4(1.0,1.0,1.0,1.0)
获取向量元素 可通过 s,t,p,q (纹理中)
v1.st = vec2(1.0,2.0)
不可以如下
va.st = v2.st
向量数据类型还可以swizzle(调换)操作
v1.bgra = v2,bgra
//向量的一次性所有分量操作
v1.x = v2.x + 5.0f
v1.xyz = v2.xyz + vec3(5,4,3)
矩阵类型
与向量类型不同矩阵类型仅支持 bool 整数
mat4 m1
vec4 v2
vec4 vOutPos
矩阵可以和向量相乘 应用顶点模型/投影矩阵变化时
m1 = {10f,10f,10f,10f,
10f,10f,10f,10f,
10f,10f,10f,10f,}
vOutPos = v2 * m1;
m1 = mat4(1.0f); /// m1 变单元矩阵
存储限定符
着色器变量声明过程中的修饰符
输入变量:从外部(客户端/上一个阶段着色器的属性/Uniform等)
输出变量:从任何着色器阶段进入写入的变量
限定符常用
<none>只是普通的本地变量,外部不可见 不可访问
const 一个编译常量 或者是一个对函数来说为只读的参数
in/varying 从以前阶段传递过来的变量
in/varying centroid 一个从以前阶段传递过来的变量 使用质心插值
out/attribute. 传递到下一个阶段或者在一个函数中指定一个返回值
out/attribute centroid 传递到下一个阶段 质心插值
uniform 从一个客户端代码传递过来的变量 在顶点之间不做改变
varying从顶点着色器传递到片元着色器 一半会传递颜色值
/*
uniform
在计算机图形学中,uniform是一个术语,用于描述在图形渲染过程中保持不变的变量或值。
uniform变量通常用于传递渲染相关的参数,如光照强度、材质属性、变换矩阵等。这些变量在整个渲染过程中保持不变,无论是对单个物体还是整个场景进行渲染。
在OpenGL和OpenGL ES等图形 API 中,uniform变量通过uniform变量声明和赋值来进行设置。你可以在着色器代码中使用uniform变量,并在应用程序中通过相应的 API 函数将其值传递给图形渲染上下文。
使用uniform变量可以方便地在应用程序和着色器之间共享数据,并实现更加灵活和可定制的渲染效果
外部 applocation传递给 vertx/fragment shader 变量修饰
A.他是通过glUniform**()
B.在vertex fragment shader 程序内部uniform 和 const类型 表示不能被shader修改
注意
1.被uniform 修饰的变量 只能被shader 使用read 不能写write 改变
2. 如果 uniform 在vertx/fragment 两者的声明方式一样 则它们可以被vertx/fragment共享
(uniform float a 在 两个着色器中 声明方式和类型一样)
使用场景
1.变换矩阵/材质/光照/颜色
uniform mat4 viewProjMatrix // 投影与模型视图矩阵
uniform mat4 viewMatrix //模型视图矩阵
uniform mat4 lightPosition //光源位置
*/
/*
varying
varying是计算机图形学中的一个术语,用于描述在图形渲染过程中从顶点着色器传递到片段着色器的数据。
在OpenGL和OpenGL ES等图形 API 中,varying变量用于在顶点着色器和片段着色器之间传递数据。顶点着色器处理顶点数据,并可以将一些数据通过varying变量传递给片段着色器。
varying变量在顶点着色器中进行声明,并在片段着色器中进行使用。它们可以用于传递顶点的位置、颜色、纹理坐标等信息,以便在片段着色器中进行进一步的处理和渲染。
通过使用varying变量,片段着色器可以根据每个像素的位置和相关的顶点数据来计算最终的颜色值,从而实现复杂的图形效果。
是vertex 与 fragment shader 之间做数据传递 如果需要做传递 则必须保证 vertex shader 与 fragment shader 中两者的声明必须保持一致(修饰符 类型 变量名)否则不能做数据传递
使用场景
//纹理坐标/顶点颜色等等
*/
/*
attribute
在计算机图形学中,attribute是一个术语,用于描述在图形渲染过程中传递给顶点着色器的数据。
attribute通常是与顶点相关的属性,如顶点的位置、颜色、纹理坐标等。这些属性在应用程序中进行设置,并通过图形 API(如OpenGL、OpenGL ES或Direct3D)传递给图形渲染上下文。
在顶点着色器中,可以通过attribute变量来访问和操作传递给顶点的属性数据。顶点着色器可以根据这些属性进行计算和变换,以生成最终的顶点坐标和其他相关数据。
attribute变量在顶点着色器的代码中进行声明,并与应用程序中设置的顶点属性相匹配。这样,顶点着色器就可以根据每个顶点的属性来进行个性化的处理和渲染。
1.只能在vertshader 中声明和使用 片元着色器 fragment shader 中不能声明也不能使用
2.在application中 glBindAttribLocation()函数来绑定每个变量的位置 然后使用 glVertexAttribPointer()为变量赋值
glGetAttribLocation()来获取变量
使用场景
顶点坐标/法线/纹理坐标/顶点颜色等
attribute vec4 a_position;
gl_position = viewProjMatrix * a_position
*/
///
ios FrameBuffer
iOS 中的 FrameBuffer(帧缓冲区)是图形渲染管道中的一个重要组成部分。它是用于存储和管理图形渲染数据的缓冲区。
FrameBuffer 通常包含多个缓冲区,用于存储不同类型的图形数据,如颜色、深度和模板等。这些缓冲区可以在图形渲染过程中被读取和写入,以生成最终的屏幕显示。
在 iOS 中,FrameBuffer 的管理和使用由图形渲染引擎(如 Metal 或 OpenGL ES)负责。应用程序通过这些图形 API 与 FrameBuffer 进行交互,将图形数据渲染到缓冲区中,并最终显示在屏幕上。
FrameBuffer 的性能和效率对图形渲染的性能和质量有着重要影响。优化 FrameBuffer 的使用可以提高图形渲染的效率和性能,例如通过减少缓冲区的切换、使用合适的像素格式和压缩方式等。
如果你在开发 iOS 图形相关的应用程序,了解和优化 FrameBuffer 的使用是提高图形性能的重要方面之一
FrameBuffer RenderBuffer 有什么关系
FrameBuffer(帧缓冲区)和 RenderBuffer(渲染缓冲区)在图形渲染中是相关的概念,但它们在层次结构和用途上略有不同。
FrameBuffer 是一个更高级别的概念,它通常包含多个 RenderBuffer。FrameBuffer 是用于存储和管理图形渲染数据的缓冲区,它可以包含颜色、深度、模板等信息。FrameBuffer 可以在图形渲染过程中被读取和写入,以生成最终的屏幕显示。
RenderBuffer 是 FrameBuffer 的一部分,它是用于存储特定类型的图形渲染数据的缓冲区。例如,一个 RenderBuffer 可以存储颜色信息,另一个 RenderBuffer 可以存储深度信息。RenderBuffer 通常用于在图形渲染过程中临时存储渲染结果,并在后续的操作中使用这些结果。
在 iOS 中,你可以使用图形渲染 API(如 Metal 或 OpenGL ES)来操作 FrameBuffer 和 RenderBuffer。通过这些 API,你可以创建、配置和使用 FrameBuffer 和 RenderBuffer 来进行图形渲染。
总的来说,FrameBuffer 是一个包含多个 RenderBuffer 的容器,用于存储和管理图形渲染数据。RenderBuffer 是 FrameBuffer 的一部分,用于存储特定类型的渲染数据。它们在图形渲染过程中协同工作,以生成最终的屏幕显示。
ios Renderbuffer
在 iOS 中,RenderBuffer 是用于图形渲染的一种数据结构,它是渲染过程中用于存储渲染结果的缓冲区。
RenderBuffer 通常包含颜色、深度和模板信息等数据,可以用于渲染到屏幕、纹理或其他目标。在 iOS 中,你可以使用 Core Graphics 框架或 Metal 框架来创建和操作 RenderBuffer。
通过使用 RenderBuffer,你可以在渲染过程中临时存储渲染结果,并在后续的操作中使用这些结果。它提供了一种在渲染过程中进行中间结果存储和处理的方式。
如果你需要在 iOS 应用中进行图形渲染,了解和使用 RenderBuffer 可以帮助你管理渲染数据和提高渲染性能。具体的使用方法和细节可以参考相关的文档和 API 参考资料。
顶点着色器和片元着色器程序如何实现变异绑定链接的
1.指定属性
2.设置源码
3.载入文件
iOS 使用OpenGLES
设置OpenGL ES相关配置
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
if(context == nil) {
NSLog(@"====failed to create context");
exit(0);
}
glView.drawableDepthFormat = GLKViewDrawableDepthFormat16;
[EAGLContext setCurrentContext:context];
glEnable(GL_DEPTH_TEST);
glClearColor(0.1, 0.5, 0.8, 1.0)
加载顶点数据
GLfloat vertexData[] = {
/// 坐标x,y,z 纹理st
1, -1, 0.0f, 1.0f, 0.0f, //右下
1, 1, -0.0f, 1.0f, 1.0f, //右上
-1, 1, 0.0f, 0.0f, 1.0f, //左上
1, -1, 0.0f, 1.0f, 0.0f, //右下
-1, 1, 0.0f, 0.0f, 1.0f, //左上
-1, -1, 0.0f, 0.0f, 0.0f, //左下
};
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
加载纹理数据
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"girl" ofType:@"jpg"];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: @(1),GLKTextureLoaderOriginBottomLeft,nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
mEffect = [[GLKBaseEffect alloc] init];
mEffect.texture2d0.enabled = GL_TRUE;
mEffect.texture2d0.name = textureInfo.name;
实现代理GLKViewDelegate
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glClearColor(0, 0, 1, 1);
[mEffect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 6);
}
金字塔glsl demo
//
// PyramidView.m
// OPenglES_Test
//
// Created by KING on 2023/12/30.
//
#import "PyramidView.h"
#import <OpenGLES/ES2/gl.h>
#import "GLESUtils.h"
#import "GLESMath.h"
@interface PyramidView()
@property (nonatomic,strong) CAEAGLLayer *caEgaLayer;
@property (nonatomic,strong) EAGLContext *myContext;
@property (nonatomic,assign) GLuint colorRenderBuffer;
@property (nonatomic,assign) GLuint colorFrameBuffer;
@property (nonatomic,assign) GLuint myProgram;
@property (nonatomic , assign) GLuint myVertices;
@end
@implementation PyramidView
{
float xDegree;
float yDegree;
float zDegree;
bool dx;
bool dy;
bool dz;
NSTimer* myTimer;
}
- (void)layoutSubviews {
[self setUpLayer];
[self setUpContext];
[self clearBUffer];
[self setUpRenderBuffer];
[self setUpFrameBuffer];
[self drawFrame];
}
///1.设置图层
- (void)setUpLayer {
self.caEgaLayer = (CAEAGLLayer *)self.layer;
[self setContentScaleFactor:[[UIScreen mainScreen] scale]];
self.caEgaLayer.opaque = YES;
self.caEgaLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat, nil];
}
///2.设置上下文
-(void)setUpContext{
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!context) {
printf("context create error");
exit(0);
}
if (![EAGLContext setCurrentContext:context]) {
printf("setCurrentContext context create error");
exit(0);
}
self.myContext = context;
}
///3.清空缓冲区
-(void)clearBUffer {
//1.导入框架#import <OpenGLES/ES2/gl.h>
/*
2.创建2个帧缓存区,渲染缓存区,帧缓存区
@property (nonatomic , assign) GLuint myColorRenderBuffer;
@property (nonatomic , assign) GLuint myColorFrameBuffer;
A.离屏渲染,详细解释见课件
B.buffer的分类,详细见课件
buffer分为frame buffer 和 render buffer2个大类。其中frame buffer 相当于render buffer的管理者。frame buffer object即称FBO,常用于离屏渲染缓存等。render buffer则又可分为3类。colorBuffer、depthBuffer、stencilBuffer。
//绑定buffer标识符
glGenRenderbuffers(<#GLsizei n#>, <#GLuint *renderbuffers#>)
glGenFramebuffers(<#GLsizei n#>, <#GLuint *framebuffers#>)
//绑定空间
glBindRenderbuffer(<#GLenum target#>, <#GLuint renderbuffer#>)
glBindFramebuffer(<#GLenum target#>, <#GLuint framebuffer#>)
*/
glDeleteBuffers(1, &_colorRenderBuffer);
_colorRenderBuffer = 0;
glDeleteBuffers(1, &_colorFrameBuffer);
_colorFrameBuffer = 0;
}
///4.设置renderBuffer
-(void)setUpRenderBuffer {
//1.定义一个缓存区
GLuint buffer;
//2.申请一个缓存区标志
glGenRenderbuffers(1, &buffer);
//3.
self.colorRenderBuffer = buffer;
//4.将标识符绑定到GL_RENDERBUFFER
glBindRenderbuffer(GL_RENDERBUFFER, self.colorRenderBuffer);
//frame buffer仅仅是管理者,不需要分配空间;render buffer的存储空间的分配,对于不同的render buffer,使用不同的API进行分配,而只有分配空间的时候,render buffer句柄才确定其类型
//为color renderBuffer 分配空间
[self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.caEgaLayer];
}
///5,设置frameBuffer
-(void)setUpFrameBuffer {
//1.定义一个缓存区
GLuint buffer;
//2.申请一个缓存区标志
glGenFramebuffers(1, &buffer);
//3.
self.colorFrameBuffer = buffer;
//4.设置当前的framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, self.colorFrameBuffer);
//5.将_myColorRenderBuffer 装配到GL_COLOR_ATTACHMENT0 附着点上
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.colorRenderBuffer);
//接下来,可以调用OpenGL ES进行绘制处理,最后则需要在EGALContext的OC方法进行最终的渲染绘制。这里渲染的color buffer,这个方法会将buffer渲染到CALayer上。- (BOOL)presentRenderbuffer:(NSUInteger)target;
}
///6.绘制render
-(void)drawFrame {
glClearColor(0.2, 0.5, 0.8, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
CGFloat scale = [[UIScreen mainScreen] scale];
glViewport(self.frame.origin.x * scale, self.frame.origin.y * scale, scale * self.frame.size.width, scale * self.frame.size.height);
/// 获取顶点或者片元着色器的位置
NSString *vertFile = [[NSBundle mainBundle] pathForResource:@"pyramidv" ofType:@"vsh"];
NSString *frameFile = [[NSBundle mainBundle] pathForResource:@"pyramidf" ofType:@"fsh"];
if (self.myProgram) {
glDeleteProgram(self.myProgram);
self.myProgram = 0;
}
self.myProgram = [self loadShaderWithVertFile:vertFile frameFile:frameFile];
/// 链接
glLinkProgram(self.myProgram);
GLint linkSuccess;
glGetProgramiv(self.myProgram, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
NSLog(@"link statues failed");
exit(0);
}
glUseProgram(self.myProgram);
/// 创建索引数组
GLuint indices[] = {
0,3,2,
0,1,3,
0,2,4,
0,4,1,
2,3,4,
1,4,3,
};
/// 顶点数据
if (self.myVertices == 0) {
glGenBuffers(1, &_myVertices);
}
//顶点数组
//前3顶点值(x,y,z),后3位颜色值(RGB)
GLfloat attrArr[] =
{
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //左上
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //右上
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //左下
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //右下
0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //顶点
};
//-----处理顶点数据-------
glBindBuffer(GL_ARRAY_BUFFER, _myVertices);
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
//1.glGetAttribLocation,用来获取vertex attribute的入口的.2.告诉OpenGL ES,通过glEnableVertexAttribArray,3.最后数据是通过glVertexAttribPointer传递过去的。
//注意:第二参数字符串必须和shaderv.vsh中的输入变量:position保持一致
GLuint position = glGetAttribLocation(self.myProgram, "position");
//打开position 默认是关闭的
glEnableVertexAttribArray(position);
// 1.位置 2.每次传多少个 3.类型 4.是否需要归一化5.步长 6.读取开始位置
glVertexAttribPointer(position, 3,GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), NULL);
//3.设置读取方式
//参数1:index,顶点数据的索引
//参数2:size,每个顶点属性的组件数量,1,2,3,或者4.默认初始值是4.
//参数3:type,数据中的每个组件的类型,常用的有GL_FLOAT,GL_BYTE,GL_SHORT。默认初始值为GL_FLOAT
//参数4:normalized,固定点数据值是否应该归一化,或者直接转换为固定值。(GL_FALSE)
//参数5:stride,连续顶点属性之间的偏移量,默认为0;
//参数6:指定一个指针,指向数组中的第一个顶点属性的第一个组件。默认为0
// 颜色数据
GLuint positionColor = glGetAttribLocation(self.myProgram, "positionColor");
//打开positionColor 默认是关闭的
glEnableVertexAttribArray(positionColor);
// 1.位置 2.每次传多少个 3.类型 4.是否需要归一化5.步长 6.读取开始位置
glVertexAttribPointer(positionColor, 3,GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (float *)NULL + 3);
//注意,想要获取shader里面的变量,这里记得要在glLinkProgram后面,后面,后面!
/*
一个一致变量在一个图元的绘制过程中是不会改变的,所以其值不能在glBegin/glEnd中设置。一致变量适合描述在一个图元中、一帧中甚至一个场景中都不变的值。一致变量在顶点shader和片断shader中都是只读的。首先你需要获得变量在内存中的位置,这个信息只有在连接程序之后才可获得
*/
//找到myProgram中的projectionMatrix、modelViewMatrix 2个矩阵的地址。如果找到则返回地址,否则返回-1,表示没有找到2个对象。
// 投影矩阵
GLuint projectionMatrixLocation = glGetUniformLocation(self.myProgram, "projectionMatrix");
// 纵横比 透视投影
float aspect = self.frame.size.width / self.frame.size.height;
/// 创建矩阵4x4
KSMatrix4 _projectionMatrix;
// 加载单元矩阵
ksMatrixLoadIdentity(&_projectionMatrix);
/// 设置透视投影
ksPerspective(&_projectionMatrix, 30.0, aspect, 5.0f, 20.0f);
/// 将次矩阵传递到顶点着色器中去
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, (GLfloat *)&_projectionMatrix.m[0][0]);
// 开启正背面剔除
glEnable(GL_CULL_FACE);
// 模型视图矩阵
GLuint modelViewMatrixLocation = glGetUniformLocation(self.myProgram, "modelViewMatrix");
/// 创建矩阵4x4
KSMatrix4 _modelViewMatrix;
// 加载单元矩阵
ksMatrixLoadIdentity(&_modelViewMatrix);
/// z轴平移
ksTranslate(&_modelViewMatrix, 0, 0, -10);
/// 创建旋转矩阵
KSMatrix4 _rotationMatrix;
ksMatrixLoadIdentity(&_rotationMatrix);
ksRotate(&_rotationMatrix, xDegree, 1.0, 0.0, 0.0);
ksRotate(&_rotationMatrix, yDegree, 0.0, 1.0, 0.0);
ksRotate(&_rotationMatrix, zDegree, 0.0, 0.0, 1.0);
/// 将旋转矩阵和模型视图矩阵结合
ksMatrixMultiply(&_modelViewMatrix, &_rotationMatrix, &_modelViewMatrix);
glUniformMatrix4fv(modelViewMatrixLocation, 1, GL_FALSE, (GLfloat *)&_modelViewMatrix.m[0][0]);
// 索引绘图
glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_INT, indices);
[self.myContext presentRenderbuffer:GL_RENDERBUFFER];
}
-(GLint)loadShaderWithVertFile:(NSString *)vertFile frameFile:(NSString *)frameFile {
GLuint program = glCreateProgram();
GLuint vShader,fShader;
[self complieShaderPath:vertFile shader:&vShader type:GL_VERTEX_SHADER];
[self complieShaderPath:frameFile shader:&fShader type:GL_FRAGMENT_SHADER];
glAttachShader(program, vShader);
glAttachShader(program, fShader);
glDeleteShader(vShader);
glDeleteShader(fShader);
return program;
}
-(void)complieShaderPath:(NSString *)path shader:(GLuint *)shader type:(GLuint)type {
NSString *file = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
const GLchar *source = (GLchar *)[file UTF8String];
*shader = glCreateShader(type);
glShaderSource(*shader , 1, &source, NULL);
glCompileShader(*shader);
}
+(Class)layerClass {
return [CAEAGLLayer class];
}
-(void)changeRotateDirectTag:(NSInteger)tag {
if (!myTimer) {
myTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(degree) userInfo:nil repeats:YES];
}
if (tag == 100) {
dx = !dx;
} else if (tag == 200) {
dy = !dy;
} else if (tag == 300) {
dz = !dz;
} else {
dx = false;
dy = false;
dz = false;
[myTimer invalidate];
myTimer = nil;
}
}
-(void)degree{
xDegree += dx * 5;
yDegree += dy * 5;
zDegree += dz * 5;
[self drawFrame];
}
- (void)dealloc {
[myTimer invalidate];
myTimer = nil;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
shader
attribute vec4 position;
attribute vec4 positionColor;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
varying lowp vec4 varyColor;
void main() {
varyColor = positionColor;
vec4 vPos;
vPos = projectionMatrix * modelViewMatrix * position;
gl_Position = vPos;
}
varying lowp vec4 varyColor;
void main() {
gl_FragColor = varyColor;
}
GLKi demo
//
// PyramidViewController02.m
// OPenglES_Test
//
// Created by KING on 2023/12/31.
//
#import "PyramidViewController02.h"
#import "PyramidView02.h"
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
@interface PyramidViewController02 ()
@property (nonatomic,strong) PyramidView02 *pramidView;
@property (nonatomic,strong)EAGLContext *myContext;
@property (nonatomic,strong)GLKBaseEffect *mEffect;
@property(nonatomic,assign)int count;
//旋转的度数
@property(nonatomic,assign)float XDegree;
@property(nonatomic,assign)float YDegree;
@property(nonatomic,assign)float ZDegree;
//是否旋转X,Y,Z
@property(nonatomic,assign) BOOL XB;
@property(nonatomic,assign) BOOL YB;
@property(nonatomic,assign) BOOL ZB;
@end
@implementation PyramidViewController02
{
dispatch_source_t timer;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// self.pramidView =[[PyramidView02 alloc] initWithFrame:self.view.bounds];
// [self.view addSubview:_pramidView];
[self setUpContext];
[self render];
UIButton *buttonX = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonX setTitle:@"X" forState:UIControlStateNormal];
buttonX.backgroundColor = UIColor.blackColor;
buttonX.tag = 100;
buttonX.frame = CGRectMake(10, self.view.frame.size.height - 200.0, 100, 50);
[buttonX addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:buttonX];
UIButton *buttonY = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonY setTitle:@"Y" forState:UIControlStateNormal];
buttonY.tag = 200;
buttonY.frame = CGRectMake(120, self.view.frame.size.height - 200.0, 100, 50);
[buttonY addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:buttonY];
UIButton *buttonZ = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonZ setTitle:@"Z" forState:UIControlStateNormal];
buttonZ.tag = 300;
buttonZ.frame = CGRectMake(230, self.view.frame.size.height - 200.0, 100, 50);
[buttonZ addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:buttonZ];
UIButton *buttonS = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonS setTitle:@"stop" forState:UIControlStateNormal];
buttonS.frame = CGRectMake(220, self.view.frame.size.height - 100.0, 100, 50);
[buttonS addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:buttonS];
}
-(void)btnClick:(UIButton *)btn {
dispatch_source_cancel(timer);
timer = nil;
if (btn.tag == 100) {
_XB = !_XB;
} else if (btn.tag == 200) {
_YB = !_YB;
} else if (btn.tag == 300) {
_ZB = !_ZB;
} else {
_XB = false;
_YB = false;
_ZB = false;
}
[self render];
}
-(void)setUpContext {
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
GLKView *view = (GLKView *)self.view;
self.myContext = context;
view.context = context;
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
if (![EAGLContext setCurrentContext:context]) {
printf("setcurrent context failed\n");
return;
}
glEnable(GL_DEPTH_TEST);
}
-(void)render {
//1.顶点数据
//前3个元素,是顶点数据;中间3个元素,是顶点颜色值,最后2个是纹理坐标
GLfloat attrArr[] =
{
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f,//左上
0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f, 1.0f,//右上
-0.5f, -0.5f, 0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f,//左下
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 1.0f, 0.0f,//右下
0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f,//顶点
};
//2.绘图索引
GLuint indices[] =
{
0, 3, 2,
0, 1, 3,
0, 2, 4,
0, 4, 1,
2, 3, 4,
1, 4, 3,
};
/// 顶点个数
self.count = sizeof(indices)/sizeof(GLuint);
/// 将顶点数据载入缓冲区
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_STATIC_DRAW);
//将索引数据存储到索引数组缓冲区
GLuint index;
glGenBuffers(1, &index);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
///顶点数据加进去
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, NULL);
// 颜色数据
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 3);
// 纹理数据
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 6);
/// 获取纹理
NSString *path = [[NSBundle mainBundle] pathForResource:@"star" ofType:@"jpg"];
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:@"1",GLKTextureLoaderOriginBottomLeft, nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:path options:dict error:nil];
//effect
self.mEffect = [[GLKBaseEffect alloc] init];
self.mEffect.texture2d0.enabled = GL_TRUE;
self.mEffect.texture2d0.name = textureInfo.name;
//投影方式
float aspect = fabs(self.view.frame.size.width/self.view.frame.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(80.0), aspect, 1.0, 50);
projectionMatrix = GLKMatrix4Scale(projectionMatrix, 1.0, 1.0, 1.0);
/// 设置投影矩阵
self.mEffect.transform.projectionMatrix = projectionMatrix;
/// 模型视图
GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -2.0f);
//模型视图矩阵传入
self.mEffect.transform.modelviewMatrix = modelViewMatrix;
double seconds = 0.1;
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC, 0.0);
dispatch_source_set_event_handler(timer, ^{
self.XDegree += 0.1f * self.XB;
self.YDegree += 0.1f * self.YB;
self.ZDegree += 0.1f * self.ZB ;
});
dispatch_resume(timer);
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(0.0, 0.0, 0.0, 1);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
[self.mEffect prepareToDraw];
// 索引绘图
glDrawElements(GL_TRIANGLES, self.count, GL_UNSIGNED_INT, 0);
}
-(void)update{
// 矩阵改变
GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0, 0, -2.0);
modelViewMatrix = GLKMatrix4RotateX(modelViewMatrix, self.XDegree);
modelViewMatrix = GLKMatrix4RotateX(modelViewMatrix, self.YDegree);
modelViewMatrix = GLKMatrix4RotateX(modelViewMatrix, self.ZDegree);
//
self.mEffect.transform.modelviewMatrix = modelViewMatrix;
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end