鉴于网上的资料较为零散,这里总结一个自用的文章好了。
1.一些基础操作
这个博客介绍的非常详细,学习或者查阅可以翻看。
http://blog.csdn.net/wangdingqiaoit/article/details/51457675
2.这里介绍一个网上写的工具类GLFundamentals.hpp,里面有很多定义好的功能,很方便,我等下上传到这里。
2.1 读写shader
方法一。使用工具类
直接包含就可以了,当然openGL的环境自己配置好
GLuint program = gl::init_program("vertex.glsl", "fragment.glsl")
方法二。将shader简单直接写到cpp文件中,适合简单的shader脚本。举个栗子
#define VPROG_SRC_TEX(ver) \
ver \
"layout(location = 0) in vec3 pos1;\n" \
"layout(location = 2) in vec2 vTexCoord;\n" \
"\n" \
" out vec2 fTexCoord;\n" \
"\n" \
"uniform mat4 worldMatrix;\n" \
"uniform mat4 projMatrix;\n" \
"\n" \
"void main()\n" \
"{\n" \
" gl_Position = (projMatrix * worldMatrix) * vec4(pos1,1);\n" \
" fTexCoord = vTexCoord;\n" \
"}\n" \
static const char* kGlesVProgTex = VPROG_SRC_TEX("#version 330\n");
#undef VPROG_SRC_TEX
#define FSHADER_SRC_TEX(ver) \
ver \
"uniform sampler2D DiffuseTexture;\n" \
"in vec2 fTexCoord;\n" \
" out vec4 fragColor;\n" \
"\n" \
"void main()\n" \
"{\n" \
"vec4 tD = texture(DiffuseTexture, fTexCoord);\n"\
"fragColor.rgb = vec3(tD);\n" \
"fragColor.a = tD.a;\n" \
"}\n" \
static const char* kGlesFShaderTex = FSHADER_SRC_TEX("#version 330\n");
#undef FSHADER_SRC_TEX
这样就直接得到shader的指针,然后老一套
static GLuint CreateShader(GLenum type, const char* text)
{
GLuint ret = glCreateShader(type);
glShaderSource(ret, 1, &text, NULL);
glCompileShader(ret);
GLint compileResult = GL_TRUE;
glGetShaderiv(ret,GL_COMPILE_STATUS,&compileResult);
if(compileResult == GL_FALSE){
char szLog[1024] = {0};
GLsizei logLen = 0;
glGetShaderInfoLog(ret,1024,&logLen,szLog);
LogToFile::log("shaderError.txt","log: %s \ncode: %s\n",szLog,text);
}
return ret;
}
g_VProg_tex = CreateShader(GL_VERTEX_SHADER, kGlesVProgTex);
g_FShader_tex = CreateShader_temp(GL_FRAGMENT_SHADER, kGlesFShaderTex);
g_Program_tex = glCreateProgram();
//glBindAttribLocation(g_Program_tex, 0, "pos1");
//glBindAttribLocation(g_Program_tex, 2, "fTexCoord");
glAttachShader(g_Program_tex, g_VProg_tex);
glAttachShader(g_Program_tex, g_FShader_tex);
//glBindFragDataLocation(g_Program_tex, 0, "fragColor");
glLinkProgram(g_Program_tex);
3.读取OBJ
OBJ这个格式可以说是很容易理解了,网上也解释的很详细。如果只是简单的mesh,那就只用读取顶点pos和index就好了,下面是我写的一个Util,可以读取带纹理的OBJ,唔准确说是只读取diffuseTexture,像什么高光啊之类的自己再多读取并绑定一下就好了
GLuint LoadModelTexture(string filename){
GLuint texture_ID;
Mat I = imread(filename);
//设置长宽
int width = I.cols;
int height = I.rows;
//设置图像指针
GLubyte* pixels;
//获取图像指针
int pixellength = width*height * 3;
pixels = new GLubyte[pixellength];
memcpy(pixels, I.data, pixellength*sizeof(char));
//将texture_ID设置为2D纹理信息
glGenTextures(1, &texture_ID);
glBindTexture(GL_TEXTURE_2D, texture_ID);
//纹理放大缩小使用线性插值
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//LogToFile::log("errorcpp.txt","LoadModelTexture1\n");
//将图像内存用作纹理信息
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
// free(pixels);
delete [] pixels;
//LogToFile::log("errorcpp.txt","LoadModelTexture2\n");
return texture_ID;
}
上面的是读取图片、绑定并返回ID。用到了openCV来读取的,当然也可以用SOIL,devIL之类的都可以,只要能获得图像指针就ok。
接下来解析OBJ,并绑定到buffer中
tag3DModel ImportOBJModel(string objName){
// LogToFile::log("errorcpp.txt","start do ImportOBJModel\n");
tag3DModel t3DModel;
std::ifstream fin(objName.c_str());
char chkeyword = 0;
string s,s1,s2,s3;
while (getline(fin, s)){
istringstream in(s);
string sNAN;
chkeyword = s[0];
switch(chkeyword){
case 'm':
{
t3DModel.bIsTextured = true;
break;
}
case 'u':{
t3DObject t3DObj;
//存放图片名称
string s1 = s.substr(7); //"usemtl "
tagMaterialInfo tinfo;
tinfo.strName = "textured_" + s1 + "_map_Kd.png";
//LogToFile::log("errorcpp.txt","strName = %s\n",tinfo.strName.c_str());
GLuint texture_ID = LoadModelTexture(tinfo.strName);
// LogToFile::log("errorcpp.txt","end u\n");
tinfo.ID = texture_ID;
t3DModel.tMatInfoVec.push_back(tinfo);
t3DObj.nMaterialID = texture_ID;
t3DModel.t3DObjVec.push_back(t3DObj);
t3DModel.objCount++;
break;
}
case 'v':{
chkeyword = s[1];
if(chkeyword == ' '){
vec3 vNewVert;
in>>sNAN>>s1>>s2>>s3;
//LogToFile::log("errorcpp.txt","%s %s %s\n",s1.c_str(),s2.c_str(),s3.c_str());
vNewVert.x = atof(s1.c_str());
vNewVert.y = -atof(s2.c_str());
vNewVert.z = -atof(s3.c_str());
// LogToFile::log("errorcpp.txt","v %f %f %f\n",vNewVert.x,vNewVert.y,vNewVert.z);
t3DModel.m_pos.push_back(vNewVert);
}else if(chkeyword == 't'){
in>>sNAN>>s1>>s2;
vec2 newTex;
newTex.u = atof(s1.c_str());
newTex.v =1.0 - atof(s2.c_str());
//LogToFile::log("errorcpp.txt","vt %f %f\n",newTex.u,newTex.v);
t3DModel.m_texcoord.push_back(newTex);
}else if(chkeyword == 'n'){
in>>sNAN>>s1>>s2>>s3;
vec3 newNormal;
newNormal.x = atof(s1.c_str());
newNormal.y = atof(s2.c_str());
newNormal.z = atof(s3.c_str());
//LogToFile::log("errorcpp.txt","vn %f %f %f\n",newNormal.x,newNormal.y,newNormal.z);
t3DModel.m_normal.push_back(newNormal);
}
break;
}
case 'f':{ //v/t/n
//LogToFile::log("errorcpp.txt","f\n");
t3DObject *pCurObj = &t3DModel.t3DObjVec[t3DModel.objCount-1];
unsigned int vIdx = 0, tIdx = 0, nIdx = 0;
vec3 vPosVert;
vec2 vTexcoord;
vec3 vNormal;
size_t nDistance = 0;
in>>sNAN>>s1>>s2>>s3;
string pattern = "/";
//LogToFile::log("errorcpp.txt","%s %s %s\n",s1.c_str(),s2.c_str(),s3.c_str());
int pos = s1.find(pattern.c_str(),0);
string sTemp = s1.substr(0,pos);
vIdx = atoi(sTemp.c_str());
// LogToFile::log("errorcpp.txt","%d %s\n",vIdx,sTemp.c_str());
int pos1 = s1.find(pattern.c_str(),pos+1);
sTemp = s1.substr(pos+1,pos1-pos-1);
tIdx = atoi(sTemp.c_str());
//LogToFile::log("errorcpp.txt","%d %s\n",tIdx,sTemp.c_str());
sTemp = s1.substr(pos1+1);
nIdx = atoi(sTemp.c_str());
//LogToFile::log("errorcpp.txt","%d %s\n",nIdx,sTemp.c_str());
//LogToFile::log("errorcpp.txt","f %d/%d/%d ",vIdx,tIdx,nIdx);
//LogToFile::log("errorcpp.txt","m_pos size = %d\n",t3DModel.m_pos.size());
std::map::iterator pFindPos
= t3DModel.m_VObjectIndexMap.find(tVertInfo(t3DModel.m_pos[vIdx - 1], t3DModel.m_texcoord[tIdx - 1], t3DModel.m_normal[nIdx - 1]));
if(t3DModel.m_VObjectIndexMap.end() != pFindPos)
{
pCurObj->Indexes.push_back(pFindPos->second);
}else{
pCurObj->PosVerts.push_back(t3DModel.m_pos[vIdx - 1]);
pCurObj->Texcoords.push_back (t3DModel.m_texcoord[tIdx - 1]);
pCurObj->Normals.push_back(t3DModel.m_normal[nIdx - 1]);
pCurObj->Indexes.push_back(pCurObj->PosVerts.size()-1);
}
pos = s2.find(pattern.c_str(),0);
sTemp = s2.substr(0,pos);
vIdx = atoi(sTemp.c_str());
pos1 = s2.find(pattern.c_str(),pos+1);
sTemp = s2.substr(pos+1,pos1-pos-1);
tIdx = atoi(sTemp.c_str());
sTemp = s2.substr(pos1+1);
nIdx = atoi(sTemp.c_str());
// pCurObj->PosVerts.push_back(t3DModel.m_pos[vIdx - 1]);
// pCurObj->Texcoords.push_back (t3DModel.m_texcoord[tIdx - 1]);
// pCurObj->Normals.push_back(t3DModel.m_normal[nIdx - 1]);
// pCurObj->Indexes.push_back(pCurObj->PosVerts.size()-1);
//LogToFile::log("errorcpp.txt"," %d/%d/%d ",vIdx,tIdx,nIdx);
std::map::iterator pFindPos1
= t3DModel.m_VObjectIndexMap.find(tVertInfo(t3DModel.m_pos[vIdx - 1], t3DModel.m_texcoord[tIdx - 1], t3DModel.m_normal[nIdx - 1]));
if(t3DModel.m_VObjectIndexMap.end() != pFindPos1)
{
pCurObj->Indexes.push_back(pFindPos1->second);
}else{
pCurObj->PosVerts.push_back(t3DModel.m_pos[vIdx - 1]);
pCurObj->Texcoords.push_back (t3DModel.m_texcoord[tIdx - 1]);
pCurObj->Normals.push_back(t3DModel.m_normal[nIdx - 1]);
pCurObj->Indexes.push_back(pCurObj->PosVerts.size()-1);
}
pos = s3.find(pattern.c_str(),0);
sTemp = s3.substr(0,pos);
vIdx = atoi(sTemp.c_str());
pos1 = s3.find(pattern.c_str(),pos+1);
sTemp = s3.substr(pos+1,pos1-pos-1);
tIdx = atoi(sTemp.c_str());
sTemp = s3.substr(pos1+1);
nIdx = atoi(sTemp.c_str());
// pCurObj->PosVerts.push_back(t3DModel.m_pos[vIdx - 1]);
// pCurObj->Texcoords.push_back (t3DModel.m_texcoord[tIdx - 1]);
// pCurObj->Normals.push_back(t3DModel.m_normal[nIdx - 1]);
// pCurObj->Indexes.push_back(pCurObj->PosVerts.size()-1);
//LogToFile::log("errorcpp.txt"," %d/%d/%d \n",vIdx,tIdx,nIdx);
std::map::iterator pFindPos2
= t3DModel.m_VObjectIndexMap.find(tVertInfo(t3DModel.m_pos[vIdx - 1], t3DModel.m_texcoord[tIdx - 1], t3DModel.m_normal[nIdx - 1]));
if(t3DModel.m_VObjectIndexMap.end() != pFindPos2)
{
pCurObj->Indexes.push_back(pFindPos2->second);
}else{
pCurObj->PosVerts.push_back(t3DModel.m_pos[vIdx - 1]);
pCurObj->Texcoords.push_back (t3DModel.m_texcoord[tIdx - 1]);
pCurObj->Normals.push_back(t3DModel.m_normal[nIdx - 1]);
pCurObj->Indexes.push_back(pCurObj->PosVerts.size()-1);
}
break;
}
}
}
//LogToFile::log("errorcpp.txt","allocate buffer\n");
for(unsigned int i = 0; i < t3DModel.t3DObjVec.size(); i++)
{
glGenBuffers(1, &t3DModel.t3DObjVec[i].nPosVBO);
glBindBuffer(GL_ARRAY_BUFFER, t3DModel.t3DObjVec[i].nPosVBO);
glBufferData(GL_ARRAY_BUFFER, t3DModel.t3DObjVec[i].PosVerts.size() * sizeof(vec3),
(GLvoid*)&t3DModel.t3DObjVec[i].PosVerts[0], usage);
glGenBuffers(1, &t3DModel.t3DObjVec[i].nNormVBO);
glBindBuffer(GL_ARRAY_BUFFER, t3DModel.t3DObjVec[i].nNormVBO);
glBufferData(GL_ARRAY_BUFFER, t3DModel.t3DObjVec[i].Normals.size() * sizeof(vec3),
(GLvoid*)&t3DModel.t3DObjVec[i].Normals[0], usage);
glGenBuffers(1, &t3DModel.t3DObjVec[i].nTexcoordVBO);
glBindBuffer(GL_ARRAY_BUFFER, t3DModel.t3DObjVec[i].nTexcoordVBO);
glBufferData(GL_ARRAY_BUFFER, t3DModel.t3DObjVec[i].Texcoords.size() * sizeof(vec2),
(GLvoid*)&t3DModel.t3DObjVec[i].Texcoords[0], usage);
glGenBuffers(1, &t3DModel.t3DObjVec[i].nIndexVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, t3DModel.t3DObjVec[i].nIndexVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, t3DModel.t3DObjVec[i].Indexes.size() * sizeof(unsigned int),
(GLvoid*)&t3DModel.t3DObjVec[i].Indexes[0], usage);
t3DModel.t3DObjVec[i].nNumIndexes = t3DModel.t3DObjVec[i].Indexes.size();
}
return t3DModel;
}
调用只需要短短的2步:
tag3DModel t3DModel = ImportOBJModel("textured.obj");
drawModel(t3DModel,g_Word2Cam,g_ProjMat);
4.TIPS
写shader时候出错很难检查,建议用glGetShaderInfoLog来检查,事半功倍。然后LogToFile文件是写的一个将error写进文本文件的一个辅助类工具,大家可以删掉直接cout或print
读取纹理的UV时,由于坐标系不同的原因,V坐标是相反的,所以读取时候需要1-V
MyOpenGLUtil.h
LogToFile.h
差不多了,有什么遗漏的以后再补。。。