OPenGL GLSL

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/282523.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入了解小红书笔记详情API:为内容创新提供动力

一、小红书笔记详情API简介 小红书笔记详情API是一种允许开发者访问小红书平台上的笔记详细数据的接口。通过这个API&#xff0c;我们可以获取笔记的标题、内容、标签、点赞数、评论数等详细信息。这些数据对于内容创作者和品牌来说至关重要&#xff0c;可以帮助他们了解用户喜…

day13--JDK8~17新特性(上):

第18章_JDK8-17新特性&#xff08;上&#xff09; 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 本章专题与脉络 1. Java版本迭代概述 1.1 发布特点&#xff08;小步快跑&#xff0c;快速迭代…

Java技术栈 —— Nginx的使用

Java技术栈 —— Nginx的使用 一、认识Nginx二、搭建Nginx环境2.1 在Ubuntu上安装Nginx 三、使用Nginx3.1 配置负载均衡(HTTP) 一、认识Nginx 企业需要运行多个相同的副本&#xff0c;并将负载分散在整个系统集群上&#xff0c;为了高性能的负载均衡&#xff0c;引入了Nginx代…

vue实现滑动切换:切换选项时滑块有滑动过渡的效果

效果图 思路&#xff1a; 1. 高亮的色块是独立的一个盒子&#xff0c;需要插入当前激活的内容用来撑开色块盒子的宽度&#xff0c;这样色块的宽度就会和当前激活的内容宽度一致&#xff0c;色块的字体颜色设置透明即可 2. 色块滑动的距离是读当前激活元素的offsetLeft&#x…

UG装配-接触对齐

UG装配约束命令在如下位置 首选接触&#xff1a;含接触和对齐&#xff0c;自动判断两种类型 接触&#xff1a;约束对象使其曲面法向在相反方向&#xff0c;并共面或共线 对齐&#xff1a;约束对象使其曲面法向在同一方向&#xff0c;并共面或共线 自动判断中心/轴&#xff1…

RK3568笔记七:yolov5-seg实例分割测试验证

若该文为原创文章&#xff0c;转载请注明原文出处。 记录的目的是想在RK3568上实现实例分割&#xff0c;在github的rknn_mode_zoo仓库里看到了例子&#xff0c;带着疑问测试了一下&#xff0c;结果跑通了&#xff0c;这里记录下全过程。 一、环境 1、硬件&#xff1a;正点原…

kafka 的零拷贝原理

文章目录 kafka 的零拷贝原理 今天来跟大家聊聊kafka的零拷贝原理是什么&#xff1f; kafka 的零拷贝原理 零拷贝是一种减少数据拷贝的机制&#xff0c;能够有效提升数据的效率&#xff1b;   在实际应用中&#xff0c;如果我们需要把磁盘中的某个文件内容发送到远程服务器上…

深度学习 | 注意力机制、自注意力机制

卷积神经网络的思想主要是通过卷积层对图像进行特征提取&#xff0c;从而达到降低计算复杂度的目的&#xff0c;利用的是空间特征信息&#xff1b;循环神级网络主要是对序列数据进行建模&#xff0c;利用的是时间维度的信息。 而第三种 注意力机制 网络&#xff0c;关注的是数据…

2023-12-20 LeetCode每日一题(判别首字母缩略词)

2023-12-20每日一题 一、题目编号 2828. 判别首字母缩略词二、题目链接 点击跳转到题目位置 三、题目描述 给你一个字符串数组 words 和一个字符串 s &#xff0c;请你判断 s 是不是 words 的 首字母缩略词 。 如果可以按顺序串联 words 中每个字符串的第一个字符形成字符…

使用频率分析求周期性

通常很难通过观察时间测量值来表征数据中的振荡行为。频谱分析有助于确定信号是否为周期性信号并测量不同周期。 办公楼内的温度计每半小时测量一次室内温度&#xff0c;持续四个月。加载数据并对其绘图。将温度转换为摄氏度。测量时间以周为单位。因此&#xff0c;采样率为 2 …

洛谷:集合与差分

