Jump to content
Unity Insider Forum

Hilfe bei Ausrichtung von Raycast Grid (ohne Transforms)


Hans im Gestrüpp

Recommended Posts

Hallo,

ich bin zurzeit dabei, eine Funktion zu erstellen, die mehrere Rays verschießt, allesamt parallel zueinander. Sie heißt "MultiLineCast" und wird genauso genutzt wie "Physics.Linecast" und der Check gibt true zurück sollte auch nur ein Ray sein Ziel erreichen. Als Parameter fällt Transform weg um die Möglichkeit zu erhalten die Funktion allein auf Basis von Vektoren auszuführen.

Der Test Code für die Bündelung und Ausrichtung der Rays sieht momentan so aus:

private void OnDrawGizmos() {
        
        if(origin != null && target != null) {

            Gizmos.color = Color.cyan;
            Gizmos.DrawSphere(origin.position, 0.2f);
            Gizmos.DrawSphere(target.position, 0.2f);

            for(int r = 0; r < numRows; r++) {

                for(int c = 0; c < numColumns; c++) {

                    Gizmos.color = Color.green;
                    Gizmos.DrawRay(origin.position + new Vector3(width * c, height * r, 0), (target.position - origin.position));

                }
            }
        }
    }

was dann so aussieht:

previewRaycast.png.5590c0ad99611f0392cc79173abf5c29.png

So weit so gut. Hier tut sich folgendes Problem auf, das ich nicht bewältigen kann da ich in Mathe eine Null bin:

pRayGrid.png.0bcaeba86e4efd3e2e3a25e83b083316.png

Problem: Wenn ich einen der Punkte verschiebe, bleiben die Ray Ursprünge immer gleich im World Space (rote Kennzeichnung). Ich hätte allerdings gerne dass es sich wie bei Kennzeichnung blau verhält. Ich habe wirklich alles probiert und im Internet gesucht, aber all die Formeln und Snippets von UnityAnswers konnte ich einfach nicht umsetzen.

Ich versuche sozusagen ein längs gestapeltes Bündel Rays von einem Punkt zum andern zu schießen während alle Rays im Stapel bündig bleiben, als würde ich einfach nur ein festes Objekt ausrichten.

Wenn mir jemand bitte nur ein paar verständliche Formeln anbieten könnte die zu Unity's Kontext passen, das wäre sehr hilfreich.

 

Vielen Dank schonmal für eure Zeit.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hier ist ein Ansatz, es funktioniert soweit mit der Ausnahme, wenn die beiden Punkte sich nur in Y unterscheiden, dann muss eine Ausnahmebehandlung erfolgen (fehlt noch im Code)
Also zum Beispiel: Vektor1(1, 0.5 , 5) und Vektor2(1, 0.9 , 5)

Dies kommt daher, daß ich das "Koordinatensystem" zwischen den beiden Punkten über die Y-Achse aufspanne.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MultiRay : MonoBehaviour {

    public Transform origin;
    public Transform target;

    public int numRows = 5;
    public int numColumns = 5;
    public float width = 0.25f;
    public float height = 0.25f;

    private void OnDrawGizmos()
    {

        if (origin != null && target != null)
        {

            Gizmos.color = Color.cyan;
            Gizmos.DrawSphere(origin.position, 0.2f);
            Gizmos.DrawSphere(target.position, 0.2f);

            Vector3 dir = (target.position - origin.position).normalized;

            Vector3 crossVector = (-Vector3.Cross(Vector3.up, dir)).normalized;
            Gizmos.color = Color.red;
            Gizmos.DrawRay(origin.position, crossVector * 3.0f);

            Vector3 crossVector2 = (-Vector3.Cross(crossVector, dir)).normalized;
            Gizmos.color = Color.yellow;
            Gizmos.DrawRay(origin.position, crossVector2 * 3.0f);


            for (int r = 0; r < numRows; r++)
            {

                for (int c = 0; c < numColumns; c++)
                {

                    Gizmos.color = Color.green;
                    Vector3 startPoint = -((crossVector * (numColumns-1) * width + crossVector2 * (numRows-1) * height) / 2.0f) + 
                                          origin.position + crossVector * c * width + crossVector2 * r * height;
                    Gizmos.DrawRay(startPoint , (target.position - origin.position));
                    //Gizmos.DrawRay(origin.position + crossVector*c*width + crossVector2 * r*height , (target.position - origin.position));

                }
            }
        }
    }
}

