3D-Grafik Linie mit Textur

S

s_m_w

Gast
Hallo,

Ich habe eine Bezierkurve mit Breite b, die ich gerne mit einer Textur füllen würde. Das Problem ist jedoch, dass die Textur mit der Linie mitgehen soll (ansonsten wäre es ein recht trivialies Problem mit TexturePaint).

Die Bezierkurve wird als zwei Arrays, die jeweils Koordinaten zweier Bezierkurven enthalten, die jeweils den Linken und Rechten Rand der Bezierkurve definieren, übergeben. Als ersten Ansatz habe ich aus diesen Punkten Polygone erzeugt, meine Textur rotiert und dann damit die Polygone gefüllt, doch das Ergebnis ist nicht ganz erfreulich:

hx2psw.png


Im folgenden der Code:

("Vec" ist ein Point2D mit einigen Vektoroperatrionen, die selbsterklärend sein sollten)

Java:
    void drawTexturedLineFromVecArray(Graphics2D g, ArrayList<Vec> Pt1, ArrayList<Vec> Pt2, BufferedImage Texture) {
        ArrayList<Polygon> Polys = new ArrayList();
        ArrayList<Double> Angles = new ArrayList();

        // Transform the coordinates into polygons
        Iterator<Vec> it1 = Pt1.iterator();
        Iterator<Vec> it2 = Pt2.iterator();
        Vec Left = it1.next();
        Vec Right = it2.next();

        Polygon newP;

        while (it1.hasNext()) {
            Vec UpperLeft = it1.next();
            Vec UpperRight = it2.next();

            newP = new Polygon();
            newP.addPoint((int) UpperLeft.x, (int) UpperLeft.y);
            newP.addPoint((int) UpperRight.x, (int) UpperRight.y);
            newP.addPoint((int) Right.x, (int) Right.y);
            newP.addPoint((int) Left.x, (int) Left.y);

            Vec AngleVec;
            Vec v1, v2;
            v1 = UpperLeft.add(UpperRight);
            v1 = v1.multiply(0.5);
            v2 = Left.add(Right);
            v2 = v2.multiply(0.5);
            AngleVec = v1.subtract(v2);

            Angles.add(Math.atan2(AngleVec.y, AngleVec.x) + Math.PI / 2);

            Polys.add(newP);
            Left = UpperLeft;
            Right = UpperRight;
        }

        // Here is where it gets interesting

        int newTextureWidth = 50;
        int newTextureHeight = 50;

        Iterator<Polygon> it3 = Polys.iterator();
        Iterator<Double> angleit = Angles.iterator();
        // Go through all Polygons and their respective angles
        while (it3.hasNext()) {
            Polygon P = it3.next();
            // generate a new image
            BufferedImage RotatedTexture = new BufferedImage(newTextureWidth, newTextureHeight, BufferedImage.TYPE_INT_ARGB);
            Graphics2D TextureGraphics = (Graphics2D) RotatedTexture.getGraphics();

            // Use our original texture as paint material
            TextureGraphics.setPaint(new TexturePaint(Texture,
                    new Rectangle2D.Float(0, 0, Texture.getWidth(), Texture.getHeight())));

            AffineTransform xform = new AffineTransform();

            xform.setToIdentity();
            // rotate around the center
            xform.rotate(angleit.next(), RotatedTexture.getWidth() / 2, RotatedTexture.getHeight() / 2);
            TextureGraphics.transform(xform);
            TextureGraphics.fillRect(0, 0, RotatedTexture.getWidth(), RotatedTexture.getHeight());
            xform.setToIdentity();

            g.setPaint(new TexturePaint(RotatedTexture,
                    new Rectangle2D.Float(0, 0, RotatedTexture.getWidth(), RotatedTexture.getHeight())));
            g.fillPolygon(P);

        }
    }

Die Bezierkurve wird wie folgt erzeugt (keine Probleme hier; nur als Zeitersparnis für die Helfer):

