赞
踩
对于三维模型,有两个最重要的坐标系统,一是顶点的位置(X,Y,Z)坐标,另一个就是UV坐标。U和V分别是图片在显示器水平、垂直方向上的坐标,取值一般都是0~1,也 就是(水平方向的第U个像素/图片宽度,垂直方向的第V个像素/图片高度)。
纹理实际上是一个二维数组,它的元素是一些颜色值。单个的颜色值被称为纹理元素(texture elements)或纹理像素(texel)。每一个纹理像素在纹理中都有一个唯一的地址。这个地址可以被认为是一个列(column)和行(row)的值,它们分别由U和V来表示。
在使用opengl和shader显示纹理时候需要对每一次面片的绘制过程中对面片的每一个顶点指定纹理坐标。
float pi = 3.14159265; float step = 1.0 * 360 / num_samples; float rr = pi / 180; z = -height; for (int i = 0; i < num_samples; i++)//对360度完成num_samples次采样 { float r_r_r = i * step * rr; float x = cos(r_r_r); float y = sin(r_r_r); m_vertices_.push_back(x); m_vertices_.push_back(y); m_vertices_.push_back(z); } //生成圆柱体下面一圈的顶点 z = height; for (int i = 0; i < num_samples; i++) { float r_r_r = i * step * rr; float x = cos(r_r_r); float y = sin(r_r_r); m_vertices_.push_back(x); m_vertices_.push_back(y); m_vertices_.push_back(z); }//生成圆柱体上面一圈的顶点 for (int i = 0; i < num_samples; i++) { m_faces_.push_back(i); m_faces_.push_back((i + 1) % num_samples); m_faces_.push_back((i + num_samples)); m_faces_.push_back((i + num_samples)); m_faces_.push_back((i + 1) % num_samples); m_faces_.push_back((i + 1) % (num_samples)+num_samples); //由四个顶点生成2个三角面片; m_vt_list_.push_back(1.0 * i / num_samples); m_vt_list_.push_back(0.0); //将0-360度映射到UV坐标的0-1; m_vt_list_.push_back(1.0 * ((i + 1)) / num_samples); m_vt_list_.push_back(0.0); //将0-360度映射到UV坐标的0-1; m_vt_list_.push_back(1.0 * i / num_samples); m_vt_list_.push_back(1.0); //将0-360度映射到UV坐标的0-1; m_vt_list_.push_back(1.0 * i / num_samples); m_vt_list_.push_back(1.0); //将0-360度映射到UV坐标的0-1; m_vt_list_.push_back(1.0 * ((i + 1)) / num_samples); m_vt_list_.push_back(0.0); //将0-360度映射到UV坐标的0-1; m_vt_list_.push_back(1.0 * ((i + 1)) / num_samples); m_vt_list_.push_back(1.0); //将0-360度映射到UV坐标的0-1; }
在使用opengl和shader显示纹理时候需要对每一次面片的绘制过程中对面片的每一个顶点指定纹理坐标。
opengl 和 shader中使用纹理
opengl:
GLuint textures;
glGenTextures(1, &textures);//申明纹理变量
#loadTexture();//对纹理赋值
glBindTexture(GL_TEXTURE_2D, nodes[m_i]->m_textures);
glUniform1i(glGetUniformLocation(nodes[m_i]->m_program, "texture"), 0);//将纹理传给shader
Shader中纹理的使用
Shader中通过纹理坐标得到颜色值:
in vec2 texCoord;//二维UV坐标
uniform sampler2D texture;//纹理
void main()
{
fColor = texture2D( texture, texCoord );//获取二维UV坐标texCoord处的纹理值
}
主程序中将中UV坐标texCoord传给shader的语法与以前上机课中顶点坐标传给shader类似,主要代码如下:
GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao);//建立顶点数组对象 GLuint buffer; glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER,sizeof(vec3)*num_face * 3, + sizeof(vec2)*num_face * 3, NULL, GL_STATIC_DRAW);//申请buffer GLintptr offset = 0; glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vec3)*num_face * 3, points);//将顶点几何坐标传给shader offset += sizeof(vec3)*num_face * 3; glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vec2) * num_face * 3, UV_ Coordinates);//将顶点UV坐标传给shader offset = 0; GLuint vPosition; vPosition = glGetAttribLocation(this->program_all[m_i], "vPosition"); glEnableVertexAttribArray(vPosition); glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 0,BUFFER_OFFSET(offset)); //shader中vPosition的取值处 offset += sizeof(vec3) * num_face * 3; GLuint vTexCoord; vTexCoord = glGetAttribLocation(this->program_all[m_i], "vTexCoord"); glEnableVertexAttribArray(vTexCoord); glVertexAttribPointer(vTexCoord, 2, GL_FLOAT, GL_FALSE, 0,BUFFER_OFFSET(offset)); //shader中texCoord的取值处
void My_Mesh::generate_disk(int num_division) { this->clear_data(); this->m_center_ = point3f(0, 0, 0); this->m_min_box_ = point3f(-1, -1, 0); this->m_max_box_ = point3f(1, 1, 0); int num_samples = num_division; float pi = 3.14159265; float step = 1.0 * 360 / num_samples; float rr = pi / 180; float z = 0; for (int i = 0; i < num_samples; i++) { float r_r_r = i * step * rr; float x = cos(r_r_r); float y = sin(r_r_r); m_vertices_.push_back(x); m_vertices_.push_back(y); m_vertices_.push_back(z); m_normals_.push_back(x); m_normals_.push_back(y); m_normals_.push_back(0); float r; float g; float b; My_Mesh::normal_to_color(x, y, 0, r, g, b); m_color_list_.push_back(r); m_color_list_.push_back(g); m_color_list_.push_back(b); }
接下来,我们参考这样的ppt上的图
可以看到还需要存入一个中心点的位置及其法向量:
因此写下这段代码:
m_vertices_.push_back(0);
m_vertices_.push_back(0);
m_vertices_.push_back(0);
m_normals_.push_back(0);
m_normals_.push_back(0);
m_normals_.push_back(1);
接下来绘制面片:
观察上面的图可以看到,我们绘制三角形,点的组成如图所示,因此在设定三角形的时候,三角形的三个点,其中一个点是整个圆盘的中心点,位置是固定的,是0.5,0.5:
因此需要:
m_vt_list_.push_back(0.5);
m_vt_list_.push_back(0.5);
然后组成圆盘的边上的这些点,通过半径乘以角度来得到该点在以圆盘中心为原点的坐标系的x、y值:
float r_r_r = (i)* step * rr;
float x = cos(r_r_r);
float y = sin(r_r_r);
但是此时的x、y值并不是UV坐标下的值,我们需要通过坐标系转换来实现将x、y转换到UV坐标
由于UV坐标长这样:
而在圆盘的坐标系中,圆是单位圆,所以半径为1
比如圆盘坐标系下的点(1,0)代表的是UV坐标的(0.5,0)
而点(0,1)代表UV坐标的(0.5,1)
经过计算不难得到
u=(x+1)/2
v=(y+1)/2
因此,我们存放三角面片时应该需要这样:
m_vt_list_.push_back((x + 1) / 2);
m_vt_list_.push_back((y + 1) / 2);
而一个三角形由两个点组成,只需要将小角度偏移一点点,就可以得到下一个点了,
因此第一个θ角为:
float r_r_r = (i)* step * rr;
的时候
第二个θ角只需要在i的基础上+1:
r_r_r = (i + 1) % num_samples * step * rr;
然后按照上面的方法将点存放进去即可,
最后把texture_Mapping中的圆盘注释文件打开就可以得到结果:
接下来实现圆锥的操作:
圆锥的纹理的覆盖这里思考了两种方式,一种是利用圆盘的代码,将纹理均匀对称的覆盖到圆锥上面:
结果如图所示:
但是这种只适合纹理是均匀的圆形的图像
这种做法很简单,我们只需要将圆盘的代码拷贝过来,然后在存放初始中心顶点的时候,将其高度设置为height即可实现:
m_vertices_.push_back(0);
m_vertices_.push_back(0);
m_vertices_.push_back(height);
接下来我们尝试另外一种绘制圆锥纹理的方法:
我们参考ppt,
圆锥相比于圆盘需要修改的地方是初始放入顶点的位置在(0,0,height)
m_vertices_.push_back(0);
m_vertices_.push_back(0);
m_vertices_.push_back(height);
接下来放入三角面元的索引时如下:
m_faces_.push_back(num_samples);
m_faces_.push_back(i);
m_faces_.push_back((i + 1) % (num_samples));
m_vt_list_.push_back(0.5);
m_vt_list_.push_back(1);
m_vt_list_.push_back(1.0 * (i) / num_samples);
m_vt_list_.push_back(0);
m_vt_list_.push_back(1.0 * (i+1) / num_samples);
m_vt_list_.push_back(0);
运行后可以看到结果
(代码解析见后面那一块)
mesh.cpp
#include "mesh.h" #include<sstream> #include <fstream> #include <iosfwd> #include <algorithm> #include <gl/GL.h> #include <math.h> #include <algorithm> #pragma comment(lib, "glew32.lib") My_Mesh::My_Mesh() { vTranslation[0] = Theta[0] = 0; vTranslation[1] = Theta[1] = 0; vTranslation[2] = Theta[2] = 0; Theta[0] = 45; } My_Mesh::~My_Mesh() { } void My_Mesh::normal_to_color(float nx, float ny, float nz, float& r, float& g, float& b) { r = float(std::min(std::max(0.5 * (nx + 1.0), 0.0), 1.0)); g = float(std::min(std::max(0.5 * (ny + 1.0), 0.0), 1.0)); b = float(std::min(std::max(0.5 * (nz + 1.0), 0.0), 1.0)); }; const VtList& My_Mesh::get_vts() { return this->m_vt_list_; }; void My_Mesh::clear_data() { m_vertices_.clear(); m_normals_.clear(); m_faces_.clear(); m_color_list_.clear(); m_vt_list_.clear(); }; void My_Mesh::get_boundingbox(point3f& min_p, point3f& max_p) const { min_p = this->m_min_box_; max_p = this->m_max_box_; }; const STLVectorf& My_Mesh::get_colors() { return this->m_color_list_; }; const VertexList& My_Mesh::get_vertices() { return this->m_vertices_; }; const NormalList& My_Mesh::get_normals() { return this->m_normals_; }; const FaceList& My_Mesh::get_faces() { return this->m_faces_; }; int My_Mesh::num_faces() { return this->m_faces_.size()/3; }; int My_Mesh::num_vertices() { return this->m_vertices_.size()/3; }; const point3f& My_Mesh::get_center() { return this->m_center_; }; void My_Mesh::generate_disk(int num_division) { this->clear_data(); this->m_center_ = point3f(0, 0, 0); this->m_min_box_ = point3f(-1, -1, 0); this->m_max_box_ = point3f(1, 1, 0); int num_samples = num_division; float pi = 3.14159265; float step = 1.0 * 360 / num_samples; float rr = pi / 180; float z = 0; for (int i = 0; i < num_samples; i++) { float r_r_r = i * step * rr; float x = cos(r_r_r); float y = sin(r_r_r); m_vertices_.push_back(x); m_vertices_.push_back(y); m_vertices_.push_back(z); m_normals_.push_back(x); m_normals_.push_back(y); m_normals_.push_back(0); float r; float g; float b; My_Mesh::normal_to_color(x, y, 0, r, g, b); m_color_list_.push_back(r); m_color_list_.push_back(g); m_color_list_.push_back(b); } m_vertices_.push_back(0); m_vertices_.push_back(0); m_vertices_.push_back(0); m_normals_.push_back(0); m_normals_.push_back(0); m_normals_.push_back(1); float r; float g; float b; My_Mesh::normal_to_color(0, 0, 1, r, g, b); m_color_list_.push_back(r); m_color_list_.push_back(g); m_color_list_.push_back(b); for (int i = 0; i < (num_samples); i++) { m_faces_.push_back(num_samples); m_faces_.push_back((i) % (num_samples)); m_faces_.push_back((i + 1) % (num_samples)); m_vt_list_.push_back(0.5); m_vt_list_.push_back(0.5); float r_r_r = (i)* step * rr; float x = cos(r_r_r); float y = sin(r_r_r); m_vt_list_.push_back((x + 1) / 2); m_vt_list_.push_back((y + 1) / 2); r_r_r = (i + 1) % num_samples * step * rr; x = cos(r_r_r); y = sin(r_r_r); m_vt_list_.push_back((x + 1) / 2); m_vt_list_.push_back((1 + y) / 2); } }; void My_Mesh::generate_cone(int num_division, float height) { //请在此添加代码生成圆锥体 this->clear_data(); this->m_center_ = point3f(0, 0, height / 2); this->m_min_box_ = point3f(-1, -1, 0); this->m_max_box_ = point3f(1, 1, height); int num_samples = num_division; float pi = 3.14159265; float step = 1.0 * 360 / num_samples; float rr = pi / 180; float z = 0; for (int i = 0; i < num_samples; i++) { float r_r_r = i * step * rr; float x = cos(r_r_r); float y = sin(r_r_r); m_vertices_.push_back(x); m_vertices_.push_back(y); m_vertices_.push_back(z); m_normals_.push_back(x); m_normals_.push_back(y); m_normals_.push_back(0); float r; float g; float b; My_Mesh::normal_to_color(x, y, 0, r, g, b); m_color_list_.push_back(r); m_color_list_.push_back(g); m_color_list_.push_back(b); } m_vertices_.push_back(0); m_vertices_.push_back(0); m_vertices_.push_back(height); m_normals_.push_back(0); m_normals_.push_back(0); m_normals_.push_back(1); float r; float g; float b; My_Mesh::normal_to_color(0, 0, 1, r, g, b); m_color_list_.push_back(r); m_color_list_.push_back(g); m_color_list_.push_back(b); for (int i = 0; i < (num_samples); i++) { m_faces_.push_back(num_samples); m_faces_.push_back(i); m_faces_.push_back((i + 1) % (num_samples)); m_vt_list_.push_back(0.5); m_vt_list_.push_back(1); m_vt_list_.push_back(1.0 * (i) / num_samples); m_vt_list_.push_back(0); m_vt_list_.push_back(1.0 * (i + 1) / num_samples); m_vt_list_.push_back(0); } }; void My_Mesh::generate_cylinder(int num_division, float height) { this->clear_data(); this->m_center_ = point3f(0, 0, 0); this->m_min_box_ = point3f(-1, -1, -height); this->m_max_box_ = point3f(1, 1, height); int num_samples = num_division; float z = -height; float pi = 3.14159265; float step = 1.0 * 360 / num_samples; float rr = pi / 180; //圆柱体Z轴向上,按cos和sin生成x,y坐标 for (int i = 0; i < num_samples; i++) { float r_r_r = i * step * rr; float x = cos(r_r_r); float y = sin(r_r_r); m_vertices_.push_back(x); m_vertices_.push_back(y); m_vertices_.push_back(z); m_normals_.push_back(x); m_normals_.push_back(y); m_normals_.push_back(0); //法线由里向外 float r; float g; float b; My_Mesh::normal_to_color(x, y, z, r, g, b); //这里采用法线来生成颜色,学生可以自定义自己的颜色生成方式 m_color_list_.push_back(r); m_color_list_.push_back(g); m_color_list_.push_back(b); } z = height; //圆柱体Z轴向上,按cos和sin生成x,y坐标, for (int i = 0; i < num_samples; i++) { float r_r_r = i * step * rr; float x = cos(r_r_r); float y = sin(r_r_r); m_vertices_.push_back(x); m_vertices_.push_back(y); m_vertices_.push_back(z); m_normals_.push_back(x); m_normals_.push_back(y); m_normals_.push_back(0); //法线由里向外 float r; float g; float b; My_Mesh::normal_to_color(x, y, z, r, g, b); //这里采用法线来生成颜色,学生可以自定义自己的颜色生成方式 m_color_list_.push_back(r); m_color_list_.push_back(g); m_color_list_.push_back(b); } //生成三角面片 for (int i = 0; i < num_samples; i++) { m_faces_.push_back(i); m_faces_.push_back((i + 1) % num_samples); m_faces_.push_back((i) +num_samples); m_faces_.push_back((i ) +num_samples); m_faces_.push_back((i + 1) % num_samples); m_faces_.push_back((i + 1) % (num_samples)+num_samples); //生成三角面片 m_vt_list_.push_back(1.0 * i / num_samples); m_vt_list_.push_back(0.0); //纹理坐标 m_vt_list_.push_back(1.0 * ((i + 1)) / num_samples); m_vt_list_.push_back(0.0); //纹理坐标 m_vt_list_.push_back(1.0 * i / num_samples); m_vt_list_.push_back(1.0); //纹理坐标 m_vt_list_.push_back(1.0 * i / num_samples); m_vt_list_.push_back(1.0); //纹理坐标 m_vt_list_.push_back(1.0 * ((i + 1)) / num_samples); m_vt_list_.push_back(0.0); //纹理坐标 m_vt_list_.push_back(1.0 * ((i + 1)) / num_samples); m_vt_list_.push_back(1.0); //纹理坐标 } }; void My_Mesh::set_texture_file(std::string s) { this->texture_file_name = s; }; std::string My_Mesh::get_texture_file() { return this->texture_file_name; }; void My_Mesh::set_translate(float x, float y, float z) { vTranslation[0] = x; vTranslation[1] = y; vTranslation[2] = z; }; void My_Mesh::get_translate(float& x, float& y, float& z) { x = vTranslation[0]; y = vTranslation[1]; z = vTranslation[2]; }; void My_Mesh::set_theta(float x, float y, float z) { Theta[0] = x; Theta[1] = y; Theta[2] = z; }; void My_Mesh::get_theta(float& x, float& y, float& z) { x = Theta[0]; y = Theta[1]; z = Theta[2]; }; void My_Mesh::set_theta_step(float x, float y, float z) { Theta_step[0] = x; Theta_step[1] = y; Theta_step[2] = z; }; void My_Mesh::add_theta_step() { Theta[0] = Theta[0] + Theta_step[0]; Theta[1] = Theta[1] + Theta_step[1]; Theta[2] = Theta[2] + Theta_step[2]; };
Mesh_Painter.cpp
#include "Mesh_Painter.h" #include "FreeImage.h" Mesh_Painter::Mesh_Painter() { } Mesh_Painter::~Mesh_Painter() { } void Mesh_Painter::draw_meshes() { for (unsigned int i = 0; i < this->m_my_meshes_.size(); i++) { glUseProgram(this->program_all[i]);//指定使用渲染器,不同的模型可以指定不同的渲染器,这里我们使用的渲染器来自相同的文件,学生可以根据自己的爱好对不同的模型设定不同的渲染器 glBindVertexArray(this->vao_all[i]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, this->textures_all[i]);//该语句必须,否则将只使用同一个纹理进行绘制 float x, y, z; this->m_my_meshes_[i]->get_theta(x, y, z); GLfloat Theta[3] = {x, y, z}; this->m_my_meshes_[i]->add_theta_step(); glUniform3fv(theta_all[i], 1, Theta); this->m_my_meshes_[i]->get_translate(x, y, z); GLfloat vTranslation[3] = { x, y, z }; glUniform3fv(trans_all[i], 1, vTranslation); glDrawArrays(GL_TRIANGLES, 0, this->m_my_meshes_[i]->num_faces() * 3); glUseProgram(0); } }; void Mesh_Painter::update_texture() { this->textures_all.clear(); for (unsigned int i = 0; i < this->m_my_meshes_.size(); i++) { GLuint textures; glGenTextures(1, &textures); //调用FreeImage生成纹理 load_texture_FreeImage(this->m_my_meshes_[i]->get_texture_file(), textures); //指定最大最小过滤方法,此两行代码必须添加,否则将无法显示纹理 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //将生成的纹理传给shader glBindTexture(GL_TEXTURE_2D, textures); glUniform1i(glGetUniformLocation(this->program_all[i], "texture"), 0); this->textures_all.push_back(textures); } }; void Mesh_Painter::load_texture_FreeImage(std::string file_name, GLuint& m_texName) { //1 获取图片格式 FREE_IMAGE_FORMAT fifmt = FreeImage_GetFileType(file_name.c_str(), 0); //2 加载图片 FIBITMAP *dib = FreeImage_Load(fifmt, file_name.c_str(), 0); //3 转化为rgb 24色; dib = FreeImage_ConvertTo24Bits(dib); //4 获取数据指针 BYTE *pixels = (BYTE*)FreeImage_GetBits(dib); int width = FreeImage_GetWidth(dib); int height = FreeImage_GetHeight(dib); /** * 产生一个纹理Id,可以认为是纹理句柄,后面的操作将书用这个纹理id */ /** * 使用这个纹理id,或者叫绑定(关联) */ glBindTexture(GL_TEXTURE_2D, m_texName); /** * 指定纹理的放大,缩小滤波,使用线性方式,即当图片放大的时候插值方式 */ /** * 将图片的rgb数据上传给opengl. */ glTexImage2D( GL_TEXTURE_2D, //! 指定是二维图片 0, //! 指定为第一级别,纹理可以做mipmap,即lod,离近的就采用级别大的,远则使用较小的纹理 GL_RGB, //! 纹理的使用的存储格式 width, //! 宽度,老一点的显卡,不支持不规则的纹理,即宽度和高度不是2^n。 height, //! 宽度,老一点的显卡,不支持不规则的纹理,即宽度和高度不是2^n。 0, //! 是否的边 GL_BGR_EXT, //! 数据的格式,bmp中,windows,操作系统中存储的数据是bgr格式 GL_UNSIGNED_BYTE, //! 数据是8bit数据 pixels ); /** * 释放内存 */ FreeImage_Unload(dib); }; void Mesh_Painter::update_vertex_buffer() { this->vao_all.clear(); this->buffer_all.clear(); this->vPosition_all.clear(); this->vColor_all.clear(); this->vTexCoord_all.clear(); this->vNormal_all.clear(); for (unsigned int m_i = 0; m_i < this->m_my_meshes_.size(); m_i++) { int num_face = this->m_my_meshes_[m_i]->num_faces(); int num_vertex = this->m_my_meshes_[m_i]->num_vertices(); const VertexList& vertex_list = this->m_my_meshes_[m_i]->get_vertices(); const NormalList& normal_list = this->m_my_meshes_[m_i]->get_normals(); const FaceList& face_list = this->m_my_meshes_[m_i]->get_faces(); const STLVectorf& color_list = this->m_my_meshes_[m_i]->get_colors(); const VtList& vt_list = this->m_my_meshes_[m_i]->get_vts(); // Create a vertex array object GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); GLuint buffer; glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vec3)*num_face * 3 + sizeof(vec3)*num_face * 3 + sizeof(vec3)*num_face * 3 + sizeof(vec2)*num_face * 3 , NULL, GL_STATIC_DRAW) ; //获得足够的空间存储坐标,颜色,法线以及纹理坐标等等 // Specify an offset to keep track of where we're placing data in our // vertex array buffer. We'll use the same technique when we // associate the offsets with vertex attribute pointers. vec3* points = new vec3[num_face * 3]; point3f p_center_ = this->m_my_meshes_[m_i]->get_center(); point3f p_min_box_, p_max_box_; this->m_my_meshes_[m_i]->get_boundingbox(p_min_box_, p_max_box_); float d = p_min_box_.distance(p_max_box_); for (int i = 0; i < num_face; i++) { int index = face_list[3 * i]; points[3 * i] = vec3( (vertex_list[index * 3 + 0] - p_center_.x) / (1.5 * d), (vertex_list[index * 3 + 1] - p_center_.y) / (1.5 * d), (vertex_list[index * 3 + 2] - p_center_.z) / (1.5 * d) ); index = face_list[3 * i + 1]; points[3 * i + 1] = vec3( (vertex_list[index * 3 + 0] - p_center_.x) / (1.5 * d), (vertex_list[index * 3 + 1] - p_center_.y) / (1.5 * d), (vertex_list[index * 3 + 2] - p_center_.z) / (1.5 * d) ); index = face_list[3 * i + 2]; points[3 * i + 2] = vec3( (vertex_list[index * 3 + 0] - p_center_.x) / (1.5 * d), (vertex_list[index * 3 + 1] - p_center_.y) / (1.5 * d), (vertex_list[index * 3 + 2] - p_center_.z) / (1.5 * d) ); } GLintptr offset = 0; glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vec3)*num_face * 3, points); //顶点坐标传给shader offset += sizeof(vec3)*num_face * 3; delete[] points; /************************************************************************/ /* */ /************************************************************************/ points = new vec3[num_face * 3]; for (int i = 0; i < num_face; i++) { int index = face_list[3 * i]; points[3 * i] = vec3( (normal_list[index * 3 + 0]), (normal_list[index * 3 + 1]), (normal_list[index * 3 + 2]) ); index = face_list[3 * i + 1]; points[3 * i + 1] = vec3( (normal_list[index * 3 + 0]), (normal_list[index * 3 + 1]), (normal_list[index * 3 + 2]) ); index = face_list[3 * i + 2]; points[3 * i + 2] = vec3( (normal_list[index * 3 + 0]), (normal_list[index * 3 + 1]), (normal_list[index * 3 + 2]) ); } glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vec3) * num_face * 3, points); offset += sizeof(vec3) * num_face * 3; delete[] points; //法线传给shader /************************************************************************/ /* */ /************************************************************************/ points = new vec3[num_face * 3]; for (int i = 0; i < num_face; i++) { int index = face_list[3 * i]; points[3 * i] = vec3( (color_list[index * 3 + 0]), (color_list[index * 3 + 1]), (color_list[index * 3 + 2]) ); index = face_list[3 * i + 1]; points[3 * i + 1] = vec3( (color_list[index * 3 + 0]), (color_list[index * 3 + 1]), (color_list[index * 3 + 2]) ); index = face_list[3 * i + 2]; points[3 * i + 2] = vec3( (color_list[index * 3 + 0]), (color_list[index * 3 + 1]), (color_list[index * 3 + 2]) ); } glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vec3) * num_face * 3, points); //颜色传给shader offset += sizeof(vec3) * num_face * 3; delete[] points; /************************************************************************/ /* */ /************************************************************************/ vec2* points_2 = new vec2[num_face * 3]; for (int i = 0; i < num_face; i++) { points_2[i * 3] = vec2(vt_list[i * 6 + 0], vt_list[i * 6 + 1]); points_2[i * 3 + 1] = vec2(vt_list[i * 6 + 2], vt_list[i * 6 + 3]); points_2[i * 3 + 2] = vec2(vt_list[i * 6 + 4], vt_list[i * 6 + 5]); } glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vec2) * num_face * 3, points_2); offset += sizeof(vec2) * num_face * 3; delete points_2; //纹理坐标传给shader /************************************************************************/ /* */ /************************************************************************/ // Load shaders and use the resulting shader program // set up vertex arrays offset = 0; GLuint vPosition; vPosition = glGetAttribLocation(this->program_all[m_i], "vPosition"); glEnableVertexAttribArray(vPosition); glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset)); offset += sizeof(vec3) * num_face * 3; //指定vPosition在shader中使用时的位置 GLuint vNormal; vNormal = glGetAttribLocation(this->program_all[m_i], "vNormal"); glEnableVertexAttribArray(vNormal); glVertexAttribPointer(vNormal, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset)); offset += sizeof(vec3) * num_face * 3; //指定vNormal在shader中使用时的位置 GLuint vColor; vColor = glGetAttribLocation(this->program_all[m_i], "vColor"); glEnableVertexAttribArray(vColor); glVertexAttribPointer(vColor, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset)); offset += sizeof(vec3) * num_face * 3; //指定vColor在shader中使用时的位置 GLuint vTexCoord; vTexCoord = glGetAttribLocation(this->program_all[m_i], "vTexCoord"); glEnableVertexAttribArray(vTexCoord); glVertexAttribPointer(vTexCoord, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset)); //指定vTexCoord在shader中使用时的位置 /************************************************************************/ /* */ /************************************************************************/ this->vao_all.push_back(vao); this->buffer_all.push_back(buffer); this->vPosition_all.push_back(vPosition); this->vColor_all.push_back(vColor); this->vTexCoord_all.push_back(vTexCoord); this->vNormal_all.push_back(vNormal); } }; void Mesh_Painter::init_shaders(std::string vs, std::string fs) { this->program_all.clear(); this->theta_all.clear(); this->trans_all.clear(); for (unsigned int i = 0; i < this->m_my_meshes_.size(); i++) { GLuint program = InitShader(vs.c_str(), fs.c_str()); //指定使用的渲染器,不同的模型可以指定不同的渲染器,这里我们使用的渲染器来自相同的文件,学生可以根据自己的爱好对不同的模型设定不同的渲染器 this->program_all.push_back(program); GLuint theta = glGetUniformLocation(program, "theta"); GLuint trans = glGetUniformLocation(program, "translation"); theta_all.push_back(theta); trans_all.push_back(trans); } }; void Mesh_Painter::add_mesh(My_Mesh* m) { this->m_my_meshes_.push_back(m); }; void Mesh_Painter::clear_mehs() { this->m_my_meshes_.clear(); this->textures_all.clear(); this->program_all.clear(); this->vao_all.clear(); this->buffer_all.clear(); this->vPosition_all.clear(); this->vColor_all.clear(); this->vTexCoord_all.clear(); this->vNormal_all.clear(); };
Texture_Mapping.cpp
// rotating cube with two texture objects // change textures with 1 and 2 keys #include "Angel.h" #include "mesh.h" #include "FreeImage.h" #include "Mesh_Painter.h" #pragma comment(lib, "glew32.lib") #pragma comment(lib, "FreeImage.lib") typedef Angel::vec4 point4; typedef Angel::vec4 color4; std::vector<My_Mesh*> my_meshs; Mesh_Painter* mp_; // Texture objects and storage for texture image // Vertex data arrays // Array of rotation angles (in degrees) for each coordinate axis //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void init() { glEnable(GL_DEPTH_TEST); glEnable( GL_DEPTH_TEST ); glEnable(GL_LIGHTING); glClearColor( 1.0, 1.0, 1.0, 1.0 ); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); mp_->draw_meshes(); glutSwapBuffers(); }; //---------------------------------------------------------------------------- void mouse( int button, int state, int x, int y ) { } //---------------------------------------------------------------------------- void idle(void) { glutPostRedisplay(); } //---------------------------------------------------------------------------- void keyboard( unsigned char key, int mousex, int mousey ) { glutPostRedisplay(); } //---------------------------------------------------------------------------- int main( int argc, char **argv ) { glutInit( &argc, argv ); glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH ); glutInitWindowSize( 512, 512 ); glutInitContextVersion( 3, 2 ); glutInitContextProfile( GLUT_CORE_PROFILE ); glutCreateWindow( "纹理映射实例程序!" ); glewExperimental = GL_TRUE; glewInit(); init(); mp_ = new Mesh_Painter; My_Mesh* my_mesh1 = new My_Mesh; my_mesh1->generate_cylinder(100, 3);//生成圆柱表面 my_mesh1->set_texture_file("texture/cylinder10.jpg");//指定纹理图像文件 my_mesh1->set_translate(-0.5, 0, 0); my_mesh1->set_theta(90, 0., 30.);//旋转轴 my_mesh1->set_theta_step(0, 0, 0);//旋转速度 mp_->add_mesh(my_mesh1); my_meshs.push_back(my_mesh1); My_Mesh* my_mesh2 = new My_Mesh; my_mesh2->generate_disk(100); my_mesh2->set_texture_file("texture/disk.jpg"); my_mesh2->set_translate(0.0, 0, 0); my_mesh2->set_theta(0, 0, 0); my_mesh2->set_theta_step(0, 1, 0); my_meshs.push_back(my_mesh2); mp_->add_mesh(my_mesh2); My_Mesh* my_mesh3 = new My_Mesh; my_mesh3->generate_cone(100, 2); my_mesh3->set_texture_file("texture/cone.jpg"); my_mesh3->set_translate(0.5, 0, 0); my_mesh3->set_theta(0, 0.0, 0.); my_mesh3->set_theta_step(0.0, 0.05, 0); my_meshs.push_back(my_mesh3); mp_->add_mesh(my_mesh3); mp_->init_shaders("v_texture.glsl","f_texture.glsl"); mp_->update_vertex_buffer(); mp_->update_texture(); glutDisplayFunc( display ); glutKeyboardFunc( keyboard ); glutMouseFunc( mouse ); glutIdleFunc( idle ); glutMainLoop(); for (unsigned int i = 0; i < my_meshs.size(); i++) { delete my_meshs[i]; } delete mp_; return 0; }
vshader:
#version 330 core in vec3 vPosition; in vec3 vColor; in vec3 vNormal; in vec2 vTexCoord; in vec3 vFaceIndecies; out vec4 color; out vec2 texCoord; out vec4 normal; uniform vec3 theta; uniform vec3 translation; void main() { const float DegreesToRadians = 3.14159265 / 180.0; vec3 c = cos( DegreesToRadians * theta ); vec3 s = sin( DegreesToRadians * theta ); mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0, 0.0, c.x, -s.x, 0.0, 0.0, s.x, c.x, 0.0, 0.0, 0.0, 0.0, 1.0); mat4 ry = mat4( c.y, 0.0, s.y, 0.0, 0.0, 1.0, 0.0, 0.0, -s.y, 0.0, c.y, 0.0, 0.0, 0.0, 0.0, 1.0 ); // Workaround for bug in ATI driver ry[1][0] = 0.0; ry[1][1] = 1.0; mat4 rz = mat4( c.z, -s.z, 0.0, 0.0, s.z, c.z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ); // Workaround for bug in ATI driver rz[2][2] = 1.0; color = vec4(vColor, 0); texCoord = vTexCoord; normal = vec4(vNormal, 0); gl_Position = vec4(vPosition, 1.0); gl_Position = rz * ry * rx * gl_Position; vec4 t = rz * ry * rx * vec4(translation, 1.0); gl_Position = gl_Position + vec4(translation, 0.0); }
fshader
#version 330 core in vec4 color; in vec2 texCoord; in vec4 normal; in vec3 faceIndecies; out vec4 fColor; out vec4 fNormal; uniform sampler2D texture; void main() { //fColor = vec4(1, 0, 0, 0 ) * texture2D( texture, texCoord ); fColor = texture2D( texture, texCoord ); //fColor = color; //fColor = vec4(0, 0, 0, 0 ); fNormal = normal; }
在程序中读取带纹理的obj文件,载入相应的纹理图片文件,将带纹理的模型显示在程序窗口中。实现效果如下:
具体内容包括:
下面是一个obj文件实例
g pCube1
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
f 1/1/1 2/2/2 4/4/3 3/3/4
"g pCube1"表示组,这里的成组是指把"g pCube1"后出现的面都结合到一起,组成一个整的多边形几何体。
"v -0.500000 -0.500000 0.500000"这句"v"代表点的几何坐标
"vt 1.000000 0.000000"这句"vt"代表点的贴图坐标。
"vn 0.000000 0.000000 1.000000"这句"vn"代表点的法线。
"f 1/1/1 2/2/2 4/4/3 3/3/4"这是在面的数据中多了贴图坐标uv点和法线的索引号,索引号分别用左斜线(/)隔开。 格式:“f 顶点索引/uv点索引/法线索引”。
简单的来说就是:
texture_mapping是主函数,mesh.h是mesh的类,在里面声明了存放顶点的位置、颜色、法向量、纹理坐标等顶点信息的变量和函数声明,然后在mesh.cpp里的函数将顶点信息存放进去,先由主函数来调用mesh.cpp里的函数,可以用generate_cylinder或者load_obj来生成顶点信息,随后将这些信息传递给mesh_painter。
然后mesh_painter里有这些函数:
一句话:主函数里调用mesh.cpp里的东西来生成顶点信息,再调用mesh_painter里的那些函数传入着色器并且绘制。
给学弟学妹们的提示:
这个是大致的思路,然后你们再去看mesh和mesh_painter里面的每一个函数都在做什么,实现了什么功能,涉及到着色器再去看看着色器。
涉及到纹理绘制的部分的语句可能会有不懂的地方(比如update_texture函数和片元着色器的uniform sampler2D texture 和 fColor = texture2D( texture, texCoord );),所以可以先去看learnOpengl的纹理那一节的文章。
(当然如果vao vbo还有glbufferdata glattribpointer这些函数如果不懂可以去看看learnopenGL的你好三角形)
freeimage是解析纹理图片,这个应该可以不看
把我说的弄懂的话就可以读懂整个框架了
这里还遇到了个坑:
实验四的框架把物体初始化的平移和旋转放在着色器里进行
你这样做之后就会发现你的相机视角会变得很奇怪
解决方法:
rotate和translate不要在着色器里搞
对了 建议每实现完一个功能 比如实现了相机移动、光照、阴影的时候,每实现完一个功能就记得存档一下 做个备份
不然你在这个基础上修改的时候,如果修改修改着无法运行了,想从头再来的时候,可能无法回到之前正常成功运行的时候了
对于实验四来说,需要修改的仅仅是在Mesh中书写load_obj这个函数
但是想要读懂并会写大作业 需要读懂框架
void My_Mesh::load_obj(std::string obj_File) { this->clear_data(); //请在此添加代码实现对含有UV坐标的obj文件的读取 //打开文件流 std::ifstream fin(obj_File); std::string line; if (!fin.is_open()) { std::cout << "文件 " << obj_File << " 打开失败" << std::endl; exit(-1); } std::vector<float> normals;//临时存储法线信息 std::vector<float> vtlist; //临时存储纹理信息 //计算各种类型的数据的数量 int v_num = 0; int vt_num = 0; int vn_num = 0; int f_num = 0; //保存vertices三个坐标下的最大值 float max_x = 0; float max_y = 0; float max_z = 0; //按行读取 while (std::getline(fin, line)) { std::istringstream sin(line); //以一行的数据作为 string stream 解析并且读取 std::string type; float x, y, z; char slash; //读取obj文件 sin >> type; if (type == "v") { sin >> x >> y >> z; m_vertices_.push_back(x); m_vertices_.push_back(y); m_vertices_.push_back(z); v_num++; //更新最大值 if (max_x < fabs(x))max_x = fabs(x); if (max_y < fabs(y))max_y = fabs(y); if (max_z < fabs(z))max_z = fabs(z); } if (type == "vt") { sin >> x >> y; vtlist.push_back(x); vtlist.push_back(y); vt_num++; } if (type == "vn") { sin >> x >> y >> z; normals.push_back(x); normals.push_back(y); normals.push_back(z); vn_num++; } if (type == "f") { float a, b, c; for (int i = 0; i < 3; i++) { sin >> x >> slash >> y >> slash >> z; //生成三角面片 m_faces_.push_back(x - 1); //纹理坐标 a = vtlist[2 * (y - 1)]; b = vtlist[2 * (y - 1) + 1]; m_vt_list_.push_back(a); m_vt_list_.push_back(b); //法线由里向外 a = normals[3 * (z - 1)]; b = normals[3 * (z - 1) + 1]; c = normals[3 * (z - 1) + 2]; m_normals_.push_back(a); m_normals_.push_back(b); m_normals_.push_back(c); //这里采用法线来生成颜色,学生可以自定义自己的颜色生成方式 float rr; float gg; float bb; My_Mesh::normal_to_color(a, b, c, rr, gg, bb); m_color_list_.push_back(rr); m_color_list_.push_back(gg); m_color_list_.push_back(bb); } f_num++; } } //设置m_center_、>m_min_box_、>m_max_box_ this->m_center_ = point3f(0, 0, 0); this->m_min_box_ = point3f(-max_x, -max_y, -max_z); this->m_max_box_ = point3f(max_x, max_y, max_z); std::cout << max_x << " " << max_y << " " << max_z << std::endl; std::cout << v_num << " " << vn_num << " " << vt_num << " " << f_num << std::endl; };
Texture_Mapping.cpp
// rotating cube with two texture objects // change textures with 1 and 2 keys #include "Angel.h" #include "mesh.h" #include "FreeImage.h" #include "Mesh_Painter.h" #pragma comment(lib, "glew32.lib") #pragma comment(lib, "FreeImage.lib") typedef Angel::vec4 point4; typedef Angel::vec4 color4; std::vector<My_Mesh*> my_meshs; Mesh_Painter* mp_; // Texture objects and storage for texture image // Vertex data arrays // Array of rotation angles (in degrees) for each coordinate axis //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void init() { glEnable(GL_DEPTH_TEST); glEnable( GL_DEPTH_TEST ); glEnable(GL_LIGHTING); glClearColor( 1.0, 1.0, 1.0, 1.0 ); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); mp_->draw_meshes(); glutSwapBuffers(); }; //---------------------------------------------------------------------------- void mouse( int button, int state, int x, int y ) { } //---------------------------------------------------------------------------- void idle(void) { glutPostRedisplay(); } //---------------------------------------------------------------------------- void keyboard( unsigned char key, int mousex, int mousey ) { glutPostRedisplay(); } //---------------------------------------------------------------------------- int main( int argc, char **argv ) { glutInit( &argc, argv ); glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH ); glutInitWindowSize( 512, 512 ); glutInitContextVersion( 3, 2 ); glutInitContextProfile( GLUT_CORE_PROFILE ); glutCreateWindow( "2018133151_黄慰林_实验四" ); glewExperimental = GL_TRUE; glewInit(); init(); mp_ = new Mesh_Painter; My_Mesh* my_mesh4 = new My_Mesh; my_mesh4->load_obj("texture/table.obj"); my_mesh4->set_texture_file("texture/table.png"); my_mesh4->set_translate(0.0, 0.6, 0); my_mesh4->set_theta(90, 0., 0.); my_mesh4->set_theta_step(0.1, -0.1, 0.1); my_meshs.push_back(my_mesh4); mp_->add_mesh(my_mesh4); My_Mesh* my_mesh2 = new My_Mesh; my_mesh2->load_obj("texture/wawa.obj"); my_mesh2->set_texture_file("texture/wawa.png"); my_mesh2->set_translate(0.0, 0, 0); my_mesh2->set_theta(90, 0., 0.); my_mesh2->set_theta_step(0.1, -0.1, 0.1); my_meshs.push_back(my_mesh2); mp_->add_mesh(my_mesh2); My_Mesh* my_mesh1 = new My_Mesh; my_mesh1->generate_cylinder(3, 1); my_mesh1->set_texture_file("texture/cylinder10.jpg"); my_mesh1->set_translate(-0.6, 0, 0); my_mesh1->set_theta(90, 0., 0.); my_mesh1->set_theta_step(0.1, 0.1, 0.1); mp_->add_mesh(my_mesh1); my_meshs.push_back(my_mesh1); My_Mesh* my_mesh3 = new My_Mesh; my_mesh3->generate_cylinder(20,3); my_mesh3->set_texture_file("texture/cylinder10.jpg"); my_mesh3->set_translate(0.6, 0, 0); my_mesh3->set_theta(90, 0., 0.); my_mesh3->set_theta_step(0.1, 0.1, -0.1); my_meshs.push_back(my_mesh3); mp_->add_mesh(my_mesh3); mp_->init_shaders("v_texture.glsl","f_texture.glsl"); mp_->update_vertex_buffer(); mp_->update_texture(); glutDisplayFunc( display ); glutKeyboardFunc( keyboard ); glutMouseFunc( mouse ); glutIdleFunc( idle ); glutMainLoop(); for (unsigned int i = 0; i < my_meshs.size(); i++) { delete my_meshs[i]; } delete mp_; return 0; }
Mesh_Painter.cpp
#include "Mesh_Painter.h" #include "FreeImage.h" Mesh_Painter::Mesh_Painter() { } Mesh_Painter::~Mesh_Painter() { } void Mesh_Painter::draw_meshes() { for (unsigned int i = 0; i < this->m_my_meshes_.size(); i++) { glUseProgram(this->program_all[i]); glUseProgram(this->program_all[i]);//指定使用渲染器,不同的模型可以指定不同的渲染器,这里我们使用的渲染器来自相同的文件,学生可以根据自己的爱好对不同的模型设定不同的渲染器 glBindVertexArray(this->vao_all[i]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, this->textures_all[i]);//该语句必须,否则将只使用同一个纹理进行绘制 float x, y, z; this->m_my_meshes_[i]->get_theta(x, y, z); GLfloat Theta[3] = {x, y, z}; this->m_my_meshes_[i]->add_theta_step(); glUniform3fv(theta_all[i], 1, Theta); this->m_my_meshes_[i]->get_translate(x, y, z); GLfloat vTranslation[3] = { x, y, z }; glUniform3fv(trans_all[i], 1, vTranslation); glDrawArrays(GL_TRIANGLES, 0, this->m_my_meshes_[i]->num_faces() * 3); glUseProgram(0); } }; void Mesh_Painter::update_texture() { this->textures_all.clear(); for (unsigned int i = 0; i < this->m_my_meshes_.size(); i++) { //实现纹理创建和赋值 GLuint textures; glGenTextures(1, &textures); //调用FreeImage生成纹理 load_texture_FreeImage(this->m_my_meshes_[i]->get_texture_file(), textures); //指定最大最小过滤方法,此两行代码必须添加,否则将无法显示纹理 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //将生成的纹理传给shader glBindTexture(GL_TEXTURE_2D, textures); glUniform1i(glGetUniformLocation(this->program_all[i], "texture"), 0); this->textures_all.push_back(textures); } }; void Mesh_Painter::load_texture_FreeImage(std::string file_name, GLuint& m_texName) { //1 获取图片格式 FREE_IMAGE_FORMAT fifmt = FreeImage_GetFileType(file_name.c_str(), 0); //2 加载图片 FIBITMAP *dib = FreeImage_Load(fifmt, file_name.c_str(), 0); //3 转化为rgb 24色; dib = FreeImage_ConvertTo24Bits(dib); //4 获取数据指针 BYTE *pixels = (BYTE*)FreeImage_GetBits(dib); int width = FreeImage_GetWidth(dib); int height = FreeImage_GetHeight(dib); /** * 产生一个纹理Id,可以认为是纹理句柄,后面的操作将书用这个纹理id */ /** * 使用这个纹理id,或者叫绑定(关联) */ glBindTexture(GL_TEXTURE_2D, m_texName); /** * 指定纹理的放大,缩小滤波,使用线性方式,即当图片放大的时候插值方式 */ /** * 将图片的rgb数据上传给opengl. */ glTexImage2D( GL_TEXTURE_2D, //! 指定是二维图片 0, //! 指定为第一级别,纹理可以做mipmap,即lod,离近的就采用级别大的,远则使用较小的纹理 GL_RGB, //! 纹理的使用的存储格式 width, //! 宽度,老一点的显卡,不支持不规则的纹理,即宽度和高度不是2^n。 height, //! 宽度,老一点的显卡,不支持不规则的纹理,即宽度和高度不是2^n。 0, //! 是否的边 GL_BGR_EXT, //! 数据的格式,bmp中,windows,操作系统中存储的数据是bgr格式 GL_UNSIGNED_BYTE, //! 数据是8bit数据 pixels ); /** * 释放内存 */ FreeImage_Unload(dib); }; void Mesh_Painter::update_vertex_buffer() { this->vao_all.clear(); this->buffer_all.clear(); this->vPosition_all.clear(); this->vColor_all.clear(); this->vTexCoord_all.clear(); this->vNormal_all.clear(); for (unsigned int m_i = 0; m_i < this->m_my_meshes_.size(); m_i++) { //在这里添加代码实现顶点坐标,法线,颜色,纹理坐标到shader的映射 int num_face = this->m_my_meshes_[m_i]->num_faces(); int num_vertex = this->m_my_meshes_[m_i]->num_vertices(); const VertexList& vertex_list = this->m_my_meshes_[m_i]->get_vertices(); const NormalList& normal_list = this->m_my_meshes_[m_i]->get_normals(); const FaceList& face_list = this->m_my_meshes_[m_i]->get_faces(); const STLVectorf& color_list = this->m_my_meshes_[m_i]->get_colors(); const VtList& vt_list = this->m_my_meshes_[m_i]->get_vts(); // Create a vertex array object GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); GLuint buffer; glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vec3) * num_face * 3 + sizeof(vec3) * num_face * 3 + sizeof(vec3) * num_face * 3 + sizeof(vec2) * num_face * 3 , NULL, GL_STATIC_DRAW) ; //获得足够的空间存储坐标,颜色,法线以及纹理坐标等等 // Specify an offset to keep track of where we're placing data in our // vertex array buffer. We'll use the same technique when we // associate the offsets with vertex attribute pointers. vec3* points = new vec3[num_face * 3]; point3f p_center_ = this->m_my_meshes_[m_i]->get_center(); point3f p_min_box_, p_max_box_; this->m_my_meshes_[m_i]->get_boundingbox(p_min_box_, p_max_box_); float d = p_min_box_.distance(p_max_box_); for (int i = 0; i < num_face; i++) { int index = face_list[3 * i]; points[3 * i] = vec3( (vertex_list[index * 3 + 0] - p_center_.x) / (1.5 * d), (vertex_list[index * 3 + 1] - p_center_.y) / (1.5 * d), (vertex_list[index * 3 + 2] - p_center_.z) / (1.5 * d) ); index = face_list[3 * i + 1]; points[3 * i + 1] = vec3( (vertex_list[index * 3 + 0] - p_center_.x) / (1.5 * d), (vertex_list[index * 3 + 1] - p_center_.y) / (1.5 * d), (vertex_list[index * 3 + 2] - p_center_.z) / (1.5 * d) ); index = face_list[3 * i + 2]; points[3 * i + 2] = vec3( (vertex_list[index * 3 + 0] - p_center_.x) / (1.5 * d), (vertex_list[index * 3 + 1] - p_center_.y) / (1.5 * d), (vertex_list[index * 3 + 2] - p_center_.z) / (1.5 * d) ); } GLintptr offset = 0; glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vec3) * num_face * 3, points); //顶点坐标传给shader offset += sizeof(vec3) * num_face * 3; delete[] points; /************************************************************************/ /* */ /************************************************************************/ points = new vec3[num_face * 3]; for (int i = 0; i < num_face; i++) { int index = face_list[3 * i]; points[3 * i] = vec3( (normal_list[index * 3 + 0]), (normal_list[index * 3 + 1]), (normal_list[index * 3 + 2]) ); index = face_list[3 * i + 1]; points[3 * i + 1] = vec3( (normal_list[index * 3 + 0]), (normal_list[index * 3 + 1]), (normal_list[index * 3 + 2]) ); index = face_list[3 * i + 2]; points[3 * i + 2] = vec3( (normal_list[index * 3 + 0]), (normal_list[index * 3 + 1]), (normal_list[index * 3 + 2]) ); } glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vec3) * num_face * 3, points); offset += sizeof(vec3) * num_face * 3; delete[] points; //法线传给shader /************************************************************************/ /* */ /************************************************************************/ points = new vec3[num_face * 3]; for (int i = 0; i < num_face; i++) { int index = face_list[3 * i]; points[3 * i] = vec3( (color_list[index * 3 + 0]), (color_list[index * 3 + 1]), (color_list[index * 3 + 2]) ); index = face_list[3 * i + 1]; points[3 * i + 1] = vec3( (color_list[index * 3 + 0]), (color_list[index * 3 + 1]), (color_list[index * 3 + 2]) ); index = face_list[3 * i + 2]; points[3 * i + 2] = vec3( (color_list[index * 3 + 0]), (color_list[index * 3 + 1]), (color_list[index * 3 + 2]) ); } glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vec3) * num_face * 3, points); //颜色传给shader offset += sizeof(vec3) * num_face * 3; delete[] points; /************************************************************************/ /* */ /************************************************************************/ vec2* points_2 = new vec2[num_face * 3]; for (int i = 0; i < num_face; i++) { points_2[i * 3] = vec2(vt_list[i * 6 + 0], vt_list[i * 6 + 1]); points_2[i * 3 + 1] = vec2(vt_list[i * 6 + 2], vt_list[i * 6 + 3]); points_2[i * 3 + 2] = vec2(vt_list[i * 6 + 4], vt_list[i * 6 + 5]); } glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vec2) * num_face * 3, points_2); offset += sizeof(vec2) * num_face * 3; delete points_2; //纹理坐标传给shader /************************************************************************/ /* */ /************************************************************************/ // Load shaders and use the resulting shader program // set up vertex arrays offset = 0; GLuint vPosition; vPosition = glGetAttribLocation(this->program_all[m_i], "vPosition"); glEnableVertexAttribArray(vPosition); glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset)); offset += sizeof(vec3) * num_face * 3; //指定vPosition在shader中使用时的位置 GLuint vNormal; vNormal = glGetAttribLocation(this->program_all[m_i], "vNormal"); glEnableVertexAttribArray(vNormal); glVertexAttribPointer(vNormal, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset)); offset += sizeof(vec3) * num_face * 3; //指定vNormal在shader中使用时的位置 GLuint vColor; vColor = glGetAttribLocation(this->program_all[m_i], "vColor"); glEnableVertexAttribArray(vColor); glVertexAttribPointer(vColor, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset)); offset += sizeof(vec3) * num_face * 3; //指定vColor在shader中使用时的位置 GLuint vTexCoord; vTexCoord = glGetAttribLocation(this->program_all[m_i], "vTexCoord"); glEnableVertexAttribArray(vTexCoord); glVertexAttribPointer(vTexCoord, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offset)); //指定vTexCoord在shader中使用时的位置 /************************************************************************/ /* */ /************************************************************************/ this->vao_all.push_back(vao); this->buffer_all.push_back(buffer); this->vPosition_all.push_back(vPosition); this->vColor_all.push_back(vColor); this->vTexCoord_all.push_back(vTexCoord); this->vNormal_all.push_back(vNormal); } }; void Mesh_Painter::init_shaders(std::string vs, std::string fs) { this->program_all.clear(); this->theta_all.clear(); this->trans_all.clear(); for (unsigned int i = 0; i < this->m_my_meshes_.size(); i++) { GLuint program = InitShader(vs.c_str(), fs.c_str()); glUseProgram(program); this->program_all.push_back(program); GLuint theta = glGetUniformLocation(program, "theta"); GLuint trans = glGetUniformLocation(program, "translation"); theta_all.push_back(theta); trans_all.push_back(trans); } }; void Mesh_Painter::add_mesh(My_Mesh* m) { this->m_my_meshes_.push_back(m); }; void Mesh_Painter::clear_mehs() { this->m_my_meshes_.clear(); this->textures_all.clear(); this->program_all.clear(); this->vao_all.clear(); this->buffer_all.clear(); this->vPosition_all.clear(); this->vColor_all.clear(); this->vTexCoord_all.clear(); this->vNormal_all.clear(); };
mesh.cpp
#include "mesh.h" #include<sstream> #include <fstream> #include <iosfwd> #include <algorithm> #include <gl/GL.h> #include <math.h> #include <algorithm> #include <iostream> #include<vector> My_Mesh::My_Mesh() { vTranslation[0] = Theta[0] = 0; vTranslation[1] = Theta[1] = 0; vTranslation[2] = Theta[2] = 0; Theta[0] = 45; } My_Mesh::~My_Mesh() { } void My_Mesh::load_obj(std::string obj_File) { this->clear_data(); //请在此添加代码实现对含有UV坐标的obj文件的读取 //打开文件流 std::ifstream fin(obj_File); std::string line; if (!fin.is_open()) { std::cout << "文件 " << obj_File << " 打开失败" << std::endl; exit(-1); } std::vector<float> normals;//临时存储法线信息 std::vector<float> vtlist; //临时存储纹理信息 //计算各种类型的数据的数量 int v_num = 0; int vt_num = 0; int vn_num = 0; int f_num = 0; //保存vertices三个坐标下的最大值 float max_x = 0; float max_y = 0; float max_z = 0; //按行读取 while (std::getline(fin, line)) { std::istringstream sin(line); //以一行的数据作为 string stream 解析并且读取 std::string type; float x, y, z; char slash; //读取obj文件 sin >> type; if (type == "v") { sin >> x >> y >> z; m_vertices_.push_back(x); m_vertices_.push_back(y); m_vertices_.push_back(z); v_num++; //更新最大值 if (max_x < fabs(x))max_x = fabs(x); if (max_y < fabs(y))max_y = fabs(y); if (max_z < fabs(z))max_z = fabs(z); } if (type == "vt") { sin >> x >> y; vtlist.push_back(x); vtlist.push_back(y); vt_num++; } if (type == "vn") { sin >> x >> y >> z; normals.push_back(x); normals.push_back(y); normals.push_back(z); vn_num++; } if (type == "f") { float a, b, c; for (int i = 0; i < 3; i++) { sin >> x >> slash >> y >> slash >> z; //生成三角面片 m_faces_.push_back(x - 1); //纹理坐标 a = vtlist[2 * (y - 1)]; b = vtlist[2 * (y - 1) + 1]; m_vt_list_.push_back(a); m_vt_list_.push_back(b); //法线由里向外 a = normals[3 * (z - 1)]; b = normals[3 * (z - 1) + 1]; c = normals[3 * (z - 1) + 2]; m_normals_.push_back(a); m_normals_.push_back(b); m_normals_.push_back(c); //这里采用法线来生成颜色,学生可以自定义自己的颜色生成方式 float rr; float gg; float bb; My_Mesh::normal_to_color(a, b, c, rr, gg, bb); m_color_list_.push_back(rr); m_color_list_.push_back(gg); m_color_list_.push_back(bb); } f_num++; } } //设置m_center_、>m_min_box_、>m_max_box_ this->m_center_ = point3f(0, 0, 0); this->m_min_box_ = point3f(-max_x, -max_y, -max_z); this->m_max_box_ = point3f(max_x, max_y, max_z); std::cout << max_x << " " << max_y << " " << max_z << std::endl; std::cout << v_num << " " << vn_num << " " << vt_num << " " << f_num << std::endl; }; void My_Mesh::normal_to_color(float nx, float ny, float nz, float& r, float& g, float& b) { r = float(std::min(std::max(0.5 * (nx + 1.0), 0.0), 1.0)); g = float(std::min(std::max(0.5 * (ny + 1.0), 0.0), 1.0)); b = float(std::min(std::max(0.5 * (nz + 1.0), 0.0), 1.0)); }; const VtList& My_Mesh::get_vts() { return this->m_vt_list_; }; void My_Mesh::clear_data() { m_vertices_.clear(); m_normals_.clear(); m_faces_.clear(); m_color_list_.clear(); m_vt_list_.clear(); }; void My_Mesh::get_boundingbox(point3f& min_p, point3f& max_p) const { min_p = this->m_min_box_; max_p = this->m_max_box_; }; const STLVectorf& My_Mesh::get_colors() { return this->m_color_list_; }; const VertexList& My_Mesh::get_vertices() { return this->m_vertices_; }; const NormalList& My_Mesh::get_normals() { return this->m_normals_; }; const FaceList& My_Mesh::get_faces() { return this->m_faces_; }; int My_Mesh::num_faces() { return this->m_faces_.size()/3; }; int My_Mesh::num_vertices() { return this->m_vertices_.size()/3; }; const point3f& My_Mesh::get_center() { return this->m_center_; }; void My_Mesh::generate_cylinder(int num_division, float height) { this->clear_data(); this->m_center_ = point3f(0, 0, 0); this->m_min_box_ = point3f(-1, -1, -height); this->m_max_box_ = point3f(1, 1, height); int num_samples = num_division; float z = -height; float pi = 3.14159265; float step = 1.0 * 360 / num_samples; float rr = pi / 180; //圆柱体Z轴向上,按cos和sin生成x,y坐标 for (int i = 0; i < num_samples; i++) { float r_r_r = i * step * rr; float x = cos(r_r_r); float y = sin(r_r_r); m_vertices_.push_back(x); m_vertices_.push_back(y); m_vertices_.push_back(z); m_normals_.push_back(x); m_normals_.push_back(y); m_normals_.push_back(0); //法线由里向外 float r; float g; float b; My_Mesh::normal_to_color(x, y, z, r, g, b); //这里采用法线来生成颜色,学生可以自定义自己的颜色生成方式 m_color_list_.push_back(r); m_color_list_.push_back(g); m_color_list_.push_back(b); } z = height; //圆柱体Z轴向上,按cos和sin生成x,y坐标, for (int i = 0; i < num_samples; i++) { float r_r_r = i * step * rr; float x = cos(r_r_r); float y = sin(r_r_r); m_vertices_.push_back(x); m_vertices_.push_back(y); m_vertices_.push_back(z); m_normals_.push_back(x); m_normals_.push_back(y); m_normals_.push_back(0); //法线由里向外 float r; float g; float b; My_Mesh::normal_to_color(x, y, z, r, g, b); m_color_list_.push_back(r); m_color_list_.push_back(g); m_color_list_.push_back(b); //这里采用法线来生成颜色,学生可以自定义自己的颜色生成方式 } for (int i = 0; i < num_samples; i++) { m_faces_.push_back(i); m_faces_.push_back((i + 1) % num_samples); m_faces_.push_back((i + num_samples) % (num_samples)+num_samples); m_faces_.push_back((i + num_samples) % (num_samples)+num_samples); m_faces_.push_back((i + 1) % num_samples); m_faces_.push_back((i + num_samples + 1) % (num_samples)+num_samples); //生成三角面片 m_vt_list_.push_back(1.0 * i / num_samples); m_vt_list_.push_back(0.0); //纹理坐标 m_vt_list_.push_back(1.0 * ((i + 1)) / num_samples); m_vt_list_.push_back(0.0); //纹理坐标 m_vt_list_.push_back(1.0 * i / num_samples); m_vt_list_.push_back(1.0); //纹理坐标 m_vt_list_.push_back(1.0 * i / num_samples); m_vt_list_.push_back(1.0); //纹理坐标 m_vt_list_.push_back(1.0 * ((i + 1)) / num_samples); m_vt_list_.push_back(0.0); //纹理坐标 m_vt_list_.push_back(1.0 * ((i + 1)) / num_samples); m_vt_list_.push_back(1.0); //纹理坐标 } }; void My_Mesh::set_texture_file(std::string s) { this->texture_file_name = s; }; std::string My_Mesh::get_texture_file() { return this->texture_file_name; }; void My_Mesh::set_translate(float x, float y, float z) { vTranslation[0] = x; vTranslation[1] = y; vTranslation[2] = z; }; void My_Mesh::get_translate(float& x, float& y, float& z) { x = vTranslation[0]; y = vTranslation[1]; z = vTranslation[2]; }; void My_Mesh::set_theta(float x, float y, float z) { Theta[0] = x; Theta[1] = y; Theta[2] = z; }; void My_Mesh::get_theta(float& x, float& y, float& z) { x = Theta[0]; y = Theta[1]; z = Theta[2]; }; void My_Mesh::set_theta_step(float x, float y, float z) { Theta_step[0] = x; Theta_step[1] = y; Theta_step[2] = z; }; void My_Mesh::add_theta_step() { Theta[0] = Theta[0] + Theta_step[0]; Theta[1] = Theta[1] + Theta_step[1]; Theta[2] = Theta[2] + Theta_step[2]; };
f_texture.glsl
#version 330 core in vec4 color; in vec2 texCoord; in vec4 normal; in vec3 faceIndecies; out vec4 fColor; out vec4 fNormal; uniform sampler2D texture; void main() { //fColor = vec4(1, 0, 0, 0 ) * texture2D( texture, texCoord ); //fColor = texture2D( texture, texCoord ); //fColor = color; //fColor = vec4(1, 0, 0, 0 ); fColor = color *0.5 + texture2D( texture, texCoord) * 0.5; fNormal = normal; }
v_texture.glsl
#version 330 core in vec3 vPosition; in vec3 vColor; in vec3 vNormal; in vec2 vTexCoord; in vec3 vFaceIndecies; out vec4 color; out vec2 texCoord; out vec4 normal; uniform vec3 theta; uniform vec3 translation; void main() { const float DegreesToRadians = 3.14159265 / 180.0; vec3 c = cos( DegreesToRadians * theta ); vec3 s = sin( DegreesToRadians * theta ); mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0, 0.0, c.x, -s.x, 0.0, 0.0, s.x, c.x, 0.0, 0.0, 0.0, 0.0, 1.0); mat4 ry = mat4( c.y, 0.0, s.y, 0.0, 0.0, 1.0, 0.0, 0.0, -s.y, 0.0, c.y, 0.0, 0.0, 0.0, 0.0, 1.0 ); // Workaround for bug in ATI driver ry[1][0] = 0.0; ry[1][1] = 1.0; mat4 rz = mat4( c.z, -s.z, 0.0, 0.0, s.z, c.z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ); // Workaround for bug in ATI driver rz[2][2] = 1.0; color = vec4(vColor, 0); texCoord = vTexCoord; normal = vec4(vNormal, 0); gl_Position = vec4(vPosition, 1.0); gl_Position = rz * ry * rx * gl_Position; vec4 t = rz * ry * rx * vec4(translation, 1.0); gl_Position = gl_Position + vec4(translation, 0.0); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。