HLSL Pixelposition in Weltkoordinaten

Übersicht Sonstiges Smalltalk

Neue Antwort erstellen

faeX

Betreff: HLSL Pixelposition in Weltkoordinaten

BeitragDi, Feb 14, 2012 21:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo liebe Community!

Seit kurzem befasse ich mich mit Shaderprogrammierung, dahergehend auch mit Matrixrechnung.
Ich möchte folgendes erreichen:

Der Pixelshader hat für jeden Pixel (nicht Vertex!) die Weltkoordinaten vorliegen und kann damit rechnen.
Vertexposition als TEXCOORD zu übergeben bringt nichts, da dann dieser Wert nicht interpoliert wird. Ich brauche wirklich interpolierte Weltkoordinaten, mit denen jeder Pixel individuell berechnet werden kann. Interpolierte Farben reichen definitiv nicht.

Dann habe ich in der HLSL Semantic-liste diese Semantic VPOS gefunden. Diese sind allerdings bereits auf den Bildschirm projiziert. In dem Beispiel wird eine float4 übergeben, man kann also davon ausgehen dass z und w mit übergeben werden. Smile

Meine Frage ist nun: Mit welcher Matrix, oder wie kann ich aus dieser projizierten Koordinate wieder eine Weltkoordinate transformieren?

Meine andere Idee war es über UV-Koordinaten wieder an die Pixelkoordinaten heranzukommen. Das erscheint mir allerdings wesentlich umständlicher. Confused

Danke für Antworten!! Smile

EDIT: Ich benutze übrigens die IrrlichtEngine in C++.

Chester

BeitragDi, Feb 14, 2012 23:02
Antworten mit Zitat
Benutzer-Profile anzeigen
Gar nicht. Rein mathematisch geht bei der Projektion eine Koordinate verloren, was nicht umkehrbar ist.

Aber ob man über andere Wege mithilfe der HLSL dran kommt, weiß ich nicht, davon habe ich keine Ahnung.

Edit: Was ist z und w?

Müsste man dann nicht eigentlich ein ganz normales lösbares Gleichungssystem haben?
  • Zuletzt bearbeitet von Chester am Di, Feb 14, 2012 23:31, insgesamt einmal bearbeitet
 

BIG BUG

BeitragDi, Feb 14, 2012 23:22
Antworten mit Zitat
Benutzer-Profile anzeigen
K.A. ob das möglich ist. Wenn in ZW noch irgendwo die "Tiefe" codiert ist, dann müsste man das ja theoretisch noch umdrehen können, da Du dann aber jeden Pixel mit der umgekehrten Camera und View Projektion multiplizieren müsstest wäre es definitiv aufwändig zu programmieren und noch aufwändiger für die GPU zu berechnen(Da ja für jeden Pixel).

Eigentlich müsstest Du die World Koordinaten doch einfach auch als eigenen Output vom Vertexshader an den Pixelshader übergeben können.
Oder halt UVW oder Tangenten mißbrauchen. Sollte easy sein, aber Du musst dann natürlich auf diese Informationen verzichten.
B3D-Exporter für Cinema4D!(V1.4)
MD2-Exporter für Cinema4D!(final)

Noobody

BeitragMi, Feb 15, 2012 11:14
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich bin kein grosser Kenner von HLSL, aber laut Dokumentation is VPOS nur ein float2 und enthält nur X und Y in Screenspace und nicht die Tiefe des Fragments, d.h. du kannst wohl nicht mit der inversen Kameratransformationsmatrix multiplizieren, um wieder in Weltkoordinatensystem zu landen.

faeX hat Folgendes geschrieben:
Vertexposition als TEXCOORD zu übergeben bringt nichts, da dann dieser Wert nicht interpoliert wird.

Wenn ich einer kurzen Google-Aktion glauben will, ist das falsch. Werte in ein TEXCOORD zu pflanzen ist so ziemlich die einzige Möglichkeit, interpolierte Datenwerte vom Vertexshader an den Pixelshader weiterzureichen. Und vor allem, wenn man eine der TEXCOORD-Variablen tatsächlich als Texturkoordinate verwendet, wäre es ja sehr seltsam, wenn diese nicht interpoliert würde - das gäbe dann einfach einfarbige Dreiecke.


So oder so, es erscheint mir sehr seltsam, dass du Weltkoordinaten in einem Pixelshader benötigst. Was genau hast du denn vor?
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

faeX

