先看我们最终实现的效果如下.
assimp 在Mac 中的编译
assimp 的编译依赖cmake 工具,因此我们需要在mac上安装 cmake
查看cmake 是否安装
打开终端 输入
cmake
要是显示以下内容就代表安装了cmake
安装cmake
终端输入
brew install cmake
结果如下说明安装完成
brew 是 homebrew 工具,这个工具的安装比较简单,就不说明了
�## 编译 assimp
打开终端
- cd 到指定目录下
我的根目录是 assimpFile
- cd 到指定目录下
- git clone https://github.com/assimp/assimp.git
- cd assimp/port/iOS/
- ./build.sh
这个过程时间比较长
- ./build.sh
编译结束
从上截图我们能看出来编译的结果路径在./lib/iOS 中
由于我只编译了x86-64 和arm64 因此,我的 ./lilb/iOS 文件是这样子的
这里面的.a 文件就是我们需要的库文件
编译完成 assimp/include中的文件就是头文件
assimp/lib/ios 中的文件就是生成的assimp 库
将以上两部分copy 的一个文件夹下面供使用就可以了
这里build.sh 文件编译了6中结构体arm64e arm64 armv7s armv7 x86_64 i386
为了减少编译速度,我们可以修改编译的结构体选择我们需要的即可
我copy 到一个文件的样子如下
assimp 集成的Xcode 中
-
1 创建一个新的工程
-
2 将includes 和lib/ios中的.a 文件拖入到工程中去
工程结构如下
- 修改 include 搜索路径 :
Build Setting
search paths 中的 Header Search Paths 添加include 所在本地路径 (可以看看.a 文件,根据.a文件路径修改 include 路径)
- 修改 include 搜索路径 :
-
将使用该库的.m 文件修改成 .mm 该工程使用的是viewcontroller.m 修改成
-
4.修改viewController.mm 文件内容如下
#import "ViewController.h"
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
@end
- 编译工程
要是工程编译不出错,说明库安装成功
- 编译工程
assimp 库在ios中的使用
基础工程
GLBaseViewController 文件 ,我们使用opengl 的基本方法顺序
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import "OpenGLUtilsHeader.h"
#import "GLBaseBindObject.h"
#define __weakSelf __weak typeof(self) weakSelf = self;
NS_ASSUME_NONNULL_BEGIN
@interface GLBaseViewController : GLKViewController
@property (nonatomic ,strong) EAGLContext * eagcontext;
@property (nonatomic ,assign) GLuint program;
@property (nonatomic ,strong) Shader * shader ;
@property (nonatomic ,strong) Vertex * vertex ;
@property (nonatomic ,strong) GLBaseBindObject * bindObject ;
@property (nonatomic ,strong) NSMutableArray * vertexArr ;
///眼的位置在 0,0,1 看向 原点 ,眼的正方向是y轴, 看的区域是0.1 到20 角度是85
-(GLKMatrix4 )mvp;
-(void)loadVertex;
-(void)initSubObject;
-(void)createTextureUnit;
@end
#import "GLBaseViewController.h"
@interface GLBaseViewController ()
@property (nonatomic ,strong) TextureUnit * textureUnit0 ;
@end
@implementation GLBaseViewController
-(void)createEagContext{
self.eagcontext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:self.eagcontext];
}
-(void)configure{
GLKView *view = (GLKView*)self.view;
view.context = self.eagcontext;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
}
-(void)initCustom{
self.vertexArr = [NSMutableArray array];
glEnable(GL_DEPTH_TEST);
}
-(void)initSubObject{
}
-(void)createTextureUnit{
}
-(void)createShader{
__weakSelf
self.shader = [Shader new];
[self.shader compileLinkSuccessShaderName:self.bindObject.getShaderName completeBlock:^(GLuint program) {
[weakSelf.bindObject BindAttribLocation:program];
}];
[self.bindObject setUniformLocation:self.shader.program];
}
-(void)loadVertex{
}
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
}
-(void)viewDidLoad{
[super viewDidLoad];
[self createEagContext];
[self initSubObject];
[self configure];
[self initCustom];
[self createShader];
[self createTextureUnit];
[self loadVertex];
}
@end
GLBaseBindObject 是shader 的配置基础类
#import <Foundation/Foundation.h>
#import <GLKit/GLKit.h>
#define uniformsMaxCount 100
NS_ASSUME_NONNULL_BEGIN
@interface GLBaseBindObject : NSObject
{
@public
GLint uniforms[uniformsMaxCount];
}
-(void)BindAttribLocation:(GLuint) program;
-(void)setUniformLocation:(GLuint)program;
-(NSString *)getShaderName;
@end
NS_ASSUME_NONNULL_END
#import "GLBaseBindObject.h"
@implementation GLBaseBindObject
-(void)setUniformLocation:(GLuint)program{
}
-(void)BindAttribLocation:(GLuint) program{
}
-(NSString *)getShaderName{
return nil;
}
@end
shader 文件, 名字是Assimp
precision mediump float;
varying vec2 TexCoords;
uniform sampler2D texture_diffuse;
uniform sampler2D texture_specular;
uniform sampler2D texture_height;
void main()
{
vec4 diffuse = texture2D(texture_diffuse, TexCoords);
vec4 specular = texture2D(texture_specular, TexCoords);
vec4 height = texture2D(texture_height, TexCoords);
gl_FragColor = diffuse+specular+height;
}
precision mediump float;
attribute vec3 aPos;
//attribute vec3 aNormal;
attribute vec2 aTexCoords;
varying vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
TexCoords = aTexCoords;
gl_Position = projection * view * model * vec4(aPos, 1.0);
}
assimp 通用代码
AssimpViewController 是真正加载 模型的类
#import "AssimpViewController.h"
#import "AssimpBindObject.h"
#import "AssimpParse.h"
@interface AssimpViewController ()
@property (nonatomic ,strong) AssimpParse * assimpParse ;
@end
@implementation AssimpViewController
-(void)initSubObject{
//生命周期三秒钟
self.bindObject = [AssimpBindObject new];
self.assimpParse = [ AssimpParse new];
}
-(void)loadVertex{
[self.assimpParse parse];
}
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glClearColor(1, 1, 1, 1);
static GLfloat angle=0;
angle ++ ;
// angle = 45;
GLKMatrix4 mode =GLKMatrix4MakeRotation(angle*M_PI/180, 0, 1, 0);
float scale = 0.2;
mode = GLKMatrix4Scale(mode, scale, scale, scale);
mode = GLKMatrix4Translate(mode, 0, -5, 0);
glUniformMatrix4fv(self.bindObject->uniforms[uniform_model], 1, 0,mode.m);
GLKMatrix4 viewMatrix =
GLKMatrix4MakeLookAt(
0.0, 0.0, 5.0, // Eye position
0.0, 0.0, 0.0, // Look-at position
0.0, 1.0, 0.0); // Up direction
glUniformMatrix4fv(self.bindObject->uniforms[uniform_view], 1, 0,viewMatrix.m);
GLfloat aspectRatio= CGRectGetWidth([UIScreen mainScreen].bounds) / CGRectGetHeight([UIScreen mainScreen].bounds);
GLKMatrix4 projectionMatrix =
GLKMatrix4MakePerspective(
GLKMathDegreesToRadians(85.0f),
aspectRatio,
0.1f,
20.0f);
glUniformMatrix4fv(self.bindObject->uniforms[uniform_projection], 1, 0,projectionMatrix.m);
[self.assimpParse draw:self.bindObject];
}
#import "GLBaseViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface AssimpViewController : GLBaseViewController
@end
NS_ASSUME_NONNULL_END
AssimpBindObject shader 的具体绑定类
#import "GLBaseBindObject.h"
NS_ASSUME_NONNULL_BEGIN
// Attribute identifiers
typedef enum {
aPos,
// aNormal,
aTexCoords,
} BaseBindAttribLocation;
typedef union {
struct{
GLKVector3 aPos;
// GLKVector3 aNormal;
GLKVector2 aTexCoords;
};
float a[5];
}assimpBindAtt;
typedef enum {
uniform_model,
uniform_view,
uniform_projection,
uniform_diffuse,
uniform_specular,
uniform_height
} assimpUniformLocation;
@interface AssimpBindObject : GLBaseBindObject
@end
NS_ASSUME_NONNULL_END
#import "AssimpBindObject.h"
@implementation AssimpBindObject
-(void)BindAttribLocation:(GLuint)program{
glBindAttribLocation(program, aPos, "aPos");
glBindAttribLocation(program, aTexCoords, "aTexCoords");
}
-(void)setUniformLocation:(GLuint)program{
self->uniforms[uniform_model] = glGetUniformLocation(program, "model");
self->uniforms[uniform_view] = glGetUniformLocation(program, "view");
self->uniforms[uniform_projection] = glGetUniformLocation(program, "projection");
self->uniforms[uniform_diffuse] = glGetUniformLocation(program, "texture_diffuse");
self->uniforms[uniform_specular] = glGetUniformLocation(program, "texture_specular");
self->uniforms[uniform_height] = glGetUniformLocation(program, "texture_height");
}
-(NSString *)getShaderName{
return @"Assimp";
}
@end
具体绑定内容不做介绍了
核心代码介绍
这里我们采用库加载文件 .obj 文件 .因此我们需要知道 assimp 库的具体使用.
assimp 数据结构
- 和材质和网格(Mesh)一样,所有的场景/模型数据都包含在
Scene
对象中。Scene
对象也包含了场景根节点的引用。 - 场景的
Root node
(根节点)可能包含子节点(和其它的节点一样),它会有一系列指向场景对象中mMeshes
数组中储存的网格数据的索引。Scene
下的mMeshes
数组储存了真正的Mesh
对象,节点中的mMeshes
数组保存的只是场景中网格数组的索引。 - 一个
Mesh
对象本身包含了渲染所需要的所有相关数据,像是顶点位置、法向量、纹理坐标、面(Face)和物体的材质。 - 一个网格包含了多个面。
Face
代表的是物体的渲染图元(Primitive)(三角形、方形、点)。一个面包含了组成图元的顶点的索引。由于顶点和索引是分开的,使用一个索引缓冲来渲染是非常简单的。 - 最后,一个网格也包含了一个
Material
对象,它包含了一些函数能让我们获取物体的材质属性,比如说颜色和纹理贴图(比如漫反射和镜面光贴图)。
上述官方的话在拆开说
scene
是 manager . 包含场景和模型所有数据 .
node
相当于 组件或者零件, 一个模型有很多node组成. 打个比方scene 相当于汽车,node 是组成汽车的零件
scene->mrootNode 指向的是node的根 .相当于汽车部件 ,汽车部件可能有引擎和轮胎组成,而轮胎可能有橡胶和螺丝等组成,因此node 是一种树机构
scene->mMehses
装有所有的顶点数据, 包含顶点
法线
纹理贴图
以及顶点索引
等 (我们node 中的 mMeshes 的 int数组,每个值其实指向的是scene->mMehses的下标
)
scene->mMehses
的装有的对象是Mesh
, 装有使用opengl进行一次绘制的所有信息 ,包括顶点
法线
纹理贴图
以及顶点索引
等. (一个模型的加载需要opengl 进行多次顶点渲染,渲染是以mesh为基本单位的,因此我们这里只要学会使用mesh的一次加载和node的树状遍历就可以正确解析模型了
)
assimp 的使用 具体步骤
- 1.获取 scene
Assimp::Importer importer;
NSString * pathStr = [[NSBundle mainBundle]pathForResource:@"nanosuit" ofType:@"obj"];
const char *path = pathStr.UTF8String;
const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero
{
NSLog(@"ERROR::ASSIMP: %s",importer.GetErrorString());
return;
}
NSString * directory =[pathStr stringByDeletingLastPathComponent];
NSLog(@"%@",directory);
self.path = directory;
就是用库读取资源文件.
- 2.遍历node
-(void)processNode:(aiNode *)node{
for(unsigned int i = 0; i < node->mNumMeshes; i++)
{
aiMesh *mesh = self.scene->mMeshes[node->mMeshes[i]];
Mesh * meshObj =[self processMesh:mesh];
[meshObj parse];
[self.meshs addObject:meshObj];
}
// 接下来对它的子节点重复这一过程
for(unsigned int i = 0; i < node->mNumChildren; i++)
{
[self processNode:node->mChildren[i]];
}
}
1 .检查 node 是否含有mesh . 有mesh的标志是 node->mNumMeshes 的数量不为0. 有mesh ,就加载mesh
2.遍历node是否有 childNode , 有mNumChildren的标志是node->mNumChildren 不为0,有childNode 就递归调用加载node
- 加载mesh
-(Mesh*) processMesh:(aiMesh *)mesh{
Mesh * meshObj= [Mesh new];
for(unsigned int i = 0; i < mesh->mNumVertices; i++)
{
MeshVertex * vertex = [MeshVertex new];
GLKVector3 vector;
// positions
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertex.Position = vector;
// texture coordinates
if(mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
{
GLKVector2 vec;
vec.x = mesh->mTextureCoords[0][i].x;
vec.y = mesh->mTextureCoords[0][i].y;
vertex.TexCoords = vec;
}
else
vertex.TexCoords = GLKVector2Make(0.0f, 0.0f);
[meshObj.vertices addObject:vertex];
}
for(unsigned int i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
// retrieve all indices of the face and store them in the indices vector
for(unsigned int j = 0; j < face.mNumIndices; j++)
[meshObj.indices addObject:@(face.mIndices[j])];
}
aiMaterial* material = self.scene->mMaterials[mesh->mMaterialIndex];
// 1. diffuse maps
NSMutableArray * diffuse =[self loadMaterialTextures:material type:aiTextureType_DIFFUSE typeName:@"texture_diffuse"];
[meshObj.textures addObjectsFromArray:diffuse];
// 2. specular maps
NSMutableArray * specularMaps = [self loadMaterialTextures:material type:aiTextureType_SPECULAR typeName:@"texture_specular"];
[meshObj.textures addObjectsFromArray:specularMaps];
// 4. height maps
NSMutableArray * heightMaps = [self loadMaterialTextures:material type:aiTextureType_AMBIENT typeName:@"texture_height"];
[meshObj.textures addObjectsFromArray:heightMaps];
//
return meshObj;
}
mesh的类型是aiMesh 结构体
aiMesh->mNumVertices 代表该mesh的顶点数量
aiMesh->mVertices装有顶点数据
aiMesh->mTextureCoords装有顶点纹理
aiMesh->mNormals装有顶点发现
aiMesh->mNumFaces 装有三角形或者线,点数量(这里是三角形)
aiMesh->mFaces代表面,代表所有的三角形
aiMesh->mFaces[i]->mNumIndices 包含 三角形的索引个数
aiMesh->mFaces[i]-mIndices[j] 具体每个顶点的索引
该索引索引的顶点是该mesh中装有的顶点
aiMesh ->mMaterialIndex 指示该mesh 所用的材质索引,所有的材质都是在scene的mMaterials中
该方法 中我们把 解析mesh 所有的顶点 纹理 以及顶点索引 和材质都存放在了对象Mesh 中.
我们知道mesh 是加载的最小单位,因此我们把这些数据组装在一起
- mesh 顶点的具体加载
-(void)parse{
self.vertex= [Vertex new];
int vertexNum =self.vertices.count;
[self.vertex allocVertexNum:vertexNum andEachVertexNum:5];
for (int i=0; i<vertexNum; i++) {
float onevertex[5];
MeshVertex * meshVertex = self.vertices[i];
for (int j=0; j<3; j++) {
onevertex[j]=meshVertex.Position.v[j];
}
for (int j=0; j<2; j++) {
onevertex[j+3]=meshVertex.TexCoords.v[j];;
}
[self.vertex setVertex:onevertex index:i];
}
[self.vertex bindBufferWithUsage:GL_STATIC_DRAW];
self.elementVertex = [VertexElement new];
[self.elementVertex allocWithArray:self.indices];
}
这里Vertex 和elementVertex 是对顶点加载的封装,具体代码会在文章结尾贴出
- 5.纹理加载
-(NSMutableArray*) loadMaterialTextures:(aiMaterial *)mat type:(aiTextureType) type typeName:(NSString *) typeName{
NSMutableArray * textures = [NSMutableArray new];
for(unsigned int i = 0; i < mat->GetTextureCount(type); i++)
{
aiString str;
mat->GetTexture(type, i, &str);
NSString * filename =[NSString stringWithFormat:@"%@/%s",self.path,str.C_Str()];
UIImage * image = [UIImage imageWithContentsOfFile:filename];
AssimpTextureUnit * unit = [AssimpTextureUnit new];
unit.typeName = typeName;
[unit setImage:image andConfigTextureUnit:nil];
[textures addObject:unit];
}
return textures;
}
- 绘制 mesh
-(void)draw:(AssimpBindObject * )bindObject{
for (int i=0; i<self.textures.count; i++) {
AssimpTextureUnit * unit = [self.textures objectAtIndex:i];
[unit activeTextureUnit:GL_TEXTURE0+i];
GLint location = -1;
if ([unit.typeName isEqualToString:@"texture_diffuse"]) {
location = uniform_diffuse;
}else if ([unit.typeName isEqualToString:@"texture_height"]){
location = uniform_height;
}else if ([unit.typeName isEqualToString:@"texture_specular"]){
location = uniform_specular;
}
[unit bindtextureUnitLocationAndShaderUniformSamplerLocation:bindObject->uniforms[location]];
}
[self.vertex enableVertexInVertexAttrib:aPos numberOfCoordinates:3 attribOffset:0];
[self.vertex enableVertexInVertexAttrib:aTexCoords numberOfCoordinates:2 attribOffset:sizeof(float)*3];
[self.elementVertex drawElementIndexWithMode:GL_TRIANGLES];
}
这里很关键
首先我们先加载纹理图 我们在解析纹理的时候,只是把纹理图读取到内存中了.但是没有和纹理单元绑定.因此在绘制的时候,
我们首先需要绑定纹理单元和纹理
我们需要enable (使能) 我们已经在内存创建好的顶点数据.告诉opengl 我们现在需要使用那些顶点,很关键,忘记了,图像出不来
使用索引进行 绘制
到此主要流程完毕.
vertex 和 顶点索引以及纹理贴图省略的代码
@interface Vertex()
@property (nonatomic ,assign) GLfloat *vertex; ;
@property (nonatomic ,assign) GLsizei vertexNum ;
@property (nonatomic ,assign) GLsizei eachVertexNum ;
@property (nonatomic, assign) GLuint vertexBuffers;
@property (nonatomic ,assign) GLenum usage ;
@end
@implementation Vertex
- (instancetype)init
{
self = [super init];
if (self) {
[self _customInit];
}
return self;
}
-(void)_customInit{
glGenBuffers(1, &_vertexBuffers);
}
-(NSInteger)getAllocSpaceByteNum{
return self.getVertexWidth*self.vertexNum;
}
-(GLsizei)getVertexWidth{
return sizeof(GLfloat) * self.eachVertexNum;
}
-(void)allocVertexNum:(GLsizei)vertexNum andEachVertexNum:(GLsizei)eachVertexNum{
[self releaseVertex];
self.vertexNum = vertexNum;
self.eachVertexNum = eachVertexNum;
self.vertex =(GLfloat*)malloc(self.getAllocSpaceByteNum);
memset( self.vertex, 0, self.getAllocSpaceByteNum);
}
-(void)setVertex:(GLfloat *)vertex index:(NSInteger)index{
if (self.vertex) {
NSInteger offset = index * self.eachVertexNum;
for (NSInteger i = 0; i<self.eachVertexNum; i++) {
self.vertex[offset+i] = vertex[i];
}
}else{
NSLog(@"顶点没有空间");
}
}
-(void)releaseVertex{
if (self.vertex) {
free( self.vertex);
self.vertex = NULL;
}
}
-(void)bindBufferWithUsage: (GLenum) usage{
if (!self.vertexBuffers) {
[self _customInit];
}
glBindBuffer(GL_ARRAY_BUFFER,
self.vertexBuffers);
glBufferData( GL_ARRAY_BUFFER,
self.getAllocSpaceByteNum,
self.vertex,
usage);
}
-(void)enableVertexInVertexAttrib:(GLuint)index numberOfCoordinates:(GLint)count attribOffset:(GLsizeiptr)offset{
glBindBuffer(GL_ARRAY_BUFFER,
self.vertexBuffers);
glEnableVertexAttribArray(index);
glVertexAttribPointer(index, // Identifies the attribute to use
count, // number of coordinates for attribute
GL_FLOAT, // data is floating point
GL_FALSE, // no fixed point scaling
self.getVertexWidth , // total num bytes stored per vertex
NULL + offset);
#ifdef DEBUG
{ // Report any errors
GLenum error = glGetError();
if(GL_NO_ERROR != error)
{
NSLog(@"GL Error: 0x%x", error);
}
}
// GL_INVALID_OPERATION operation;
// GL_INVALID_VALUE
#endif
}
-(void)drawVertexWithMode:(GLenum)mode startVertexIndex:(GLint)first
numberOfVertices:(GLsizei)count {
NSAssert([self getAllocSpaceByteNum] >=
((first + count) *sizeof(GLfloat) * self.eachVertexNum),
@"Attempt to draw more vertex data than available.");
glBindBuffer(GL_ARRAY_BUFFER,
self.vertexBuffers);
glDrawArrays(mode, first, count);
}
- (void)dealloc
{
[self releaseVertex];
}
@end
#import "TextureUnit.h"
@interface TextureUnit ()
@property (nonatomic, assign) GLuint textureBuffer;
@property (nonatomic ,assign) int textureUnitLocation ;
@end
@implementation TextureUnit
- (instancetype)init
{
self = [super init];
if (self) {
[self _customInit];
}
return self;
}
-(void)_customInit{
self.textureUnitLocation = -1;
glGenTextures(1, &_textureBuffer);
}
#pragma mark - public
-(void)setPixels: (float*) pixels pixelsWidth:(GLsizei)width pixelsHeight:(GLsizei)height IntoTextureUnit:(GLenum)textureUnit andConfigTextureUnit:(nullable void(^)(void))configTextureUnitBlock PixelFormat:(GLint)internalformat{
glActiveTexture(textureUnit);
self.textureUnitLocation = [self _getTextureBindLocationForTexture:textureUnit];
glBindTexture(GL_TEXTURE_2D, _textureBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat , width, height, 0, internalformat, GL_FLOAT, pixels);
if (configTextureUnitBlock) {
configTextureUnitBlock();
}else{
[self _textureBaseConfig];
}
}
-(void)setImage:(UIImage *)image IntoTextureUnit:(GLenum)textureUnit andConfigTextureUnit:(nullable void(^)(void))configTextureUnitBlock {
[self setImage:image IntoTextureUnit:textureUnit andConfigTextureUnit:configTextureUnitBlock PixelFormat:GL_RGBA];
}
-(void)setImage:(UIImage *)image IntoTextureUnit:(GLenum)textureUnit andConfigTextureUnit:(void(^)(void))configTextureUnitBlock PixelFormat:(GLint)internalformat{
glActiveTexture(textureUnit);
self.textureUnitLocation = [self _getTextureBindLocationForTexture:textureUnit];
glBindTexture(GL_TEXTURE_2D, _textureBuffer);
GLubyte *imageData = [self _getImageData:image];
glTexImage2D(GL_TEXTURE_2D, 0, internalformat , image.size.width, image.size.height, 0, internalformat, GL_UNSIGNED_BYTE, imageData);
free(imageData);
if (configTextureUnitBlock) {
configTextureUnitBlock();
}else{
[self _textureBaseConfig];
}
}
-(void)setImage:(UIImage *)image andConfigTextureUnit:(nullable void(^)(void))configTextureUnitBlock {
[self setImage:image andConfigTextureUnit:configTextureUnitBlock PixelFormat:GL_RGBA];
}
-(void)setImage:(UIImage *)image andConfigTextureUnit:(nullable void(^)(void))configTextureUnitBlock PixelFormat:(GLint)internalformat{
glBindTexture(GL_TEXTURE_2D, _textureBuffer);
GLubyte *imageData = [self _getImageData:image];
glTexImage2D(GL_TEXTURE_2D, 0, internalformat , image.size.width, image.size.height, 0, internalformat, GL_UNSIGNED_BYTE, imageData);
free(imageData);
if (configTextureUnitBlock) {
configTextureUnitBlock();
}else{
[self _textureBaseConfig];
}
}
-(void)activeTextureUnit:(GLenum)textureUnit{
glActiveTexture(textureUnit);
glBindTexture(GL_TEXTURE_2D, _textureBuffer);
self.textureUnitLocation = [self _getTextureBindLocationForTexture:textureUnit];
}
-(void)bindtextureUnitLocationAndShaderUniformSamplerLocation:(GLint) uniformSamplerLocation {
if (self.textureUnitLocation == -1) {
NSLog(@"没有设置纹理单元或者设置纹理单元错误");
return;
}
glUniform1i(uniformSamplerLocation, self.textureUnitLocation);
GLenum error = glGetError();
if(GL_NO_ERROR != error)
{
NSLog(@"GL Error: bindtextureUnitLocationAndShaderUniformSamplerLocation 0x%x", error);
}
}
#pragma mark - private
-(int)_getTextureBindLocationForTexture:(GLenum)texture{
int textureLocation = texture-GL_TEXTURE0;
if (textureLocation>=0 && textureLocation <32) {
return textureLocation;
}
NSLog(@"超出纹理单元");
return -1;
}
-(void)_textureBaseConfig{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
- (void*)_getImageData:(UIImage*)image{
CGImageRef imageRef = [image CGImage];
size_t imageWidth = CGImageGetWidth(imageRef);
size_t imageHeight = CGImageGetHeight(imageRef);
GLubyte *imageData = (GLubyte *)malloc(imageWidth*imageHeight*4);
memset(imageData, 0,imageWidth *imageHeight*4);
CGContextRef imageContextRef = CGBitmapContextCreate(imageData, imageWidth, imageHeight, 8, imageWidth*4, CGImageGetColorSpace(imageRef), kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(imageContextRef, 0, imageHeight);
CGContextScaleCTM(imageContextRef, 1.0, -1.0);
CGContextDrawImage(imageContextRef, CGRectMake(0.0, 0.0, (CGFloat)imageWidth, (CGFloat)imageHeight), imageRef);
CGContextRelease(imageContextRef);
return imageData;
}
@end
#import "VertexElement.h"
@interface VertexElement()
@property (nonatomic, assign) GLuint indexBuffer;
@property (nonatomic ,assign) GLuint *indexs;
@property (nonatomic ,assign) GLsizei count ;
@end
@implementation VertexElement
- (instancetype)init
{
self = [super init];
if (self) {
[self _customInit];
}
return self;
}
-(void)_customInit{
glGenBuffers(1, &_indexBuffer);
}
-(void)allocWithArray:(NSArray *)indexArr{
if (self.indexs) {
[self releaseIndexs];
}
self.count = indexArr.count;
self.indexs =(GLuint*)malloc( self.count *sizeof(GLuint));
memset( self.indexs, 0, self.count *sizeof(GLuint));
for (int i =0; i< self.count; i++) {
self.indexs[i]=((NSNumber *)indexArr[i]).intValue;
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.count *sizeof(GLuint),self.indexs, GL_STATIC_DRAW);
#ifdef DEBUG
{ // Report any errors
GLenum error = glGetError();
if(GL_NO_ERROR != error)
{
NSLog(@"GL Error: 0x%x", error);
}
}
#endif
}
-(void)allocWithIndexNum:(GLsizei)count indexArr:(GLuint*)indexArr{
if (self.indexs) {
[self releaseIndexs];
}
self.count = count;
self.indexs =(GLuint*)malloc(count *sizeof(GLuint));
memset( self.indexs, 0, count *sizeof(GLuint));
for (int i =0; i<count; i++) {
self.indexs[i]=indexArr[i];
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, count *sizeof(GLuint),self.indexs, GL_STATIC_DRAW);
#ifdef DEBUG
{ // Report any errors
GLenum error = glGetError();
if(GL_NO_ERROR != error)
{
NSLog(@"GL Error: 0x%x", error);
}
}
#endif
}
-(void)releaseIndexs{
if (self.indexs) {
free( self.indexs);
self.indexs = NULL;
}
}
-(void)drawElementIndexWithMode:(GLenum)mode{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.indexBuffer);
glDrawElements(mode, self.count, GL_UNSIGNED_INT, 0);
}
+ (void)drawElementIndexWithMode:(GLenum)mode indexNum:(GLsizei)count indexArr:(GLuint*)indexArr
{
glDrawElements(mode, count, GL_UNSIGNED_INT, indexArr);
}
- (void)dealloc
{
[self releaseIndexs];
}
@end
git 中的
OpenGLZeroStudyDemo(8)-Assimp(模型加载)
不能直接运行,因为缺少 .a 文件,需要读者自己编译 ,引用才行
编译工程git-TestAssimp
OpenGLZeroStudyDemo(8)-Assimp(模型加载)
以上工程的 编译的assist 库 .a 都没有上传,需要 读者自己编译按照博客顺序添加.
.a 文件太大了. 上传不了git.实在是抱歉