Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[Direct3D/HLSL] Shader wil niet werken op AMD's

Pagina: 1
Acties:

  • Orwell
  • Registratie: December 2009
  • Laatst online: 20-11 20:58
Goed, weer een eind verder met het project 'ik wil wel eens weten hoe 3D werkt'. Deze keer heb ik weer een probleem. De shaders hebben er geen zin in op Radeons. Jep, "Radeons". Je kunt gewoon met zekerheid stellen dat als je een Radeon hebt, de boel niet werkt:
  • NVIDIA GeForce 9600GT: 100% Pass.
  • NVIDIA GeForce GTX460: 100% Pass.
  • NVIDIA GeForce GT240M: 100% Pass.
  • ATI Radeon HD4800 Series (HD4870): Passes Vertex Shading, fails Pixel Shading.
  • ATI Radeon HD4800 Series (HD4890): Passes Vertex Shading, fails Pixel Shading.
  • AMD Radeon HD5700 Series (HD5770): Passes Vertex Shading, fails Pixel Shading.
  • Intel Q45 Express Chipset: Mostly Pass, but shows artifacts on interpolated surfaces or when using saturate() or lerp().
Per Vertex Shading werkt perfect op alle videokaarten:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
VS_OUTPUT_PERVERTEX VertexVS(float3 positionin : POSITION0,float2 coordin : TEXCOORD0,float3 normalin : NORMAL0) {
    VS_OUTPUT_PERVERTEX outVS = (VS_OUTPUT_PERVERTEX)0;

    // Standaard verwerking
    outVS.position = mul(float4(positionin,1.0f),WorldViewProj);
    outVS.coord = coordin;

    // Mul met lightpos, dan coords verschuiven, zodat we coords relatief aan licht op texels hebben
    outVS.projcoord = mul(mul(float4(positionin,1.0f), LightWorldViewProj),ShadowOffset);

    // Aangezien we per vertex een kleur geven, bereken dat laatste hier alvast
    float3 positionworld = mul(float4(positionin,1.0f),World);
    float3 normalworld = normalize(mul(normalin,(float3x3)World));
    float dist = distance(camerapos,positionworld);

    // En gooi het in de functies
    float3 diffuse = calculateDiffuse(normalworld,lightdir);

    // Tel het op zodat we kleurtje hebben van deze vertex
    outVS.color = diffuse + lightambient;
    outVS.fog = calculateFog(dist);
    
    // En stuur de boel naar Pixel Shader
    return outVS;
}

PS_OUTPUT VertexPS(float3 colorin : COLOR0,float2 coordin : TEXCOORD0,float4 projcoordin : TEXCOORD1,float fogin : FOG0) {
    PS_OUTPUT outPS = (PS_OUTPUT)0;

    // Functie
    float3 shadow = calculateShadowPCF(projcoordin);

    // En dan hebben we kleur
    float4 texColor = tex2D(DiffuseS, coordin);
    outPS.color.rgb = lerp(shadow*texColor.rgb*colorin,fogcolor,fogin);
    outPS.color.a = texColor.a;
    return outPS;
}


Maar zelfs de simpelste Per Pixel Shading werkt alleen op NVIDIA's:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
VS_OUTPUT_PERPIXEL PixelVS(float3 positionin : POSITION0,float2 coordin : TEXCOORD0,float3 normalin : NORMAL0) {
    VS_OUTPUT_PERPIXEL outVS = (VS_OUTPUT_PERPIXEL)0;

    // Standaard verwerking
    outVS.position = mul(float4(positionin,1.0f),WorldViewProj);
    outVS.positionworld = mul(float4(positionin,1.0f),World);
    outVS.normalworld = mul(normalin,(float3x3)World);
    outVS.coord = coordin;

    // Mul met lightpos, dan coords verschuiven, zodat we coords relatief aan licht op texels hebben
    outVS.projcoord = mul(mul(float4(positionin,1.0f), LightWorldViewProj),ShadowOffset);

    // En doorgeven aan de pixelshader, die per pixel de kleur berekent
    return outVS;
}