BeitragMi, Feb 15, 2012 19:23
Antworten mit Zitat
Benutzer-Profile anzeigen
Den Ansatz mit VPOS habe ich mittlerweile verworfen. Das Problem dass ich nicht drauf zugreifen konnte lag an Irrlicht: Standardmäßig war aus dem PixelShader-Beispiel Version 1.1 eingestellt.

Ich brauche wirklich eine pixelperfekte Lösung. Interpolation zwischen Vertices reicht definitiv nicht aus. Die Erhöhung der Polygondichte ist insgesamt zu rechenintensiv, da die Pixelfarbe von Pixel zu Pixel sehr stark variieren kann.

Ich möchte für jeden Pixel den Winkel zwischen einem Lichtrichtungsvektor und dem vektor von Camera zu Pixel berechnen. Abhängig von diesem Winkel (0° - 180°) wähle ich dann eine Farbe aus einer Textur aus. Ich bin leider sehr im Zeitdruck und brauche schnell eine Lösung. Ich beschäftige mich schon eine Weile mit diesem Problem und hätte nicht gedacht, dass da so viele Tücken drin stecken. Habe mich extra dafür erst in Shader eingearbeitet und hatte vorher leider auch nicht so die Ahnung von "Grafikmatrixrechnung". Bitte fasst das jetzt nicht als noobig auf, aber wenn mir jemand einen fertigen Shader liefern könnte, oder mir eindeutige Instruktionen gibt wie ich das Umsetzen kann, wäre ich sehr sehr dankbar! Mir fehlt nun leider einfach die Zeit um das selbstständig zu erarbeiten und wäre sehr dankbar wenn mir jemand mit mehr Erfahrung unter die Arme greifen könnte. Ich bemühe mich natürlich selbstverständlich dann alles nachzuvollziehen und möchte prinzipiell nicht, dass man mir die Arbeit abnimmt!

Danke für Antworten! Smile

faeX

BeitragMi, Feb 15, 2012 19:31
Antworten mit Zitat
Benutzer-Profile anzeigen
OMG! Shocked
Just im Moment habe ich's hinbekommen.
Eure seelische Unterstützung hat mir geholfen!
Bei dem ganzen Probieren habe ich einen Fehler eingebaut.
Und jetzt gehts als wär nie etwas gewesen. Very Happy
Sehr geil. Smile

faeX

BeitragMi, Feb 15, 2012 20:19
Antworten mit Zitat
Benutzer-Profile anzeigen
Sorry für den Trippelpost. Aber da es sich wieder um eine Wende von geschafft und nicht geschafft handelt, halte ich ihn für akzeptabel. Sollte das nicht der Fall sein, bitte einfach in den vorherigen hineineditieren.

Das ist mein Shader:
Code: [AUSKLAPPEN]
float4x4 worldViewProj;  // World * View * Projection transformation
float3 lightDir;         // Light direction
float3 viewPos;       // camera position
float4x4 world;

float mod(float x, float y)
{
  return x - y * floor(x/y);
}

struct VS_OUTPUT
{
   float4 Position   : POSITION;   // vertex position
   float3 PixelPos     : TEXCOORD0;
};


VS_OUTPUT vertexMain(in float4 vPosition : POSITION0)
{
   VS_OUTPUT Output;

   Output.Position = mul(vPosition, worldViewProj);
   float4 worldpos = mul(vPosition, world);
   Output.PixelPos = float3(worldpos.x, worldpos.y, worldpos.z);

   return Output;
}


struct PS_OUTPUT
{
    float4 RGBColor : COLOR0;  // Pixel color   
};


texture ModelTexture;
sampler2D textureSampler = sampler_state {
    Texture = (ModelTexture);
    MinFilter = Linear;
    MagFilter = Linear;
    AddressU = Clamp;
    AddressV = Clamp;
};   

PS_OUTPUT pixelMain(float4 Position : POSITION,
               float3 PixelPos : TEXCOORD0)
{
   PS_OUTPUT Output;
   
   float3 posfromview = normalize(PixelPos - viewPos);
   float angleindex = (180*abs(dot(posfromview, lightDir)))/.05;

   Output.RGBColor = tex2D(textureSampler, float2(mod(angleindex, 64)/64, 1 - (floor(angleindex/64)/64)));
   //Output.RGBColor = float4(1, 1, 1, 1)*(angleindex)/1800;

   return Output;
}


