从0开发游戏引擎之纹理管理器实现 纹理数据绑定OpenGL滤波方式选择线性滤波

简介: 从0开发游戏引擎之纹理管理器实现 纹理数据绑定OpenGL滤波方式选择线性滤波

这一章主要是讲如何把一张图片加载进内存中转换BGR->RGB格式,然后和OpenGL做绑定渲染出来。


这一章讲解的顺序完全反过来了。基础好的读者也可以反过来看,先看重点,然后再回过头来看源码。没接触过的读者可以先简单的读一遍源码,然后再看重点分析,这样看重点分析的话会更有感觉。源码的话文章写的差不多了,我再整理一下会放到群里。


先贴出完整代码


TextureManager.h


#pragma once
#include <list>
struct  textureHeight
{
public:
  GLfloat m_iLowHeight=0;//最低高度
  GLfloat m_iHighHeight=0;//最高高度
  GLfloat m_iOptimalHeight=0;//最佳高度
};
class CCTexture
{
  friend class CTextureManager;
private:
  char name[255]; //纹理路径
  GLuint type;  //类型,保存了一个16进制数
  GLuint texID; //纹理ID
  UINT  width;     //图片的宽
  UINT height;  //图片的高
  UINT uReference; //引用计数
  int bytesPerPixel; //每个像素的位(Bit)
  GLubyte *imageData;//纹理数据(unsigned char)
  Vector3D centerPos ={0,0,1};
public:
  textureHeight *Tex=new textureHeight;
  CCTexture();
  CCTexture(const char *fileName,float width=1,float height=1);
  CCTexture(const char * name, int wid, int hei, int BitCount);
  int getbyte() { return bytesPerPixel; }
  GLuint getType() { return type; }
  char *getName() { return name; }
  GLuint getTextureID() { return texID; }
  UINT getWidth() { return width; }
  UINT getHeight() { return height; }
  BOOL saveBmp(const char * fileName);
  GLubyte *getImageData() { return imageData; }
  void setImageData(GLubyte *data) { this->imageData = data; }
  void setCenterPos(Vector3D centerPoint);
  void draw();
  ~CCTexture() ;
public:
};
class CTextureManager
{
private:
  std::list<CCTexture*> textureList;
  static CTextureManager*instance;
public:
  static CTextureManager*getInstance();
  CCTexture* addTexture(char *fileName,float width=1,float height=1);
  CCTexture *addTexture(const char*fileName);
  CCTexture * addTexture(char *name, int width, int height, int pixelFormat);
  void resetRef();//把引用计数全都归零
  void releaseRef();//把引用计数全都归零
  void CreateGLTextures(int wid, int hei, int biBitCount, OUT GLuint &texture, OUT GLubyte*&textureData);
  CTextureManager();
  ~CTextureManager();
};


TextureManager.cpp