Java:
        TargetX = (int) Target.getCenterX();
        TargetY = (int) Target.getCenterY();
        OriginX = (int) Origin.Position.x;
        OriginY = (int) Origin.Position.y;
        
        // Start and end
        int startX = (int) (OriginX + OriginOffset.x);
        int startY = (int) (OriginY + OriginOffset.y);
        Vec start = new Vec(startX, startY);
        int endX = TargetX;
        int endY = TargetY;
        Vec end = new Vec(endX, endY);
        // Two points that define the look of the laser curve
        Vec P2 = new Vec(startX*0.8+endX*0.2, startY*0.5+endY*0.25-50);
        Vec P3 = new Vec(startX*0.5+endX*0.5, (startY-100)*0.2+endY*0.8);

        //P(t) = (1-t)^3P0 + 3(1-t)^2tP1 + 3(1-t)t^2P2 + t^3P3 with t running from 0 to 1.
        double precision = 0.1;
        double laser_width = 33;
        
        Vec A, B = new Vec();
        Vec DiffVec;

        double angle = 0;
        double partX, partY;
        
        // Save all generated points so we have X different arrays of points of a line
        ArrayList<Vec>[] Points = new ArrayList[5];
        for (int j=0;j<2;j++) {
            Points[j] = new ArrayList();
        }
        
        
        
        G.setColor(new Color(255, 255, 255, 255));

        for (double t = 0; t < 1;) {
            A = new Vec((int) ((1 - t) * (1 - t) * (1 - t) * start.x + 3 * (1 - t) * (1 - t) * t * P2.x + 3 * (1 - t) * t * t * P3.x + t * t * t * end.x),
                    (int) ((1 - t) * (1 - t) * (1 - t) * start.y + 3 * (1 - t) * (1 - t) * t * P2.y + 3 * (1 - t) * t * t * P3.y + t * t * t * end.y));

            t += precision;

            B = new Vec(
                    (int) ((1 - t) * (1 - t) * (1 - t) * start.x + 3 * (1 - t) * (1 - t) * t * P2.x + 3 * (1 - t) * t * t * P3.x + t * t * t * end.x),
                    (int) ((1 - t) * (1 - t) * (1 - t) * start.y + 3 * (1 - t) * (1 - t) * t * P2.y + 3 * (1 - t) * t * t * P3.y + t * t * t * end.y));
            
            DiffVec = B.subtract(A);
            angle = DiffVec.getAngle() + Math.PI/2; 
            
            for (int j=0;j<=1;j++) {
                partX = A.x + Math.cos(angle)*(((j*2)-1)*laser_width/5);
                partY = A.y + Math.sin(angle)*(((j*2)-1)*laser_width/5);
                Points[j].add(new Vec(partX,partY));
                //G.fillRect((int)partX-3,(int)partY-3,5,5);
            }
            if (t>1) break;
            //G.drawLine((int)A.x, (int)A.y, (int)B.x, (int)B.y);
        }

        Game.getArt().drawTexturedLineFromVecArray(G,Points[0],Points[1],Game.getArt().getContinuousLaserPart());

Bestimmt gibt es genau das, was ich suche schon, habe aber per Google nichts hilfreiches gefunden
 

Marco13

Top Contributor
Hmneee.... so einfach ist das auch nicht. Man muss ja ein Mapping angeben: Für jeden Pixel auf dem Bildschirm muss klar sein, welcher Texturpixel dort hingemalt werden soll (können auch mehrere sein...). Die Bezierkurve besteht üblicherweise ja aus vielen kleinen Geradensegmenten (wenn man den deCasteljau so runtertippt, wie du es anscheinend gemacht hast). (BTW: Man könnte auch einen Path2D mit curveTo verwenden, aber das hätte auf die Frage keinen Einfluß). Selbst wenn man diese Geradensegmente mit jeweils passend verdrehten/verschobenen Bildchen füllen würde, hätte man immernoch Aliasing und vermutlich andere unschöne Effekte (Knicke oder so), von der Performance mal ganz abgesehen...

MUSS das eine Textur sein, oder kann man nicht mit ein paar bunten Strokes zeichnen...?
 

s_m_w

Neues Mitglied
(BTW: Man könnte auch einen Path2D mit curveTo verwenden, aber das hätte auf die Frage keinen Einfluß)
Ah, guter Tipp. Danke

hätte man immernoch Aliasing und vermutlich andere unschöne Effekte (Knicke oder so), von der Performance mal ganz abgesehen...
Ja, kann ich mir vorstellen. Dass die Performance grottig ist habe ich schon gemerkt..

MUSS das eine Textur sein, oder kann man nicht mit ein paar bunten Strokes zeichnen...?
Eine Textur wäre das beste, aber vermutlich muss ich mich mit farbigen Linien zufriedengeben, wenn es wirklich in Echtzeit nur schwer umsetzbar ist. Das sollte auch wesentlich einfacher umzusetzen sein
 

Marco13

Top Contributor
Hab' gerade mal gebastelt: Man kann ja auch eine Linie mit einer Textur zeichnen (mit passenden Stroke und TexturePaint), nur die Aurichtung der Textur ist halt frickelig... vielleicht bastel' ich da morgen (d.h. heute Abend, oder wenn ich Zeit habe) mal weiter...
 

Ähnliche Java Themen

Neue Themen


Oben