Hier sieht man oben links eine Debugtextur (64*64) und einen Sphere mit entsprechenden Shader.
Die Kamera guckt richtung (0/0/1), die Lichtrichtung ist ebenfalls (0/0/1).
Der angleindex wird jetzt grob über eine Skalierung des Kosinus berechnet, das kommt ungefähr hin. Er verläuft somit bei einem Winkel von 0 bis 180° also von 0 bis 3599. Mit der auskommentierten Zeile habe ich das bereits getestet. Nun möchte ich aus der Textur die entsprechende Farbe rauspicken. Zu Testzwecken ist ihr Inhalt lediglich ein Farbverlauf, der die ersten 3600 Pixel abdeckt. Eine Farbe entspricht demnach übrigens 0.05°. Zu erwarten in der Abbildung wäre natürlich ein Kreis, der nach außen hin dunkler wird. Wie in der Abbildung erkennbar läuft irgendwas falsch. Wo liegt mein Fehler? Hab schon rumprobiert, finde den Wurm aber nicht... :/
user posted image

Noobody

BeitragMi, Feb 15, 2012 20:54
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich verstehe nicht ganz, welchen Effekt du erzielen willst, aber hier ein paar Tipps:
1. Du brauchst ja anscheinend die Richtung von Kamera zu Pixel. Wenn du aber vPosition mit der worldView-Matrix multiplizierst (ohne Projektion!), erhältst du die Position des Vertex im Kameraraum, d.h. interpoliert ergibt dir das die Position des Pixels im Kameraraum. Da Positionen linear interpoliert werden können, ist dieser Wert pixelperfekt.
Da diese Position im Koordinatensystem der Kamera ist, ist die Position gleichzeitig der Vektor von Kamera zum Pixel. Den musst du nur noch normalisieren und du hast dein erwünschtes Resultat, ohne dass du Kameraposition oder Weltkoordinaten kennen musst.

2. DirectX unterstützt 1D-Texturen. Benutze sie. Der Zugriff per tex1D ist sehr viel einfacher und stabiler als deine Umrechnung, um ein Skalar in eine 2D-Texturkoordinate umzuwandeln (von der ich vermute, dass dort der Fehler passiert).
Wenn du einen verpixelten Effekt willst, dann stell den Sampler auf Nearest (in DirectX heisst das glaube ich "Point") - ist, wie schon gesagt, schneller, einfacher und stabiler, als manuell Texturkoordinaten zu runden.


Ich habe keine Ahnung von HLSL, aber so ungefähr könnte dein Shader aussehen: Code: [AUSKLAPPEN]
float4x4 worldViewProj;  // World * View * Projection transformation
float4x4 worldView;      // World * View transformation
float3 lightDir;         // Light direction (Note: HAS to be in camera space)

struct VS_OUTPUT
{
   float4 Position   : POSITION;   // vertex position
   float3 PixelPos   : TEXCOORD0;  // vertex position in camera space
};


VS_OUTPUT vertexMain(in float4 vPosition : POSITION0)
{
   VS_OUTPUT Output;

   Output.Position = mul(vPosition, worldViewProj);
   float4 camerapos = mul(vPosition, worldView);
   Output.PixelPos = float3(camerapos.x, camerapos.y, camerapos.z);

   return Output;
}


struct PS_OUTPUT
{
    float4 RGBColor : COLOR0;  // Pixel color   
};


texture ModelTexture;
sampler1D textureSampler = sampler_state {
    Texture = (ModelTexture);
    MinFilter = Linear; // Je nach dem was du vor hast, musst du das auf "Point" umstellen oder wie es in HLSL heisst
    MagFilter = Linear;
    AddressU = Clamp;
};

PS_OUTPUT pixelMain(float4 Position : POSITION,
               float3 PixelPos : TEXCOORD0)
{
   PS_OUTPUT Output;
   
   float3 posfromview = normalize(PixelPos);
   float angle = clamp(dot(posfromview, lightDir), 0.0, 1.0);

   Output.RGBColor = tex1D(textureSampler, angle);

   return Output;
}


Wird vermutlich so nicht kompilieren, aber ich hoffe, dass dir das weiterhilft.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

faeX

BeitragSa, Feb 18, 2012 13:53
Antworten mit Zitat
Benutzer-Profile anzeigen
Vielen vielen Dank! Very Happy
Habe deinen Vorschlag in meinem Source umgesetzt, und jetzt funktioniert alles wunderbar!
Man kann mit tex1D übrigens direkt auf eine 2D-Textur zugreifen, es werden sogar im Grunde die richtigen Farben angezeigt, nur dass sie ziemlich hässlich verwischen. Mit einer 1D-Textur passt dann alles. An den Interpolationseigenschaften musste ich nicht mal mehr etwas ändern.
Und nochmal Danke für den Performancetipp mit der Umrechnung in den Cameraspace! Smile

Neue Antwort erstellen


Übersicht Sonstiges Smalltalk

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group