翻译自: 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>