1
// Copyright (C) 2002-2011 Nikolaus Gebhardt
2
// This file is part of the "Irrlicht Engine".
3
// For conditions of distribution and use, see copyright notice in irrlicht.h
5
#include "IrrCompileConfig.h"
6
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
8
#include "CD3D9NormalMapRenderer.h"
9
#include "IVideoDriver.h"
10
#include "IMaterialRendererServices.h"
19
// 1.1 Shaders with two lights and vertex based attenuation
21
// Irrlicht Engine D3D9 render path normal map vertex shader
22
const char D3D9_NORMAL_MAP_VSH[] =
23
";Irrlicht Engine 0.8 D3D9 render path normal map vertex shader\n"\
24
"; c0-3: Transposed world matrix \n"\
25
"; c8-11: Transposed worldViewProj matrix (Projection * View * World) \n"\
26
"; c12: Light01 position \n"\
27
"; c13: x,y,z: Light01 color; .w: 1/LightRadius� \n"\
28
"; c14: Light02 position \n"\
29
"; c15: x,y,z: Light02 color; .w: 1/LightRadius� \n"\
31
"dcl_position v0 ; position \n"\
32
"dcl_normal v1 ; normal \n"\
33
"dcl_color v2 ; color \n"\
34
"dcl_texcoord0 v3 ; texture coord \n"\
35
"dcl_texcoord1 v4 ; tangent \n"\
36
"dcl_texcoord2 v5 ; binormal \n"\
38
"def c95, 0.5, 0.5, 0.5, 0.5 ; used for moving light vector to ps \n"\
40
"m4x4 oPos, v0, c8 ; transform position to clip space with worldViewProj matrix\n"\
42
"m3x3 r5, v4, c0 ; transform tangent U\n"\
43
"m3x3 r7, v1, c0 ; transform normal W\n"\
44
"m3x3 r6, v5, c0 ; transform binormal V\n"\
46
"m4x4 r4, v0, c0 ; vertex into world position\n"\
47
"add r2, c12, -r4 ; vtxpos - lightpos1\n"\
48
"add r3, c14, -r4 ; vtxpos - lightpos2\n"\
50
"dp3 r8.x, r5, r2 ; transform the light vector 1 with U, V, W\n"\
51
"dp3 r8.y, r6, r2 \n"\
52
"dp3 r8.z, r7, r2 \n"\
53
"dp3 r9.x, r5, r3 ; transform the light vector 2 with U, V, W\n"\
54
"dp3 r9.y, r6, r3 \n"\
55
"dp3 r9.z, r7, r3 \n"\
57
"dp3 r8.w, r8, r8 ; normalize light vector 1 (r8)\n"\
59
"mul r8, r8, r8.w \n"\
60
"dp3 r9.w, r9, r9 ; normalize light vector 2 (r9)\n"\
62
"mul r9, r9, r9.w \n"\
64
"mad oT2.xyz, r8.xyz, c95, c95 ; move light vector 1 from -1..1 into 0..1 \n"\
65
"mad oT3.xyz, r9.xyz, c95, c95 ; move light vector 2 from -1..1 into 0..1 \n"\
67
" ; calculate attenuation of light 1 \n"\
68
"dp3 r2.x, r2.xyz, r2.xyz ; r2.x = r2.x� + r2.y� + r2.z� \n"\
69
"mul r2.x, r2.x, c13.w ; r2.x * attenutation \n"\
70
"rsq r2, r2.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
71
"mul oD0, r2, c13 ; resulting light color = lightcolor * attenuation \n"\
73
" ; calculate attenuation of light 2 \n"\
74
"dp3 r3.x, r3.xyz, r3.xyz ; r3.x = r3.x� + r3.y� + r3.z� \n"\
75
"mul r3.x, r3.x, c15.w ; r2.x * attenutation \n"\
76
"rsq r3, r3.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
77
"mul oD1, r3, c15 ; resulting light color = lightcolor * attenuation \n"\
79
"mov oT0.xy, v3.xy ; move out texture coordinates 1\n"\
80
"mov oT1.xy, v3.xy ; move out texture coordinates 2\n"\
81
"mov oD0.a, v2.a ; move out original alpha value \n"\
84
// Irrlicht Engine D3D9 render path normal map pixel shader
85
const char D3D9_NORMAL_MAP_PSH_1_1[] =
86
";Irrlicht Engine 0.8 D3D9 render path normal map pixel shader\n"\
88
";t0: color map texture coord \n"\
89
";t1: normal map texture coords \n"\
90
";t2: light 1 vector in tangent space \n"\
91
";v0: light 1 color \n"\
92
";t3: light 2 vector in tangent space \n"\
93
";v1: light 2 color \n"\
94
";v0.a: vertex alpha value \n"\
96
"tex t0 ; sample color map \n"\
97
"tex t1 ; sample normal map\n"\
98
"texcoord t2 ; fetch light vector 1\n"\
99
"texcoord t3 ; fetch light vector 2\n"\
101
"dp3_sat r0, t1_bx2, t2_bx2 ; normal dot light 1 (_bx2 because moved into 0..1)\n"\
102
"mul r0, r0, v0 ; luminance1 * light color 1 \n"\
104
"dp3_sat r1, t1_bx2, t3_bx2 ; normal dot light 2 (_bx2 because moved into 0..1)\n"\
105
"mad r0, r1, v1, r0 ; (luminance2 * light color 2) + luminance 1 \n"\
107
"mul r0.xyz, t0, r0 ; total luminance * base color\n"\
108
"+mov r0.a, v0.a ; write interpolated vertex alpha value \n"\
112
// Higher-quality normal map pixel shader (requires PS 2.0)
113
// uses per-pixel normalization for improved accuracy
114
const char D3D9_NORMAL_MAP_PSH_2_0[] =
115
";Irrlicht Engine 0.8 D3D9 render path normal map pixel shader\n"\
117
";t0: color map texture coord \n"\
118
";t1: normal map texture coords \n"\
119
";t2: light 1 vector in tangent space \n"\
120
";v0: light 1 color \n"\
121
";t3: light 2 vector in tangent space \n"\
122
";v1: light 2 color \n"\
123
";v0.a: vertex alpha value \n"\
126
"def c0, 0, 0, 0, 0\n"\
127
"def c1, 1.0, 1.0, 1.0, 1.0\n"\
128
"def c2, 2.0, 2.0, 2.0, 2.0\n"\
129
"def c3, -.5, -.5, -.5, -.5\n"\
139
"texld r0, t0, s0 ; sample color map into r0 \n"\
140
"texld r4, t0, s1 ; sample normal map into r4\n"\
141
"add r4, r4, c3 ; bias the normal vector\n"\
142
"add r5, t2, c3 ; bias the light 1 vector into r5\n"\
143
"add r6, t3, c3 ; bias the light 2 vector into r6\n"\
145
"nrm r1, r4 ; normalize the normal vector into r1\n"\
146
"nrm r2, r5 ; normalize the light1 vector into r2\n"\
147
"nrm r3, r6 ; normalize the light2 vector into r3\n"\
149
"dp3 r2, r2, r1 ; let r2 = normal DOT light 1 vector\n"\
150
"max r2, r2, c0 ; clamp result to positive numbers\n"\
151
"mul r2, r2, v0 ; let r2 = luminance1 * light color 1 \n"\
153
"dp3 r3, r3, r1 ; let r3 = normal DOT light 2 vector\n"\
154
"max r3, r3, c0 ; clamp result to positive numbers\n"\
156
"mad r2, r3, v1, r2 ; let r2 = (luminance2 * light color 2) + (luminance2 * light color 1) \n"\
158
"mul r2, r2, r0 ; let r2 = total luminance * base color\n"\
159
"mov r2.w, v0.w ; write interpolated vertex alpha value \n"\
161
"mov oC0, r2 ; copy r2 to the output register \n"\
166
CD3D9NormalMapRenderer::CD3D9NormalMapRenderer(
167
IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
168
s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial)
169
: CD3D9ShaderMaterialRenderer(d3ddev, driver, 0, baseMaterial)
172
setDebugName("CD3D9NormalMapRenderer");
175
// set this as callback. We could have done this in
176
// the initialization list, but some compilers don't like it.
180
// basically, this thing simply compiles the hardcoded shaders
181
// if the hardware is able to do them, otherwise it maps to the
184
if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) ||
185
!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
187
// this hardware is not able to do shaders. Fall back to
189
outMaterialTypeNr = driver->addMaterialRenderer(this);
193
// check if already compiled normal map shaders are there.
195
video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_NORMAL_MAP_SOLID);
198
// use the already compiled shaders
199
video::CD3D9NormalMapRenderer* nmr = (video::CD3D9NormalMapRenderer*)renderer;
200
VertexShader = nmr->VertexShader;
202
VertexShader->AddRef();
204
PixelShader = nmr->PixelShader;
206
PixelShader->AddRef();
208
outMaterialTypeNr = driver->addMaterialRenderer(this);
212
// compile shaders on our own
213
if (driver->queryFeature(video::EVDF_PIXEL_SHADER_2_0))
215
init(outMaterialTypeNr, D3D9_NORMAL_MAP_VSH, D3D9_NORMAL_MAP_PSH_2_0);
219
init(outMaterialTypeNr, D3D9_NORMAL_MAP_VSH, D3D9_NORMAL_MAP_PSH_1_1);
222
// something failed, use base material
223
if (-1==outMaterialTypeNr)
224
driver->addMaterialRenderer(this);
228
CD3D9NormalMapRenderer::~CD3D9NormalMapRenderer()
230
if (CallBack == this)
235
bool CD3D9NormalMapRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
237
if (vtxtype != video::EVT_TANGENTS)
239
os::Printer::log("Error: Normal map renderer only supports vertices of type EVT_TANGENTS", ELL_ERROR);
243
return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype);
247
//! Returns the render capability of the material.
248
s32 CD3D9NormalMapRenderer::getRenderCapability() const
250
if (Driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
251
Driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
258
//! Called by the engine when the vertex and/or pixel shader constants
259
//! for an material renderer should be set.
260
void CD3D9NormalMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData)
262
video::IVideoDriver* driver = services->getVideoDriver();
264
// set transposed world matrix
265
services->setVertexShaderConstant(driver->getTransform(video::ETS_WORLD).getTransposed().pointer(), 0, 4);
267
// set transposed worldViewProj matrix
268
core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION));
269
worldViewProj *= driver->getTransform(video::ETS_VIEW);
270
worldViewProj *= driver->getTransform(video::ETS_WORLD);
271
services->setVertexShaderConstant(worldViewProj.getTransposed().pointer(), 8, 4);
273
// here we've got to fetch the fixed function lights from the
274
// driver and set them as constants
276
u32 cnt = driver->getDynamicLightCount();
278
for (u32 i=0; i<2; ++i)
283
light = driver->getDynamicLight(i);
286
light.DiffuseColor.set(0,0,0); // make light dark
290
light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation
292
services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.Position), 12+(i*2), 1);
293
services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.DiffuseColor), 13+(i*2), 1);
296
// this is not really necessary in d3d9 (used a def instruction), but to be sure:
297
f32 c95[] = {0.5f, 0.5f, 0.5f, 0.5f};
298
services->setVertexShaderConstant(c95, 95, 1);
302
} // end namespace video
303
} // end namespace irr
305
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_