I'm doing actual normal mapping (not emboss bump) by adding 2D normals to 2D offsets. But even then you've got several methods to provide the data to the HW.
Assuming you have read the emboss mapping patent, the easiest and most fast method is as follows:
* Create a light bulb texture. Note that the bulb's origin is at 0,0 in the texture, so you can just take one quadrant and mirror. It is required that the bulb's radius is 1/8th of the texture size (so if you create a 64x64 texture, the bulb's radius can only be 8 pixels, which BTW results in only 8 intensity shades)
* Setup vtx desc
Code: Select all
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_NBT, GX_NRM_NBT3, GX_F32, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); // normal map
* Add normal, tangent and bitangent to vertex data (provide them as GX_Normal3f32 in your vertex data). For this example you must scale tangent and bitangent to 1/8 of the unit lenght.
Code: Select all
GX_Position3f32(-1.0f,-1.0f, 0.0f);
GX_Normal3f32 ( 0.0f, 0.0f, 1.0f);
GX_Normal3f32 ( 0.125f, 0.0f, 0.0f);
GX_Normal3f32 ( 0.0f, 0.125f, 0.0f);
GX_TexCoord2f32(0.0f,1.0f);
* Setup a HW light (see examples in devkitpro)
* Setup a texture coordinate that always renders to (0,0) (you can use a null texmtx)
Code: Select all
Mtx nullMtx =
{{ 0.0f, 0.0f, 0.0f, 0.0f},
{ 0.0f, 0.0f, 0.0f, 0.0f},
{ 0.0f, 0.0f, 0.0f, 0.0f}};
GX_LoadTexMtxImm(nullMtx, GX_TEXMTX0, GX_MTX3x4);
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); // normal map
GX_SetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0); // (0,0)
* Setup a bumped coordinate based on the (0,0) coordinate and your HW light (setup the number of texgens to the proper value!!!)
Code: Select all
GX_SetTexCoordGen(GX_TEXCOORD2, GX_TG_BUMP0, GX_TG_TEXCOORD1, GX_IDENTITY);
* Setup a indirect stage to read normal map. Note: up to now I have been using RGB565 as normal map format. In that case, the indirect unit can only read Green and Blue color channels. So, when you use this format you MUST convert your RGB normalmaps so that the blue channel contains the normal's X value and the green channel contains the Y value. The Z value is not required since this technique is based on a 2D calculation. I haven't tried RGB8 format yet, since I wasn't aware of the data order at that time.
Code: Select all
GX_SetIndTexOrder(GX_INDTEXSTAGE0,GX_TEXCOORD0,GX_TEXMAP0);
GX_SetIndTexCoordScale(GX_INDTEXSTAGE0,GX_ITS_1,GX_ITS_1); // normal map texture scale 1:1
// setup indirect unit for tev stage 0 (for some reason I get a ABGR triplet, so transforms are done on normal map's B and G components)
f32 offset_mtx[2][3] = {
{ 0.0f, -0.125f, 0.0f}, // B -> horizontal coordinate (s)
{ 0.0f, 0.0f, -0.125f} // G -> vertical coordinate (t)
};
GX_SetNumIndStages(1);
GX_SetIndTexMatrix(GX_ITM_0, offset_mtx, 0);
* Setup the indirect stage to add the bumped coordinate
Code: Select all
GX_SetTevIndirect(
tevstage, // tevstage 0 is used to combine normal map and lightmap
GX_INDTEXSTAGE0, // ind stage is used to read normal map
GX_ITF_8, // texture format 8 bits per channel
GX_ITB_STU, // use bias on s and t channels (red and green and blue)
GX_ITM_0, // use 3x2 matrix 0
GX_ITW_OFF, // do not use texture wrapping
GX_ITW_OFF, // do not use texture wrapping
GX_FALSE, // don't add in previous coordinates
GX_FALSE, // don't use mipmap stuff
GX_ITBA_OFF // don't use bump alpha
);
* setup tevstage to use the resulting indirect texture coordinates to lookup the light bulb texture. This actually determines the light intensity.
Code: Select all
GX_SetTevKColorSel(tevstage, GX_TEV_KCSEL_1_8); // ambient intensity
GX_SetTevColorIn(tevstage, GX_CC_ZERO, GX_CC_TEXC, GX_CC_ONE, GX_CC_KONST);
GX_SetTevColorOp(tevstage, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevOrder(tevstage, GX_TEXCOORD2, GX_TEXMAP1, GX_COLORNULL);
* Bind lightmap texture to TEXMAP1 and normalmap to TEXMAP0
* Add a stage that multiplies TEVPREV with material texture. You can SCALE the value by 2 to create bright lighting. Don't forget to set the proper number of tevstages
This is about it. If you continue thinking in this line it gets obvious that you can also add reflection/specular by adding an additional stage. You can also add an extra stage to perform backface culling from the light's point of view.
However, a disadvantage of using bump coordinates is that you get artifacts at T junctions. To solve that, you can use DTT to project the light's position to the polygon and use those values (a bit harder and requires a few CPU cycles).
have fun!
Edit: forgot about setting the normal mtx before you start sending vertex data:
Code: Select all
GX_LoadNrmMtxImm(modelview, GX_PNMTX0);
GX_SetCurrentMtx(GX_PNMTX0);