什么是纹理?
纹理:最通常就是装饰3D物体,像贴纸一样贴在物体表面,在OpenGl ES中除了装饰物体表面,还用来
作为数据的容器。
在OpenGL中,纹理实际上是一个可以被采样的复杂数据集合,是GPU使用的图像数据结构,分为:2D纹理,立方体纹理和3D纹理。
2D 纹理是 OpenGLES 中最常用和最常见的纹理形式,是一个图像数据的二维数组。纹理中的一个单独数据元素称为纹素或纹理像素。
纹理映射?
通过图元的顶点坐标指定恰当的纹理坐标,通过纹理坐标在纹理图中选定特定的纹理区域, 最后通过纹理坐标与顶点的映射关系,将特定的纹理区域映射到指定图元上。
纹理映射也称为纹理贴图,简单说:将纹理坐标所指定的纹理区域,映射到顶点坐标对应的区域。
纹理坐标系:
渲染坐标系或opengl ES坐标系:
4个纹理坐标分别为:
T0(0,0),T1(0,1),T2(1,1),T3(1,0);
4个纹理坐标对应的顶点坐标:
V0(-1,0.5),V1(-1,-0.5),V2(1,-0.5),V3(1,0.5)
由于OpenGLES绘制是以三角形为单位,设置绘制的2个三角形为V0V1V2和V0V2V3.
当我们调整纹理坐标的顺序,顶点坐标顺序不变,如T0T1T2T3–>T1T2T3T0,绘制后将得到一个顺时针
旋转90度的纹理贴图。因此可以通过纹理坐标和顶点坐标的对应关系实现纹理简单旋转。
纹理映射的简单实现
步骤:
1,生成纹理,编译链接着色器程序
2,确定纹理坐标及对应的顶点坐标
3,加载图像数据到纹理,加载纹理坐标和顶点坐标到着色器程序
4.绘制
生成纹理并加载图像数据到纹理
//生成一个纹理,将纹理 id 赋值给 m_TextureId
glGenTextures(1, &m_TextureId);
//将纹理 m_TextureId 绑定到类型 GL_TEXTURE_2D 纹理
glBindTexture(GL_TEXTURE_2D, m_TextureId);
//设置纹理 S 轴(横轴)的拉伸方式为截取
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//设置纹理 T 轴(纵轴)的拉伸方式为截取
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//设置纹理采样方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//加载 RGBA 格式的图像数据
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_RenderImage.width, m_RenderImage.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_RenderImage.ppPlane[0]);
对纹理采样的片元着色器脚本
#version 300 es
precision mediump float;
in vec2 v_texCoord;
layout(location = 0) out vec4 outColor;
uniform sampler2D s_TextureMap; //声明采用器
void main()
{
// texture() 为内置的采样函数,v_texCoord 为顶点着色器传进来的纹理坐标
// 根据纹理坐标对纹理进行采样,输出采样的 rgba 值(4维向量)
outColor = texture(s_TextureMap, v_texCoord);
}
实例1:
// 生成纹理,编译链接着色器程序
void TextureMapSample::Init()
{
//create RGBA texture
glGenTextures(1, &m_TextureId);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, GL_NONE);
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 a_position; \n"
"layout(location = 1) in vec2 a_texCoord; \n"
"out vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position; \n"
" v_texCoord = a_texCoord; \n"
"} \n";
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"in vec2 v_texCoord; \n"
"layout(location = 0) out vec4 outColor; \n"
"uniform sampler2D s_TextureMap; \n"
"void main() \n"
"{ \n"
" outColor = texture(s_TextureMap, v_texCoord); \n"
"} \n";
m_ProgramObj = GLUtils::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader);
if (m_ProgramObj)
{
m_SamplerLoc = glGetUniformLocation(m_ProgramObj, "s_TextureMap");
}
else
{
LOGCATE("TextureMapSample::Init create program fail");
}
}
// 加载图像数据、纹理坐标和顶点坐标数据,绘制实现纹理映射
void TextureMapSample::Draw(int screenW, int screenH)
{
LOGCATE("TextureMapSample::Draw()");
if(m_ProgramObj == GL_NONE || m_TextureId == GL_NONE) return;
GLfloat verticesCoords[] = {
-1.0f, 0.5f, 0.0f, // Position 0
-1.0f, -0.5f, 0.0f, // Position 1
1.0f, -0.5f, 0.0f, // Position 2
1.0f, 0.5f, 0.0f, // Position 3
};
GLfloat textureCoords[] = {
0.0f, 0.0f, // TexCoord 0
0.0f, 1.0f, // TexCoord 1
1.0f, 1.0f, // TexCoord 2
1.0f, 0.0f // TexCoord 3
};
GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
//upload RGBA image data
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_RenderImage.width, m_RenderImage.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_RenderImage.ppPlane[0]);
glBindTexture(GL_TEXTURE_2D, GL_NONE);
// Use the program object
glUseProgram (m_ProgramObj);
// Load the vertex position
glVertexAttribPointer (0, 3, GL_FLOAT,
GL_FALSE, 3 * sizeof (GLfloat), verticesCoords);
// Load the texture coordinate
glVertexAttribPointer (1, 2, GL_FLOAT,
GL_FALSE, 2 * sizeof (GLfloat), textureCoords);
glEnableVertexAttribArray (0);
glEnableVertexAttribArray (1);
// Bind the RGBA map
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
// Set the RGBA map sampler to texture unit to 0
glUniform1i(m_SamplerLoc, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}
结果:
实例2:
CoordSystemSample.h代码:
/**
*
* Created by 公众号:字节流动 on 2020/4/18.
* https://github.com/githubhaohao/NDK_OpenGLES_3_0
* 最新文章首发于公众号:字节流动,有疑问或者技术交流可以添加微信 Byte-Flow ,领取视频教程, 拉你进技术交流群
*
* */
#ifndef NDK_OPENGLES_3_0_COORDSYSTEMSAMPLE_H
#define NDK_OPENGLES_3_0_COORDSYSTEMSAMPLE_H
#include "detail/type_mat.hpp"
#include "detail/type_mat4x4.hpp"
#include "GLSampleBase.h"
#include <vector>
#include <map>
#define RENDER_IMG_NUM 3
class CoordSystemSample : public GLSampleBase
{
public:
CoordSystemSample();
virtual ~CoordSystemSample();
virtual void LoadImage(NativeImage *pImage);
virtual void LoadMultiImageWithIndex(int index, NativeImage *pImage);
virtual void Init();
virtual void Draw(int screenW, int screenH);
//virtual void delay(int seconds);
virtual void Destroy();
virtual void UpdateTransformMatrix(float rotateX, float rotateY, float scaleX, float scaleY);
void UpdateMVPMatrix(glm::mat4 &mvpMatrix, int angleX, int angleY, float ratio);
void UpdateMVPMatrix1(glm::mat4 &mvpMatrix, int angleX, int angleY, float ratio);
void UpdateMatrix(glm::mat4 &mvpMatrix, int angleXRotate, int angleYRotate, float scale, glm::vec3 transVec3, float ratio);
void DrawArray();
glm::mat4 transform(float height, float dip,float fov_x,float fov_y);
glm::mat4 buildRotateX(float rad);
glm::mat4 buildRotateY(float rad);
glm::mat4 buildRotateZ(float rad);
private:
GLuint m_TextureId;
GLint m_SamplerLoc;
GLint m_SamplerLoc1;
GLint m_MVPMatLoc;
GLint m_MVPMatLoc1;
GLint m_Offset;
GLint m_MVPMatLoc2;
GLuint m_VaoId;
GLuint m_VboIds[3];
GLuint m_TextureIds[RENDER_IMG_NUM];
NativeImage m_RenderImages[RENDER_IMG_NUM];
glm::mat4 m_ModelMatrix;
std::vector<glm::vec3> windowsTrans;
std::map<GLfloat, glm::vec3> sorted;
NativeImage m_RenderImage;
glm::mat4 m_MVPMatrix;
int m_AngleX;
int m_AngleY;
float m_ScaleX;
float m_ScaleY;
float m_FrameIndex;
float m_Color;
float m_offset;
float m_time;
int m_i;
CoordSystemSample* m_pCoordSystemSample;
};
#endif //NDK_OPENGLES_3_0_COORDSYSTEMSAMPLE_H
CoordSystemSample.cpp代码:
/**
*
* Created by 公众号:字节流动 on 2020/4/18.
* https://github.com/githubhaohao/NDK_OpenGLES_3_0
* 最新文章首发于公众号:字节流动,有疑问或者技术交流可以添加微信 Byte-Flow ,领取视频教程, 拉你进技术交流群
*
* */
#include "gtc/matrix_transform.hpp"
#include "CoordSystemSample.h"
#include "../util/GLUtils.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <math.h>
#include "../glm/mat4x4.hpp"
#define DRAW_POINTS
#define POINTS_NUM 512
#define POINTS_PRE_TRIANGLES 3
#define TRIANGLES_PER_POINT 3
CoordSystemSample::CoordSystemSample()
{
m_SamplerLoc = GL_NONE;
m_MVPMatLoc = GL_NONE;
m_TextureId = GL_NONE;
m_VaoId = GL_NONE;
m_AngleX = 0;
m_AngleY = 0;
m_ScaleX = 1.0f;
m_ScaleY = 1.0f;
m_offset =0.0f;
m_time=0.0f;
//m_pCoordSystemSample = new CoordSystemSample();
}
CoordSystemSample::~CoordSystemSample()
{
NativeImageUtil::FreeNativeImage(&m_RenderImage);
}
void CoordSystemSample::Init()
{
//create RGBA texture
glGenTextures(1, &m_TextureId);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, GL_NONE);
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 a_position; \n"
"layout(location = 1) in vec2 a_texCoord; \n"
"uniform float u_Offset;\n"
"uniform float t;\n"
"out vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position; \n"
" gl_Position.y = gl_Position.y+u_Offset+t; \n"
" v_texCoord = a_texCoord; \n"
"} \n";
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"in vec2 v_texCoord; \n"
"layout(location = 0) out vec4 outColor; \n"
"uniform sampler2D s_TextureMap; \n"
"void main() \n"
"{ \n"
" outColor = texture(s_TextureMap, v_texCoord); \n"
" //outColor = texelFetch(s_TextureMap,ivec2(int(v_texCoord.x * 404.0), int(v_texCoord.y * 336.0)), 0);\n"
"} \n";
m_ProgramObj = GLUtils::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader);
if (m_ProgramObj)
{
m_SamplerLoc = glGetUniformLocation(m_ProgramObj, "s_TextureMap");
}
else
{
LOGCATE("TextureMapSample::Init create program fail");
}
};
void CoordSystemSample::LoadImage(NativeImage *pImage)
{
#if 0
LOGCATE("CoordSystemSample::LoadImage pImage = %p", pImage->ppPlane[0]);
if (pImage)
{
m_RenderImage.width = pImage->width;
m_RenderImage.height = pImage->height;
m_RenderImage.format = pImage->format;
NativeImageUtil::CopyNativeImage(pImage, &m_RenderImage);
}
#endif
}
void CoordSystemSample::LoadMultiImageWithIndex(int index, NativeImage *pImage)
{
LOGCATE("TimeTunnelSample::LoadImage pImage = %p", pImage->ppPlane[0]);
if (pImage)
{
m_RenderImage.width = pImage->width;
m_RenderImage.height = pImage->height;
m_RenderImage.format = pImage->format;
NativeImageUtil::CopyNativeImage(pImage, &m_RenderImage);
}
}
glm::mat4 CoordSystemSample::transform(float height, float dip,float fov_x,float fov_y)
{
float distance= height/(tan(glm::radians(dip)));
float radiansY=0.0;
float radiansZ=0.0;
LOGCATD("distance = %f",distance);
//glm::mat4 Projection = glm::frustum(-0.699f, 0.699f, -0.3934f, 0.3934f, imagez, 100.0f);
// glm::mat4 Projection = glm::perspective(glm::radians(fov_y), fov_x/fov_y,2.0f,200.0f); //描绘的是屏幕 任务:加一个横向fov 算出来高宽比
glm::mat4 Projection = glm::perspective(glm::radians(4.0f), fov_x/fov_y,0.1f, 200.f);
LOGCATD("aspect = %f",fov_x/fov_y);
//透视投影矩阵 第1个参数为视锥上下面之间的夹角 第2个参数为宽高比 第3,第4分别为近界面和远界面的深度
//glm::mat4 Projection = glm::pers pective(10.0f,854.0f/480.0f, imagez,100.0f);
//摄像机位置:世界空间中一个指向摄像机位置的向量(即摄像机位置)
glm::vec3 cameraPos = glm::vec3(-0.37, height, 1.31834);
//摄像机方向:摄像机指向哪个方向(即中心坐标)
glm::vec3 cameraTarget = glm::vec3(-0.37f+distance*sin(glm::radians(0.0)), 0.0f, -distance*cos(glm::radians(0.0))+1.31834);
glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);
LOGCATD("cameraDirection[0]:%f,cameraDirection[1]:%f,cameraDirection[2]:%f,",cameraDirection[0],cameraDirection[1],cameraDirection[2]);
glm::vec3 right = glm::vec3(cos(glm::radians(0.0)), 0.0, sin(glm::radians(0.0))); //右向量 水平倾角
//glm::vec4 right_trans=glm::vec4(1.0f, 0.0f, 0.0f,1.0);
glm::vec3 cameraUp = glm::normalize(glm::cross(cameraDirection,right ));
LOGCATD("cameraUp[0]:%f,cameraUp[1]:%f,cameraUp[2]:%f,",cameraUp[0],cameraUp[1],cameraUp[2]);
//glm::vec3 cameraUp = glm::normalize(glm::cross(cameraDirection, cameraRight));
glm::mat4 View = glm::lookAt(
//glm::vec3(-0.087f, 0.380198f, 0.311671f), // Camera is at (0,0,1), in World Space 0.35628f
cameraPos,
//glm::vec3(0, 0, -distance), // and looks at the origin
cameraTarget,
cameraUp
//glm::vec3(-tan(glm::radians(0.0f)), 1.0f, 0) // Head is up (set to 0,-1,0 to look upside-down)
); //描绘的是人眼
//将顶点的世界空间坐标装换为观察空间坐标
//glm::lookAt函数有三个参数,eye表示摄像机所在的位置,center表示摄像机要看向的中心点的位置,up表示摄像机的三个方位向量中的up向量
glm::mat4 Model = glm::mat4(1.0f);
//LOGCATD("XXCC Model = %f",Model[0][0]);
Model = glm::scale(Model, glm::vec3(1.0, 1.0, 1.0f)); //用于对物体进行缩放
Model = glm::translate(Model, glm::vec3(0.0f, 0.0f, 0.0f)); //用于对物体进行位移
m_MVPMatrix = Projection * View;
return m_MVPMatrix = Projection * View * Model; //* buildRotateY(glm::radians(0.0)) * buildRotateZ(glm::radians(2.0));
}
void CoordSystemSample::Draw(int screenW, int screenH)
{
LOGCATE("TextureMapSample::Draw()");
if(m_ProgramObj == GL_NONE || m_TextureId == GL_NONE) return;
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0, 0.0, 0.0, 1.0);
GLfloat verticesCoords[] = {
-0.2f, 0.0f, 0.0f, // Position 0
-0.2f, -0.5f, 0.0f, // Position 1
0.2f, -0.5f, 0.0f, // Position 2
0.2f, 0.0f, 0.0f, // Position 3
};
GLfloat textureCoords[] = {
0.0f, 0.0f, // TexCoord 0
0.0f, 1.0f, // TexCoord 1
1.0f, 1.0f, // TexCoord 2
1.0f, 0.0f
};
GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
//upload RGBA image data
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_RenderImage.width, m_RenderImage.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_RenderImage.ppPlane[0]);
glBindTexture(GL_TEXTURE_2D, GL_NONE);
// Use the program object
glUseProgram (m_ProgramObj);
// Load the vertex position
glVertexAttribPointer (0, 3, GL_FLOAT,
GL_FALSE, 3 * sizeof (GLfloat), verticesCoords);
// Load the texture coordinate
glVertexAttribPointer (1, 2, GL_FLOAT,
GL_FALSE, 2 * sizeof (GLfloat), textureCoords);
glEnableVertexAttribArray (0);
glEnableVertexAttribArray (1);
// Bind the RGBA map
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
// Set the RGBA map sampler to texture unit to 0
glUniform1i(m_SamplerLoc, 0);
m_offset=0.0+m_time;
m_time=m_time+0.02;
if(m_time>1.0)
m_time=0.0;
GLUtils::setFloat(m_ProgramObj, "u_Offset", m_offset);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
m_offset = m_offset+0.4+m_time;
GLUtils::setFloat(m_ProgramObj, "u_Offset", m_offset);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
m_offset = m_offset+0.45+m_time;
GLUtils::setFloat(m_ProgramObj, "u_Offset", m_offset);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}
void CoordSystemSample::Destroy()
{
if (m_ProgramObj)
{
glDeleteProgram(m_ProgramObj);
m_ProgramObj = GL_NONE;
}
if (m_ProgramObj1)
{
glDeleteProgram(m_ProgramObj1);
m_ProgramObj1 = GL_NONE;
}
}
/**
* @param angleX 绕X轴旋转度数
* @param angleY 绕Y轴旋转度数
* @param ratio 宽高比
* */
glm::mat4 CoordSystemSample::buildRotateX(float rad)
{
glm::mat4 xrot = glm::mat4(1.0, 0.0, 0.0, 0.0,
0.0, cos(rad), -sin(rad), 0.0,
0.0, sin(rad), cos(rad), 0.0,
0.0, 0.0, 0.0, 1.0);
return xrot;
}
glm::mat4 CoordSystemSample::buildRotateY(float rad)
{
glm::mat4 yrot = glm::mat4(cos(rad), 0.0, sin(rad), 0.0,
0.0, 1.0, 0.0, 0.0,
-sin(rad), 0.0, cos(rad), 0.0,
0.0, 0.0, 0.0, 1.0);
return yrot;
}
glm::mat4 CoordSystemSample::buildRotateZ(float rad)
{
glm::mat4 zrot = glm::mat4(cos(rad), -sin(rad), 0.0, 0.0,
sin(rad), cos(rad), 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
return zrot;
}
float distance_z = -0.2f;
void CoordSystemSample::UpdateMVPMatrix(glm::mat4 &mvpMatrix, int angleX, int angleY, float ratio)
{
}
void CoordSystemSample::UpdateTransformMatrix(float rotateX, float rotateY, float scaleX, float scaleY)
{
}
结果: