Qt3D的研究(四):指定渲染的材質以及效果,qt3d材質
Qt3D的研究(四):指定渲染的材質以及效果
在上一篇文章中我瞭解到了怎樣簡單地顯示模型。Qt3D內建了一個obj模型的解析器,這樣可以將簡單的obj模型載入並且顯示出來。其實Qt3D對於渲染的配置還是很厲害的,通過設定材質,我們可以得到很不錯的渲染效果,而且可以通過設定Effect,將自己指定的著色器載入,讓Qt 3D和OpenGL進行編譯,得到自己想要的渲染效果。
蔣彩陽原創文章,首發地址:http://blog.csdn.net/gamesdev/article/details/43983493。歡迎同行前來探討。
在上一篇文章介紹的QML代碼的基礎上,我們簡單地添加一個材質。代碼如下:
Entity { Mesh { id: mesh objectName: "toyPlane" source: "qrc:/toyplane.obj" } //! [4] PhongMaterial { id: phongMaterial } //! [4] components: [ mesh, phongMaterial ] }
運行結果如下:
這裡我們在//! [4]之間添加了一個常用的材質:Phong材質。Phong光照模型是一種常見的光照模型,他揭示了產生高光的方法。以前我的部落格也介紹並且實現了這樣的光照模型。之所以它的廣泛性,Qt 3D將其封裝了一個類,方便操作。圖中顯示的是使用Phong光照模型,讓玩具飛機呈現光滑透明的效果。我們也可以設定具體的參數,讓光照呈現不同的效果:設定全域光(ambient)、漫反射(diffuse)、鏡面反射(specular)以及自發光亮度(shininess)。添加的代碼如下所示:
import Qt3D 2.0import Qt3D.Render 2.0Entity{ id: root Camera { id: camera position: Qt.vector3d( 0.0, 0.0, 40.0 ) projectionType: CameraLens.PerspectiveProjection fieldOfView: 45 aspectRatio: 16.0 / 9.0 nearPlane : 0.1 farPlane : 1000.0 upVector: Qt.vector3d( 0.0, 1.0, 0.0 ) viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 ) } components: FrameGraph { ForwardRenderer { clearColor: Qt.rgba( 0, 0, 0, 1 ) camera: camera } } Entity { Mesh { id: mesh objectName: "toyPlane" source: "qrc:/toyplane.obj" } //! [4] PhongMaterial { id: phongMaterial ambient: Qt.rgba( 0.6, 0.2, 0.1, 1 ) diffuse: Qt.rgba( 0.2, 0.6, 0.1, 1 ) specular: Qt.rgba( 0.2, 0.9, 0.1, 1 ) shininess: 0.6 } //! [4] components: [ mesh, phongMaterial ] } Configuration { controlledCamera: camera }}
程式運行結果如下所示:
這裡呈現了一個金光閃閃的玩具飛機模型。
如果我們想自己寫著色器來為我們的模型著色,Qt 3D也提供了相應的方法,可以不藉助C++代碼來實現,直接在QML指定即可。這裡我們需要設定Effect(效果)、Technique(使用的OpenGL技術)、RenderPass(渲染遍數)、ShaderProgram(著色器)。下面是QML代碼:
import Qt3D 2.0import Qt3D.Render 2.0Entity{ id: root Camera { id: camera position: Qt.vector3d( 0.0, 0.0, 40.0 ) projectionType: CameraLens.PerspectiveProjection fieldOfView: 45 aspectRatio: 16.0 / 9.0 nearPlane : 0.1 farPlane : 1000.0 upVector: Qt.vector3d( 0.0, 1.0, 0.0 ) viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 ) } components: FrameGraph { ForwardRenderer { clearColor: Qt.rgba( 0, 0, 0, 1 ) camera: camera } } Entity { Mesh { id: mesh source: "qrc:/toyplane.obj" } //! [5] Material { id: material effect: effect Effect { id: effect techniques: [ technique ] Technique { id: technique openGLFilter { api: OpenGLFilter.Desktop profile: OpenGLFilter.None majorVersion: 2 minorVersion: 0 } renderPasses: [ renderPass ] RenderPass { id: renderPass shaderProgram: simpleSP ShaderProgram { id: simpleSP vertexShaderCode: loadSource( "qrc:/Simple.vert" ) fragmentShaderCode: loadSource( "qrc:/Simple.frag" ) } } } } } //! [5] components: [ mesh, material ] } Configuration { controlledCamera: camera }}
代碼新添加的部分在//! [5]中。這裡我們沒有使用預設的PhoneMaterial,而是使用它的父類Material,並且通過指定Effect來實現自己需要的渲染效果。Effect中含有的Technique表示使用的OpenGL技術,因為OpenGL有多個版本,分OpenGL和OpenGL ES,還分core profile和compatibility profile,這樣使得種種技術變得十分繁雜。所以Qt 3D提出了Technique這個概念。通過指定api、profile以及majorVersion和minorVersion版本,來使用我們需要的OpenGL API。接著是RenderPass渲染遍(這個翻譯總感覺不好),它表示一次渲染需要多少遍渲染操作。比如說在shadow map這個技術中,需要渲染不止一遍,所以要指定兩個RenderPass。而每一遍的RenderPass,需要指定著色器程式。因此,我們載入相應的著色器檔案,來讓系統編譯以及連結之,最後得以渲染。本例中,我們實現一個最簡單的著色器Simple.vert以及Simple.frag,他們如下所示:
// Simple.vert#version 100attribute vec3 vertexPosition;uniform mat4 mvp;void main( void ){ gl_Position = mvp * vec4( vertexPosition, 1.0 );}
// Simple.frag#version 100void main( void ){ gl_FragColor = vec4( 1.0, 0.8, 0.2, 1.0 );}
這裡需要說明的是,Qt 3D在MeshData中指定了預設的屬性(attribute)變數和一致性(uniform)變數,它們如下:
屬性(attribute)變數 |
一致性(uniform)變數 |
vertexPosition |
modelMatrix |
vertexTexCoord |
viewMatrix |
vertexNormal |
projectionMatrix |
vertexColor |
modelView |
vertexTangent |
modelViewProjection |
|
mvp |
|
inverseModelMatrix |
|
inverViewMatrix |
|
inverseProjectionMatrix |
|
inverseModelView |
|
inverseModelViewProjection |
|
modelNormalMatrix |
|
modelViewNormal |
|
viewportMatrix |
|
inverseViewportMatrix |
|
time |
※這些變數並沒有在文檔中列出,可能隨著版本的變化而變得不同
這是一個非常簡單的著色器,它以單色輸出。下面是運行:
通過逐漸豐富著色器的內容,可以讓程式擷取更加美妙的渲染效果。