翻譯自: Vertex Displacement Mapping using GLSLphp
說明: 之因此選擇這篇文檔, 是由於如今但凡提到位移貼圖(Displacement Mapping), 都要求設備支持鑲嵌細分(tessellates), 可是目前大多數的移動設備都不支持這個特性, 而本文的年代比較久遠(2006~2008), 那時的設備更不可能支持鑲嵌細分了, 說明位移貼圖並不是必需鑲嵌細分這個特性, 也意味着本文的實現方法能夠在大多數設備上運行.html
頂點位移貼圖
(Vertex Displacement Mapping
)或者簡單點兒位移貼圖
(Displacement Mapping
) 是一種技術, 它容許用一個紋理貼圖(位移圖-displacement map
)對一個多邊形網格(mesh)進行變形, 以便增長表面細節. 它的原理並不新鮮. 它甚至是一些地形生成算法的基礎(請參考 Terrain Generator GLUT 項目). 新鮮的是使用 GPU
來實現實時網格變形.web
位移貼圖須要顯卡容許在頂點着色器中訪問至少一個紋理貼圖單元. 在頂點着色器中訪問紋理貼圖被稱爲 頂點紋理存取
(Vertex Texture Fetching
). 着色器模型 3.0
強制實如今頂點着色器內至少有 4
個紋理單元能被訪問. 如今, 只有基於 nVidia
的 Geforce 6
, Geforce 7
以及更高版本支持 頂點紋理存取
. ATI
顯卡不支持 頂點紋理存取
, 甚至連最新的高端型號好比 X1950XTX
也不支持(更多解釋請看這裏 ATI X1900XTX and VTF)算法
看起來 Forceware
顯卡驅動 91.xx
和 91.xx
有點問題. 老一點的驅動 (84.xx
) 或者最新的 (96.xx
) 都能正確地工做(這篇文章中有更多細節)編程
頂點紋理存取
如今在 radeon
也可用了: ATI Catalyst 8.10 Fixes the Displacement Mapping Bug in OpenGL @ Geeks3D.瀏覽器
GPU Caps Viewer
工具容許你快速知道在頂點着色器中可訪問紋理單元數:app
截圖: 框架
這個信息能經過 OpenGL
的常量 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB
得到.函數
下面的截圖展現了對本教程使用項目的渲染. 咱們將會使用 Demoniak3D
平臺以便快速編寫位移貼圖示例.工具
例程截圖:
不一樣的例程使用了 GLSL
(OpenGL Shading Language
) 進行着色器編程.
用於變形的基本元素是從位移圖中查詢到的向量. 這個向量一般要麼保存一個 RGBA
的顏色, 要麼保存一個標量顏色(用灰度表示的高度圖). 咱們將會使用這個向量以及更精確的它的一些部件的總額, 做爲一個因子, 用來改變頂點的位置. 最多見的一種方法是按前一個因子的比例沿着頂點的法線移動頂點的位置.
截圖:
上圖能夠總結爲以下的關係:
P1 = P0 + (N * df * uf)
P0
是頂點原始的位置P1
是位移以後的頂點位置N
是頂點的法線向量df
是被規範化的位移因子(如 [0.0; 1.0]
)uf
是一個用戶選擇的縮放因子df
能從下面的關係中得到, 它把一個 RGB
值轉換成一個灰度值:
df = 0.30*dv.x + 0.59*dv.y + 0.11*dv.z
dv
就是當前被處理的頂點從位移圖中獲取的向量.
如今理論已經齊備, 只欠實踐了...
一旦所需的良好的工做條件準備穩當, 頂點着色器是至關簡單的. 就像任何一種世界上的 3D
顯卡的技術發展同樣, 頂點位移貼圖
有一些少量的限制, 若是它們不在考慮在內,將會把你的 Ultra-Boosted 7800 GTX
變成一個古老的 S3 trio
(你還記得......).
爲了完成 頂點位移貼圖
, 這裏有兩個主要限制:
OpenGL
的條款中, 它意味着內部像素格式被設置爲GL_RGBA_FLOAT32_ATI
(ATI
和 nVidia
都能用).Nearest
模式是惟一被接受的.所以一旦位移圖被以 nearest
模式過濾的浮點格式加載, 位移貼圖實際上變得簡單了, 以下面的頂點/像素着色器:
[Vertex_Shader] uniform sampler2D displacementMap; void main(void) { vec4 newVertexPos; vec4 dv; float df; gl_TexCoord[0].xy = gl_MultiTexCoord0.xy; dv = texture2D( displacementMap, gl_MultiTexCoord0.xy ); df = 0.30*dv.x + 0.59*dv.y + 0.11*dv.z; newVertexPos = vec4(gl_Normal * df * 100.0, 0.0) + gl_Vertex; gl_Position = gl_ModelViewProjectionMatrix * newVertexPos; } [Pixel_Shader] uniform sampler2D colorMap; void main(void) { gl_FragColor = texture2D(colorMap, gl_TexCoord[0].xy); }
在頂點着色器中獲取位移圖跟咱們在像素着色器中獲取紋理貼圖同樣: 使用 GLSL
的 texture2D()
函數.
Demoniak3D
的示例展現了一個 80000
個多邊形網格用一個簡單 BMP
圖像的變形:
截圖:
nearest
過濾模式是今天硬件的頂點着色器裏惟一可用的模式. 可是沒有什麼可以阻止咱們實現咱們本身的 bilinear
過濾模式. 這裏是這個函數(改編自 nVidia
的 Cg
代碼)作了這個工做:
#define textureSize 256.0 #define texelSize 1.0 / 256.0 vec4 texture2D_bilinear( uniform sampler2D tex, vec2 uv ) { vec2 f = fract( uv.xy * textureSize ); vec4 t00 = texture2D( tex, uv ); vec4 t10 = texture2D( tex, uv + vec2( texelSize, 0.0 )); vec4 tA = mix( t00, t10, f.x ); vec4 t01 = texture2D( tex, uv + vec2( 0.0, texelSize ) ); vec4 t11 = texture2D( tex, uv + vec2( texelSize, texelSize ) ); vec4 tB = mix( t01, t11, f.x ); return mix( tA, tB, f.y ); }
這個函數的使用很簡單, 只要把 texture2D()
替換成 texture2D_bilinear()
就好了:
dv = texture2D_bilinear( displacementMap, gl_MultiTexCoord0.xy );
這段代碼在頂點着色器和像素着色器裏都運行得很好.
頂點位移貼圖
最大的一個缺點是面對法線的頂點被破壞了由於對於未變形網格來講它們是有效的. 由於咱們在一個頂點着色器中, 咱們不能訪問其餘兩個來自當前被處理的面的頂點, 而後咱們沒法從新計算法線.
不過有兩種方式來解決這個棘手的問題: 第一個就是簡單地不使用......法線! 使用靜態光線(就像光線貼圖
-lightmapping
), 法線就沒用了, 由於光線來自光線圖
-light-map
.
第二個方法是爲像素着色器提供法線. 一個簡單的方法是從位移圖建立一個法線圖. 法線圖保存法線向量, 被指向模擬位移圖的起伏. 這個技巧工做得很是好, 若是咱們忘掉一些小缺點, 好比一些區域不該該被照亮.
下面這幅圖展現了一個 凹凸位移貼圖
(BumpDisplacementMapping
) 着色器的結果. 位移圖和法線圖都被根據基本圖(石頭的紋理貼圖)建立了. 這個項目也能夠在下載存檔中可用.
截圖:
頂點位移貼圖
能被用於創造很酷的效果而且容許發揮頂點處理器的威力, 它經常被遺忘於像素處理器的好處. 然而, 咱們必須考慮到一些限制, 好比完成頂點紋理存取的硬件能力(ATI/Radeon
的 GPU
不支持 頂點位移映射
),法線的問題變成錯誤, 甚至不可能像 shadow-volumes
同樣使用一些算法 (或者是你的 3D
引擎的一部分),由於這些算法處理的頂點存儲在系統內存中, 而不是存儲在 GPU
的圖形內存中......
記着這些約束, 頂點位移貼圖
容許實現, 例如,極其逼真的水呈現模擬(見更多資源部分中的連接)或甚至互動頂點位移, 以下示例所示: 頂點位移是由一個 AVI
視頻控制 (視頻來源於 K-Meleon web
瀏覽器目錄)
截圖:
nVidia - Vertex Texture Fetch
Using Vertex Texture Displacement for Realistic Water Rendering
OpenGL Setup for GLSL
例程下載: 例程
例程代碼須要 Demoniak3D
才能正常運行.
Demoniak3D
能夠從這裏下載: Demoniak3D Demo-System.
完整例程中給出了詳細的參數設置和如何使用那些圖像資源做爲紋理, 只要稍微修改一下就能夠在咱們本身的 OpenGL ES
框架下直接使用.
<?xml version="1.0" encoding="Windows-1252" standalone="yes"?> <!-- ============================================================================== AUTHOR: JeGX - jegx@ozone3d.net DATE: 10.03.2006 PURPOSE: Vertex Displacement Mapping Demo. TUTORIAL: http://www.ozone3d.net/tutorials/vertex_displacement_mapping.php ==================================== \==:: http://www.oZone3D.Net ::==/ =============================== ============================================================================== --> <hyperion version_major="1" version_minor="2" > <!-- The Scene! --> <scene name="displacement_mapping_demo" display_fps="TRUE" show_ref_grid="TRUE" vsync="TRUE" > <infos_color r="1.0" g="1.0" b="1.0" /> <window_size width="1024" height="768" /> <background_color r="0.3" g="0.0" b="0.0" /> <background_image image="data/stars.gif" /> <!-- Check the GLSL support and the number of vertex shader texture units we need in this demo. --> <check_hardware_caps glsl="TRUE" vs_tex_samplers="1" error_message="Sorry, this demo requires a Shader Model 3.0 (for vertex texture fetching) complient graphics controller. Demo startup failed. Bye..." /> </scene> <!-- Setup an EXAMINE camera. --> <camera name="myCamera" fov="60.0" navigation_mode="EXAMINE" > <position x="-143.41" y="218.55" z="241.49" /> <orientation pitch="30.0" yaw="120.0" /> </camera> <!-- The base map (or color map) --> <texture name="colorMap" filename="data/supernova.bmp" pixel_format="RGB" /> <!-- The displacement map. Note the RGBA_32F pixel format and the filtering mode (NONE==nearest). This is mandatory for vertex texture fetching on today's hardware. --> <texture name="displacementMap" filename="data/supernova.bmp" pixel_format="RGBA_32F" filtering_mode="NONE" num_mipmaps="0" /> <!-- The mesh plane's material. We have to create it in order to attach the displacement shader. --> <material name="plane_mat" shader_program_name="displacementShader" /> <!-- The mesh plane: 200*200*2 = 80000 polys. In order to get decent frame rate, do not forget to set the VBO state... --> <mesh render="TRUE" name="mesh_plane" shape_type="PLANE" texturing="TRUE" lighting="FALSE" polygon_mode="SOLID" use_vbo="TRUE" back_face_culling="FALSE" > <plane x_size="400.0" z_size="400.0" num_segs_x="200" num_segs_z="200" /> <position x="0.0" y="0.0" z="0.0" /> <orientation pitch="0.0" /> <attach_material name="plane_mat" /> <!-- The displacement map on texture unit 0. --> <texture texture_name="displacementMap" material_name="plane_mat" texture_unit="0" u_tile="1.0" v_tile="1.0" /> <!-- The color map on texture unit 1. --> <texture texture_name="colorMap" material_name="plane_mat" texture_unit="1" u_tile="1.0" v_tile="1.0" /> </mesh> <!-- The displacement shader. --> <shader_program name="displacementShader" > <constant_1i name="displacementMap" value="0" /> <constant_1i name="colorMap" value="1" /> <raw_data><![CDATA[ [Vertex_Shader] uniform float time; uniform sampler2D displacementMap; #define textureSize 256.0 #define texelSize 1.0 / 256.0 vec4 tex2D_bilinear( uniform sampler2D tex, vec2 t ) { vec2 f = fract( t.xy * textureSize ); vec4 t00 = texture2D( tex, t ); vec4 t10 = texture2D( tex, t + vec2( texelSize, 0.0 )); vec4 tA = mix( t00, t10, f.x ); vec4 t01 = texture2D( tex, t + vec2( 0.0, texelSize ) ); vec4 t11 = texture2D( tex, t + vec2( texelSize, texelSize ) ); vec4 tB = mix( t01, t11, f.x ); return mix( tA, tB, f.y ); } void main(void) { vec4 newVertexPos; vec4 dv; float df; gl_TexCoord[0].xy = gl_MultiTexCoord0.xy; dv = tex2D_bilinear( displacementMap, gl_MultiTexCoord0.xy ); //dv = texture2D( displacementMap, gl_MultiTexCoord0.xy ); df = 0.30*dv.x + 0.59*dv.y + 0.11*dv.z; newVertexPos = vec4(gl_Normal * df * 100.0, 0.0) + gl_Vertex; gl_Position = gl_ModelViewProjectionMatrix * newVertexPos; } [Pixel_Shader] uniform sampler2D colorMap; void main(void) { gl_FragColor = texture2D(colorMap, gl_TexCoord[0].xy); } ]]></raw_data> </shader_program> <!-- A little bit of interactivity: swap the mesh plane polygon rendering mode. --> <script name="switch_polygon_mode" run_mode="ASYNCHRONOUS" > <raw_data><![CDATA[ if( g_mode==NIL ) then g_mode=0; end WIREFRAME = 1; SOLID = 2; if( g_mode==1 ) then HYP_Object.SetPolygonMode( "mesh_plane", SOLID ); g_mode=0; else HYP_Object.SetPolygonMode( "mesh_plane", WIREFRAME ); g_mode=1; end ]]></raw_data> </script> <hotkey name="space_key" script="switch_polygon_mode" key="KEY_SPACE" /> <!-- The white rectangle under the supernova hud. --> <hud name="under_nova" texturing="FALSE" > <size width="220" height="220" /> <position x="380" y="250" /> </hud> <!-- The hud that displays the small supernova image. --> <hud name="nova" > <texture texture_name="colorMap" texture_unit="0" /> <size width="200" height="200" /> <position x="380" y="250" /> </hud> <!-- Display some information / commands --> <font name="myFontArial12" render="TRUE" ttf_name="Arial" size="14" > <text_2d> <color r="1.0" g="1.0" b="0.0" /> <position x="10" y="30" /> <text text="Vertex Displacement Mapping Demo" /> </text_2d> <text_2d> <color r="1.0" g="1.0" b="0.0" /> <position x="10" y="50" /> <text text="Controls:" /> </text_2d> <text_2d> <color r="1.0" g="1.0" b="0.0" /> <position x="20" y="70" /> <text text="> SPACE: switch polygon mode (WIREFRAME/SOLID)" /> </text_2d> </font> </hyperion>
<?xml version="1.0" encoding="Windows-1252" standalone="yes"?> <!-- ============================================================================== AUTHOR: JeGX - jegx@ozone3d.net DATE: 10.03.2006 PURPOSE: Vertex Displacement Mapping Demo. TUTORIAL: http://www.ozone3d.net/tutorials/vertex_displacement_mapping.php ==================================== \==:: http://www.oZone3D.Net ::==/ =============================== ============================================================================== --> <hyperion version_major="1" version_minor="2" > <!-- The Scene! --> <scene name="displacement_mapping_demo" display_fps="TRUE" show_ref_grid="TRUE" vsync="TRUE" > <infos_color r="1.0" g="1.0" b="1.0" /> <window_size width="1024" height="768" /> <background_color r="0.3" g="0.0" b="0.0" /> <!-- Check the GLSL support and the number of vertex shader texture units we need in this demo. --> <check_hardware_caps glsl="TRUE" vs_tex_samplers="1" error_message="Sorry, this demo requires a Shader Model 3.0 (for vertex texture fetching) complient graphics controller. Demo startup failed. Bye..." /> </scene> <!-- Setup an EXAMINE camera. --> <camera name="myCamera" fov="60.0" navigation_mode="EXAMINE" > <position x="-143.41" y="218.55" z="241.49" /> <orientation pitch="30.0" yaw="120.0" /> </camera> <light name="myLight" render="TRUE" type="OMNI" > <position x="10.0" y="100.0" z="45.0" /> <ambient r="0.4" g="0.4" b="0.4" /> <diffuse r="0.9" g="0.9" b="0.9" /> <specular r="0.9" g="0.9" b="0.9" /> </light> <!-- The base map (or color map) --> <texture name="colorMap" filename="data/wall002_512x512.jpg" /> <!-- The displacement map. Note the RGBA_32F pixel format and the filtering mode (NONE==nearest). This is mandatory for vertex texture fetching on today's hardware. --> <texture name="displacementMap" filename="data/wall002_hmap2_512x512.jpg" pixel_format="RGBA_32F" filtering_mode="NONE" num_mipmaps="0" /> <!-- The normal map (or bump map) --> <texture name="normalMap" filename="data/wall002_nmap2_512x512.jpg" /> <!-- The mesh plane's material. We have to create it in order to attach the displacement shader. --> <material name="plane_mat" shader_program_name="displaceBumpMappingShader" > <ambient r="0.6" g="0.6" b="0.6" /> <diffuse r="0.9" g="0.9" b="0.9" /> <specular r="0.6" g="0.6" b="0.6" /> </material> <!-- The mesh plane: 200*200*2 = 80000 polys. In order to get decent frame rate, do not forget to set the VBO state... --> <mesh render="TRUE" name="mesh_plane" shape_type="PLANE" texturing="TRUE" lighting="FALSE" polygon_mode="SOLID" use_vbo="TRUE" back_face_culling="TRUE" > <plane x_size="400.0" z_size="400.0" num_segs_x="200" num_segs_z="200" /> <position x="0.0" y="10.0" z="0.0" /> <orientation pitch="0.0" /> <attach_material name="plane_mat" /> <!-- The displacement map on texture unit 0. --> <texture texture_name="displacementMap" material_name="plane_mat" texture_unit="0" u_tile="1.0" v_tile="1.0" /> <!-- The normal map on texture unit 1. --> <texture texture_name="normalMap" material_name="plane_mat" texture_unit="1" u_tile="1.0" v_tile="1.0" /> <!-- The color map on texture unit 2. --> <texture texture_name="colorMap" material_name="plane_mat" texture_unit="2" u_tile="1.0" v_tile="1.0" /> </mesh> <!-- The displacement shader. --> <shader_program name="displaceBumpMappingShader" > <constant_1i name="displacementMap" value="0" /> <constant_1i name="normalMap" value="1" /> <constant_1i name="colorMap" value="2" /> <vertex_attrib name="tangent" value="1" /> <constant_1f name="invRadius" value="0.001" /> <raw_data><![CDATA[ [Vertex_Shader] varying vec3 lightVec; varying vec3 eyeVec; varying vec2 texCoord; attribute vec3 tangent; uniform sampler2D displacementMap; #define textureSize 1024.0 #define texelSize 1.0 / 1024.0 vec4 tex2D_bilinear( uniform sampler2D tex, vec2 t ) { vec2 f = fract( t.xy * textureSize ); vec4 t00 = texture2D( tex, t ); vec4 t10 = texture2D( tex, t + vec2( texelSize, 0.0 )); vec4 tA = mix( t00, t10, f.x ); vec4 t01 = texture2D( tex, t + vec2( 0.0, texelSize ) ); vec4 t11 = texture2D( tex, t + vec2( texelSize, texelSize ) ); vec4 tB = mix( t01, t11, f.x ); return mix( tA, tB, f.y ); } void main(void) { vec4 displacedVertexPos; vec4 displacementVec; float f; texCoord = gl_MultiTexCoord0.xy; displacementVec = tex2D_bilinear(displacementMap, gl_MultiTexCoord0.xy ); //f = (0.30*displacementVec.x + 0.59*displacementVec.y + 0.11*displacementVec.z); f = displacementVec.x; displacedVertexPos = vec4(gl_Normal * f * 10.0, 0.0) + gl_Vertex; gl_Position = gl_ModelViewProjectionMatrix * displacedVertexPos; vec3 n = normalize(gl_NormalMatrix * gl_Normal); vec3 t = normalize(gl_NormalMatrix * tangent); vec3 b = cross(n, t); vec3 vVertex = vec3(gl_ModelViewMatrix * displacedVertexPos); vec3 tmpVec = gl_LightSource[0].position.xyz - vVertex; lightVec.x = dot(tmpVec, t); lightVec.y = dot(tmpVec, b); lightVec.z = dot(tmpVec, n); tmpVec = -vVertex; eyeVec.x = dot(tmpVec, t); eyeVec.y = dot(tmpVec, b); eyeVec.z = dot(tmpVec, n); } [Pixel_Shader] varying vec3 lightVec; varying vec3 eyeVec; varying vec2 texCoord; uniform sampler2D colorMap; uniform sampler2D normalMap; uniform float invRadius; void main (void) { float distSqr = dot(lightVec, lightVec); float att = clamp(1.0 - invRadius * sqrt(distSqr), 0.0, 1.0); vec3 lVec = lightVec * inversesqrt(distSqr); vec3 vVec = normalize(eyeVec); vec4 base = texture2D(colorMap, texCoord); vec3 bump = normalize(texture2D(normalMap, texCoord).xyz * 2.0 - 1.0); vec4 vAmbient = gl_LightSource[0].ambient * gl_FrontMaterial.ambient; vec4 final_color = vAmbient*base; float diffuse = dot(lVec, bump); if(diffuse>0.0) { vec4 vDiffuse = gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * diffuse; float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), gl_FrontMaterial.shininess ); //float specular = 0.0; vec4 vSpecular = gl_LightSource[0].specular * gl_FrontMaterial.specular *specular; final_color += (vDiffuse*base + vSpecular) * att; } gl_FragColor = final_color; } ]]></raw_data> </shader_program> <!-- A little bit of interactivity: swap the mesh plane polygon rendering mode. --> <script name="switch_polygon_mode" run_mode="ASYNCHRONOUS" > <raw_data><![CDATA[ if( g_mode==NIL ) then g_mode=0; end WIREFRAME = 1; SOLID = 2; if( g_mode==1 ) then HYP_Object.SetPolygonMode( "mesh_plane", SOLID ); g_mode=0; else HYP_Object.SetPolygonMode( "mesh_plane", WIREFRAME ); g_mode=1; end ]]></raw_data> </script> <hotkey name="space_key" script="switch_polygon_mode" key="KEY_SPACE" /> <!-- Display some information / commands --> <font name="myFontArial12" render="TRUE" ttf_name="Arial" size="14" > <text_2d> <color r="1.0" g="1.0" b="0.0" /> <position x="10" y="30" /> <text text="Vertex Displacement Mapping Demo" /> </text_2d> <text_2d> <color r="1.0" g="1.0" b="0.0" /> <position x="10" y="50" /> <text text="Controls:" /> </text_2d> <text_2d> <color r="1.0" g="1.0" b="0.0" /> <position x="20" y="70" /> <text text="> SPACE: switch polygon mode (WIREFRAME/SOLID)" /> </text_2d> </font> </hyperion>
3D
演示平臺上使用.<?xml version="1.0" encoding="Windows-1252" standalone="yes"?> <!-- ============================================================================== AUTHOR: JeGX - jegx@ozone3d.net DATE: 10.03.2006 PURPOSE: Vertex Displacement Mapping Demo. TUTORIAL: http://www.ozone3d.net/tutorials/vertex_displacement_mapping.php ==================================== \==:: http://www.oZone3D.Net ::==/ =============================== ============================================================================== --> <hyperion version_major="1" version_minor="2" > <!-- The Scene! --> <scene name="displacement_mapping_demo" display_fps="TRUE" show_ref_grid="TRUE" vsync="TRUE" > <infos_color r="1.0" g="1.0" b="1.0" /> <window_size width="1024" height="768" /> <background_color r="0.3" g="0.0" b="0.0" /> <background_image image="data/stars.gif" /> <!-- Check the GLSL support and the number of vertex shader texture units we need in this demo. --> <check_hardware_caps glsl="TRUE" vs_tex_samplers="1" error_message="Sorry, this demo requires a Shader Model 3.0 (for vertex texture fetching) complient graphics controller. Demo startup failed. Bye..." /> </scene> <!-- Setup an EXAMINE camera. --> <camera name="myCamera" fov="60.0" navigation_mode="EXAMINE" > <position x="-143.41" y="218.55" z="241.49" /> <orientation pitch="30.0" yaw="120.0" /> </camera> <!-- The base map (or color map) --> <texture name="colorMap" filename="data/throbber.avi" pixel_format="RGB" > <size width="256" height="256" /> </texture> <!-- The displacement map. Note the RGBA_32F pixel format and the filtering mode (NONE==nearest). This is mandatory for vertex texture fetching on today's hardware. --> <texture name="displacementMap" type="TEXTURE_2D" filename="data/throbber.avi" pixel_format="RGBA_32F" filtering_mode="NONE" addressing_mode="CLAMP" num_mipmaps="0" > <size width="256" height="256" /> </texture> <!-- The mesh plane's material. We have to create it in order to attach the displacement shader. --> <material name="plane_mat" shader_program_name="displacementShader" /> <!-- The mesh plane: 100*100*2 = 20000 polys. In order to get decent frame rate, do not forget to set the VBO state... --> <mesh render="TRUE" name="mesh_plane" shape_type="PLANE" texturing="TRUE" lighting="FALSE" polygon_mode="SOLID" use_vbo="TRUE" back_face_culling="FALSE" > <plane x_size="400.0" z_size="400.0" num_segs_x="100" num_segs_z="100" /> <position x="0.0" y="0.0" z="0.0" /> <orientation pitch="0.0" /> <attach_material name="plane_mat" /> <!-- The displacement map on texture unit 0. --> <texture texture_name="displacementMap" material_name="plane_mat" texture_unit="0" u_tile="1.0" v_tile="1.0" /> <!-- The color map on texture unit 1. --> <texture texture_name="colorMap" material_name="plane_mat" texture_unit="1" u_tile="1.0" v_tile="1.0" /> </mesh> <!-- The displacement shader. --> <shader_program name="displacementShader" > <constant_1i name="displacementMap" value="0" /> <constant_1i name="colorMap" value="1" /> <constant_1f name="time" value="0.0" /> <raw_data><![CDATA[ [Vertex_Shader] uniform sampler2D displacementMap; #define textureSize 256.0 #define texelSize 1.0 / 256.0 vec4 tex2D_bilinear( uniform sampler2D tex, vec2 t ) { vec2 f = fract( t.xy * textureSize ); vec4 t00 = texture2D( tex, t ); vec4 t10 = texture2D( tex, t + vec2( texelSize, 0.0 )); vec4 tA = mix( t00, t10, f.x ); vec4 t01 = texture2D( tex, t + vec2( 0.0, texelSize ) ); vec4 t11 = texture2D( tex, t + vec2( texelSize, texelSize ) ); vec4 tB = mix( t01, t11, f.x ); return mix( tA, tB, f.y ); } void main(void) { vec4 displacedVertexPos; vec4 displacementVec; float f; gl_TexCoord[0].xy = gl_MultiTexCoord0.xy; //displacementVec = texture2D(displacementMap, gl_MultiTexCoord1.xy); displacementVec = tex2D_bilinear(displacementMap, gl_MultiTexCoord1.xy); f = (0.30*displacementVec.x + 0.59*displacementVec.y + 0.11*displacementVec.z); displacedVertexPos = vec4(gl_Normal * f * 100.0, 0.0) + gl_Vertex; gl_Position = gl_ModelViewProjectionMatrix * displacedVertexPos; } [Pixel_Shader] uniform sampler2D colorMap; void main(void) { gl_FragColor = texture2D(colorMap, gl_TexCoord[0].xy); } ]]></raw_data> </shader_program> <!-- Update time uniform variable for the displacement shader. --> <script name="update_scene" run_mode="EXECUTE_EACH_FRAME" > <raw_data><![CDATA[ elapsed_time = HYP_GetElapsedTime() * 0.001; HYP_GPUShader.SetConstant_1f( "displacementShader", "time", elapsed_time ); ]]></raw_data> </script> <!-- A little bit of interactivity: swap the mesh plane polygon rendering mode. --> <script name="switch_polygon_mode" run_mode="ASYNCHRONOUS" > <raw_data><![CDATA[ if( g_mode==NIL ) then g_mode=0; end WIREFRAME = 1; SOLID = 2; if( g_mode==1 ) then HYP_Object.SetPolygonMode( "mesh_plane", SOLID ); g_mode=0; else HYP_Object.SetPolygonMode( "mesh_plane", WIREFRAME ); g_mode=1; end ]]></raw_data> </script> <hotkey name="space_key" script="switch_polygon_mode" key="KEY_SPACE" /> <!-- The white rectangle under the hud. --> <hud name="under_nova" texturing="FALSE" > <size width="220" height="220" /> <position x="380" y="250" /> </hud> <!-- The hud that displays the small image. --> <hud name="nova" > <texture texture_name="colorMap" texture_unit="0" /> <size width="200" height="200" /> <position x="380" y="250" /> </hud> <!-- Display some information / commands --> <font name="myFontArial12" render="TRUE" ttf_name="Arial" size="14" > <text_2d> <color r="1.0" g="1.0" b="0.0" /> <position x="10" y="30" /> <text text="Vertex Displacement Mapping Demo" /> </text_2d> <text_2d> <color r="1.0" g="1.0" b="0.0" /> <position x="10" y="50" /> <text text="Controls:" /> </text_2d> <text_2d> <color r="1.0" g="1.0" b="0.0" /> <position x="20" y="70" /> <text text="> SPACE: switch polygon mode (WIREFRAME/SOLID)" /> </text_2d> </font> </hyperion>