Parallax mapping(视差映射)是凹凸映射的一种,同样,这里只是在OGRE里面实现,不讲原理.我会写个DX版本的parallax mappiing,到时候再讲原理,敬请期待!
/*------------------------------------------------------------
main.cpp -- Achieve parallax mapping in OGRE
(c) Seamanj.2013/7/27
------------------------------------------------------------*/
//Phase1 : Add Framework
//Phase2 : Add knot.mesh
//Phase3 : Add Light
//Phase4 : Move Light
#define Phase1 1
#define Phase2 1
#define Phase3 1
#define Phase4 1
#if Phase1
#include "ExampleApplication.h"
#include <windows.h>
#if Phase4
class MyFrameListener : public ExampleFrameListener
{
public:
MyFrameListener(RenderWindow* win, Camera* cam, SceneNode* LightPivot)
: ExampleFrameListener(win, cam), lightPivot(LightPivot)
{
}
bool frameRenderingQueued(const FrameEvent& evt)
{
lightPivot->roll(Degree(evt.timeSinceLastFrame * 30));
if(mWindow->isClosed())
return false;
return ExampleFrameListener::frameRenderingQueued(evt);
}
protected:
SceneNode* lightPivot;
};
#endif
class MyApplication : public ExampleApplication
{
#if Phase3
protected:
SceneNode* m_LightPivot;
#endif
#if Phase4
Ogre::FrameListener* FrameListener;
#endif
public:
MyApplication()
{}
~MyApplication()
{}
protected:
void createScene()
{
#if Phase2
// load each mesh with non-default hardware buffer usage options
MeshPtr mesh = MeshManager::getSingleton().load("knot.mesh", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
// build tangent vectors for our mesh
unsigned short src, dest;
if (!mesh->suggestTangentVectorBuildParams(VES_TANGENT, src, dest))
{
mesh->buildTangentVectors(VES_TANGENT, src, dest);
// this version cleans mirrored and rotated UVs but requires quality models
// mesh->buildTangentVectors(VES_TANGENT, src, dest, true, true);
}
Entity* ent = mSceneMgr->createEntity(mesh->getName(), mesh->getName());
ent->setMaterialName("Examples/OffsetMapping/Specular");//知识点1
/*知识点1:视差映射材质
---------------------------------------------
来自ogre_src_v1-7-4\Samples\Media\materials\scripts\OffsetMapping.material文件
---------------------------------------------
// Bump map with Parallax offset vertex program, support for this is required
vertex_program Examples/OffsetMappingVP cg
{
source OffsetMapping.cg
entry_point main_vp
profiles vs_1_1 arbvp1
}
// Bump map with parallax fragment program
fragment_program Examples/OffsetMappingFP cg
{
source OffsetMapping.cg
entry_point main_fp
profiles ps_2_0 arbfp1
}
// Bump map with parallax fragment program
fragment_program Examples/OffsetMappingPS asm
{
source OffsetMapping_specular.asm
// sorry, only for ps_1_4 and above:)
syntax ps_1_4
}
material Examples/OffsetMapping/Specular
{
// This is the preferred technique which uses both vertex and
// fragment programs, supports coloured lights
technique
{
// ambient / depth
pass
{
illumination_stage ambient
vertex_program_ref Ogre/BasicVertexPrograms/AmbientOneTexture
{
}
}
// do the lighting and bump mapping with parallax pass
pass
{
illumination_stage per_light
scene_blend add
depth_write off
// Vertex program reference
vertex_program_ref Examples/OffsetMappingVP
{
param_named_auto lightPosition light_position_object_space 0
param_named_auto eyePosition camera_position_object_space
param_named_auto worldViewProj worldviewproj_matrix
}
// Fragment program
fragment_program_ref Examples/OffsetMappingFP
{
param_named_auto lightDiffuse light_diffuse_colour 0
param_named_auto lightSpecular light_specular_colour 0
// Parallax Height scale and bias
param_named scaleBias float4 0.04 -0.02 1 0
}
// Normal + height(alpha) map
texture_unit
{
texture rockwall_NH.tga
tex_coord_set 0
}
// Base diffuse texture map
texture_unit
{
texture rockwall.tga
tex_coord_set 1
}
}
}
// This is the preferred technique which uses both vertex and
// fragment programs, supports coloured lights
technique
{
// do the lighting and bump mapping with parallax pass
pass
{
// Vertex program reference
vertex_program_ref Examples/OffsetMappingVP
{
param_named_auto lightPosition light_position_object_space 0
param_named_auto eyePosition camera_position_object_space
param_named_auto worldViewProj worldviewproj_matrix
}
// Fragment program
fragment_program_ref Examples/OffsetMappingPS
{
param_indexed_auto 0 light_diffuse_colour 0
param_indexed_auto 1 light_specular_colour 0
// Parallax Height scale and bias
param_indexed 2 float4 0.04 -0.02 1 0
}
// Normal + height(alpha) map
texture_unit
{
texture rockwall_NH.tga
tex_coord_set 0
}
// Base diffuse texture map
texture_unit
{
texture rockwall.tga
tex_coord_set 1
}
}
}
// Simple no-shader fallback
technique
{
pass
{
// Base diffuse texture map
texture_unit
{
texture rockwall.tga
}
}
}
}
*/
/*知识点2:视差映射shader
---------------------------------------------
来自ogre_src_v1-7-4\Samples\Media\materials\programs\Example_BumpMapping.cg文件
---------------------------------------------
Bump mapping vertex program
In this program, we want to calculate the tangent space light vector
on a per-vertex level which will get passed to the fragment program,
or to the fixed function dot3 operation, to produce the per-pixel
lighting effect.
void main_vp(float4 position : POSITION,
float3 normal : NORMAL,
float2 uv : TEXCOORD0,
float4 tangent : TANGENT0,
// outputs
out float4 oPosition : POSITION,
out float2 oUv : TEXCOORD0,
out float3 oTSLightDir : TEXCOORD1,
// parameters
uniform float4 lightPosition, // object space
uniform float4x4 worldViewProj)
{
// calculate output position
oPosition = mul(worldViewProj, position);
// pass the main uvs straight through unchanged
oUv = uv;
// calculate tangent space light vector
// Get object space light direction
// Non-normalised since we'll do that in the fragment program anyway
float3 lightDir = lightPosition.xyz - (position * lightPosition.w);
// Calculate the binormal (NB we assume both normal and tangent are
// already normalised)
// NB looks like nvidia cross params are BACKWARDS to what you'd expect
// this equates to NxT, not TxN
#if TANGENTS_HAVE_PARITY
float3 binormal = cross(tangent.xyz, normal) * tangent.www;
#else
// fixed handedness
float3 binormal = cross(tangent.xyz, normal);
#endif
// Form a rotation matrix out of the vectors
float3x3 rotation = float3x3(tangent.xyz, binormal, normal);
// Transform the light vector according to this matrix
oTSLightDir = mul(rotation, lightDir);
}
void main_fp( float2 uv : TEXCOORD0,
float3 TSlightDir : TEXCOORD1,
out float4 colour : COLOR,
uniform float4 lightDiffuse,
uniform sampler2D normalMap : register(s0))
{
// retrieve normalised light vector, expand from range-compressed
float3 lightVec = normalize(TSlightDir).xyz;
// get bump map vector, again expand from range-compressed
float3 bumpVec = expand(tex2D(normalMap, uv).xyz);
// Calculate dot product
colour = lightDiffuse * dot(bumpVec, lightVec);
}
*/
mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
#endif
#if Phase3
mSceneMgr->setAmbientLight(ColourValue::Black); // disable ambient lighting
m_LightPivot = mSceneMgr->getRootSceneNode()->createChildSceneNode();
// create white light
Light* l = mSceneMgr->createLight();
l->setPosition(200, 0, 0);
l->setDiffuseColour(1, 1, 1);
l->setSpecularColour(1, 1, 1);
// create white flare
BillboardSet* bbs = mSceneMgr->createBillboardSet();
bbs->setMaterialName("Examples/Flare");
bbs->createBillboard(200, 0, 0)->setColour(ColourValue::White);
m_LightPivot->attachObject(l);
m_LightPivot->attachObject(bbs);
#endif
}
#if Phase4
void createFrameListener()
{
FrameListener = new MyFrameListener(mWindow, mCamera, m_LightPivot);
mRoot->addFrameListener(FrameListener);
}
#endif
};
INT WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
MyApplication app;
try
{
app.go();
}
catch( Exception& e)
{
MessageBoxA( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
}
return 0;
}
#endif
/*rockwall.tga
---------------------------------------------
来自ogre_src_v1-7-4\Samples\Media\materials\textures
---------------------------------------------
*/
/*rockwall_NH.tga
---------------------------------------------
来自ogre_src_v1-7-4\Samples\Media\materials\textures
---------------------------------------------
*/
最终运行结果:
来个近写