2d Szene - Bildschirm- zu Weltkoordinaten?

Hey Leute.
Eigentlich ganz einfach was ich jetzt will.
Ich will (Opengl, usw…) einen Bildschirm Punkt (zB Mousepress Punkt) quasi in einen punkt
in meiner szene umrechnen. Wahrscheinlich ist es nicht schwer, aber selber komm ich da nicht drauf… irgendwie.
Kann mir vorstellen das es in 3d noch schwerer ist, aber das brauch ich momentan nicht.
Nun, in einem Forum fand ich folgendes:

“Or you can create 3D points - your screen coordinates (x, y) - devided by screen size
(you have to get coords in interval <-1,1>), and z coordinate will be -1 (starting point)
and 1 (ending point). These are NDC (normalized device coordinates). Then multiply
them by inverse projection matrix and inverse modelview matrix.
Results should be starting and ending points of ray.”

Hat der recht? Das heisst ich mache dann inverse(projection * camera) * point(p.x / displayWidth | p.y / displayHeight);
oder wie? Kann es gerade nicht testen, aber warum muss ich denn die inversen holen?.. Ich verstehe nicht den
zusammenhang …

Danke!

Naja, um von einem realen Punkt b zum Bildschirmpunkt x zu kommen multiplizierst du den realen Punkt mit einer Matrix A,
Für die Umkehrung, also um vom Bildschirmpunkt x zum realen Punkt b zu kommen multiplizierst du den Bildschirmpunkt mit der inversen Matrix A, also mit A[SUP]-1[/SUP].
Soweit passt das schon, denk ich.

Also im Grunde :
A * b = x
und umgestellt
b = A[SUP]-1[/SUP] * x

Die Invertierung ist gewissermaßen der Ersatz für die nicht mögliche Division bei Matrizen
A * A[SUP]-1[/SUP] = E (Einheitsmatrix)

Da du am Bildschirm aber nur zweidimensional auswählst, könntest du einen weiteren Punkt mit einer veränderten Z-Koordinate rücktransformieren, und damit dann eine Gerade berechnen auf der das Objekt dann liegen sollte, das mit dem Klick gemeint ist.

Hm, back to this:
Ich bekomm es irgendwie nicht hin.
Meine matrix wenn “projection * camera”:

0.6293247 0.0 0.0 0.0
0.0 0.8390996 0.0 0.0
0.0 0.0 -0.0020001999 0.0
0.0 0.0 0.0 1.0

an diesem punkt versteh ich es ehrlich gesagt schon nicht.
wenn ich das ganze zB mit dem Punkt 1 multipliziere, (also 1
in zB einem vbo von irgendner figur) dann kommt ein punkt mit
der x koordinate 0.629 raus… aber das sollte doch die bildschirm koordinate sein?
oder etwa nicht? (Sehen tue ich aber alles richtig, das wunder mich gerade)

Naja. jedenfalls das ganze invertiert:

1.589005 0.0 -0.0 0.0
0.0 1.1917536 0.0 -0.0
-0.0 0.0 -499.95007 0.0
0.0 -0.0 0.0 1.0

das müsste ich ja nun mit einem bildschirm punkt mal nehmen?..
zB P[100,100] also P[100,100,0,1] , kommt folgendes raus:

158.901
119.175
  0.000
  1.000

was ja definitiv nicht stimmt, oder doch? Ich meine, die WELTKOORDINATEN gehen doch
letzten endes auch nur von -1 bis 1, oder nicht?

Ich glaube ich habe grundsätzliche Lücken in diesem pipeline verständniss, auch wenn ich mir das schon
tausendachthundert mal durchgelesen habe… naja ich machs nochmal.

Auch wenn es schwierig/aufwändig ist, das ganze händisch mit Beispielmatrizen und Zahlen durchzuexerzieren, allgemein: Oft werden die Koordinaten normalisiert. “Da weiß man, was man hat”. Es macht viele Umrechnungen einfacher. In diesem fall würde für den Punkt (1,0,0) eben der Punkt (0.629, 0, 0) rauskommen. Diese 0.629 müssen dann noch mit der Bildschirmbreite multipliziert werden, um die Bildschirmkoordinaten zu bekommen. Wenn der Bildschirm 1000 pixel breit ist, landet dieser Punkt eben bei (629,0).