#include "Engine.h"
CTextureManager*CTextureManager::instance = NULL;
CCTexture::CCTexture()
{
  texID = 0;
  uReference = 1;
  imageData = NULL;
}
CCTexture::CCTexture(const char* fileName,float wid,float hei)
{
  texID = 0;
  CImage img;
  HRESULT hr = img.Load(CUser::getInstance()->CharToWchar(fileName));
  if (FAILED(hr))
  {
    char temp[256];
    sprintf_s(temp, 256, "%s打开失败", fileName);
    MessageBox(NULL, CUser::getInstance()->CharToWchar(temp), L"错误", 0);
    return;
  }
  strcpy(name, fileName);
  HBITMAP hbmp = img;
  BITMAP bm;
  GetObject(hbmp, sizeof(bm), &bm);
  if (wid > 1 && hei > 1)
  {
    width = wid;  height = hei;
  }
  else 
  {
    width = bm.bmWidth; height = bm.bmHeight;
  }
  bytesPerPixel = bm.bmBitsPixel / 8;
  if (bytesPerPixel == 3)
  {
    type = GL_RGB;
  }
  else if (bytesPerPixel == 4)
  {
    type = GL_RGBA;
  }
  else if (bytesPerPixel == 1)
  {
    type = GL_LUMINANCE;
  }
  imageData = new GLubyte[width*height*bytesPerPixel];
  memcpy(imageData, bm.bmBits, width*height*bytesPerPixel);
  // Convert From BGR To RGB Format And Add An Alpha Value Of 255
  if (bytesPerPixel != 1)
  {
    for (long i = 0; i < width * height; i++)
    {
      GLubyte temp = imageData[0 + i*bytesPerPixel];
      imageData[0 + i*bytesPerPixel] = imageData[2 + i*bytesPerPixel];
      imageData[2 + i*bytesPerPixel] = temp;
    }
  }
  else //等于8位时处理的
  {
    for (int i = 0; i < height; i++)
    {
      memcpy(imageData + i*width, img.GetPixelAddress(0, i), width);
    }
  }
  glGenTextures(1, (GLuint*)&texID);
  glBindTexture(GL_TEXTURE_2D, texID);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//纹理过滤模式
  gluBuild2DMipmaps(GL_TEXTURE_2D, type, width, height, type, GL_UNSIGNED_BYTE, imageData);
  /*glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, type, width, height, 0, type, GL_UNSIGNED_BYTE, imageData);*/
}
CCTexture::CCTexture(const char *name, int wid, int hei, int BitCount)
{
  uReference =1;
  strcpy(this->name,name);
  bytesPerPixel = BitCount / 8;
  this->width = wid;
  this->height = hei;
  glGenTextures(1, &texID);
  glBindTexture(GL_TEXTURE_2D, texID);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  imageData = new GLubyte[width*height*bytesPerPixel];
  //memset(imageData, 0, width*height*bytesPerPixel);
  if (bytesPerPixel == 1)
  {
    for (int i = 0; i < width*height; ++i)
    {
      imageData[i] = 0;
    }
    type = GL_LUMINANCE;
  }
  else if (bytesPerPixel == 3)
  {
    for (int i = 0; i < width*height; ++i)
    {
      imageData[i * 3 + 0] = 0;
      imageData[i * 3 + 1] = 0;
      imageData[i * 3 + 2] = 0;
    }
    type = GL_RGB;
  }
  else if (bytesPerPixel == 4)
  {
    for (int i = 0; i < width*height; ++i)
    {
      imageData[i * 4 + 0] = 0;
      imageData[i * 4 + 1] = 0;
      imageData[i * 4 + 2] = 0;
      imageData[i * 4 + 3] = 0;
    }
    type = GL_RGBA;
  }
  glTexImage2D(GL_TEXTURE_2D, 0, type, wid, hei, 0, type, GL_UNSIGNED_BYTE, imageData);
}
BOOL CCTexture::saveBmp(const char *fileName)
{
  //如果位图数据指针为0,则没有数据传入,函数返回
  if (!imageData)
    return 0;
  //灰度图
  static RGBQUAD *pColorTable = NULL;
  if (pColorTable == NULL)
  {
    pColorTable = new RGBQUAD[256];
    for (int i = 0; i < 256; i++)
    {
      pColorTable[i].rgbBlue = i;
      pColorTable[i].rgbGreen = i;
      pColorTable[i].rgbRed = i;
      pColorTable[i].rgbReserved = 0;
    }
  }
  //颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0
  int colorTablesize = 0;
  if (bytesPerPixel == 1)
    colorTablesize = 1024;
  //待存储图像数据每行字节数为4的倍数
  int lineByte = (width * bytesPerPixel + 3) / 4 * 4;
  //以二进制写的方式打开文件
  FILE *fp = fopen(fileName, "wb");
  if (fp == 0) return 0;
  //申请位图文件头结构变量,填写文件头信息
  BITMAPFILEHEADER fileHead;
  fileHead.bfType = 0x4D42;//bmp类型
               //bfSize是图像文件4个组成部分之和
  fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
    + colorTablesize + lineByte*height;
  fileHead.bfReserved1 = 0;
  fileHead.bfReserved2 = 0;
  //bfOffBits是图像文件前三个部分所需空间之和
  fileHead.bfOffBits = 54 + colorTablesize;
  //写文件头进文件
  fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);
  //申请位图信息头结构变量,填写信息头信息
  BITMAPINFOHEADER head;
  head.biBitCount = bytesPerPixel * 8;
  head.biClrImportant = 0;
  head.biClrUsed = 0;
  head.biCompression = 0;
  head.biHeight = height;
  head.biPlanes = 1;
  head.biSize = 40;
  head.biSizeImage = lineByte*height;
  head.biWidth = width;
  head.biXPelsPerMeter = 0;
  head.biYPelsPerMeter = 0;
  //写位图信息头进内存
  fwrite(&head, sizeof(BITMAPINFOHEADER), 1, fp);
  //如果灰度图像,有颜色表,写入文件
  if (bytesPerPixel == 1)
    fwrite(pColorTable, sizeof(RGBQUAD), 256, fp);
  //写位图数据进文件
  if (bytesPerPixel == 1)
  {
    fwrite(imageData, height*lineByte, 1, fp);
  }
  else
  {
    GLubyte *newData = new GLubyte[width * height*bytesPerPixel];
    memcpy(newData, imageData, width * height*bytesPerPixel);
    for (long i = 0; i < width * height; i++)
    {
      GLubyte temp = newData[0 + i*bytesPerPixel];
      newData[0 + i*bytesPerPixel] = newData[2 + i*bytesPerPixel];
      newData[2 + i*bytesPerPixel] = temp;
    }
    fwrite(newData, height*lineByte, 1, fp);
    delete[]newData;
  }
  //关闭文件
  fclose(fp);
  return 1;
}
void CCTexture::setCenterPos(Vector3D center)
{
  this->centerPos = center;
}
void CCTexture::draw()
{
  float halfWid = width / 2;
  float halfHei = height / 2;
  Vector3D temp = centerPos;
  glEnable(GL_TEXTURE_2D);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glBindTexture(GL_TEXTURE_2D, texID);
  glBegin(GL_QUADS);
  glTexCoord2f(0, 0); glVertex3f(centerPos.x- halfWid, centerPos.y+halfHei, 1);
  glTexCoord2f(1, 0); glVertex3f(centerPos.x+ halfWid, centerPos.y+halfHei, 1);
  glTexCoord2f(1, 1); glVertex3f(centerPos.x + halfWid, centerPos.y-halfHei, 1);
  glTexCoord2f(0, 1); glVertex3f(centerPos.x -halfWid, centerPos.y-halfHei, 1);
  glEnd();
  glDisable(GL_TEXTURE_2D);
  glDisable(GL_BLEND);
}
CCTexture::~CCTexture()
{
  glDeleteTextures(1,&texID);
  delete imageData;
}
CTextureManager::CTextureManager()
{
}
CTextureManager*CTextureManager::getInstance()
{
  if (instance == NULL)
  {
    instance = new CTextureManager;
  }
  return instance;
}
CCTexture* CTextureManager::addTexture(char *filename,float width, float height)
{
  list<CCTexture*>::iterator iter;
  for (iter = textureList.begin(); iter != textureList.end(); iter++)
  {
    if (strcmp((*iter)->getName(), filename) == 0)
    {
      (*iter)->uReference++;
      return *iter;
    }
  }
  textureList.push_back(new CCTexture(filename));
  return textureList.back();
}
CCTexture* CTextureManager::addTexture(const char *filename)
{
  const char*lp = strrchr(filename, '.');
  char temp[255];
  if(strcmp(lp,".bmp")==0||strcmp(lp,".jpg")==0)
  {
    strcpy(temp, filename);
  }
  else 
  {
    memset(temp, 0, 255);
    strncpy(temp,filename,lp-filename);
    strcat(temp, ".png");
  }
  list<CCTexture*>::iterator iter;
  for (iter = textureList.begin(); iter != textureList.end(); iter++)
  {
    if (strcmp((*iter)->getName(), filename) == 0)
    {
      (*iter)->uReference++;
      return *iter;
    }
  }
  textureList.push_back(new CCTexture(temp));
  return textureList.back();
}
CCTexture* CTextureManager::addTexture(char *name, int width, int height, int BitCount)
{
  list<CCTexture*>::iterator iter;
  for (iter = textureList.begin(); iter != textureList.end(); iter++)
  {
    if (strcmp((*iter)->getName(), name) == 0)
    {
      (*iter)->uReference++;
      return *iter;
    }
  }
  textureList.push_back(new CCTexture(name, width, height, BitCount));
  return textureList.back();
}
void CTextureManager::releaseRef()
{
  for (auto iter = textureList.begin(); iter != textureList.end();)
  {
    if ((*iter)->uReference == 0)
    {
      delete(*iter);
      textureList.erase(iter++);
    }
    else
      iter++;
  }
}
void CTextureManager::resetRef()
{
  for (auto iter = textureList.begin(); iter != textureList.end(); iter++)
  {
    (*iter)->uReference = 0;
  }
}
void CTextureManager::CreateGLTextures(int wid, int hei, int biBitCount, OUT GLuint &texture, OUT GLubyte*&textureData)
{
  glGenTextures(1, &texture);
  glBindTexture(GL_TEXTURE_2D, texture);
  if (biBitCount == 8)
  {
    textureData = new GLubyte[wid*hei];
    memset(textureData, 0, wid*hei);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);   // 设置过滤器为线性过滤
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, 1, wid, hei, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, textureData);
  }
  else if (biBitCount == 24)
  {
    textureData = new GLubyte[wid*hei * 3];
    memset(textureData, 0, wid*hei * 3);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);   // 设置过滤器为线性过滤
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, wid, hei, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData);
  }
}
CTextureManager::~CTextureManager()
{
  for (auto iter = textureList.begin();iter != textureList.end();)
  {
    delete (*iter);
    textureList.erase(iter++);
  }
  textureList.clear();
}


