Specular reflections aren't working right

I'm having a problem with specular reflection.  It flickers as I move around my object.

Sometimes when I'm looking at a face, and I swivel the camera just a few degrees, I get specular reflection.  When I swivel a few more, the reflection is gone - leading to the flicker.

But specular reflection is only based on the position of the camera, not the direction it's looking.  So it confuses me that swiveling the camera would change the specular reflection in any way, much less so drastically.

Also, I find it confusing that I should see specular reflection at all from a face that receives no direct light.

It seems to only happen to faces whose normal is  perfectly perpendicular to the direction of the light.

I'd be very grateful if someone could help me solve this problem.  I've been at it for days, and it's driving me insane.

Thanks


Answer this question

Specular reflections aren't working right

  • Brent Lee

    In this case the mesh is a square face consisting of 2 triangles. So, 6 vertices in the XY plane z = -1, each with the same vertex normal, [0, 0, -1]

    The light direction is [1,0,0].

    I've tinkered with the power and specular color settings and I still see flicker. But it still doesn't seem right that you should see any specular reflection at all since the camera can't be at any position where direct light will be reflected back to the camera.

  • PCU

    You're right. I'm not sure what I compiled a few nights ago that didn't work, but this definately solves the problem.

    So kudos to you, because you're the only one on any of the forums that knew the answer and helped me out. Thanks.

  • Jay McG

    Such symptoms occur with high specular power values, along with badly tesselated meshes (meshes with many triangles not distributed uniformly)... Try relaxing the specular power value, and lower the specular color also...

  • Bruce MacKenzie

    Yes I saw the popping the first time. It's mostly a shortcoming from the fact that specular is calculated at the vertices only (rather than per pixel).
    But as I said, just pushing the power value to 15.0f solved the issue...

  • Rohit Wason

    Just modifying the specular power to 15.0f solved all the issues...

  • jslapp

    Using the same program I posted, except my material is now:

    D3DMATERIAL9 m;
    ::ZeroMemory(&m, sizeof(m));
    m.Specular.a = m.Specular.b = m.Specular.g = m.Specular.r = 1.0f;
    m.Power = 15.0f;


    I still see the same problem.

    Did you see the issue before you changed the power setting

  • McLean Schofield - MSFT

    Yeah, but I tried that, and I still noticed the flickering.

    Could you post the corrected code you used that fixed the problem

  • Santiago Cepas Lopez

    Ok, here's the functions that changed (had to play a little with the Animate function to increase interaction rate)...



    HRESULT CALLBACK DeviceReset( IDirect3DDevice9* pDevice, const D3DSURFACE_DESC* surface, void* )
    {
    pDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
    pDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);
    pDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
    pDevice->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);
    RecalcLook(pDevice);
    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(
    &proj,
    D3DX_PI / 4,
    (float)surface->Width / (float)surface->Height,
    1.0f,
    1000.0f);
    pDevice->SetTransform(D3DTS_PROJECTION, &proj);
    D3DLIGHT9 l;
    ::ZeroMemory(&l, sizeof(l));
    l.Type = D3DLIGHT_DIRECTIONAL;
    l.Ambient.a = l.Ambient.b = l.Ambient.g = l.Ambient.r = 1.0f;
    l.Diffuse = l.Ambient;
    l.Specular = l.Ambient;
    l.Direction = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
    pDevice->SetLight(0, &l);
    pDevice->LightEnable(0, TRUE);
    D3DMATERIAL9 m;
    ::ZeroMemory(&m, sizeof(m));
    m.Specular.a = m.Specular.b = m.Specular.g = m.Specular.r = 1.0f;
    m.Power = 15.0f;
    pDevice->SetMaterial(&m);
    return S_OK;
    }
    void CALLBACK Animate( IDirect3DDevice9* pDevice, double, float, void* )
    {
    float old = g_rot;
    if ( GetAsyncKeyState(VK_LCONTROL) & 0x800f ) {
    if ( GetAsyncKeyState('A') & 0x800f ) {
    g_rx -= 0.011f;
    }
    if ( GetAsyncKeyState('D') & 0x800f ) {
    g_rx += 0.011f;
    }
    if ( GetAsyncKeyState('W') & 0x800f ) {
    g_ry += 0.011f;
    }
    if ( GetAsyncKeyState('S') & 0x800f ) {
    g_ry -= 0.011f;
    }
    g_right = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
    g_up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
    g_look = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
    D3DXMATRIX m;
    D3DXMatrixRotationAxis(&m, &g_up, g_rx);
    D3DXVec3TransformCoord(&g_right, &g_right, &m);
    D3DXVec3TransformCoord(&g_look, &g_look, &m);
    D3DXMatrixRotationAxis(&m, &g_right, g_ry);
    D3DXVec3TransformCoord(&g_up, &g_up, &m);
    D3DXVec3TransformCoord(&g_look, &g_look, &m);
    RecalcLook(pDevice);
    }
    else {
    if ( GetAsyncKeyState('A') & 0x800f ) {
    g_pos -= g_right * 0.01f;
    RecalcLook(pDevice);
    }
    if ( GetAsyncKeyState('D') & 0x800f ) {
    g_pos += g_right * 0.01f;
    RecalcLook(pDevice);
    }
    if ( GetAsyncKeyState('W') & 0x800f) {
    if (GetAsyncKeyState(VK_LSHIFT) & 0x800f) {
    g_pos += g_up * 0.01f;
    RecalcLook(pDevice);
    }
    else {
    g_pos += g_look * 0.01f;
    RecalcLook(pDevice);
    }
    }
    if ( GetAsyncKeyState('S') & 0x800f) {
    if (GetAsyncKeyState(VK_LSHIFT) & 0x800f) {
    g_pos -= g_up * 0.01f;
    RecalcLook(pDevice);
    }
    else {
    g_pos -= g_look * 0.01f;
    RecalcLook(pDevice);
    }
    }
    }
    if ( GetAsyncKeyState(VK_RIGHT) ) {
    g_rot += 0.011f;
    }
    if ( GetAsyncKeyState(VK_LEFT) ) {
    g_rot -= 0.011f;
    }
    if (g_rot != old) {
    D3DXMATRIX m;
    D3DXMatrixRotationY(&m, g_rot);
    pDevice->SetTransform(D3DTS_WORLD, &m);
    }
    }



  • BlakeW

    Here's a sample app I prepared to demonstrate the problem:

    #include <windows.h>
    #include <d3d9.h>
    #include <d3dx9.h>
    #include <dxut.h>

    struct VERTEX {
    float x, y, z;
    float nx, ny, nz;
    };

    #define VERTEX_FVF (D3DFVF_XYZ | D3DFVF_NORMAL)

    IDirect3DVertexBuffer9* g_pVB;
    float g_rot = 0.0f;
    D3DXVECTOR3 g_pos(-5.0f, 0.0f, 0.0f);
    D3DXVECTOR3 g_right(0.0f, 0.0f, -1.0f);
    D3DXVECTOR3 g_up(0.0f, 1.0f, 0.0f);
    D3DXVECTOR3 g_look(1.0f, 0.0f, 0.0f);
    float g_rx = D3DX_PI / 2;
    float g_ry = 0.0f;

    HRESULT CALLBACK DeviceCreated( IDirect3DDevice9* pDevice, const D3DSURFACE_DESC* surface, void* )
    {
    VERTEX vertices[] = {
    // front
    { -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f },
    { -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f },
    { 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f },
    { -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f },
    { 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f },
    { 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f },
    // left size
    { -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f },
    { -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f },
    { -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f },
    { -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f },
    { -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f },
    { -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f },
    };

    pDevice->CreateVertexBuffer(sizeof(vertices), D3DUSAGE_WRITEONLY, VERTEX_FVF, D3DPOOL_MANAGED, &g_pVB, NULL);
    VERTEX* pBuffer;
    g_pVB->Lock(0, 0, reinterpret_cast<void**>(&pBuffer), 0);
    memcpy(pBuffer, vertices, sizeof(vertices));
    g_pVB->Unlock();

    return S_OK;
    }

    void RecalcLook(IDirect3DDevice9* pDevice)
    {
    D3DXVec3Normalize(&g_look, &g_look);
    D3DXVec3Cross(&g_up, &g_look, &g_right);
    D3DXVec3Normalize(&g_up, &g_up);
    D3DXVec3Cross(&g_right, &g_up, &g_look);
    D3DXVec3Normalize(&g_right, &g_right);

    float x = -D3DXVec3Dot(&g_right, &g_pos);
    float y = -D3DXVec3Dot(&g_up, &g_pos);
    float z = -D3DXVec3Dot(&g_look, &g_pos);

    D3DXMATRIX view;
    view(0, 0) = g_right.x;
    view(0, 1) = g_up.x;
    view(0, 2) = g_look.x;
    view(0, 3) = 0.0f;

    view(1, 0) = g_right.y;
    view(1, 1) = g_up.y;
    view(1, 2) = g_look.y;
    view(1, 3) = 0.0f;

    view(2, 0) = g_right.z;
    view(2, 1) = g_up.z;
    view(2, 2) = g_look.z;
    view(2, 3) = 0.0f;

    view(3, 0) = x;
    view(3, 1) = y;
    view(3, 2) = z;
    view(3, 3) = 1.0f;

    pDevice->SetTransform(D3DTS_VIEW, &view);
    }

    HRESULT CALLBACK DeviceReset( IDirect3DDevice9* pDevice, const D3DSURFACE_DESC* surface, void* )
    {
    pDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
    pDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);
    pDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
    pDevice->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);

    RecalcLook(pDevice);

    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(
    &proj,
    D3DX_PI / 4,
    (float)surface->Width / (float)surface->Height,
    1.0f,
    1000.0f);

    pDevice->SetTransform(D3DTS_PROJECTION, &proj);

    D3DLIGHT9 l;
    ::ZeroMemory(&l, sizeof(l));
    l.Type = D3DLIGHT_DIRECTIONAL;
    l.Ambient.a = l.Ambient.b = l.Ambient.g = l.Ambient.r = 1.0f;
    l.Diffuse = l.Ambient;
    l.Specular = l.Ambient;
    l.Direction = D3DXVECTOR3(0.0f, 0.0f, 1.0f);

    pDevice->SetLight(0, &l);
    pDevice->LightEnable(0, TRUE);

    D3DMATERIAL9 m;
    ::ZeroMemory(&m, sizeof(m));
    m.Specular.a = m.Specular.b = m.Specular.g = m.Specular.r = 1.0f;
    m.Power = 5.0f;

    pDevice->SetMaterial(&m);

    return S_OK;
    }

    void CALLBACK DeviceDestroyed(void*)
    {
    g_pVB->Release();
    }

    void CALLBACK Animate( IDirect3DDevice9* pDevice, double, float, void* )
    {
    float old = g_rot;

    if ( GetAsyncKeyState(VK_LCONTROL) & 0x800f ) {
    if ( GetAsyncKeyState('A') & 0x800f ) {
    g_rx -= 0.001f;
    }
    if ( GetAsyncKeyState('D') & 0x800f ) {
    g_rx += 0.001f;
    }
    if ( GetAsyncKeyState('W') & 0x800f ) {
    g_ry += 0.001f;
    }
    if ( GetAsyncKeyState('S') & 0x800f ) {
    g_ry -= 0.001f;
    }

    g_right = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
    g_up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
    g_look = D3DXVECTOR3(0.0f, 0.0f, 1.0f);

    D3DXMATRIX m;
    D3DXMatrixRotationAxis(&m, &g_up, g_rx);

    D3DXVec3TransformCoord(&g_right, &g_right, &m);
    D3DXVec3TransformCoord(&g_look, &g_look, &m);

    D3DXMatrixRotationAxis(&m, &g_right, g_ry);

    D3DXVec3TransformCoord(&g_up, &g_up, &m);
    D3DXVec3TransformCoord(&g_look, &g_look, &m);

    RecalcLook(pDevice);
    }
    else {
    if ( GetAsyncKeyState('A') & 0x800f ) {
    g_pos -= g_right * 0.01f;
    RecalcLook(pDevice);
    }
    if ( GetAsyncKeyState('D') & 0x800f ) {
    g_pos += g_right * 0.01f;
    RecalcLook(pDevice);
    }
    if ( GetAsyncKeyState('W') & 0x800f) {
    if (GetAsyncKeyState(VK_LSHIFT) & 0x800f) {
    g_pos += g_up * 0.01f;
    RecalcLook(pDevice);
    }
    else {
    g_pos += g_look * 0.01f;
    RecalcLook(pDevice);
    }
    }
    if ( GetAsyncKeyState('S') & 0x800f) {
    if (GetAsyncKeyState(VK_LSHIFT) & 0x800f) {
    g_pos -= g_up * 0.01f;
    RecalcLook(pDevice);
    }
    else {
    g_pos -= g_look * 0.01f;
    RecalcLook(pDevice);
    }
    }
    }
    if ( GetAsyncKeyState(VK_RIGHT) ) {
    g_rot += 0.001f;
    }
    if ( GetAsyncKeyState(VK_LEFT) ) {
    g_rot -= 0.001f;
    }

    if (g_rot != old) {
    D3DXMATRIX m;
    D3DXMatrixRotationY(&m, g_rot);

    pDevice->SetTransform(D3DTS_WORLD, &m);
    }
    }

    void CALLBACK Render( IDirect3DDevice9* pDevice, double, float, void* )
    {
    pDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, 0, 0, 0), 1.0f, 0);

    pDevice->BeginScene();

    pDevice->SetFVF(VERTEX_FVF);
    pDevice->SetStreamSource(0, g_pVB, 0, sizeof(VERTEX));
    pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 4);

    pDevice->EndScene();
    }

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, INT cmdShow)
    {
    DXUTInit();

    DXUTSetCallbackDeviceCreated(DeviceCreated);
    DXUTSetCallbackDeviceDestroyed(DeviceDestroyed);
    DXUTSetCallbackFrameRender(Render);
    DXUTSetCallbackDeviceReset(DeviceReset);
    DXUTSetCallbackFrameMove(Animate);

    DXUTCreateWindow();
    DXUTCreateDevice();

    DXUTMainLoop();
    }



  • SB1000

    Are you using fixed function lighting If you use a shader it were useful if you could post some code.

    Just a guess: maybe your normals are not correct or you don't transform them correctly.


  • Specular reflections aren't working right