Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

LInsoDeTeh

Treue Seele

  • »LInsoDeTeh« ist der Autor dieses Themas

Beiträge: 372

Wohnort: Essen, Deutschland

Beruf: Team Lead Inhouse-Entwicklung

  • Private Nachricht senden

1

28.10.2012, 18:58

[XNA/HLSL] Problem mit Transparenz bei Partikeleffekt

Hi Leute,

zur Zeit arbeite ich an Partikeleffekten für z.B. die Antriebe/Düsen der Raumschiffe in meinem Projekt. Doch da ich mich mit diesem Projekt auch shadertechnisch auf Neuland gewagt habe, fehlt mir hier bei einem kleinen Problem der richtige Denkanstoß. Folgendes Problem:



Aus der Düse des Raumschiffes werden Partikel geschossen, um einen Feuereffekt zu erzeugen:


(Link)




So weit, so gut, doch wenn ich das Raumschiff andersherum fliegen lasse, sieht das ganze so aus:


(Link)




Wie man sieht, ist die Zeichenreihenfolge andersherum und die (halb-)transparenten Bereiche werden nicht transparent dargestellt, sondern überlagern den jeweils dahinterliegenden Partikel.

Ich habe bereits mit if (col.a == 0) { discard; } im Shader gearbeitet, damit habe ich erreicht, dass die Textur nicht mehr eckig gezeichnet wird, sondern nur die Bereiche mit Alpha>0, wodurch diese runde, aber leider nicht (halb-)transparente Textur entsteht.



Hat einer eine Idee, wie ich das ganze fixen kann?

Das Zeichnen geschieht relativ simpel:







C#-Quelltext

1
2
3
4
5
6
7
8
9
10
List lstVertices = new List();List lstIndices = new List()short idx = 0;  

for (int i = 0; i < lstParticles.Count; i++) {VertexPositionNormalTexture vert1 = new VertexPositionNormalTexture(lstParticles[i].Location + new Vector3(-0.15f, 0.15f, 0.0f), Vector3.Forward, Vector2.Zero); lstVertices.Add(vert1);VertexPositionNormalTexture vert2 = new VertexPositionNormalTexture(lstParticles[i].Location + new Vector3(-0.15f, -0.15f, 0.0f), Vector3.Forward, Vector2.UnitY); lstVertices.Add(vert2);VertexPositionNormalTexture vert3 = new VertexPositionNormalTexture(lstParticles[i].Location + new Vector3(0.15f, -0.15f, 0.0f), Vector3.Forward, Vector2.One); lstVertices.Add(vert3);VertexPositionNormalTexture vert4 = new VertexPositionNormalTexture(lstParticles[i].Location + new Vector3(0.15f, 0.15f, 0.0f), Vector3.Forward, Vector2.UnitX); lstVertices.Add(vert4);  
lstIndices.Add(idx); lstIndices.Add((short)(idx + 2)); lstIndices.Add((short)(idx + 1)); lstIndices.Add(idx); lstIndices.Add((short)(idx + 3)); lstIndices.Add((short)(idx + 2));idx += 4; }                  


if (lstVertices.Count > 0) {fx.Parameters["World"].SetValue(World);fx.Parameters["View"].SetValue(View);fx.Parameters["Projection"].SetValue(Projection);fx.Parameters["tex"].SetValue(ParticleImage); 
fx.CurrentTechnique.Passes[0].Apply();

grdev.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, lstVertices.ToArray(), 0, lstVertices.Count, lstIndices.ToArray(), 0, lstIndices.Count / 3); }



PS: Ich weiß, dass die Angabe des Vektors Vector3.Forward dazu führt, dass diese Primitives nur von vorne aus sichtbar sind, da werd ich später noch den Kameravektor einsetzen, aber das ist nicht die Ursache für das Problem.
PPS: Diese Code-Autoformatierung hier im Forum ist ja schon gruselig teilweise, ne? ;)



Die relevanten Teile des dazugehörigen Shaders (der sich als Effekt hinter dem Objekt fx verbirgt) sieht genauso simpel aus (und enthalten oben erwähnte discard-Zeile):

HLSL-Quelltext