保存BMP格式图片(只能保存BMP)


这个函数当时主要是能把编辑器里刷的地形保存出去使用的。


1.BOOL CCTexture::saveBmp(const char *fileName)
{
  //如果位图数据指针为0,则没有数据传入,函数返回
  if (!imageData)
    return 0;
  //灰度图
  static RGBQUAD *pColorTable = NULL;
  if (pColorTable == NULL)
  {
    pColorTable = new RGBQUAD[256];
    for (int i = 0; i < 256; i++)
    {
      pColorTable[i].rgbBlue = i;
      pColorTable[i].rgbGreen = i;
      pColorTable[i].rgbRed = i;
      pColorTable[i].rgbReserved = 0;
    }
  }
  //颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0
  int colorTablesize = 0;
  if (bytesPerPixel == 1)
    colorTablesize = 1024;
  //待存储图像数据每行字节数为4的倍数
  int lineByte = (width * bytesPerPixel + 3) / 4 * 4;
  //以二进制写的方式打开文件
  FILE *fp = fopen(fileName, "wb");
  if (fp == 0) return 0;
  //申请位图文件头结构变量,填写文件头信息
  BITMAPFILEHEADER fileHead;
  fileHead.bfType = 0x4D42;//bmp类型
               //bfSize是图像文件4个组成部分之和
  fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
    + colorTablesize + lineByte*height;
  fileHead.bfReserved1 = 0;
  fileHead.bfReserved2 = 0;
  //bfOffBits是图像文件前三个部分所需空间之和
  fileHead.bfOffBits = 54 + colorTablesize;
  //写文件头进文件
  fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);
  //申请位图信息头结构变量,填写信息头信息
  BITMAPINFOHEADER head;
  head.biBitCount = bytesPerPixel * 8;
  head.biClrImportant = 0;
  head.biClrUsed = 0;
  head.biCompression = 0;
  head.biHeight = height;
  head.biPlanes = 1;
  head.biSize = 40;
  head.biSizeImage = lineByte*height;
  head.biWidth = width;
  head.biXPelsPerMeter = 0;
  head.biYPelsPerMeter = 0;
  //写位图信息头进内存
  fwrite(&head, sizeof(BITMAPINFOHEADER), 1, fp);
  //如果灰度图像,有颜色表,写入文件
  if (bytesPerPixel == 1)
    fwrite(pColorTable, sizeof(RGBQUAD), 256, fp);
  //写位图数据进文件
  if (bytesPerPixel == 1)
  {
    fwrite(imageData, height*lineByte, 1, fp);
  }
  else
  {
    GLubyte *newData = new GLubyte[width * height*bytesPerPixel];
    memcpy(newData, imageData, width * height*bytesPerPixel);
    for (long i = 0; i < width * height; i++)
    {
      GLubyte temp = newData[0 + i*bytesPerPixel];
      newData[0 + i*bytesPerPixel] = newData[2 + i*bytesPerPixel];
      newData[2 + i*bytesPerPixel] = temp;
    }
    fwrite(newData, height*lineByte, 1, fp);
    delete[]newData;
  }
  //关闭文件
  fclose(fp);
  return 1;
}