1.学籍管理(map&#xff09; #include<iostream> #include<map> #include<string> using namespace std; map<string,int>a; int n; string name; int op,score; int main() {cin>>n;for(int i1;i<n;i){cin>>op;if(op!4)cin>>na…

异常检测 | Matlab基于GNN图神经网络的数据异常数据检测

异常检测 | Matlab基于GNN图神经网络的数据异常数据检测 目录 异常检测 | Matlab基于GNN图神经网络的数据异常数据检测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 Matlab基于GNN图神经网络的数据异常数据检测。其核心思想是学习一个函数映射。本次使用人类活…

Powermill各版本安装指南

下载链接 https://pan.baidu.com/s/1CsrYEUQNmDa820RxDV2G6Q?pwd0531 1.鼠标右击【PowerMill2024(64bit)】压缩包&#xff08;win11及以上系统需先点击“显示更多选项”&#xff09;【解压到 PowerMill2024(64bit)】。 2.打开解压后的文件夹&#xff0c;双击打开【Setup】文…

70内网安全-域横向内网漫游Socks代理隧道技术(下)

这节课解决代理的问题&#xff0c; 他是内网里面的穿透技术&#xff0c;隧道主要安全设备和流量监控的拦截问题&#xff0c;我们在做渗透的时候需要回显数据或者一些重要的信息&#xff0c;走的协议不一样&#xff0c;tcp/ip有七层&#xff0c; 在不同层里面有不同的协议&…

flowable工作流看这一篇就够了(进阶篇 下)

目录 三、多人会签 3.1、多实例介绍 3.2、基本应用 案例一&#xff08;静态指定数量&#xff09; 案例二&#xff08;动态数量和指派审批人&#xff09; 案例三&#xff08;表达式方式&#xff09; 案例四&#xff08;Java方法控制完成条件&#xff09; 3.3、服务任务 …

加入近屿智能OJAC的AIGC星辰大海深度训练营:开启您的AI大模型之旅!

成为AI领域的专家吗&#xff1f;想要实现升职加薪吗&#xff1f;加入第六期近屿智能OJAC第六期AIGC星辰大海&#xff1a;大模型工程师与产品专家深度训练营&#xff0c;正是你学习AIGC技术&#xff0c;实现转型的绝佳机会。在这里&#xff0c;不仅是学习&#xff0c;更是您职业…

亲爱的程序猿们,元旦快乐!

新年祝福 在这个充满欢笑和祝福的日子里&#xff0c;我想对你们说&#xff1a; 新的一年&#xff0c;愿你们像代码一样充满逻辑&#xff0c;像算法一样追求高效&#xff0c;像编程语言一样多样化&#xff01; 2024年即将到来&#xff0c;预测几个行业趋势&#xff1a; 人工…

【数据结构】排序之交换排序(冒泡 | 快排)

交换目录 1. 前言2. 交换排序3. 冒泡排序3.1 分析3.2 代码实现 4. 快速排序4.1 hoare版本4.1.1 分析4.1.2 hoare版本代码 4.2 挖坑法4.2.1 分析4.2.2 挖坑法代码实现 4.3 前后指针版本4.3.1 分析4.3.2 前后指针版本代码实现 1. 前言 在之前的博客中介绍了插入排序&#xff0c;…

Windows搭建RTSP视频流服务(EasyDarWin服务器版)

文章目录 引言1、安装FFmpeg2、安装EasyDarWin3、实现本地\虚拟摄像头推流服务4、使用VLC或PotPlayer可视化播放器播放视频5、RTSP / RTMP系列文章 引言 RTSP和RTMP视频流的区别 RTSP &#xff08;Real-Time Streaming Protocol&#xff09;实时流媒体协议。 RTSP定义流格式&am…

Spring高手之路-Spring AOP

目录 什么是AOP Spring AOP有如下概念 补充&#xff1a; AOP是如何实现的 Spring AOP 是通过代理模式实现的。 Spring AOP默认使用标准的JDK动态代理进行AOP代理。 什么是AOP AOP(Aspect-Oriented Programming)&#xff0c;即面向切面编程&#xff0c;用人话说就是把公共的…