1
2
3
4
5
6
7
8
VertexShaderOutput VertexShaderFunction(VertexShaderInput input) {VertexShaderOutput output;

float4 worldPosition = mul(input.Position, World);float4 viewPosition = mul(worldPosition, View); 
output.Position = mul(viewPosition, Projection);output.Texture = input.Texture; output.Normal = normalize(mul(input.Normal, World));  
return output; }  
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { float4 texcol = tex2D(texSampler,input.Texture);if (texcol.a == 0) { discard; }       

return texcol; }




Jemand ne Idee?
Danke schonmal im Voraus für eure Hilfe!

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »LInsoDeTeh« (28.10.2012, 19:07)


Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

2

28.10.2012, 19:06

Ein alt bekanntes Problem.
Die Lösung des Ganzen ist es den Z-Buffer Schreibzugriff beim Rendern der Partikel abzustellen.
Dann solltest du aber entweden additives Blending verwender oder du musst die zu zeichnenden Partikel erst nach der Entfernung zu Kameraebene sortieren.
Sonst kommt es zu Farbartefakten.

LInsoDeTeh

Treue Seele

  • »LInsoDeTeh« ist der Autor dieses Themas

Beiträge: 372

Wohnort: Essen, Deutschland

Beruf: Team Lead Inhouse-Entwicklung

  • Private Nachricht senden

3

28.10.2012, 19:10

Das Problem mit dem Umgehen des z-Buffers (ich habe es vorher in einem Sprite-Batch gezeichnet, da gibt es ja keinen Z-Buffer) ist, dass der Effekt dann immer "vorne" ist, auch wenn sich der Partikel hinter einem Objekt befindet :-/
Damit hatte ich auch schon beim Bloom-Effekt für die Sonnen meine lieben Problemchen, da es ein Postprocess Effekt ist...

Das mit dem Sortieren vorher erscheint mir sinnvoll, aber kostet das nicht wahnsinnig Rechenleistung?

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

4

28.10.2012, 19:22

Ich sagte auch, du sollst den ZBufferschreibzugriff abschalten und nicht den ganzen Buffer.
Wie das in Dx geht weiß ich gerade nicht auswendig. Ich glaube mich aber daran erinnern zu können, dass die Funktion(?) ZBufferWriteEnable oder so ähnlich hies.

Mit dem richtigen Sortieralgo sollte sich die Rechenleistung durchaus in Grenzen halten.

EDIT:
Wie man den ZBuffer readonly setzt:
http://msdn.microsoft.com/en-us/library/…0(v=vs.85).aspx

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Spiele Programmierer« (28.10.2012, 19:30)


David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

5

28.10.2012, 22:45

Eine korrekte Tiefensortierung der einzelnen Partikel ist z.T. gar nicht wünschenswert, weil so oft unerwünschtes "Partikel-Plopping" entstehen kann. Generell genügt es die Partikel-Effekte zu sortieren (oder die Emitter). Das Rendern ist straight forward:

  1. Opaque Geometrie rendern
  2. ...
  3. Z-Write abstellen
  4. Blend-Modus aktivieren
  5. Partikel-Batch zeichnen
@D13_Dreinig

LInsoDeTeh

Treue Seele

  • »LInsoDeTeh« ist der Autor dieses Themas

Beiträge: 372

Wohnort: Essen, Deutschland

Beruf: Team Lead Inhouse-Entwicklung

  • Private Nachricht senden

6

29.10.2012, 20:07

Hat funktioniert!

Habe auf das Sortieren verzichtet und nur mit schreibgeschütztem Z-Buffer gearbeitet. Nun sieht es so aus, wie es soll :)

Vielen Dank für eure Hilfe!



So sieht's nun aus:


(Link)




PS: Wen es interessiert, in XNA geht das so:

Da alle Eigenschaften von DephtStencilState ReadOnly sind, muss man immer ein neues DepthStencilState-Objekt erzeugen.



C#-Quelltext

1
2
3
4
5
6
DepthStencilState dscopy = GraphicsDevice.DepthStencilState;DepthStencilState ds = new DepthStencilState();ds.DepthBufferWriteEnable = false;

//Andere Einstellungen für den DS vornehmen
GraphicsDevice.DepthStencilState = ds;
//Partikel rendern
GraphicsDevice.DepthStencilState = dscopy;

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »LInsoDeTeh« (29.10.2012, 20:17)


Werbeanzeige