加载文件&绑定纹理选择滤波类型


因为使用的是Windows的图像API加载的,加载进来的图像格式是BGR格式的,要从BGR转换成OpenGL需要的RGB格式。图片过滤方式选择 GL_LINEAR(也叫线性过滤,(Bi)linear Filtering)它会基于纹理坐标附近的纹理像素,计算出一个插值,近似出这些纹理像素之间的颜色。


使用线性过滤的优点与缺点

优点:

       1.质量高:避免了在远距离情况下的采样频率低和数据频率高造成的失真和摩尔纹,效果比无Mipmap好得多。


       2.性能好:避免了不使用Mipmap下距离远时采样频率低和数据频率高而照成texture cache命中率不高(相邻Pixel采样Texel时uv相差比较大)使性能下降。


缺点:

        1.占用显存,可使用ue的纹理流缓存优化(IO换显存)。


CCTexture::CCTexture(const char* fileName,float wid,float hei)
{
  texID = 0;
  CImage img;
  HRESULT hr = img.Load(CUser::getInstance()->CharToWchar(fileName));
  if (FAILED(hr))
  {
    char temp[256];
    sprintf_s(temp, 256, "%s打开失败", fileName);
    MessageBox(NULL, CUser::getInstance()->CharToWchar(temp), L"错误", 0);
    return;
  }
  strcpy(name, fileName);
  HBITMAP hbmp = img;
  BITMAP bm;
  GetObject(hbmp, sizeof(bm), &bm);
  if (wid > 1 && hei > 1)
  {
    width = wid;  height = hei;
  }
  else 
  {
    width = bm.bmWidth; height = bm.bmHeight;
  }
  bytesPerPixel = bm.bmBitsPixel / 8;
  if (bytesPerPixel == 3)
  {
    type = GL_RGB;
  }
  else if (bytesPerPixel == 4)
  {
    type = GL_RGBA;
  }
  else if (bytesPerPixel == 1)
  {
    type = GL_LUMINANCE;
  }
  imageData = new GLubyte[width*height*bytesPerPixel];
  memcpy(imageData, bm.bmBits, width*height*bytesPerPixel);
  // Convert From BGR To RGB Format And Add An Alpha Value Of 255
  if (bytesPerPixel != 1)
  {
    for (long i = 0; i < width * height; i++)
    {
      GLubyte temp = imageData[0 + i*bytesPerPixel];
      imageData[0 + i*bytesPerPixel] = imageData[2 + i*bytesPerPixel];
      imageData[2 + i*bytesPerPixel] = temp;
    }
  }
  else //等于8位时处理的
  {
    for (int i = 0; i < height; i++)
    {
      memcpy(imageData + i*width, img.GetPixelAddress(0, i), width);
    }
  }
  glGenTextures(1, (GLuint*)&texID);
  glBindTexture(GL_TEXTURE_2D, texID);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//纹理过滤模式
  gluBuild2DMipmaps(GL_TEXTURE_2D, type, width, height, type, GL_UNSIGNED_BYTE, imageData);
}


