繪制一個Obj模型,效果如下圖所示
創(chuàng)新互聯(lián)建站網(wǎng)絡公司擁有10多年的成都網(wǎng)站開發(fā)建設經(jīng)驗,上1000+客戶的共同信賴。提供成都網(wǎng)站設計、成都網(wǎng)站建設、網(wǎng)站開發(fā)、網(wǎng)站定制、賣友情鏈接、建網(wǎng)站、網(wǎng)站搭建、響應式網(wǎng)站、網(wǎng)頁設計師打造企業(yè)風格,提供周到的售前咨詢和貼心的售后服務
這里給模型加載頂點和紋理的信息,加上環(huán)境光、漫反射和鏡面反射,這里我用的是一個方向光。
并且讓模型每一幀旋轉(zhuǎn)一個角度達到動態(tài)旋轉(zhuǎn)的效果。
1、Obj模型基本內(nèi)容及加載
v 表示頂點數(shù)據(jù)
vt 表示紋理數(shù)據(jù)
vn 表示法線數(shù)據(jù)
f 表示一個面的頂點數(shù)據(jù)的Index
這里我是直接解析的模型,代碼如下所示:
objmode.h
#ifndef OBJMODE_H #define OBJMODE_H #include <QObject> #include <QString> #include <QStringList> #include <QVector> #include <QFile> #include <QTextStream> struct VertexData { float postion[3]; float texcoord[2]; float normal[3]; }; struct VertexPos { float postion[3]; }; struct VertexTex { float coord[2]; }; struct VertexNor { float normal[3]; }; struct VertexIndex { int posIndex; int coordIndex; int normalIndex; }; class ObjMode : QObject { public: ObjMode(); ~ObjMode(); bool loadObjModel(QString nFileStr, QVector&nVertextData, QVector&index); private: QVectorm_VertexInfo; QVectorm_TextureInfo; QVectorm_NormalInfo; QVectorm_VertexIndex; QVectorm_FaceIndex; }; #endif // OBJMODE_H
其中l(wèi)oadObjModel()函數(shù)就是加載模型的函數(shù),輸入為文件路徑,會返回頂點的數(shù)據(jù)內(nèi)容和每個面的三角形對應的頂點的索引。
函數(shù)實現(xiàn)如下所示:
bool ObjMode::loadObjModel(QString nFileStr, QVector<VertexData> &nVertextData, \ QVector<unsigned int> &index) { QFile nObjFile(nFileStr); if (!nObjFile.exists()) return false; if (!nObjFile.open(QFile::ReadOnly)) return false; nVertextData.clear(); index.clear(); m_TextureInfo.clear(); m_NormalInfo.clear(); m_VertexInfo.clear(); m_VertexIndex.clear(); m_FaceIndex.clear(); QTextStream nTextStream(&nObjFile); for (;!nTextStream.atEnd();) { QString nLineString = nTextStream.readLine(); QByteArray nData = nLineString.toLocal8Bit(); if (nData.length() <= 2) continue; if (nData.at(0) == 'v') { QStringList nStrList = nLineString.split(" "); if (nData[1] == 't') { if (nStrList.count() <= 0 || nStrList.at(0) != "vt") continue; VertexTex nTexture; for (int i=1; i<nStrList.count(); ++i) nTexture.coord[i - 1] = nStrList.at(i).toFloat(); m_TextureInfo << nTexture; } else if (nData[1] == 'n') { if (nStrList.count() <= 0 || nStrList.at(0) != "vn") continue; VertexNor nNormal; for (int i=1; i<nStrList.count(); ++i) nNormal.normal[i - 1] = nStrList.at(i).toFloat(); m_NormalInfo << nNormal; } else { if (nStrList.count() <= 0 || nStrList.at(0) != "v") continue; VertexPos nPos; for (int i=1; i<nStrList.count(); ++i) nPos.postion[i - 1] = nStrList.at(i).toFloat(); m_VertexInfo << nPos; } } else if (nData[0] == 'f') { QStringList nStrList = nLineString.split(" "); if (nStrList.count() <= 0 || nStrList.at(0) != "f") continue; for (int i=1; i<nStrList.count(); ++i) { VertexIndex nIndex; QString nFaceIndexStr = nStrList.at(i); QStringList nFaceList = nFaceIndexStr.split("/"); nIndex.posIndex = nFaceList.at(0).toUInt() - 1; nIndex.coordIndex = nFaceList.at(1).toUInt() - 1; nIndex.normalIndex = nFaceList.at(2).toUInt() - 1; bool isFinded = false; for (int j=0; j<m_VertexIndex.count(); ++j) { if (nIndex.posIndex == m_VertexIndex.at(j).posIndex && \ nIndex.coordIndex == m_VertexIndex.at(j).coordIndex && \ nIndex.normalIndex == m_VertexIndex.at(j).normalIndex) { isFinded = true; m_FaceIndex << j; break; } } if (!isFinded) { m_VertexIndex << nIndex; m_FaceIndex << m_VertexIndex.count() - 1; } } } } nObjFile.close(); for (int i=0; i<m_VertexIndex.count(); ++i) { VertexData nPerVertextData; int posIndex = m_VertexIndex.at(i).posIndex; int textureIndex = m_VertexIndex.at(i).coordIndex; int normalIndex = m_VertexIndex.at(i).normalIndex; memcpy(nPerVertextData.postion, m_VertexInfo.at(posIndex).postion, sizeof(VertexPos)); memcpy(nPerVertextData.texcoord, m_TextureInfo.at(textureIndex).coord, sizeof(VertexTex)); memcpy(nPerVertextData.normal, m_NormalInfo.at(normalIndex).normal, sizeof(VertexNor)); nVertextData.push_back(nPerVertextData); } for (int i=0; i<m_FaceIndex.count(); ++i) { index.push_back(m_FaceIndex.at(i)); } return true; }
2、創(chuàng)建紋理
GLuint OpenGLOperate::createTexture(QString nFile) { GLuint textureId = 0; QFile file(nFile); if (!file.exists()) return 0; QImage p_w_picpath(nFile); QImage textureImage; int width = p_w_picpath.width(); int height = p_w_picpath.height(); textureImage = p_w_picpath.convertToFormat(QImage::Format_RGBA8888); textureImage = textureImage.mirrored(); m_OpenGLCore->glGenTextures(1, &textureId); m_OpenGLCore->glBindTexture(GL_TEXTURE_2D, textureId); m_OpenGLCore->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); m_OpenGLCore->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); m_OpenGLCore->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); m_OpenGLCore->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); m_OpenGLCore->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, \ GL_RGBA, GL_UNSIGNED_BYTE, textureImage.bits()); m_OpenGLCore->glBindTexture(GL_TEXTURE_2D, 0); return textureId; }
為Shader的紋理賦值,默認使用0號紋理單元
m_Texture = m_OpenGLOperate->createTexture(":/niutou.bmp"); OpenGLCore->glBindTexture(GL_TEXTURE_2D, m_Texture); OpenGLCore->glUniform1i(m_TextureLocation, 0);
3、關于環(huán)境光、漫反射及高光
環(huán)境光:在無光源下的環(huán)境的亮度;這里將環(huán)境光直接寫到fragment shader中(也可以在用uniform在CPU上設置)
設置環(huán)境光的亮度及材質(zhì)
// Ambient vec4 M_AmbientLightColor = vec4(0.2, 0.2, 0.2, 1.0); vec4 M_AmbientMaterial = vec4(0.2, 0.2, 0.2, 1.0); vec4 ambientColor = M_AmbientLightColor * M_AmbientMaterial;
漫反射:在光的照射下物體反射的顏色,也就是物體反射的顏色
光照強度的計算:物體表面的點指向光源的向量 點乘 法線,就是發(fā)光強度。
分析:指向光源的向量與法線的夾角為0度時,反射的光線越多,發(fā)光強度越大。夾角為90度時,發(fā)光強度就為0,如果大于90度則為背光面。
// Diffuse vec3 M_LightPos = vec3(10.0, 10.0, 0.0); vec3 LightNormal = normalize(M_LightPos); // 指向光源的單位向量,方向光 vec3 NormalNormal = normalize(M_normal); // 法線的單位向量 // 點乘獲取光照強度 vec4 M_DiffuseLightColor = vec4(1.0, 1.0, 1.0, 1.0); vec4 M_DiffuseMaterial = vec4(0.9, 0.9, 0.9, 1.0); vec4 diffuseColor = M_DiffuseLightColor * M_DiffuseMaterial * max(0.0, dot(NormalNormal, LightNormal));
鏡面發(fā)射:高光,在金屬等物體表面的光
標準phong模型 光照強度的計算:反射光線 點乘 直線眼睛的向量作為基底,然后取一個冪
分析:當反射光線與指向眼睛的向量夾角為0度時,則為最亮的部分
// 鏡面反射 vec4 specularLightColor = vec4(1.0, 1.0, 1.0, 1.0); vec4 specularMaterial = vec4(0.4, 0.4, 0.4, 1.0); vec3 reflerDir = normalize(reflect(-LightNormal, NormalNormal)); vec3 eyeDir = normalize(vec3(0.0) - M_WordPos); vec4 specularColor = specularLightColor * specularMaterial * pow(max(0.0, dot(reflerDir, eyeDir)), 180);
4、法線矩陣(Normal Matrix)
當模型矩陣變換時,法線也會變,需要重新計算法線,公式為:
法線矩陣 = 模型矩陣的逆的轉(zhuǎn)置
變換后的法線 = 法線矩陣 * 法線
QMatrix4x4 nMormalMat; // 法線矩陣 QMatrix4x4 nModeMat; // 模型矩陣 nModeMat.translate(0, -50, -200); if (m_Rote > 360) m_Rote = 0; else m_Rote += 1.0f; nModeMat.rotate(m_Rote, 0.0f, 1.0f, 0.0f); QMatrix4x4 nNormalMatrix = nModeMat.inverted().transposed();
Vertex Shader:
attribute vec3 pos; attribute vec2 coord; attribute vec3 normal; uniform mat4 M; uniform mat4 V; uniform mat4 P; uniform mat4 NM; varying vec2 M_coord; varying vec3 M_normal; varying vec3 M_WordPos; void main() { M_coord = coord; M_WordPos = vec3(M * vec4(pos, 1.0)); M_normal = mat3(NM) * normal;// 計算法線 gl_Position = P * V * M * vec4(pos, 1.0); }
Fragment Shader
uniform sampler2D U_MainTexture; varying vec2 M_coord; varying vec3 M_normal; varying vec3 M_WordPos; //uniform vec3 M_LightPos; // 平行光 //uniform vec4 M_AmbientLightColor; //uniform vec4 M_AmbientMaterial; //uniform vec4 M_DiffuseLightColor; //uniform vec4 M_DiffuseMaterial; void main() { // Ambient vec4 M_AmbientLightColor = vec4(0.2, 0.2, 0.2, 1.0); vec4 M_AmbientMaterial = vec4(0.2, 0.2, 0.2, 1.0); vec4 ambientColor = M_AmbientLightColor * M_AmbientMaterial; // Diffuse vec3 M_LightPos = vec3(10.0, 10.0, 0.0); vec3 LightNormal = normalize(M_LightPos); // 指向光源的單位向量 vec3 NormalNormal = normalize(M_normal); // 法線的單位向量 // 點乘獲取光照強度 vec4 M_DiffuseLightColor = vec4(1.0, 1.0, 1.0, 1.0); vec4 M_DiffuseMaterial = vec4(0.9, 0.9, 0.9, 1.0); vec4 diffuseColor = M_DiffuseLightColor * M_DiffuseMaterial * max(0.0, dot(NormalNormal, LightNormal)); // 鏡面反射 vec4 specularLightColor = vec4(1.0, 1.0, 1.0, 1.0); vec4 specularMaterial = vec4(0.4, 0.4, 0.4, 1.0); vec3 reflerDir = normalize(reflect(-LightNormal, NormalNormal)); vec3 eyeDir = normalize(vec3(0.0) - M_WordPos); vec4 specularColor = specularLightColor * specularMaterial * pow(max(0.0, dot(reflerDir, eyeDir)), 180); gl_FragColor = ambientColor + texture2D(U_MainTexture, M_coord) * 1 + specularColor; }
為了使模型看的更清楚,我沒用漫反射。如果使用漫反射可以將最后一句改成:
gl_FragColor = ambientColor + texture2D(U_MainTexture, M_coord) * diffuseColor + specularColor;
網(wǎng)站題目:基于Qt的OpenGL可編程管線學習(2)-obj模型繪制
標題網(wǎng)址:http://www.rwnh.cn/article22/gcgejc.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供用戶體驗、服務器托管、品牌網(wǎng)站建設、做網(wǎng)站、小程序開發(fā)、定制網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)