PS_OUTPUT PixelPS(float3 positionworldin : POSITION1,float3 normalworldin : NORMAL0,float2 coordin : TEXCOORD0,float4 projcoordin : TEXCOORD1) {
    PS_OUTPUT outPS = (PS_OUTPUT)0;

    // Prepwork voor functies
    normalworldin = normalize(normalworldin);
    float dist = distance(camerapos,positionworldin);

    // Functies
    float fog = calculateFog(dist);
    float3 diffuse = calculateDiffuse(normalworldin,lightdir);
    float3 shadow = calculateShadowPCF(projcoordin);

    // En dan eindelijk hebben we kleur
    float4 texColor = tex2D(DiffuseS, coordin);
    outPS.color.rgb = lerp(shadow*texColor.rgb*(diffuse + lightambient),fogcolor,fog);
    outPS.color.a = texColor.a;
    return outPS;
}


Aangezien ik alleen maar die 9600GT binnen bereik heb, kan ik niet even makkelijk een avondje de code langslopen. Met degene van de HD4890 ben ik nu dus via mail (dat werkt handig zeg :|) alles aan het langsgaan. Probeersels als: zet de kleur eens op float4(1,1,1,1), zet fog uit, zet schaduwen uit, etc.

Even een voorbeeld op NVIDIA's:
Afbeeldingslocatie: http://img819.imageshack.us/img819/1737/tweak.jpg
En op ATI's:
Afbeeldingslocatie: http://img703.imageshack.us/img703/2824/naamloosox.jpg
Jep, het dak en de plantenbakken. Die gebruiken Per Vertex. De rest (per pixel (normal)(specular)) is foetsie. Als ik naar het aantal triangles kijk, zie ik dat de draw calls (binnen view) wel uitgevoerd worden. Daardoor kloppen de framerates ook aardig.

Heb op internet verder niets kunnen vinden over bijvoorbeeld andere registers (of enig andere hack) op ATI's. Ook als ik zijn kaart zelf de *.fxo laat maken, gebeurt dit. Als ik met D3DXSHADER_DEBUG de output controleer, is alles goed.

De Intel is een verhaal apart in PerPixel. Die krijgt het niet eens voor elkaar om de interpolatie (tussen VS en PS) goed te doen. Heb er even geen screen van (die dingen hebben ze op school), maar de strepen en artifacts zitten overal overheen. Zelfde voor lerp(), wat net zo goed interpolatie is. Nog nooit zoiets vaags gezien. Maar het werkt beter dan op de ATI's. |:(

En omdat ik er niet meer uitkom, vraag ik het hier. Laten we hopen dat hier zat mensen zijn die Per Pixel Lighting wèl op ATI's aan de praat krijgen. ;)

Als er meer code nodig is, zegt het maar. Beetje huiverig om de hele zooi (ja, het is veel) hier te dumpen.

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 17-10 16:43
Heb je PIX al eens losgelaten op een computer met een ATI kaart? En welk programma gebruik je om de .fx bestanden te compilen? Ik zie dat je veel getest heb, maar wat heb je geprobeerd qua debugging? En hoe ziet je PS_OUT structure er uit? (Heb je die wel goed gedecoreerd met :COLOR0 enzo?)

~ Mijn prog blog!


  • Orwell
  • Registratie: December 2009
  • Laatst online: 20-11 20:58
Heb je PIX al eens losgelaten op een computer met een ATI kaart?
Helaas nog niet nee. Heb hier zelf wel NVIDIA PerfHUD in gebruik, maar 'k zal inderdaad eens PIX uitproberen. Altijd handig.
En welk programma gebruik je om de .fx bestanden te compilen?
Tijdens opstarten dit:

C++:
1
2
3
4
5
6
D3DXCreateEffectFromFile(d3ddev,"Data\\Shaders\\shaders.fx",0,0,D3DXSHADER_DEBUG,0,&FX,&error);
if(error) {
    MessageBox(hwnd,(char*)error->GetBufferPointer(),"Error",MB_ICONERROR);
} else {
    FX->GetVanAllesEnNogWatByName();
}


Wat dus neerkomt op:
Batchfile:
1
fxc.exe /T fx_2_0 /Fo shaders.fxo shaders.fx


Ze geven allebei niks bijzonders aan. De errorbuffer is leeg, en fxc sluit af zonder speciale meldingen. Ze genereren allebei dus een (zeggen ze) foutloze shaders.fxo. Je zou kunnen zeggen dat ik 'gewoon' D3DCompiler_43.dll op twee manieren gebruik.
Ik zie dat je veel getest heb, maar wat heb je geprobeerd qua debugging?
Van alles en nog wat. Zo'n beetje alles heb ik wel een keertje op 1.0f gezet zogezegd. Maar het helpt allemaal niet, want de vertices zijn er gewoon niet. Dan zou je gaan denken aan de Transform.

Die transform op zich werkt perfect op de CPU (om het bereik van de lichtbron in te stellen):

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void Renderer::getOptimalShadowMapSize() {
    xwidth = ywidth = 1.0f;

    // Maak een nepperd aan, zodat je kunt gaan berekenen
    D3DXMatrixLookAtLH(&matLightView, &lightdir, &lightlookat, &lightup);
    D3DXMatrixOrthoLH(&matLightProj,xwidth,ywidth,-1000.0f,1000.0f);

    for(int a = 0;a < nummodels-2;a++) {
        D3DXMATRIX matLightWorldViewProj = D3DXMATRIX(models[a].worldpos*matLightView*matLightProj);
        D3DXVECTOR4 screenpos;
        D3DXVECTOR3 worldpos = D3DXVECTOR3(models[a].worldpos._41,models[a].worldpos._42,models[a].worldpos._43);
        D3DXVec3Transform(&screenpos,&worldpos,&matLightWorldViewProj);
        
        if(fabsf(screenpos.x/2.0f) > xwidth) { // WAAROM CRASHT STD::ABS en FABS?
            xwidth = fabsf(screenpos.x/2.0f);
        }
        if(fabsf(screenpos.y/2.0f) > ywidth) { // WAAROM CRASHT STD::ABS en FABS?
            ywidth = fabsf(screenpos.y/2.0f);
        }
    }
    xwidth += 20.0f;
    ywidth += 20.0f;
}


Wat dus bewijst dat de gegevens die naar de GPU gaan werken. En dat is irritant, want het is nogal lastig om in de shaders te debuggen behalve wat variabeles op 1 of 0 zetten. En dit spul is nu net weer niet eventjes op 1 of 0 te zetten.
En hoe ziet je PS_OUT structure er uit? (Heb je die wel goed gedecoreerd met :COLOR0 enzo?)
Een beetje een zinloze struct, maar:
C++:
1
2
3
struct PS_OUTPUT {
    float4 color            : COLOR0;
};


Zou net zo goed van de functie zelf een float4 kunnen maken, maar goed, dit is tenminste niet fout.

En voor de volledigheid:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct VS_OUTPUT_PERPIXEL {
    float4 position         : POSITION0;
    float3 positionworld    : POSITION1;
    float3 normalworld      : NORMAL0;
    float2 coord            : TEXCOORD0;
    float4 projcoord        : TEXCOORD1;
};
struct VS_OUTPUT_PERVERTEX {
    float4 position         : POSITION0;
    float3 color            : COLOR0;
    float2 coord            : TEXCOORD0;
    float4 projcoord        : TEXCOORD1;
    float  fog              : FOG0;
};

[ Voor 3% gewijzigd door Orwell op 25-02-2011 13:25 ]