Abschuss Sonne:
MgvOxqy.png

Link zu diesem Kommentar
Auf anderen Seiten teilen

So die Ausnahmebehandlung auch noch fix eingebaut. Damit funktioniert es nun für alle Konstellationen.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MultiRay : MonoBehaviour {

    public Transform origin;
    public Transform target;

    public int numRows = 5;
    public int numColumns = 5;
    public float width = 0.25f;
    public float height = 0.25f;

    private void OnDrawGizmos()
    {

        if (origin != null && target != null)
        {

            Gizmos.color = Color.cyan;
            Gizmos.DrawSphere(origin.position, 0.2f);
            Gizmos.DrawSphere(target.position, 0.2f);

            Vector3 dir = (target.position - origin.position).normalized;

            Vector3 crossVector = (-Vector3.Cross(Vector3.up, dir)).normalized;
            Gizmos.color = Color.red;
            Gizmos.DrawRay(origin.position, crossVector * 3.0f);

            Vector3 crossVector2 = (-Vector3.Cross(crossVector, dir)).normalized;
            Gizmos.color = Color.yellow;
            Gizmos.DrawRay(origin.position, crossVector2 * 3.0f);

            ExceptionHandling(origin.position, target.position, ref crossVector, ref crossVector2);

            for (int r = 0; r < numRows; r++)
            {

                for (int c = 0; c < numColumns; c++)
                {

                    Gizmos.color = Color.green;
                    Vector3 startPoint = -((crossVector * (numColumns-1) * width + crossVector2 * (numRows-1) * height) / 2.0f) + 
                                          origin.position + crossVector * c * width + crossVector2 * r * height;
                    Gizmos.DrawRay(startPoint , (target.position - origin.position));
                    //Gizmos.DrawRay(origin.position + crossVector*c*width + crossVector2 * r*height , (target.position - origin.position));

                }
            }
        }
    }

    void ExceptionHandling(Vector3 orgin, Vector3 target, ref Vector3 crossVector, ref Vector3 crossVector2)
    {
        // Prüfen ob sich die beiden Vektoren nur über die Y-Achse unterscheiden
        Vector3 diff = orgin - target;
        if (diff.x == 0 && diff.z== 0)
        {
            crossVector = Vector3.right;
            crossVector2 = Vector3.forward;
        }
    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wow, danke dafür Zer0! Ich hatte kleine Denkanstöße erwartet, aber dank dir kann ich dieses Unterprojekt schonmal abhaken. Ich frage mich wirklich wie man so gut wird in solchen Berechnungen. Für mich ergibt zum Beispiel die Formel für den Vektor startPoint überhaupt keinen Sinn. Wie kann man da durchblicken?! :)

Wenn ich hier eine Offtopic Frage einbinden dürfte: Welche Gebiete der Mathematik sind denn ganz besonders hilfreich, um besser mit Vektoren und Rotationen klarzukommen?

 

Edit: Im Nachinein fällt mir auf, dass ich die Variablen width und height eigentlich als Definition der Dimensionen aller Rays integrieren würde, sozusagen als Stapelhöhe und -breite und die Anzahl der Rays (numRows, numColumns) würde dann als Resolution dienen.

Hier meine frühere, nennen wir es mal "Implementierung" dieser Funktionalität:

for(int r = 0; r < numRows; r++) {

	for(int c = 0; c < numColumns; c++) {

    		Gizmos.DrawRay(origin.position + new Vector3((width / numColumns) * c, (height / numRows) * r, 0), target.position - origin.position);
	}
}

Allerdings verändert sich die Breite bzw. Höhe beim Ändern der Ray Anzahl in geringem Maße (mit jeder Iteration weniger). Außerdem fehlt hier natürlich auch die elegante Ausrichtung.

@Zer0Cool, wie würde ich dieses Verhalten in die startPoint Formel einbringen?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich hoffe, ich hab beim Überfliegen das Problem nicht falsch verstanden, aber warum nicht einfach Gizmos.matrix nutzen?

Hier ein kleines Beispiel, das nicht zu deinem Problem passt, aber die Funktionsweise vermutlich gut verdeutlicht:

private void OnDrawGizmos()
{
  Gizmos.matrix = transform.localToWorldMatrix;
  
  Gizmos.DrawRay(Vector3.zero, Vector3.forward);
  Gizmos.DrawRay(Vector3.right, Vector3.forward);
}

Das einfach mal auf ein Objekt packen und mit Position, Rotation und Scale des Objekts spielen.

Die Matrix4x4-Klasse hat eine statische Funktion namens Matrix4x4.TRS. Damit kannst du eine Matrix erstellen, statt sie wie im Beispiel aus einer Transform-Komponente zu ziehen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hey Sascha, danke für den Tipp!

Dein Code snippet kann ich leider nicht anwenden, da Transforms wegfallen um die entstehende Funktion im Fall der Fälle allein mit Vektoren betreiben zu können, so wie bei Physics.LineCast.

Ich habe diese Matrix.TRS Funktion mal unter die Lupe genommen und mir die Member angeschaut, daraus werde ich allerdings nicht schlau. Ich habe zwar eine Vorstellung davon wie in meinem Fall die Matrix aussehen müsste (Länge: 2 (Startpunkt, Endpunkt) Höhe und Breite unbestimmt (da einstellbar)), aber die Umsetzung ist das Problem.

Wie lege ich z.B. die Länge einer Matrix von Punkt A nach Punkt B fest? Oder wie ändere ich die Höhe und Breite mit zwei Variablen in einem loop während Start und Ende der Matrix mittig an Startpunkt und Endpunkt anliegen?

5a6c6d614ee72_MatrixDiagram.png.daf50bc4c39975d8a10655eb934f544a.png

Auch wenn es ja nun dank Zer0Cold nicht mehr nötig ist, wäre ich um meiner Erfahrung Willen dankbar wenn mir jemand erklären könnte wie ich mein Vorhaben mit Matrizen umsetzen kann. Falls mal jemand Zeit hat. :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Die Matrix4x4 ist die kompakte Form einer 3D-Transformation. Die enthält in einer einzelnen Matrix Verschiebung, Drehung und Skalierung statt dafür drei einzelne Structs zu haben. TRS benutzt du, um so eine Matrix aus diesen drei Structs zusammen zu bauen.

So gibt z.B.

var matrix = Matrx4x4.TRS(transform.position, transform.rotation, transform.lossyScale);

exakt dasselbe Ergebnis wie

var matrix = transform.localToWorldMatrix;

(wenn ich jetzt nicht irgendeinen Denkfehler drin habe).

vor 4 Stunden schrieb Hans im Gestrüpp:

Dein Code snippet kann ich leider nicht anwenden, da Transforms wegfallen um die entstehende Funktion im Fall der Fälle allein mit Vektoren betreiben zu können, so wie bei Physics.LineCast.

Hab ja extra gesagt:

vor 5 Stunden schrieb Sascha:

Hier ein kleines Beispiel, das nicht zu deinem Problem passt, aber die Funktionsweise vermutlich gut verdeutlicht

Das ist so nicht zur Anwendung gedacht gewesen, sondern zum Kopieren - und dann kannst du damit ein Gefühl dafür kriegen, was das Ding macht.

Das Beispiel zeichnet zwei Linien. Beide sind einen Meter lang und gehen nach vorne. Die eine ist einen Meter rechts neben der anderen. Dadurch, dass aber vorher Gizmos.matrix gesetzt wird, werden die nachfolgenden Gizmos-Befehle transformiert, und zwar entsprechend der Matrix. Dass ich da jetzt die Matrix aus der Transform-Komponente gezogen habe, ist wirklich nur als Beispiel, damit du im Editor über die Werte der Komponente im Inspektor rumspielen kannst. Im eigentlichen Code würdest du dann Matrix4x4.TRS benutzen, um die eine beliebige Matrix selbstzubauen.

Das könnte dann etwa so aussehen:

private void OnDrawGizmos()
{
  Gizmos.matrix = Matrix4x4.TRS(startPosition, Quaternion.LookDirection(direction), Vector3.forward * length);
  
  for(var x = -4; x <= 4; x++)
  {
    for(var y = -4; y <= 4; y++)
    {
      Gizmos.DrawRay(new Vector3(x, y, 0), Vector3.forward);
    }
  }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...