OpenGl clipping (Schnittebene)


  • Mod

    XMAMan__ schrieb:

    Ich finde deine Frage ziemlich intressant. Der erste Gedanke der mir dazu eingefall ist: Zeichne ein 3D-Viereck, was auf der XY-Ebene liegt. Dies liegt z.B in der Mitte von dein Objekt was du untersuchen willst.

    Normalerweise würde OpenGL nun beim Tiefentest fragen: if(z < aktuellerZWertImPuffer) then zeichne_pixel(x,y)

    Dieser Tiefentest findet ja glaube zwischen dem Vertexshader und dem Pixelshader statt. In der Grafikpipeline ist das glaube der Teil "Triangle Raserization".

    findet offiziel in den "ROPs" statt, die sich ganz am ende der pipeline befinden. (nach allen shadern usw).

    Jetzt müstest du bei diesen Tiefentest nur noch das Abfrage von < in > ändern. Schon müsste es gehen 😃

    naja, was soll dann genau gehen? du ueberzeichnest alles was nah ist, damit hast du aber noch kein querschnitt erzeugt. wenn du z.B. eine kugel zeichnest und dann in der mitte schneiden willst mit deinem trick, wuerdest du nichst mehr von der kugel sehen, nur noch dein viereck.

    Frage an die Pros hier: Kann man beim Tiefentest den Vergleichsoperator umdrehen?

    ja, das kann man mit glDepthFunc


  • Mod

    XMAMan__ schrieb:

    Haha, mir ist noch ne leichtere Lösung eingefallen:

    Verändere die Near-Ebene einfach so, dass sie durch den Objekt geht:

    gluPerspective(fov, ratio, nearDist, farDist);

    nearDist muss also veränderbar sein und durch dein Objekt wandern.

    du machst es ein wenig umstaendlich, wenn du eine clip plane haben willst, kannst du einfach: glClipPlane benutzen.
    er schrieb ja

    ja wenn ich "clippe" dann wird immer alles vor/bzw hinter der ebene gelöscht

    es ist nur nicht klar was genau er will, nur was er nicht will 🤡



  • rapso schrieb:

    XMAMan__ schrieb:

    Ich finde deine Frage ziemlich intressant. Der erste Gedanke der mir dazu eingefall ist: Zeichne ein 3D-Viereck, was auf der XY-Ebene liegt. Dies liegt z.B in der Mitte von dein Objekt was du untersuchen willst.

    Normalerweise würde OpenGL nun beim Tiefentest fragen: if(z < aktuellerZWertImPuffer) then zeichne_pixel(x,y)

    Dieser Tiefentest findet ja glaube zwischen dem Vertexshader und dem Pixelshader statt. In der Grafikpipeline ist das glaube der Teil "Triangle Raserization".

    findet offiziel in den "ROPs" statt, die sich ganz am ende der pipeline befinden. (nach allen shadern usw).

    Und in Wirklichkeit?
    Wäre ja ziemlich bekloppt das bis ganz zum Schluss zu verzögern - vor allem weil man den Z-Wert im Fragment-Shader eh nimmer ändern kann.



  • hustbaer schrieb:

    [...]

    Und in Wirklichkeit?

    In Wirklichkeit hängt's davon ab. Wenn gewisse Voraussetzungen erfüllt sind (depth buffer wird richtig gecleared, shader schreibt die depth nicht bzw. nur conservative, z compare mode wird nicht zwischendrin geändert, kein alphatesting oder sonstiges fragment discard etc.), kann die Hardware coarse und fine grained early z culling machen, also verdeckte Fragmente schon vor dem Shader wegwerfen, was unter gewissen Umständen (Anwendung ist fragment bound) massiven Einfluss auf die Performance haben kann. Daher macht man ja auch so Dinge wie einen z prepass etc.

    hustbaer schrieb:

    Wäre ja ziemlich bekloppt das bis ganz zum Schluss zu verzögern - vor allem weil man den Z-Wert im Fragment-Shader eh nimmer ändern kann.

    Nun, man kann den Z-Wert im Fragment Shader aber ändern 😉


  • Mod

    hustbaer schrieb:

    rapso schrieb:

    XMAMan__ schrieb:

    Ich finde deine Frage ziemlich intressant. Der erste Gedanke der mir dazu eingefall ist: Zeichne ein 3D-Viereck, was auf der XY-Ebene liegt. Dies liegt z.B in der Mitte von dein Objekt was du untersuchen willst.

    Normalerweise würde OpenGL nun beim Tiefentest fragen: if(z < aktuellerZWertImPuffer) then zeichne_pixel(x,y)

    Dieser Tiefentest findet ja glaube zwischen dem Vertexshader und dem Pixelshader statt. In der Grafikpipeline ist das glaube der Teil "Triangle Raserization".

    findet offiziel in den "ROPs" statt, die sich ganz am ende der pipeline befinden. (nach allen shadern usw).

    Und in Wirklichkeit?
    Wäre ja ziemlich bekloppt das bis ganz zum Schluss zu verzögern - vor allem weil man den Z-Wert im Fragment-Shader eh nimmer ändern kann.

    es war mit absicht zum schluss verzoegert worden. vor GeForce3 gab es keine optimierung diesbezueglich, einfach weil es viel chipflaeche kostet sowas zwischenzuspeichern und die GPUs als streaming prozessoren ausgelegt sind, nicht als on-demand mit caches. wenn du also auf einer GF1 oder GF2 fragmente verarbeitest, hast du vielleicht 1, 2 oder 3 texture lookups, diese sind vermutlich DXT1 oder 3/5, hast also bei aufwendigen dingen 3 lookups mit DXT 3 -> 3bytes transfer, in derselben zeit musst du 4bytes z/stencil laden. wenn du also am anfang der pipeline stallst um 4byte zu laden, kann es effektiver sein diese streaming zeit dafuer zu nutzen texturen zu sampeln und ALU operationen auszufuehren, wenn auch die register combiner recht limitiert waren.

    vram kann weit mehr als 300cycles latenz haben bei damals schon 10GB/s+, das einzige problem was du also hast ist latenz zu verstecken, nicht wirklich bandbreite, denn die meiste wird zbuffer read haben, danach framebuffer read, danach framebuffer write, dann erst texturen (und am ende mesh daten, die aber schon immer nen gewissen L2 cache hatten).
    natuerlich zieht sich eine GPU (gerade damals) nicht nur 4byte, sondern kacheln, was also mindestens eine cacheline -> 128byte war. dasselbe gilt auch fuer texturen, es macht also nicht viel sinn einzelne pixel aus den fragment pipelines wegzumaskieren, ein pixel zieht soviel wie vielleicht 32pixel.
    ROPs haben natuerlich keine RGB werte mehr rausschreiben muessen wenn kein modify stadtfand, aber sie waren auch nicht tief genug die latenz vom vram zu verstecken um lazy (abhaengig vom z-test) den framebuffer zu laden.



  • dot schrieb:

    hustbaer schrieb:

    Wäre ja ziemlich bekloppt das bis ganz zum Schluss zu verzögern - vor allem weil man den Z-Wert im Fragment-Shader eh nimmer ändern kann.

    Nun, man kann den Z-Wert im Fragment Shader aber ändern 😉

    Krass.
    Wusste ich nicht. Macht das auch irgendeinen Sinn?

    (Die Fragen die vor dem EDIT hier standen hab' ich mir selbst ergoogelt 😉



  • hustbaer schrieb:

    dot schrieb:

    hustbaer schrieb:

    Wäre ja ziemlich bekloppt das bis ganz zum Schluss zu verzögern - vor allem weil man den Z-Wert im Fragment-Shader eh nimmer ändern kann.

    Nun, man kann den Z-Wert im Fragment Shader aber ändern 😉

    Krass.
    Wusste ich nicht. Macht das auch irgendeinen Sinn?

    Denk z.B. an einen Impostor, also ein 3D Objekt, das in eine Textur gerendert wird und wo dann z.B. ab einer gewissen Entfernung nur die Textur auf ein Quad gepappt wird, damit man nicht ständig das ganze Teil rendern muss. In dem Fall willst du evtl. die Tiefe auch in eine Textur rendern und dann die Tiefenwerte der Fragmente des Quad anpassen, damit man nicht merkt, dass das Teil in Wahrheit flach ist.

    Generell ist wohl der häufigste Anwendungsfall, auf normalem Weg rasterisierte Polygone mit anderem Zeug (Output eines CUDA Volume Raycasters oder was auch immer) richtig zusammenzusetzen.



  • Ah, durchaus einleuchtend.

    dot schrieb:

    Generell ist wohl der häufigste Anwendungsfall, auf normalem Weg rasterisierte Polygone mit anderem Zeug (Output eines CUDA Volume Raycasters oder was auch immer) richtig zusammenzusetzen.

    Ja, oder gleich im Fragment-Shader (Parallax Occlusion Mapping, Voxel und dergleichen).
    Oder vorgerenderte "3D Sprites".
    Oder ganze 3D-Szenen oder Szenenteile "mergen" (EDIT: OK, das ist das was du "Impostor" nennst, oder?)

    Der Gedanke "geht nicht" war wohl so fest in meinem Hirn eingebrannt dass mein erster Gedanke wirklich "wozu soll das bitte gut sein?" war 🙂

    pS: geht das mit PowerVR auch, oder ist deren tile based rendering dahingehend eingeschränkt dass immer ein Z-Prepass "mit ohne" Shader gemacht wird?


  • Mod

    hustbaer schrieb:

    pS: geht das mit PowerVR auch, oder ist deren tile based rendering dahingehend eingeschränkt dass immer ein Z-Prepass "mit ohne" Shader gemacht wird?

    PowerVR can ziemlich alles was du moechtest, da deren GPUs einfach nur programme ausfuehren, egal was fuer welche. natuerlich ist dann die deferred optimierung komplett aus, aenlich wie sie bei alphablend (ohne zwrite) und bei alphatest polys aus ist was occlusion angeht.
    Andere deferred GPUs haben ein EarlyZ der dennoch anbleiben sollte, wenn sie depth out unterstuetzen.

    Ob die API dafuer existiert ist natuerlich eine andere frage. Unter OpenGL ES muss dafuer GL_EXT_frag_depth vorhanden sein, auf desktop geht es ab GLSL 1.1 http://www.opengl.org/sdk/docs/manglsl/xhtml/gl_FragDepth.xml und bei DirectX sollte es ab SM3 gehen, wenn ich mich recht entsinne.



  • Also die Aufgabe hat sich jetzt ein wenig geändert,
    ich soll nur auf jedenfall GLSL nutzen.
    Und nun soll ich nur ein beliebiges Objekt clippen können und "hinter" der clipping ebene noch was zeichnen.
    Also rein prinzipiel sowas wie
    aktiviere ClippingEbene
    zeichne Objekt
    deaktiviere ClippingEbene
    zeiche Objekt welches nicht mehr geclippt wird

    Also etwas einfach nur zu clippen mit Shadern hab ich hinbekommen

    Vertex-Shader:

    varying vec3 lightDir,normal;
    varying float clipDist;
    
    void main()
    {
       normal = normalize(gl_NormalMatrix * gl_Normal);
    
       lightDir = normalize(vec3(gl_LightSource[0].position));
       gl_TexCoord[0] = gl_MultiTexCoord0;
    
       vec4 myClipPlane = vec4(0.0,0.0,1.0,0.0);
    
       clipDist = dot(gl_Vertex.xyz, myClipPlane.xyz) + myClipPlane.w;
    
       gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    }
    

    Fragment-Shader:

    varying vec3 lightDir,normal;
    uniform sampler2D tex, tex2;
    varying float clipDist;
    void main()
    {
       float epsilon = 0.1;
       if(clipDist < 0.0)
              discard;
       else if(clipDist > 0.0 && clipDist < epsilon)
              gl_FragColor = vec4(1.0,1.0,1.0,1.0);
    
       else
       {
          vec3 ct,cf;
          vec4 texel;
          float intensity,at,af;
          intensity = max(dot(lightDir,normal),0.0);
    
          cf = intensity * (gl_FrontMaterial.diffuse).rgb + gl_FrontMaterial.ambient.rgb;
          af = gl_FrontMaterial.diffuse.a;
          texel = texture2D(tex,gl_TexCoord[0].st) + texture2D(tex2,gl_TexCoord[0].st);
    
          ct = texel.rgb;
          at = texel.a;
          gl_FragColor = vec4(ct * cf, at * af);
        }
    
    }
    

    Hat jemand ne Idee wie ich das bewerkstelligen kann mit dem Objekt "hinter" der Ebene ?

    mfg

    Edit: Wäre es vllt eine Idee einfach noch 2 zusätzlicher Shader zu benutzen die nur für die ungeclippten Objekte zuständig sind ?


Anmelden zum Antworten