Analog dazu: Wenn man einen Pixel mit den Koordinaten (345,0) anklickt, wird der erst normalisiert - also durch die Bildschirmgröße geteilt. Das Ergebnis ist (bei 1000 praktischen Pixeln) der Punkt (0.345,0,0). Wenn man den dann in die invertierte Matrix reinsteckt, kommt (0.548,0,0) raus, und das sind dann in Weltkoordinaten.

das heißt die weltkoordinaten sind immer letzten endes die im -1 -> 1 koordinaten system?
Da wird ja quasi die ganze zeit hinunhergerechnet und kommt beim seblen hinaus… sinn ._.
aber okay ^^ Danke deine erklärung hat mir geholfen, ich probiers später an nem beispiel aus
und poste das Ergebnis ^^

Öhm. Die Koordinaten sind so gesehen erstmal nur Zahlen. Ja, man könnte sagen, dass sie ja Einheiten haben (“Meter”), aber … ob man seine Figur in einem Spiel nur 1m oder 10m oder 13234.32m hoch macht, ist so gesehen erstmal egal (solange keine Physik und Zeit dazukommt). Die Umrechnung auf normalisierte Koordinaten hat mehrere Gründe. Auf verschlungenen Wegen damit verwandt, und nur weil mich genau diese Frage auch gerade beschäftigt: Wenn man das Fenster größer zieht - sieht man dann mehr von der Welt, oder sieht man noch genausoviel, aber das, was man sieht, wird größer gezeichnet?

Man sieht mehr. Sonst m+sste man ja bei onresize() die projektion an die neuen verhältnisse umrechnen… (sprich neu setzen)

Sei deine Matrix A = { {0.6293247, 0.0, 0.0, 0.0},{0.0, 0.8390996, 0.0, 0.0},{0.0, 0.0, -0.0020001999, 0.0},{0.0, 0.0, 0.0. 1.0} }
und dein realer Punkt b = {158.901, 119.175, 0.000, 1.000}
dann liefert A * b = x = {100,100,0,1}
Die Inverse
A[SUP]-1[/SUP] = { {1.589005, 0.0, 0.0, 0.0},{0.0, 1.1917536, 0.0, 0.0},{0.0, 0.0, -499.95007, 0.0},{0.0, 0.0, 0.0, 1.0} }
das hattest du ja berechnet… und
A[SUP]-1[/SUP] * x = {158.901, 119.175, 0.000, 1.000} = b
Wo ist jetzt das Problem ?

Völliger Quatsch was ich da gesagt hab. Der Clip Space bleibt ja auch erhalten. Das heißt es bleit alles gleich.
Für eine veränderung muss man die projektion neu setzen…

Pappwinni, Ich probieres demnächst noch einmal aus, und sag es dir dann ^^

*** Edit ***

Okay, das problem ist folgendes, und zwar der letzte satz meiner anfangsfrage…

„was ja definitiv nicht stimmt, oder doch? Ich meine, die WELTKOORDINATEN gehen doch
letzten endes auch nur von -1 bis 1, oder nicht?“ …

Öhm. Die Weltkoordinaten gehen von -wohinDuWillst bis +wohinDuWillst. Das ist ja nur das “abstrakte Modell der Welt”, man kann einen Bereich der Welt von -1…+1 Bildschirmfüllend darstellen, oder einen von -10000…+10000 …!?

ja das ist mir klar…
aber schau mal…
ich mach ja: RenderObject#moveX / Y / Z um einen bestimmten wert.
Mit diesem wert mach ich dann Matrix4f#translate(Vector3f…)) …
und um diesen wert verändere ich RenderObject#x, y, z. Das heisst wenn ich um 1 x translate,
dann ist RenderObject#getX = 1. Und ich will wissen, wohin ich mit der Maus klicken sollte, um auf diesem “x = 1”
zu landen… versteht ihr ungefähr was ich nicht verstehe?

Ich versuchs noch einmal zu erklären.

CPU:

Ich habe ein RenderObject. Wenn ich zB moveX(10) aufrufe, dann passiert:

→ x += 10
→ model.translate(new Vector3f(10, 0, 0));

Ich habe eine Kamera. Projection matrix:

code
[spoiler]this.aspect = (float) Display.getWidth() / (float) Display.getHeight(); this.top = (float) (Math.tan(Math.toRadians(fov) / 2)); this.bottom = -top; this.right = top * aspect; this.left = -right; projection.m00 = 2 / (right - left); projection.m03 = -(right + left) / (right - left); projection.m11 = 2 / (top - bottom); projection.m13 = -(top + bottom) / (top - bottom); projection.m22 = -2 / (far - near);[/spoiler]

→ Camera Matrix, entspricht der model matrix eines Render Objects (x y z und model wird genauso verändert wie bei render object

Ich habe Maus Eingaben:

→ Die Mitte des Bildschirms entspricht maus.x = 400, maus.y = 300
→ Display.width = 800, Display.height = 600

::: Wenn ich nun ein RendeRobject auf position (0, 0) habe, muss ich meine maus also, um diesen Punkt zu treffen, auf (400, 300) bewgen… wie rechne ich das also um? :::

GPU:

projectionmatrix * cameramatrix * RenderObject.modelmatrix * vertex

jetzt klarer wo mein problem ist? :frowning:

So halb. Ehrlich gesagt habe ich, als ich das ganze mal umgesetzt habe, auch ein bißchen „rumprobiert“, obwohl man ja eigentlich in der Lage sein sollte, das beginnend mit einem weißen Blatt Papier und einem Bleistift from scratch bis zum Ende herzuleiten und dann nur noch runterzuimplementieren :o

Du hattest jetzt gefragt: Wenn ich nun ein RendeRobject auf position (0, 0) habe, muss ich meine maus also, um diesen Punkt zu treffen, auf (400, 300) bewgen… wie rechne ich das also um?

Das ist etwas ungewöhnlich. Normalerweise sollte man jeden Welt-Punkt einfach durch die Kette aus
projection * camera * model
scheuchen können, um genau die Bildschirmkoordinaten zu bekommen. (Genau das MACHT diese Kette ja - für jeden Vertex).

Bisher (vorher) hatte ich gedacht, dass du genau die umgekehrte Richtung brauchst: Wenn man irgendwo hin klickt - welches Objekt wurde dann getroffen? Das ist etwas frickeliger, weil man den „Picking Ray“ berechnen muss. Also den Strahl, der vom Auge durch den Bildschirmpunkt in die Szene geschossen wird, und dort dann ggf. ein Objekt trifft.

Da kommt jetzt noch dazu, dass ich mich von anderen Threads zu erinnern glaube, dass es unterschiedliche Interpretationen des Wortes „Camera Matrix“ bzw. „View Matrix“ gibt. Meines Wissens sind das getrennte Begriffe, aber erfreulicherweise ist das eine genau das Inverse vom anderen.

Wo ich das mal gebraucht habe
[spoiler]

Ich hatte mal (aus „Langeweile“?) angefangen, so ein paar Rendering-Utilities zu schreiben. Das ganze ist im Moment in einer sehr frühen, rudimentären, unfertigen Version (Version 0.0.0 :smiley: ) auf JavaGL Rendering . Mehr als „das ist NICHT GUT“ will ich da jetzt erstmal nicht dazu sagen, aber vielleicht f(i/ä)ndest du einige Snippets daraus hilfreich, die ich hier mal kommentarlos zusammenkopiere:

Aus PickingUtils.java:

    /**
     * Compute a picking {@link Ray} given the camera matrix, projection 
     * matrix, viewport and position. The camera matrix contains the 
     * rotation and translation for the camera. The projectionMatrix 
     * contains solely the perspective projection transformation. The 
     * viewport describes the rectangle that the picking occurs in. 
     * The x and y coordinates are the position where the picking ray 
     * should start, in screen coordinates.
     * 
     * @param cameraMatrix The camera matrix
     * @param projectionMatrix The projection matrix
     * @param viewport The viewport
     * @param x The x position
     * @param y The y position
     * @return The picking ray
     */
    public static Ray computePickingRay(
        Matrix4f cameraMatrix, Matrix4f projectionMatrix, 
        Rectangle viewport, int x, int y)
    {
        int fy = viewport.getHeight() - y;
        Point3f p0 = MatrixUtils.unProject(
            new Point3f(x,fy,0), cameraMatrix, projectionMatrix, viewport); 
        Point3f p1 = MatrixUtils.unProject(
            new Point3f(x,fy,1), cameraMatrix, projectionMatrix, viewport); 
    
        Point3f rayOrigin = p0;
        Vector3f rayDirection = new Vector3f();
        rayDirection.sub(p1, p0);
        rayDirection.normalize();
    
        Ray ray = Rays.create(rayOrigin, rayDirection);
        //System.out.println("Ray "+ray);
        return ray;
    }

Aus MatrixUtils.java:

    /**
     * Unprojects the given point (in screen coordinates) based on the
     * given modelview (camera) and projection matrix and the viewport. 
     * 
     * @param point The point
     * @param modelview The modelview matrix
     * @param projection The projection matrix
     * @param viewport The current viewport
     * @return The unprojected point
     */
    public static Point3f unProject(
        Tuple3f point, Matrix4f modelview, 
        Matrix4f projection, Rectangle viewport)
    {
        Matrix4f matrix = new Matrix4f();
        matrix.mul(projection, modelview);
        try
        {
            matrix.invert();
        }
        catch (SingularMatrixException e)
        {
            return new Point3f();
        }
        
        Point4f temp = new Point4f(point.x, point.y, point.z, 1);
        temp.x = (temp.x - viewport.getX()) / viewport.getWidth();
        temp.y = (temp.y - viewport.getY()) / viewport.getHeight();
        temp.x = temp.x * 2 - 1;
        temp.y = temp.y * 2 - 1;
        temp.z = temp.z * 2 - 1;

        matrix.transform(temp);
        Point3f result = new Point3f(temp.x, temp.y, temp.z);
        result.scale(1.0f / temp.w);
        return result;
    }

(Die beiden Snippets sollten „weitgehend“ standalone sein, abgesehen von den Matrix/Vector-Klassen, die aus https://java.net/projects/vecmath stammen, und solchen „trivialen“ Klassen wie dem „Ray“, der aus einem Punkt und einem Vector besteht).

Nicht mehr standalone ist dann der Teil, wo der Ray dann mit einer „Geometry“ (bzw. ihren Dreiecken) geschnitten wird:

    public TrianglePickingResult<T> computePickingResult(Ray ray)
    {
        Point3f p0 = new Point3f();
        Point3f p1 = new Point3f();
        Point3f p2 = new Point3f();

        Point3f rayOrigin = ray.getOrigin();
        Vector3f rayDirection = ray.getDirection();
        
        Point3f result = new Point3f();
        Point3f closestResult = new Point3f(0,0,Float.POSITIVE_INFINITY);
        Array3f vertices = geometry.getVertices();
        IntArray indices = geometry.getIndices();
        int closestTriangleIndex = -1;
        for (int i = 0; i < indices.getSize()/3; i++)
        {
            int vi0 = indices.get(i * 3 + 0);
            int vi1 = indices.get(i * 3 + 1);
            int vi2 = indices.get(i * 3 + 2);

            vertices.get3f(vi0, p0);
            vertices.get3f(vi1, p1);
            vertices.get3f(vi2, p2);

            boolean intersect = RayTriangle.intersect(
                rayOrigin, rayDirection, p0, p1, p2, result);
            if (intersect)
            {
                if (result.z < closestResult.z)
                {
                    closestResult.set(result);
                    closestTriangleIndex = i;
                }
            }
        }

        if (closestTriangleIndex >= 0)
        {
            Point3f barycentricCoordinates = new Point3f();
            barycentricCoordinates.x = (1-closestResult.x-closestResult.y);
            barycentricCoordinates.y = closestResult.x;
            barycentricCoordinates.z = closestResult.y;
            return PickingResults.create(geometry, closestResult.z, 
                closestTriangleIndex, barycentricCoordinates);
        }
        return null;
    }

Das „RayTriangle.intersect“ ist dann aber etwas zu viel, um es noch hier zu posten)

Wenn jemand wie @Fancy nichts konkretes dazu sagt, kann ich Mitte/Ende nächster Woche, wenn ich wieder einen Hauch mehr Zeit habe, ggf. nochmal weiterantworten…

[/spoiler]

Also danke erstmal für die Antwort.
Ich schau mir deine rendering dinger mal an, ty.

Wenn jemand wie @Fancy nichts konkretes dazu sagt, kann ich Mitte/Ende nächster Woche, wenn ich wieder einen Hauch mehr Zeit habe, ggf. nochmal weiterantworten…

Ich denke das wird nicht nötig sein, denn ich bin einfach nur dumm.
(OT: Ich erwähnte es schon mehrmals, aber um diese Zeit zu coden tut mir nicht gut -.-)

Natürlich berechne ich projection * camera * model. aber nur, und eben NUR auf der Grafikkarte. Das ich diese Werte
ggbf auch auf der Cpu brauchen KÖNNTE, ist mir irgendwie nicht eingefallen. also statt auf der cpu die selbe berechnung wie
auf der gpu zu machen und dann die richtigen Werte zu haben, (ja es ging mir um das andersrum - aber das war eben auch falsch)
hab ich versucht irgendnen mist zu machen, um werte von einem space in einen ganz anderen umzurechnen, was völliger müll ist…

Also ich versuchs heute noch mal wie ein Mensch, poste nachher das Ergebnis… ^^

Okay, nein.
ich bin da eindeutig zu blöd für.

Ich verstehe nicht was ich jetzt tun sollte, versuche aber noch einmal alles zu erklären.

Wenn ich die Kamera erstelle, benutz ich wie gesagt folgende werte für left, right, top, bottom:
(es geht die ganze zeit um orthografisches 2d!)

		this.top = (float) (Math.tan(Math.toRadians(fov) / 2));
		this.bottom = -top;
        this.right = top * aspect;
        this.left = -right;```

So. Bei einem Fov von 100, den ich benutze, enspricht das den werten: `right: 1.5890049, left: -1.5890049, top: 1.1917536, bottom: -1.1917536`

So. Das heißt doch jetzt: 
Wenn ich ein Rechteck hab, und es um 1.589... verschiebe, dann ist die x position dieses rechtecks 1.589... und es befindet sich genau aus dem bild. 
Mit der Model Matrix passiert also folgendes: model.translate(new Vecto3f(1.589..., 0, 0));

(ich lasse die model view / kamera matrix nun weg, da sich die kamera erstmal nicht bewegen soll.)

gut. projection * model ergibt bei der oben genannten Verschiebung folgende Matrix:

```0.6293247 0.0 0.0 0.6293247
0.0 0.8390996 0.0 0.0
0.0 0.0 -0.0020001999 0.0
0.0 0.0 0.0 1.0```

Interressant. Eine Matrix mit irgendwelchen noch seltsameren fließkommazahlen < 1.
Aber das soll mich ja angeblich nicht kümmern, so sei halt mein Maßstab. 

Okay. Was ich jetzt will ist folgendes: 

Es gilt:

Screen / Display Maße: 800 x 600

mousex = Mouse.getX() - Display.getWidth() / 2, damit der Ursprung quasi in der Mitte liegt (wie bei meiner projektion) und nicht 
unten links. Ganz rechts enspricht mousex also 400 und nicht 800. 
diese 400 soll ja, laut meiner projektion, in meiner szene dem "right" wert entsprechen, bzw dem was bei projection * model rauskommt. 
Heißt so viel wie eine neue Matrix erzeugen, dann matrix.translate(new Vector3f(mousex -> 400, 0, 0)) -> das ganze mit der inversen projektion multiplizieren. 
dabei kommt die folgende Matrix raus:

```1.589005 0.0 0.0 635.602
0.0 1.1917536 0.0 0.0
0.0 0.0 -499.95007 0.0
0.0 0.0 0.0 1.0```

was natürlich keinen sinn macht. Der wert den ich suchen würde sei ja 
der vierte wert der ersten zeile, also 635.602, aber erwarten sollte ich ja "right", also 1.589..., oder eben, wie nach projektion 0.6293...



Wo ist jetzt mein verdammter Denkfehler?
Was verstehe ich falsch. Irgendwo ist doch wieder pure Dummheit versteckt...

Hilfe :(

Ich verstehe nicht was ich falsch denke.

Ja, es ist schwierig. Wie orthographische Projektion und “FOV” zusammenpassen, leuchtet mir nicht ganz ein (FOV ist der “Öffnungswinkel” des Blockfeldes - das würde eine perspektivische Projektion bedeuten!).

Ansonsten dämmert mir die Vermutung, dass du vielleicht einfach die Umrechnung in Bildschirmkoordinaten nicht machst. Irgendwo rufst du ja vermutlich glViewport auf. Das verwendest du ja bisher nicht. Nirgendwo in den Berechnungen ist erkennbar, ob der Bildschirm 800x600 oder 1600x1200 pixel groß ist. (Nur den aspect verwendest du, aber da steckt die Größe ja nicht mehr drin).

Vielleicht ein kleiner verwandter link zu http://forum.byte-welt.net/threads/12223-Viewing-Pipeline

Nichts
[spoiler]


package bytewelt;

import javax.vecmath.Matrix4f;
import javax.vecmath.Point2f;
import javax.vecmath.Point3f;
import javax.vecmath.Tuple2f;
import javax.vecmath.Tuple3f;


// Parts taken from http://www.songho.ca/opengl/gl_transform.html
public class Viewing
{
    private static final int SCREEN_SIZE_X = 800;
    private static final int SCREEN_SIZE_Y = 600;
    
    public static void main(String[] args)
    {
        float left = -1.5890049f;
        float right = 1.5890049f;
        float bottom = -1.1917536f;
        float top = 1.1917536f;
        float near = 1.0f;
        float far = 100.0f;
        Matrix4f p = setOrthoFrustum(left, right, bottom, top, near, far);
        System.out.println(p);

        Point3f pointL = new Point3f(left,0,0);
        Point3f pointR = new Point3f(right,0,0);
        Point3f pointB = new Point3f(0,bottom,0);
        Point3f pointT = new Point3f(0,top,0);

        printInfo("pointL", pointL, p);
        printInfo("pointR", pointR, p);
        printInfo("pointB", pointB, p);
        printInfo("pointT", pointT, p);
    }
    
    private static void printInfo(String name, Point3f point, Matrix4f p)
    {
        Point3f result = new Point3f();
        p.transform(point, result);
        Tuple2f screen = toScreen(result);
        System.out.println(name);
        System.out.println("  at "+point);
        System.out.println("  transformed "+result);
        System.out.println("  on screen "+screen);
        System.out.println("  back "+toDevice(screen));
    }
    
    private static Tuple2f toScreen(Tuple3f point)
    {
        float x = (point.x + 1) * (SCREEN_SIZE_X / 2.0f);
        float y = (point.y + 1) * (SCREEN_SIZE_Y / 2.0f);
        return new Point2f(x,y);
    }

    private static Tuple3f toDevice(Tuple2f point)
    {
        float x = -1.0f + 2.0f * (point.x / SCREEN_SIZE_X);
        float y = -1.0f + 2.0f * (point.y / SCREEN_SIZE_Y);
        return new Point3f(x,y,0);
    }
    
    //  0  1  2  3 
    //  4  5  6  7
    //  8  9 10 11
    // 12 13 14 15
    
    static Matrix4f setOrthoFrustum(float l, float r, float b, float t, float n, float f)
    {
        Matrix4f m = new Matrix4f();
        m.setIdentity();
        m.m00 = 2.0f / (r - l);
        m.m03  = -(r + l) / (r - l);
        m.m11  = 2 / (t - b);
        m.m13  = -(t + b) / (t - b);
        m.m22 = -2 / (f - n);
        m.m23 = -(f + n) / (f - n);
        return m;
    }    
}

[/spoiler]

Hm. Aber die Größe des Display sollte doch egal sein?
Mit Fov mein ich doch quasi nur, wie viel ich vom bild sehe. Sprich
ich dachte mir bei ner orth. proj., je größer fov, desto kleiner alles,
also mehr auf dem bild…
Ja die Größe steckt da nicht drin, aber doch left right top bottom - das sollte doch irgendwie reichen??

glViewport? Ist das nicht irgendetwas total veraltetes?

Hm. Du hast irgendeine Matrix. Diese Matrix sieht aus, wie sie aussieht. Es ist die gleiche Matrix, egal, ob der Bildschirm 800x600 oder 1600x1200 pixel hat. Jetzt hat man eine Mausposition von (-400,-300) (wenn (0,0) in der Mitte ist). Woher soll man nun wissen, ob diese Position ganz unten links ist (für 800x600), oder einfach nur „ein bißchen unten links“ (für 1600x1200)? Irgendwo muss diese Information ja wieder in die Rechnung eingebracht werden. glViewport ist nicht veraltet - oder willst du andeuten, dass du es nicht aufrufst? :smiley:

wieso sollte ich es denn bitte aufrufen?

ja das ist mir ja bewusst. aber … hä?
ich verstehe dein beispiel “Nichts” nicht…