相关文章
|
25天前
|
Java Android开发
Android开发之使用OpenGL实现翻书动画
本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。
30 1
Android开发之使用OpenGL实现翻书动画
|
25天前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
21 1
Android开发之OpenGL的画笔工具GL10
|
4月前
|
XML Java Android开发
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
37 1
|
算法 Ubuntu Linux
红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...
红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...
从0开发游戏引擎之使用OpenGL绘制三维球体
绘制球体的难点主要在于 要在遍历循环中 根据经纬度反复的使用Cos、Sin函数算出球面上的XYZ三个顶点坐标,一直反复计算,最终三角面多的形成了一个球的形状。
|
监控 API Android开发
音视频开发进阶指南(第四章)-OpenGL-ES显示图片
安卓平台 本节使用OpenGL ES显示PNG图片,基于JNI开发,使用EGL作为OpenGL ES和显示设备之前的桥梁。另外PNG图片的数据读取使用libpng。
184 0
|
存储 缓存 异构计算
NDK OpenGL ES 3.0 开发(二十二):PBO
OpenGL PBO(Pixel Buffer Object),被称为像素缓冲区对象,主要被用于异步像素传输操作。PBO 仅用于执行像素传输,不连接到纹理,且与 FBO (帧缓冲区对象)无关。
526 0
NDK OpenGL ES 3.0 开发(二十二):PBO
|
计算机视觉 索引
NDK OpenGL ES 3.0 开发(二十一):3D 模型加载和渲染
3D 模型的设计一般是由许多小模型拼接组合成一个完整的大模型,一个小模型作为一个独立的渲染单元,我们称这些小模型为网格(Mesh)。
271 0
NDK OpenGL ES 3.0 开发(二十一):3D 模型加载和渲染
|
API 开发工具 Android开发
NDK OpenGL ES 3.0 开发(二十):3D 模型
OpenGLES 3D 模型本质上是由一系列三角形在 3D 空间(OpenGL 坐标系)中构建而成,另外还包含了用于描述三角形表面的纹理、光照、材质等信息。
478 0
NDK OpenGL ES 3.0 开发(二十):3D 模型
|
4月前
|
XML 小程序 Java
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
53 0