中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

基于Qt的OpenGL可編程管線學習(2)-obj模型繪制

繪制一個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è)風格,提供周到的售前咨詢和貼心的售后服務

基于Qt的OpenGL可編程管線學習(2)- obj模型繪制

這里給模型加載頂點和紋理的信息,加上環(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)

外貿(mào)網(wǎng)站建設
浦城县| 安远县| 达日县| 靖宇县| 伊金霍洛旗| 增城市| 太白县| 鄂伦春自治旗| 湟中县| 新建县| 政和县| 临邑县| 亳州市| 阆中市| 克什克腾旗| 巴马| 靖西县| 磐安县| 都匀市| 东方市| 基隆市| 老河口市| 勐海县| 潞西市| 慈利县| 永春县| 金寨县| 循化| 盐亭县| 平利县| 水富县| 娱乐| 高要市| 安龙县| 黄骅市| 兴宁市| 灵山县| 南平市| 盐亭县| 蓝田县| 图们市|