• Bitte schaltet eure Ad Blocker aus. SLinfo kann nur betrieben werden, wenn es durch Werbung Einnahmen erzielt. Vielen Dank!!
  • Wir freuen uns, wenn du dich in unserem Forum anmeldest. Bitte beachte, dass die Freigabe per Hand durchgeführt wird (Schutz vor Spammer). Damit kann die Freigabe bis zu 24 Stunden dauern.
  • Wir verwenden Cookies, um Inhalte und Anzeigen zu personalisieren, Funktionen für soziale Medien anbieten zu können und die Zugriffe auf unsere Website zu analysieren. Sie geben Einwilligung zu unseren Cookies, wenn Sie unsere Webseite weiterhin nutzen.

Pfadfinderbiene, Tutorial

Jenna Felton

Superstar
Pathfinding: Biene, Tutorial

Hallo, da ich schon soetwas quasi angekündigt habe, möchte ich hier eine Art Tutorial für Pathfinding machen, in dem eine Biene, angetrieben mit dem KI den Weg von Blume zur Blume finden wird. Die KI gehört zur Technologie von Pathfinding, die sich zur Zeit am Ende der Entwicklungsphase befindet. Viel wird sich dabei nicht mehr ändern, so dass man damit schon spielen kann.

Vielleicht (als Vorschlag) sollte man deshalb einen Unterforum in Bauen / Bauen und Basteln einrichten, und den Thread, sofern genug informativ dorthin verschieben. Pathfinding betrifft nicht nur das Scripten, daher passt ins Scripterforum auch nicht vollständig.

Warum die Biene. Zum einen weil ich die Tierchen mag, zum anderen schweben sie, das ist schon etwas anderes/neues als die rollende Steine der Linden Realms. Das macht sie zwar immer noch einfach zu realisieren, die Pfadfinder-KI benötigt eigentlich wenige und einfache Befehle, um komplexe Vorgänge auszulösen. Das Schweben macht sie aber etwas komplizierter und anspruchsvoller, so dass man damit schon die Technik gut kenenlernen kann. Die Biene wird aber neben dem Pfadfindercode auch einiges mehr enthalten.

Ich mache aber schrittweise, weil ich selber erst am Anfang bin, daher wird der Tread einige Tage oder Wochen dauern. Man kann hier aber nicht nur lesen, sondern posten und diskutieren. Zuerst aber das Teil 0, wo ich Links einstelle was man so lesen sollte zum Thema und ich gebe eine kurze Beschreibung für die benutzte Befehle, damit man die Scripte leichter verstehen kann. Ich werde aber nicht die ganze Wiki zitieren sondern nur das erklären was ich nutzen will. Daher wird der Post hier immer wieder erweitert.

Pathfinding wird öft als "PF" abgekürzt. Ist sonst ein Zungerbrecher, daher mache ich so auch ab und zu.

Teil 0

Zunächst einige Links.

Das Pathfinding beginnt in der Wiki hier: Pathfinding in Second Life. Allerdings finde ich als Einstieg wesentlich besser diese Seite: Good Building Practices, diese wird als eine Art Dokumentation zum Bauen allgemein und Pathfinding fungieren, und schon jetzt sehr gut ausgebaut.

Pathfinding ist eine Technologie, die mittels einer KI ermöglicht, den sogenannten Characters (Spielfiguren) einen Weg in der gegebenen Umgebung zu finden. Die Umgebung ist dabei die Navmesh, also eine Art Karte, die von der Topologie der Sim und Gegenstände daraus berechnet wird. Die Berechnung führt die Sim selbst aus, die Benutzer bekommen davon aber nur mit wenn sie mit einem Viewer unterwegs sind, der die Pfadfindererweiterung enthällt. Dann hat die Regionleiste oben einen Symbol, der Angibt, ob Pathfindung in der Region aktiviert ist und ob die Navmesh aktuell ist. Ist sie nicht aktuell, zeigt der Viewer auch einen Button unten, mit dem man diese Berechung starten kann (das dauert, daher wird nicht ständig durchgeführt, wenn sich die Hindernisse auf der Sim verschieben)

Ansonsten wird die Pathfindungs-Operationen mittels der LSL Skripte ausgeöst, daher reicht für das Tutorial hier jeder Viewer. Wer Firestorm mag, oder Singularity, oder..., kann sicher dabei bleiben. Nur wer die Pfade sehen möchte, welche die die KI berechnet hat, oder wissen möchte, ob PF auf der Region aktiv ist, der braucht den Pathfinderviewer. Hier kann man ihn herunterladen: Pathfinding

Inzwischen ist auch die Betaversion des SL Viewers erschienen, die unter anderem den Viewercode für Pathfinding enthällt (Version 3.4.0-262596.)

Zu holen auf der Downloadseite. Wesentlich ausführlicher hat Maddy darüber gebloggt.

So, inzwischen ist das Pathfinding auch im Maingrid aktiv, aber nicht überall eingeschaltet. Im Betagrid, wo ich die meiste Tests gemacht habe, fand ich keine Region mit aktiven PF, außer der vorgeschlagenen PathTest1, PathTest2, PathTest3 und PathTest4.

Funktionen

llCreateCharacter

Erstellt den Character aus einem Objekt der den Skript enthällt. Bevor ein Objekt die PF-Funktionen nutzen kann, muss es ein Character werden, also die Spielfigur. Diese Funktion ist also die erste, die aufgerufen wird und werden muss. Die Character-Eigenschaft ist eine Eigenschaft des Objekts und des Skripts. Löscht man den Skript, bleibt das Objekt der Character bis die Funktion llDeleteCharacter aufgerufen wurde. Die llCreateCharacter Funktion wird mit einer Liste von Optionen erstellt, die das Verhalten des Characters angeben:

  • CHARACTER_DESIRED_SPEED - Geschwindigkeit mit der sich der Char normal bewegen sollte.
  • CHARACTER_MAX_SPEED - Höchstgeschwindigkeit für das Character
  • CHARACTER_RADIUS - Radius der Kollisionskapsule die den Character einschliest: Die Kapsule hat für die Sim die Form eines Zylinders mit Halbkugeln an den Seiten.
  • CHARACTER_LENGTH - Länge des Kollisionskapsule.
  • CHARACTER_ORIENTATION - Ist die Kapsule vertikal oder horizontal?
  • TRAVERSAL_TYPE - Korrigiert die Geschwindigkeit an den Orten, die nicht 100% begehbar sind (Begehbarkeit wird bei der Einstellung der Umgebung für Charactertypen A bis D eingetragen)
  • CHARACTER_TYPE - Bestimmt welches Typ ist der Char, A bis D oder keines (voreinstellung)
  • CHARACTER_AVOIDANCE_MODE - Soll der Char andere Chars und Hindernisse ausweichen?
  • CHARACTER_MAX_ACCEL, CHARACTER_MAX_DECEL - wie schnell wird der Char beschläunigen oder bremsen.
  • CHARACTER_DESIRED_TURN_SPEED - Geschwindigkeit an den Kurven.
  • CHARACTER_MAX_TURN_RADIUS - Radius der Kurven.

Die Werte haben Voreinstellungen so dass man die Liste sogar leer lassen kann.

llUpdateCharacter

Damit lassen sich die Charactereigenschaften dynamisch ändern. Die Funktion erwartet eine Liste von Werten, die zu ändern sind.

llNavigateTo

Diese Funktion erwartet einen Vektor und Liste mit Optionen. Der Vector gibt die (regionale) Koordinate des Punktes, zu dem sich der Char begeben soll. Als Option wird derzeit nur die FORCE_DIRECT_PATH unterstützt. Ist die gesetzt, nimmt der Char einen direkten Weg, und keinen berechneten. Das könnte etwa helfen wenn der Char in einer Falle steckt oder so.

llExecCharacterCmd

Der Character soll einen Befehl ausführen, der an die Funktion übergeben wird. Etwa in die Luft springen, oder anhalten (werden wir nutzen.)

path_update

Dieses Ereignis wird ausgelöst, wenn sich am Pfad etwas ändert, etwa wenn der Char das Ziel erreicht hat oder der Pfad plötzlich blokiert ist. Dann kann man den Nächsten Punkt ansteuern.

So, im moment reicht das für den Teil 0. Im nächsten Teil geht aber zur Sache :) wenn ich Bilder bearbeitet und hochgeladen habe.

LG
 
Zuletzt bearbeitet:
Teil 1: Visitor

Ok, Teil 1, hier werden wir einfach einen Character bauen, der eine bestimmte Position ansteuert. Dazu werden wir die Funktion llNavigateTo benutzen, natürlich nachdem wir den Character erstellt haben, mit llCreateCharacter.

Die Tests und Bilder habe ich im Betagrid gemacht etwa auf dieser Position: PathTest1 (in Aditi)

1. Zielmarkierung

Zuerst müssen wir aber den Zielpunkt markieren, wir brauchen die Regionkoordinate für die Funktion, und zwar am Simboden, am besten lassen wir sie ausgeben. Der Skript ist einfach:

Code:
default {
    state_entry() {}
    
    touch_start(integer total_number) {
        if (llDetectedKey(0) == llGetOwner()) {
            vector pos = llGetPos();
            vector msc = llGetScale();
            
            pos.z = pos.z - msc.z/2.0;
            
            llWhisper(0, (string)pos);
        }
    }    
}

Die PF Characters benötigen die Position auf dem Boden (höhere Positonen ergeben Fehler), daher wird die lokale Position umgerechnet, bevor die Ausgabe stattfindet. Dieser Skript geht einfach in ein Konus, den wir Phantom machen:

attachment.php

Den Konus klicken wir an, der gibt dann die Position am Boden aus:

attachment.php

in diesem Fall ist es der Vector <93.76396, 31.10127, 22.00080>. Diese Angabe müssen wir uns merken.

2. Spielfigur: Visitor, Typ 1

So, jetzt kommt der eigentliche Character. Es wird zwei Typen geben in diesem Teil, die sich leicht unterscheiden, hier ist der erste.

Code:
vector  TARGET = <0, 0, 20>;

default {
	state_entry() {
		llSay(0, "Hello World");

		llDeleteCharacter();
		llCreateCharacter([
			CHARACTER_MAX_SPEED,       3.0,
			CHARACTER_DESIRED_SPEED,   2.0,
			CHARACTER_RADIUS,          0.125,
			CHARACTER_LENGTH,          1.0,
			CHARACTER_AVOIDANCE_MODE, AVOID_CHARACTERS,
			CHARACTER_DESIRED_TURN_SPEED, 3.0,
			CHARACTER_MAX_TURN_RADIUS, 0.5
			]);
	}
	on_rez(integer start_param) {
		llResetScript();
	}

	touch_start(integer total_number) {
		if (llDetectedKey(0) == llGetOwner()) {
			TARGET = (vector)llGetObjectDesc();
			llNavigateTo(TARGET, []);
		}
	}

	path_update(integer update, list reserved) {
		if (update == PU_SLOWDOWN_DISTANCE_REACHED) {
			llSay(0, "Nearing the target");
		}

		else if (update == PU_GOAL_REACHED) {
			llSay(0, "I am at target");
		}

		else if (update == PU_FAILURE_INVALID_START) {
			llSay(0, "Navigation failed. Trying direct path");
			llNavigateTo(TARGET, [FORCE_DIRECT_PATH, TRUE]);
		}

		else {
			llSay(0, "I am Lost");
			llExecCharacterCmd(CHARACTER_CMD_SMOOTH_STOP, []);
		}
	}
}

Wichtige Erklärungen

Die Variable TARGET gibt die Zielposition an. Damit man die nicht immer wieder im Skript einstelen muss, überschreibt der Skript den Wert aus der Angabe in der Objektbeschreibung, so kann man die Characterobjekte im Inventar einstellen dann rezzen, ist einfacher.

Die Funktion llCreateCharacter(), wandelt das Objekt zu einem Character um, das machen wir gleich beim Initialisieren, damit wir gleich den Char haben, und andere Funktionen sich nicht beschweren. Der Aufruf llDeleteCharacter(); vorher, macht die Charserstellung sauber: Falls einmal das Objekt schon Character mit allen Einstellungen war, wird dieses gelöscht und bereit gemacht zum erstellen neues Chars.

So, die eigentliche Bewegung beginnt im Touchevent. Hier wird zunächst die Zielposition von der Objektbeschreibung ausgelesen und übernommen, danach legt der Char los, die Funktion llNavigateTo wird zunächst ohne Parameter aufgerufen.

Die PF Engine ruft dann beim Ausführen den Ereignis path_update, teilweise mehrfach auf, so dass man darauf reagieren kann. Der Skript reagiert dann so: Ist der Aufrufsgrund PU_SLOWDOWN_DISTANCE_REACHED oder PU_GOAL_REACHED, sind wir nae oder am Ziel, passiert nichts. Ist der Grund PU_FAILURE_INVALID_START, konnte kein Pfad zum Ziel berechnet werden, der Char versucht dann einen direkten Weg - wir rufen nochmal llNavigateTo auf, diesmal geben aber an, wir wollen direkt hin. Und bei anderen Gründen gab es einen Fehler, wir halten nur an - Funktion llExecCharacterCmd mit dem Haltebefehl.

Den Skript legen wir am besten in eine Kugel (die habe ich rot gefärbt) namens Visitor 1, und nehmen sie auf ins Inventar - zur mehrfachen Benutzung. Dann dort die Objektbeschreibung der Kugel korrigiert und den obigen Vector zur Zielposition eingetragen:

attachment.php
[/IMG]​

Jetzt rezzen wir den Visitor. Ich habe einen Ort um die Ecke genommen. Damit der keinen direkten Weg nimmt. Die Charhöhe ist als 1m eingestellt, daher schwebt die Kugel 50cm über dem Boden. Damit das auf dem Bild sichtbar ist, habe ich art Scheibe darunter gerezzt, also direkt unter der Kugel:

attachment.php

Jetzt spätestens muss man die Zielposition als Beschreibung eintragen. Da bereits vorgenommen, reicht nur ein Klick darauf:

attachment.php

Ich weiß nicht wie man Videos macht, ich habe nur mehrere Schreenshots zusamengefügt, so dass man den Verlauf sehen kann. Die orangene Linie ist der Pfad am Boden, über dem der Char gelaufen ist. Am Ende habe ich ebenfalls die Scheibe gerezzt damit man die Halteposition auf dem bild sehen kann. Wie man sieht, der Char ist nicht ganz am Ziel. Darauf werde ich genauer später kommen.

So. Jetzt machen wir paar Weiteren Läufe. Die Nächste Startposition ist hinter einem Baum. Der Char könnte den Baum links und rechts passieren, die Kugel hat sich für links entschieden :)

attachment.php

Habe leider nur zwei Screenshots gemacht, daher sieht man nur die Kugel am Anfang hinter dem Baum und am Ende beim Konus. Beim letzten Lauf wird die KI es etwas schwerer haben, die Kugel muss hinter zwei Ecken laufen, was sie aber problem meistert:

attachment.php

So sehen die drei angekommene Visitorchars aus dann, die Rezzscheibe habe ich wieder wegen der fehlenden Tiefe im Bild gerezzt:

attachment.php

Dem Chat kann man entnehmen, der Char hat zunächst die Annäherung angekündigt (PU_SLOWDOWN_DISTANCE_REACHED), dann die Ankunft (PU_GOAL_REACHED). Interessant ist auch zu beobachten, wenn es schon paar Chars ankamen und den Weg versperrt haben, dann versucht der neue Ankömmling, den Weg zu finden und beginnt, willd ums Ziel zu kreisen, aber irgendwann findet er den Anschluss. Das kann auch 10 Minuten dauern, leider bekomme ich dabei kein Ereignis ausgelöst und kann nicht darauf reagieren. Evtl ist das einen Vorschlag in Jira wert.

Egal. Wie man auf dem Bild gut sehen kann, haben die Chars das Ziel nicht wirklich genau getroffen (obwohl alle drei meinten, die wären am Ziel), Der Abstand ist so 50 bis 80cm vom Ziel entfernt. Der Zielkonus ist phantom, also müsste er die Kugel nicht abstoßen können. Nun, eine Biene, die 60cm von der Blume entfernt landet, würde eigentlich runterfallen. Das Problem ist bekannt und hier in Jira angesprochen. Dort habe ich einen Workaround gepostet. Und zwar, erreicht der Char das Ziel, wird es zusätzlich genau auf die Position verschoben. Die Korrektur ergibt dann den Typ 2 unseres Visitorchars.

3. Spielfigur: Visitor, Typ 2

Ich brauche hier den Code nicht voll zu posten, die Veränderung betrifft nur zwei Zeilen. Ersetzt bitte diesen Codeabschnitt

Code:
		else if (update == PU_GOAL_REACHED) {
			llSay(0, "I am at target");
		}

einfach durch diesen:

Code:
		else if (update == PU_GOAL_REACHED) {
			llSay(0, "I am at target");
			// ++ visitor1 -> visitor2
			llExecCharacterCmd(CHARACTER_CMD_SMOOTH_STOP, []);
			llSetRegionPos(TARGET);
                }

Was passiert hier? Sobald die Kugel meint, sie hätte das Ziel erreicht, wird der Lauf angehalten: Der Stopbefehl bendet den Navigationsbefehl. Anschließend wird der Character via llSetRegionPos sehr genau auf die Zielpositon versetzt. Seine Kapsule bleibt allerdings am Boden und die Kugel wird daher 50cm über dem Boden schweben. Der erweiterte Skript geht dann wieder in eine Kugel (die habe ich gelb gefärbt) und un den Inventar aufgenommen. Der Rest ist identisch, im Inventar die Zielposition als Objektbeschreibung der Kugel eintragen, diese Rezzen und zum Starten anklicken.

attachment.php

Ich habe die Rote Visitorkugeln gelöscht und die erste Startposition gennommen. Der Pfad war derselbe, aber diesmal hat die Kugl genau die Position getroffen. Mehr noch, startet man jetzt mehrere Läufe von egal welcher Position, reien sich die Visitoren witzigerweise schön am Ziel ein:

attachment.php

So, das wars dann vom Teil 1. Im nächsten Teil wird der Char zwischen mehreren Zielen pendeln und den Hindernisslauf machen. Dazu muss ich meinen Skript vom anderen Thread für den Tutorial etwas anpassen.
 
Zuletzt bearbeitet:
Schon cool! Ich hab es allerdings nicht auf dem Testgrid sondern auf unserem mainland getestet.(RC-Magnum-Region)
Interessant auch, daß der Prim einen LI von 15 hat, linkt man allerdings einen zweiten ran, bleibt das bei 15...damit will noch mehr experimentiert werden.
Bin schon auf den nächsten Teil des Tutorials gespannt.
 
Hallo Amadeus, bin noch nicht ganz fertig. Habe unter anderen einen Bug entdeckt, und musste den einschränken, der Bugreport wird aber bereits bearbeitet :)

Und das wegen Landimpakt, das ist richtig, Characters haben immer 15, das Impakt geht von der Pille aus, die den Character darstellt und für die Sim den Kollisionsrahmen angibt. Daher konstant 15. Habe ich in Jira gelesen irgendwo, aber nicht selber überprüft, schön dass Du es bestätigt hast :)
 
Codemodul fürs Testen von PF-Characters

Ok, fast fertig mit dem Teil 2 (es gibt schon erste Bilder)

Dabei musste der Code schon einen etwas größeren Schritt machen, daher möchte ich ein kleines Modul herausziehen, damit der eigentliche Code für den Character kleiner wird und man das Modul auch bei eigenen Tests benutzen kann. Dank dem Codemodul habe ich auf den Bug vorhin gekommen.

Code:
[COLOR=#FF8C00]// --- ----------------------------------------------------[/COLOR]

list PFE_REPORTS = [
    PU_SLOWDOWN_DISTANCE_REACHED,            "Near the Goal (SLOWDOWN_DISTANCE_REACHED)",
    PU_GOAL_REACHED,                         "Goal Reached (GOAL_REACHED)",
    PU_FAILURE_INVALID_START,                "Fail: Can't Start (INVALID_START)",
    PU_FAILURE_INVALID_GOAL,                 "Fail: Wrong Goal (INVALID_GOAL)",
    PU_FAILURE_UNREACHABLE,                  "Fail: Lost Goal (UNREACHABLE)",
    PU_FAILURE_TARGET_GONE,                  "Fail: Goal is Gone (TARGET_GONE)",
    PU_FAILURE_NO_VALID_DESTINATION,         "Fail: Path is Gone (NO_VALID_DESTINATION)",
    PU_EVADE_HIDDEN,                         "Evade: Now Hiding (HIDDEN)",
    PU_EVADE_SPOTTED,                        "Evade: Now Running (SPOTTED)",
    PU_FAILURE_NO_NAVMESH,                   "Fail: Missing Navmesh (NO_NAVMESH)",
    PU_FAILURE_DYNAMIC_PATHFINDING_DISABLED, "Fail: Can't Navigate Here (DYNAMIC_PATHFINDING_DISABLED)",
    PU_FAILURE_PARCEL_UNREACHABLE,           "Fail: Can't Navigate to Goal (PARCEL_UNREACHABLE)"
    ];

reportPFEvent(integer value) {
    value = llListFindList(PFE_REPORTS, [value]);
    if (value < 0) {
        llOwnerSay("Unknown Event ("+(string)value+")");
    }
    else {
        llOwnerSay(llList2String(PFE_REPORTS, value+1));
    }
}

[COLOR=#ff8c00]// --- ----------------------------------------------------[/COLOR]

default {
    path_update(integer update, list reserved) {
        reportPFEvent(update);
        
        [COLOR=#ff8c00]// ... weitere Ereignisverarbeitung[/COLOR]
    }
}

[COLOR=#ff8c00]// --- ----------------------------------------------------[/COLOR]

Das Modul ist eine Erweiterung des path_update Ereignis. Sobald dieser von der PF-Engine aufgerufen wird, wird der Aufruf an die Funktion reportPFEvent weitergeleitet, diese erzeugt eine gelbe Ownernachrcht die meldet dann was los war. Die Liste vor der Funktion kann man später erweitern, falls es neue Grundkonstanten hinzukommen, oder ins Deutsche übersetzen wenn einem danach ist.
 
Zuletzt bearbeitet:
Teil 2: Pendlerchar

So, im Teil 2 soll ein Char erstellt werden, der zwischen mehreren Stationen bzw. Wegweiser pendelt. Die Stationen werden dann später die Blumen sein. Wichtig ist, die Anzahl davon soll zur Laufzeit erweiterbar sein (einfacherhalber aber keine Stationen wegfallen) und die Positionen nicht durch den Skript festlegbar. Dazu muss ein kleines Protokoll her, der es erlaubt, dass der char die Position der Stationen abfragen kann und die Stationen die Positionen auch so melden können. Der Char wird "Shuttle" oder "Pendler" bezeichnet.


1. Protokoll


Der Chat Channel ist 1606231603 (PFWPC in Zahlen, also "PF WayPoint Channel".)

a) Positionsabfrage durch den Pendler

  1. Der Char schreit den String "pf.waypoints?"
  2. Die Stationen schreien den String "pf.waypoint:<x, y, z>|h", wobei x, y, z die Bodenposition des Wegpunktes in globalen Koordinaten, und h ist die Höhe des Wegpunktes über dem Boden
  3. Der Char speichert alle Koordinatenangaben

b) Simultane Positionsmeldung der Stationen.

  1. Die Station wird angeklickt (nach Verschieben und/oder Skallieren)
  2. Die Station schreit den String "pf.waypoint:<x, y, z>|h", mit derselben Bedeutung, meldet dadurch die neue Position
  3. Der Char korrigiert die Koordinatenangabe für die Station

Globale Koordinaten erlauben es den Fehler zu vermeiden, dass der Char den falschen Wegpunkt nimmt. Beim Visitor aus dem Teil 1 konnte man das beobachten: Man rezzt den Visitor auf einer anderen Sim als der Konus steht, und der Visitor rennt zum Punkt mit derselben lokalen Kordinate, aber eben auf der Sim wo er gerezzt war und daher zur falschen Adresse. Globale Koordinaten vermeiden dies, indem der Char sie richtig in lokale Koordinaten der aktuellen Sim umrechnet. Normalerweise sollten dadurch Stationen besuchbar sein, die auf benachbarten Sims liegen, ich konnte aber noch keinen sauberen Simübergang beim Testchar beobachten, daran wird aber bei den Lindens gearbeitet. Im Moment müssen beim Test der Pendler und die Stationen noch auf derselben Sim bleiben.


2. Skript: Station bzw Zielmarkierung


Code:
integer PFWPC = 1606231603;

reportPosition() {
	llSetText(llGetObjectName(), (vector)llGetObjectDesc(), 1.0);
	
	vector loc = llGetPos();
	vector pos = loc + llGetRegionCorner();
	vector msc = llGetScale();
	
	pos.z = pos.z - msc.z / 2.0;
	string info = (string)pos+"|"+(string)msc.z;
	
	llShout(PFWPC, "pf.waypoint:"+info);
	llWhisper(0, info+" ( "+(string)loc+" )");
}

default {
	state_entry() {
		llListen(PFWPC, "", NULL_KEY, "pf.waypoints?");
	}
	
	on_rez(integer start_param) {
		llResetScript();
	}

	listen(integer channel, string name, key id, string message) {
		reportPosition();
	}
	
	touch_start(integer total_number) {
		if (llDetectedKey(0) == llGetOwner()) {
			reportPosition();
		}
	}	
}

Der Code ist etwas umfangreicher als beim ersten Mal. Als Höhe der Station wird dabei die Höhe der Konusspitze gemeldet. Der Wert gilt aber nur wenn der Konus am Simboden steht. Kleiner Gimix dabei, der Name des Stationsprims erscheint zusätzlich über dem Prim als Hovertext.

Der Code geht wieder in ein Phantom-Konus, den wir nach Skriptinstallation ins Inventar aufnehmen. Den Koni kann man die Namen geben, ich habe für "Alpha" und "Beta" entschieden. Der Char wird nämlich sagen im Chat, welchen Konus es besuchen will, so wird es dann übersichtlich.


3. Pendlerchar


So, jjetzt der eigentliche Character Skript. Es gibt nur eine Version

Code:
integer PFWPC    = 1606231603;

list    lTargets = []; [COLOR="#FFA500"]// [(key object)*][/COLOR]
list    lCoords  = []; [COLOR="#FFA500"]// [(vector pos)*][/COLOR]
list    lHeights = []; [COLOR="#FFA500"]// [(float height)*][/COLOR]

integer gTargNum = -1;
key     kTarget  = NULL_KEY;
vector  vTarget;
float   fHeight;

[COLOR="#FFA500"]// --- ----------------------------------------------------[/COLOR]

goToTarget(integer targNum) {
	gTargNum = targNum;
	if (gTargNum >= llGetListLength(lTargets)) gTargNum = 0;

	kTarget = llList2Key(lTargets, gTargNum);
	vTarget = llList2Vector(lCoords, gTargNum);
	fHeight = llList2Float(lHeights, gTargNum);

	llSay(0, "Visit "+llKey2Name(kTarget)
		+" at "+(string)vTarget);

	llNavigateTo(vTarget, []);
}

[COLOR="#FFA500"]// --- ----------------------------------------------------[/COLOR]

default {
	state_entry() {
		llSay(0, "Hello World");
		
		llDeleteCharacter();
		llCreateCharacter([
			CHARACTER_MAX_SPEED,       3.0,
			CHARACTER_DESIRED_SPEED,   2.0,
			CHARACTER_RADIUS,          0.125,
			CHARACTER_LENGTH,          10.0,
			CHARACTER_AVOIDANCE_MODE, AVOID_CHARACTERS,
			CHARACTER_DESIRED_TURN_SPEED, 3.0,
			CHARACTER_MAX_TURN_RADIUS, 0.5
			]);

		[COLOR="#FFA500"]// Fix: PATHBUG-177[/COLOR]
		llUpdateCharacter([CHARACTER_LENGTH, 1.0]);

		llListen(PFWPC, "", NULL_KEY, "");
		llShout(PFWPC, "pf.waypoints?");
	}
	on_rez(integer start_param) {
		llResetScript();
	}

	[COLOR="#FFA500"]// message = "pf.waypoint:<x, y, z>|h"[/COLOR]
	listen(integer channel, string name, key id, string message) {
		if (llGetSubString(message, 0, 11) == "pf.waypoint:") {
			message = llGetSubString(message, 12, -1);

			list tmp = llParseString2List(message, ["|"], []);

			vector target = (vector)llList2String(tmp, 0) - llGetRegionCorner();
			float  height = (float)llList2String(tmp, 1) * 2.0;
			if      (height < 0.5)  height = 0.5;
			else if (height > 10.0) height = 10.0;

			channel = llListFindList(lTargets, [id]);
			if (channel < 0) {
				lTargets += [id];
				lCoords  += [target];
				lHeights += [height];
			}
			else {
				lCoords  = llListReplaceList(lCoords,  [target], channel, channel);
				lHeights = llListReplaceList(lHeights, [height], channel, channel);
			}

			if (id == kTarget) {
				vTarget = target;
				fHeight = height;
				llNavigateTo(vTarget, []);
			}
			
			channel = (integer)llGetListLength(lTargets);
			llSetText((string)channel+" points", <1.0, 1.0, 1.0>, 1.0);
		}
	}

	touch_start(integer total_number) {
		if (llDetectedKey(0) == llGetOwner() && lTargets != []) {
			llSetTimerEvent(0.0);
			if (gTargNum < 0) goToTarget(0);
			else {
				llExecCharacterCmd(CHARACTER_CMD_SMOOTH_STOP, []);
				gTargNum = -1;
				kTarget  = NULL_KEY;
			}
		}
	}

	path_update(integer update, list reserved) {
		[COLOR="#FFA500"]// We are near target.[/COLOR]
		if (update == PU_SLOWDOWN_DISTANCE_REACHED) {
			if (gTargNum > -1) llSetTimerEvent(10.0);
		}
		
		[COLOR="#FFA500"]// We are at target.[/COLOR]
		if (update == PU_GOAL_REACHED) {
			llExecCharacterCmd(CHARACTER_CMD_SMOOTH_STOP, []);

			if (gTargNum > -1) {
				llSetRegionPos(vTarget);
				llUpdateCharacter([CHARACTER_LENGTH, fHeight]);

				llSetTimerEvent(10.0);
			}
		}

		[COLOR="#FFA500"]// Navigation failed. Try direct[/COLOR]
		else if (update == PU_FAILURE_INVALID_START) {
			llNavigateTo(vTarget, [FORCE_DIRECT_PATH, TRUE]);
		}

		[COLOR="#FFA500"]// Otherwise, the bee is lost[/COLOR]
		else {
			llExecCharacterCmd(CHARACTER_CMD_SMOOTH_STOP, []);
		}
	}

	timer() {
		llSetTimerEvent(0.0);
		goToTarget(gTargNum+1);
	}
}

Das Meiste dabei ist der Verwaltungscode: Implementierung des obigen Protokolls zur Koordinatenabfrage, auswahl des Ziels und im Touchevent auch der Code zum Starten/Anhalten des Pendlerlaufs. Kurze Erklärung

In den drei Listen lTargets, lCoords, lHeights werden die Ziele gespeichert, mit der UUID, der Bodenposition und der Höhe. Variablen danach geben an, zu welchem Ziel der Pendler wandert gerade und was sind seine Bodenposition und Höhe. Die Funktion goToTarget belegt diese Variablen und startet den Lauf via PF-Navigation.

Wird der Skript initialisiert (default, state_entry), wird der Char wie gehabt erstellt. Jetzt kommt ein Fix für den Bug vorhin. Der Char ist mit der maximalen Höhe erstellt und dann sofort auf die niedrigste Höhe reduzert, die wir benutzen wollen. Der bug besteht darin, dass wenn der Char zuerst niedrig erstellt wird und dann die Höhe vergrößert wird (von 12.5 cm auf 4m im ersten Entwurf) dann meint die PF-Engine, der Char hat die Navmesh verlassen weil zu hoch und will nicht navigieren.

Wozu wird überhaupt die Höhe geändert? Durch die Höhe wird das Schweben realisiert, bei 10m der Charhöhe hängt die Biene 5m über dem Boden. Durch Veränderung der Characterhöhe soll die Biene visuell auf Blumen landen, die alle unterschielich hoch positioniert sein können. Daher melden die Koni auch die ihre Spitzenhöhe, anstatt eine einheitliche Höhe im Skript zu benutzen, wie beim Visitorchar aus dem Teil 1.

Jetzt das listen Ereignis. Hier wird die Koordnate der Stationen empfangen und die Werte entschlüsselt. Die Spitzenhöhe wird dabei sofort in die doppelte Characterhöhe umgewandelt, das Ergebnis darf dabei im Bereich 0.5m bis 10m liegen, bedingt durch Pathfinding. Nach Empfang können dabei zwei Fälle passieren: Entweder ist der Pendler zur Station unterwegs, die ihre Position meldet, oder nicht. Im zweiten Fall wird lediglich die neue Position gespeichert. Im ersten Fall wird zusätzlich die Navigation zur neuen Positon gestartet/korrigiert.

Im touch_start Ereignis wird geprüft, ob der Besitzer angeklickt hat, wenn ja und es schon welche Stationen bekannt sind, wird entweder der Lauf gestartet oder angehalten.

Im path_update wird die Navigiation dann gesteuert. Hat der Pendler das Ziel nahe oder erreicht, wird er sofort auf den Zielpunkt verschoben (der Trick aus dem Tel 1, via llSetRegionPos) und auf die Konusspitze aufgesetzt, indem die Characterhöhe aktualisiert wird (llUpdateCharacter), danach wird ein Timer von 10 Sekunden gestartet. War die Navigation irgendwie nicht möglich, wird ein direkter Weg genommen. Bei anderen Fehlern wird ganz angehalten.

Ist Wartezeit vorbei, wählt das timer Ereignis ein neues Ziel aus.

So, diesen Skript installieren wir in eine Kugel (mal orangen gefärbt) und nach aufnehmen geben wir den Namen, etwa "Shuttle".


4. Characters Floater


Rezzt man nun den Char (er wird zum Character weil der Skript als solches den Prim initilisiert) kann man diesem im Characterfloater. Der ist beim athfinderviewer über das Menü Bild / Pathfinding / Characters... zu finden. Beim Beta oder TPVs wird die Stelle evtl anders sein. So sieht jedenfalls der Floater aus, der Char ist ausgewählt (und zwei Koni auch gerezzt, die sind aber nicht im Floater zu finden, da keine Characters)

attachment.php

Dieser Floater wird guter Freund sein beim Testen. Wenn ein Char sich entläuft, kann man den hier wieder finden, und entweder zu ihm teleportieren oder direkt von der Sim nehmen. Ich merke gerade bei der Kugel ist noch der Vektor geblieben, ich habe einfach einen der Visitoren zum Pendler umgewandelt. Für den Pendlerskript spielt das Beschreibungsfeld des Prims keine Rolle.


5. Lauf mit Landung


Wir machen den einen Konus (bei mir "Alpha") 1m hoch, den anderen ( bei mir "Beta") 4m hoch, beide anklicken damit die Höhe an den Char übertragen wird. Dann diesen anklicken. Der Pendler nimmt dann die Fahrt auf, der Weg zwischen beiden Koni nimmt dabei denselben Pfad, die Höhe ist aber unterschiedlich, am Ende setzt sich die Kugel direkt auf die Spitze:

attachment.php

Man muss nicht nur zwei Koni nehmen, mit zwei ist es einfacher, das Bild zu machen :)


6. Zwei Punkte, zwei Wege


Die Hin und Rückweg müssen nicht immer einen Pfad nehmen. Ist das Gelende uneben, kann die PF Engine beim Weg B nach A einen anderen Pfad nehmen als beim Weg A nach B. Hier etwa wenn der Char einen Hang nehmen soll. Die Koni sind gleich hoch dismal:

attachment.php

Man kann entweder neue Koni und den Pendler rezzen, oder die Szene verschieben. Dafür den Pendler per Klick anhalten, Koni verschieben, beide anklicken (so Pendler weiß wo sie sind) und den Pendler per Klick starten.

Die Navigation wird meiner Meinung nach besonders schön, wenn sie über eine unebene Fläche verläuft, dann geht der Char nicht schnurrtraks gerade, sondern sucht sich den Weg, wird dadurch lebendiger, belastet aber vermuttlich die Sim stärker.


7. Pfadwechsel


Stellt man zwischen den beiden Koni einen Phantomblock, läuft der Pendler als nichts geschehen durch diese Box hindurch, linkes Bild (habe den Hovertext wegradiert):

attachment.php

Sobald man aber die Box solid macht, findet der Character sofort den Weg herum, rechtes Bild). Manchmal ist er unsicher wohin, das dauert aber nicht lange. Zum Nachspielen bitte die Wegpunkte nicht so dicht nahe einander aufstellen (in diesem Beispiel waren es unter 10 Meter, und der Pendler läuft mit 2m/s), sonst hat man es schwer, die Wand rechtzeitig auf solid umzustellen und noch das Verhalten zu beobachten.


8. Überfliegen von Hindernissen


Wir versuchen nun, die Trennwand verkleinern und schauen was dabei passiert. Bis sie etwa über 20cm über dem Boden absteht, fliegt sie der Character brav um:

attachment.php

Ist die Wandhöhe aber auf 20cm gesunken, läuft der Pendler plötzlich darüber:

attachment.php

Die Gegenstandshöhe, ab der dieser Pfadwechsel stattfindet, scheint weder von der Gegenstandsgröße abhängen, noch von der Größe der Kollisionspile des Characters, also der Eigenschaften von CHARACTER_RADIUS und CHARACTER_LENGTH. Wer damit auch genauer spielen möchte, den Radius kann man leicht unter llCreateCharacter() einstellen (s. Code im Abscnitt 3) und die Länge kann man durch die Höhe der Koni wählen, ihre Höhe verursacht die doppelte Länge des Characters (damit die Kugel auf dieser Höhe schwebt).

Ich rede die ganze Zeit über die Pille, sie kann man aber auch sehen. Dazu hilft wieder der "Characters" Floater aus dem Abschnitt 4. Dazu entweder das Menü Bild / Pathfinding / Characters... und dort den Char auswählen, oder auf den Char mit der rechten Maustaste anklicken und im Kontextmenü den Eintrag Show in Characters wählen, dann ist der Char bereits ausgewählt. Dort im Floater braucht man noch das Kästchen bei "Show physics capsule" ankreuzen.

So sieht die Pille für den Pendler aus (den dazu am besten anhalten), so kann man erkennen warum die Kugel überhaupt schwebt:

attachment.php


9. Ausblick


So, solange keine Änderungen kommen, ist der Teil 2 abgeschlossen. Im Teil 3 möchte ich Blumen haben, die Honig produzieren (ok, ist Abstraktion), der Character soll dann eine Biene sein, die diese Blumen besucht, den erzeugten Honig erntet und beim Bienenstock abgibt. Dazu werde ich die Biene skulpten müssen, Mesch ist mir noch zu hoch, skriptseitig wird noch erweitertes Protokoll benötigt, so wie andere Kleinigkeiten, die ich noch nicht kenne.

LG
 
Zuletzt bearbeitet:
Sieht ja schonmal hervorragend aus! Ich hab jetzt eine Hoverlamp, die ziwsichen zwei Punkten hin und her schwebt, lustiger Effekt im Dunkeln. die besteht übrigens normal aus 6 Prims, mit dem Script werden es wieder 15, also scheint das so ne Art Mindestprimkosten zu sein, wo zumindest normale Prims gegengerechnet werden.
 
Hallo (alle) und danke Amadeus :)

Habe den Post editiert, damit er geschlossen bleibt. Die Änderungen sind:

1. Der Pendelskript, jetzt reagiert er stabiler aufs Ankliken, zuvor hat nicht immer das Anhalten zwischen den Stationen funktioniert, weil der Pendler trotz Anhalten irgendwie weiter lief und wenn das Ziel erreicht wurde, startete der Timer für den nächsten Lauf. Das ist jetzt beseitigt.

2. Zwei Testfälle und ein Bild hinzugefügt, damit ist die Liste fertig die zeigen wollte.

3. Ausblick sagt was ich dann vor habe im nächsten Teil. Wird aber etwas dauern.

LG und gute Nacht
 
Ich glaube ich bin noch zu schnell. Der Pendler hat sich als Ideal herausgestellt, um Pfade zu testen. Es gibt zwar Möglichkeit, via Viewer Pfade zu testen, wenn der Viewer die Pfadfindererweiterung enthällt. Aber wenn so Läufer über das Gelände läuft und man den und die Wegpunkte auch 'anfassen' kann, ist das was anderes.

Daher mache ich noch den Einen oder Anderen Testfall, wo ich den Pendler eine Rampe steigen lasse, oder unter einer Brücke laufen, also es ist an der Stelle die Umgebung dran. Wenn ich untersucht und gezeigt habe, wie man diese für die PF-Characters vorbereitet, danach kann man mit der Biene fortsetzen, und der Pendler ist hier der beste Meilenstein, denke ich.

Außerdem möchte ich mich nicht mehr so an die Threadform 'Tutorial' festlegen. Ich werde mich zwar an eine Anleitungsform halten, indem ich was vormache, was man nachmachen kann, und hoffentlich auch woanders benutzen, wie die Lampe von Amadeus. Aber der Treadverlauf neigt sich irgendwie richtungs 'Projekt'. Mal sehen was daraus wirklich wird.
 
Zuletzt bearbeitet:
Teil 3: Einrichtung der Umgebung

Guten Abend, ich fange jetzt mit der Fortsetzung an. Dabei möchte ich folgende Aspekte untersuchen:

  • Besteigen einer Rampe (im Abschnitt 8 lesten Teils hat der Pendler ja nicht mal 25cm geschafft.)
  • Überqueren einer Brücke.
  • Passieren eines Wegs unter einer Brücke (kommt etwa vor, wenn der Char durch einen Loch in der Wand muss.)
  • Ausweichen der Objekte, die Phantom sind (für Menschen passierbar, für Chars aber Tabu.)
  • Pfadtests im Viewer.
  • Charactertypen: Einflüss auf die Characterbewegung abhängig davon.
  • Einrichtung der Umgebung in einer Skybox oder hochgestellten Platform, die nicht vom Boden erreichbar ist.
  • Mögliche Tücken bei der Optimierung der Umgebung.
  • Uns was sonst noch anfällt (hier könnten neue Punkte hinzukommen.)

Damit müsste der Grosteil der Möglichkeiten bzw. Gegebenheitenbei der Umgebungseinstellung abgedeckt sein. Wir werden den Pendler vom letzten Teil nehmen, fast ohne Modfikationen. Modfikationen habe ich bisher zwar vorgenommen aber nicht gebraucht. Nur die Wegmarkierung wird leicht erweitert.

Die Tests mache ich diesmal auf dem PathTest3, ganz neben dem PathTest1 im Betagrid, auf Maingrid solte aber nichts anders sein. Als Viewer habe ich den SL Beta genommen, der Pathfinderteil ist bei dem Viewer entspricht dem Pfadfinderviewer, soweit ich beurteilen kann, ist aber näher an den offiziellen Viewer, der später rauskommt. Die Links und SLURL müssen im Beitrag #1 zu finden sein.


1. Zielmarkierung


Die Veränderung des Markierungsskript (den für Koni) ist nur deshalb erforderlich, damit man die Reihenfolge genau vorgeben möchte, in der der Char die Punkte ablaufen soll. Wir werden diesmal nämlich mehr als zwei davon brauchen. Die Veränderung besteht lediglich daraus, dass der Markierungsskript die Position nicht sofort meldet, sondern eine Pause anlegt. Indem verschiedene Markierungen andere Pausen anlegen, kommen ihre Rückmeldungen der Position in einer bestimmten Reihenfolge an, in der der Pendler die Punkte ablaufen wird.

Die Länge der Pause wird im Beschreibungsfeld des Markierungsobjektes angegeben. dadurch spart man das Abspeichern des Skripts mit anderen Pausenwerten. Bei der Vorversion stand da die Farbe des Hovertextes als Vektor, jetzt wird eine Kombination angegeben, die Länge in Sekungen, gefolgt vom Farbvektor, getrennt durch Semikolon. Hier ist der Skript

Code:
integer PFWPC = 1606231603;

reportPosition() {
    list  desc = llParseString2List(llGetObjectDesc(), [";"], []);

    float wait = llList2Float(desc, 0);
    if (wait > .0) llSleep(wait);
    
    llSetText(llGetObjectName(), (vector)llList2String(desc, 1), 1.0);
    
    vector loc = llGetPos();
    vector pos = loc + llGetRegionCorner();
    vector msc = llGetScale();
    
    pos.z = pos.z - msc.z / 2.0;
    string info = (string)pos+"|"+(string)msc.z;
    
    llShout(PFWPC, "pf.waypoint:"+info);
    llWhisper(0, info+" ( "+(string)loc+" )");
}

[COLOR=#ff8c00]// --- ----------------------------------------------------[/COLOR]

default {
    state_entry() {
        llListen(PFWPC, "", NULL_KEY, "pf.waypoints?");
    }
    
    on_rez(integer start_param) {
        llResetScript();
    }

    listen(integer channel, string name, key id, string message) {
        reportPosition();
    }
    
    touch_start(integer total_number) {
        if (llDetectedKey(0) == llGetOwner()) {
            reportPosition();
        }
    }    
}

Dieser Skript wird in Konusprims gelegt und aufgenommen in den Inventar, ich habe die Koni dann im Inventar kopiert und folgende Namen + Beschreibungen gegeben:


  • Name "Alpha", Beschreibung: "1;<1.0, 0.5, 0.25>"
  • Name "Beta", Beschreibung: "2;<1.0, 0.75, 0.5>"
  • Name "Gamma", Beschreibung: "3;<1.0, 1.0, 0.75>"
  • Name "Delta", Beschreibung: "4;<1.0, 1.0, 1.0>"

Dadurch bekommen sie unterschiedlich gefärbte Texte, und versenden ihre Positionen in 1s Abstand.


2. Pendler


Wie gesagt, man kann den Pendler vom Teil 3 nehmen. Meine Erweiterung war lediglich aus Einbundung des Testmoduls damit man die Pfadfinder-EReignisse lesen kann. Aber bisher hat er da nichts verdächtiges gemeldet, sogar wenn er einen ganz komischen Pfad genommen hat. Daher kann man die Erweiterung lassen. Ich schreibe den Code hier später rein, falls das doch benötigt wird.


3. Brückenkonstruktion


Für den Abschnitt mit einer Rampe und Brücke (erste drei Punkte der Liste oben) habe ich diese Konstruktion aufgebaut, sie besteht aus zwei Säulen der Größe 4m x 10m, 6m hoch, im Abstand von 22m, zwei Rampen, jede 2m schmal, 10m lang, symmetrisch an der Säulenseite angebracht und als Brücke eine Glasplatte dadrauf, die Kacheln sind 1m groß. Damit sollte die Brücke hoch genug sein damit ein Kleiner Char (bis 6m hoch) darunter passt, und nicht genug, damit der großmögliche (10m) darunter laufen kann.

attachment.php

Über der Konstruktion werden dann die vier Koni aufgestelt, der Pendler soll dann der Weg von Alpha über die Rampe zu Beta, dann über die Brücke (Glasplatte) zu Gamma, dann wieder die Rampe runter zu Delta und danach wieder zum Anfang, Alpha vorne unten. Der Pendler aus dem vorigen Teil würde, so wie es ist, darüber nicht laufen können. Die Aufgabe ist deshalb, die Brückenkonstruktion so einzustellen, dass der Pendler diesem Pfad genau so folgen kann (mit geringer Abweichung.)


4. Erster Pfadtest


Zunächst möchten wir eine Sache prüfen, ob und wie der Viewer einen Testpfad anzeigen kann. Der Abschnitt ist nur mit einem PF-Erweiterten Vewer nachvollziehbar, wie dem SL Beta Viewer derzeit. Hier geht man ins Menü Build - Pathfinding - View/Test... Es erscheint ein Floater, der nach Herunterladen der aktuellen Navmesh etwa so aussieht, wir brauchen den zweiten Tab "Test Path", zum ersten Tab kommen wir noch, später:

attachment.php

Ist der Floater offen, kann man Markierungen setzen: Hält man die Strg oder Umsch Taste gedruckt, verwandelt sich der Mauszeiger zu einem großen S. Bei der Strg Taste setzt man den Anfangspunkt, bei der Umschalttaste den Endpunkt. Die Punkte erscheinen wie Pillen aus. Hat man den Anfangspunkt gesetzt, und hält man die Umschalttaste um den Endpunkt zu setzen, wird der Pfad dynamisch zum aktuellen Mauszeiger gezogen, wo möglich. Hat man den Endpunkt gesetzt, kann man die Taste loslassen, der Pfad bleibt angezeigt und ist von llen seiten anzuschauen.

Hier im Linken Teilbild habe ich den Testpfad zwischen den beiden unteren Markierungen gezogen. Der scheint in Ordnung. Im Rechten Bild habe ich den Endpunkt irgendwo gesetzt, und der Pfad geht durch die Steinwand als wäre sie gar nicht da:

attachment.php

Außerdem kann man kein Pfad zu einem der oberen Ziele führen, man versucht zwar den Endpunkt oben auf die Brücke zu setzen, trift aber irgendein Punkt, weit entfern auf dem Simboden. Ist die Pfadberechnung defekt? Nein, die Konstruktion wurde mit dem Attribut "Movable Obstacle" gerezzt, der Attribut wird automatisch vergeben. Dadurch existiert die Konstruktion für die Navmesh tatsächlich nicht. Das kann man schön erkennen, wenn man die Navmesh anschaut.

Dazu benötigen wir erneut den View/Test Floater, (Menü Build - Pathfinding - View/Test...) aber diesmal gehen wir auf den linken Tab "View". Welche Häckhen hier aktiviert sind, steuert wie die Welt angezeigt wird. Zu Anfang ist nur das Häckhen "World" aktiv, wir sehen also ur die Welt, also wie immer. Um Navmesh zu sehen müssen wir das Häckhen "Navmesh" anktivieren. Sofort ändert sich das Bild, die Navmesh wird als eine blaue Fläche dargestellt. Nun, deaktivieren wir das Häckchen "World", verschwindet die Brückenkonstruktion von der Bildfläche:

attachment.php

Sie ist nur sichtbar, wenn das Häckchen "World" aktiv ist. Das erklärt, warum die Testpfade sie nicht berücksichtigen können. Ich hoffe den Unterschied kann man erkennen, ich wollte die Dateigröße gering halten.

Ok, jetzt lassen wir den Pendler über die Konstruktion laufen. Den Pendler gerezzt (am besten draußen, sonst kann er sich in den Ecken verlaufen), nach 4 Sekunden hat er 4 Wegpunkte registriert. Anklicken. Zum Punkt Alpha unten läuft er normal, Jetzt sollte er die Rampe hoch laufen, zu Beta daoben. Sein Ziel ist eigentlich der Punkt am Boden unter dem unseren Zielpunkt. Die Säule versperrt aber den Weg, also sucht der Pendler den näcsten Punkt zu seinem Ziel:

attachment.php

Zumindest interpretiere ich diesen komischen Weg. Die Fortsetzung ist aber auch interessant. Der Pendler sollte eigentlich den geraden Weg über die Brücke nehmen können. Statdessen versucht er scheinbar so schnell es geht von der Brücke weg und erst am Boden zur anderen Seite:

attachment.php

Im Vorletzten Abschnitt passiert dasselbe: Anstatt direkt über die Rampe runter, läuft der Pender lieber von der Säule runter und auf dem Boden um den Flügel herum zum Ziel:

attachment.php

Den letzten Abschnitt kann ich aber nicht erklären. Eigentlich sollte der Pendler unter der Brücke laufen können, er ist als Character nur 2m Hoch, die Brücke aber 6. Statdessen nimmt er den Weg herum:

attachment.php

Möglicherweise will er den ganzen Linkset meiden. Die Physik stand aber auf "Prim" bei den Prims, keine Komvexe Hülle. Da muss ich noch nachforschen. Nachtrag: ER scheint tatsächlich den Linkset zu vermeiden aber solange er in der Projektion zu Boden mit festen Prims gefüllt ist. Hochschieben der Brückenplatte bis auf 20m hat den Char jedenfalls nicht dazu gebracht, darunter zu laufen.

Aber eines der folgenden Möglichkeiten hat erlaubt dass er unter der Brüdke läuft:

  • Entlinken der Brückenplatte, beide Säulenteile bleiben verlinkt, die Bodenplatte bleibt fest (nicht Phantom), der Char läuft dann doch darunter.
  • Umlinken der Brückenkonstruktion und zuweisen dem Brückenprim den Physikalischen Shape "None". Umlinken ist erforderlich weil der Rootprim nicht auf "kein Shape" gestellt sein darf. Sobald der Brückenprim aus der Physikengine raus ist, stört es den Char nicht (welches eigentlich nicht damit kollidieren würde)
  • Setzen die ganze Konstruktion auf Phantom. Dann stört sie dem Char nicht, wird aber selbst nicht mehr begehbar.

So, Ich habe während dessen noch den Character Floater angeschaut bzw die Prozessorzeit des Pendlers. Während beim Weg von außen zum Punkt A der Pendler etwa 23µs gebraucht hat, bei diesen geschwungenen Wegen oder beim Abstieg an falscher Stele stieg die Last auf 39µs. Die Rampen waren anscheinend nicht so einfach für die PF Engine.


5. Linkset-Floater


Ok, wir wollen nun unsere Konstruktion der PF-Engine bekannt machen. Dazu haben wir eigentlich nur eine Steuermöglichkeit: Auswahl eines geeigneten Pahtfinderattributs. Das geschieht über den Linkset-Floater, den wir auf zwei Wegen öffnen können:

  • Den Linkset, also die Brückenkonstruktion anklicken, im Kontextmenü den Menubutton "Show in linksets",
  • Oder im Hauptmenü Build / Pathfinding den Button "Linksets" anklicken. Dann muss man noch im Floater die Konstruktion auswählen.

Der Floater mit der ausgewählten Konstruktion wird in etwa so aussehen:

attachment.php

Hier im Bild werden zwei Linksets angezeigt, die Konstruktion und der Linkset der Zielmarkierungen, ich habe die Koni miteinander verlinkt um sie einfacher zusammen mit der Brückenkonstruktion rezzen und ausrichten zu können (der Teil hier braucht sehr viele Anläufe :) ) Das Bild ist etwas geschummelt, original ist der Floater unverschämte 1015 Pixel breit, ich musste auf 800 Pixel verkleinern, was eigentlich ohne Problemme ging.

Hier kann man einiges mit den Linksets machen, zb löschen, Kopieren, wiederfinden (hinteleportieren) und den PF-Attribut zuweisen, dazu klickt man auf den Listenbutton (im Bild hervorgehoben.) Das Menü sieht dann so aus:

attachment.php

Wir können also einen der sechs Attribute dem ausgewählten Linkset zuweisen

  • Movable obstacle - Das Linkset ist ein bewegliches Hinderniss. Anscheinend ein Standartwert für Objekte, die keinen Attribut zugewiesen haben (frisch gerezzt etwa) und nicht phantom sind.
  • Movable phantom - Das Linkset ist phantom, daher kein Hinderniss. Anscheinend ein Standartwert für Objekte, die keinen Attribut zugewiesen haben und die phantom sind. Die Koni waren phantom und haben diese Einstelung bekommen.
  • Static obstacle - Das Linkset ist ein unbewegliches Hinderniss.
  • Walkable - Das Linset ist für die Chars begehbar.
  • Exclusion volume - Das Linkset ist phantom, Avatare oder physikalische Objekte können sie durchqueren, aber nicht die Chars (Tabubereiche.)
  • Material volume - Das Linkset ist phantom, auch die Chars können sie mit evtl veränderten Bewegungsparametern durchqueren.

Das werden wir uns im Verlauf genauer anschauen.


6. Anstz 1: Static Obstacle (allgemeine optimierung)


Im ersten Ansatz deklarieren wir die Brückenkonstruktion zunächst als statisches Hindernis. Ist eigentlich nicht richtig, begehhbare Objekte wie die Brücke sind keine Hindernisse, wir werden später das richtig machen. Diesmal wollen wir schauen, wie Hindernisse behandelt werden.

Wir öffnen also die Liste (Brückenkonstruktion ist im Floater ausgewählt) und ändern den Attribut von "Movable obstacle" auf "Static obstacle". Dann betätigen wir den "Apply changes" Button. Die Änderung wird übertragen (oder was auch immer sonst passiert) dann stellt der Viewer fest, die Navmesh wurde verändert und muss erneut berechnet werden: Es erscheint in der Regionleiste oben ein Warnsymbol und in der Symbolleiste ein Button mit dem man die Bereinigung durchführen kann:

attachment.php

Den Button müssen wir nun betätigen. Er blendet sich sanft aus und paar Sekunden später verschwindet das Warnsymbol. Erst jetzt ist die Brückenkonstruktion erfolgreich umgestellt.

So, Frage 1: Was ist nun mit der Navmesh passiert?

Vorher hat sie die Brückenkonstruktion nicht gesehen. Wir öffnen den View-Floater (Menü Build / Pathfinding, dann "View/Test".) Sieh da, die Navmes hat jetzt zwei schwarze Löcher bekommen, die Konstruktion hat sie quasi mit dem Pfeilern ausgestanzt. Auch braucht man den "World" Häckhen nicht mehr um sie zu sehen, ist das Häckchen "Static obstacles" gesetzt, sieht man die Konstruktion in rot:

attachment.php

Im Bild habe ich beide Views kombiniert, die Ansicht mit der Konstruktion ist halbtransparent und liegt über der Ansicht der reinen Navmesh. Daher sieht man die Konstruktion und die Löcher, die sie in der Navmesh ausstanzt. Die Löcher sind normalerweise pechschwarz mit roten Rändern, wegen der Übermalung mit dem halbtransparenten Bild sind sie rot geworden.

Die Löcher sind eigentlich Tabubereiche für die Characters. Das heist bei der Pfadberechnung gehen sie nicht hinein Das ist der Sinn der Einstellung statisch; die Engine kennt diese Löcher schon vor dem losschicken des Chars. Interessant ist, das die obere Zielmarkierungen genau im Bereich der Löcher sind. Der Pendler sollte daher gar nicht loslaufen wenn das Ziel in diesem Bereich ist. Tut er aber trotzdem. Entweder ist das ein Bug und wird später beseitigt (dann funktioniert dieser Fall nicht mehr wie beschrieben) oder es reicht für die Engine, wenn er auf der Grenze anhält, dann springt der Pendler die Zielkoordinate an, aber mit einem Befehl das nicht zum PF gehört.

Nachtrag: Ich habe die Pfeiler 10m x 10m gemacht, dh. am Boen bis zum Ziel war mindestens 5m vom Lochrand. Das hat den Char gar nicht gestört, der Pendler hat immer angenommen er hätte das Ziel erreicht wenn er den Punkt am Lochrand erreicht hat am nächsten zum Ziel liegt. So meine Beobachtung.

Ok, Frage 2: Hat die Umstellung auf den Pfadtest via Viewer etwas verändert?

Im ersten Test war das ja so, dass die orangene Tespfade durch die Pfahle der Brücke durchgingen wie durch Luft. Jetzt sind aber Löcher in der Navmesh. Außerdem kann man sehen, die Brücke selbst macht dort kein Löch. Um Tespfade zu sehen, wählen wir alle Häckhen im Floater ab, dafür aber das Häckhen "World" aus, sonst ist alles schwarz. Dann Wechsel zum Tab "Test". Nun kann man Start- und Zielmarkierungen um die Konstruktion setzen:

attachment.php

Erfreulicherweise respektiert der Tespfad jetzt die Pfeiler unserer Konstruktion, läuft jetzt richtig herum. Leider kann man immer noch die Zielmarkierung auf der Konstruktion nicht setzen, man trifft den Boden irgendwo dahinter.

Und Frage 3: Wie läuft jetzt der Pendler die Ziele ab?

Also, den Pendler rezzen und per Klick starten. Wie erwartet, hat er keine Angst mehr, unter die Brücke zu laufen. Allerdings kann er nicht richtig die Obere Ziele besuchen:

attachment.php

Ich habe diesmal die Telpfade nicht getrennt, sondern in einem Bild eingezeichnet. Außerdem habe ich imaginäre Pfade und die hinterm Stein gestrichelt dargestellt, echte Pfade am sichtbaren Boden durchgezogen. Ist aber beides schematisch. Das Laufverhalten ist diesmal so:

  • Pfad A nach B: Beta ist näher zur Mittellinie als Alpha, also läuft der Pendler hinter die rechte Rampe, beim Punkt am Boden der zum Ziel am nächsten liegt, sagt er er wäre am Ziel, dann bespringt er den Zielpunkt via des Verschiebebefehls (llSetRegionPos, gehört nicht zu PF).
  • Pfad B nach G: Diesmal läuft der Pendler tatsächlich über die Brücke, ist aber sicher nur Zufall: Er läuft nicht direkt zu Gamma, sondern fällt irgendwan zu Boden und dort um den Pfeiler herum zur nächsten Position, um Gamma dann zu bespringen.
  • Pfad G nach D (gelb): Hier hätte der Pendler auch die Linke Rampe nehmen können. Er sucht den Boden zuerst auf, und dann unter der Brücke zu Delta.
  • Pfad D nach A: Nur hier läuft der Pendler wie erwartet: mehr oder weniger auf dem direkten (und freien) Weg zum Ziel.

Die Prozessorzeit: Bewegt sich der Pendler am Boden, verbraucht er 23µs, wie der Pendler aus dem Teil 2 (zwei Ziele am Boden), auf der Brücke oder beim Suchen des Weges zum oberen Ziel (Beta, Gamma), steigt der Verbrauch wieder auf 39µs.

So, jetzt habe ich eine automatische Verwarnung vom vBulletin bekommen, ich schreibe zu viel :) Aber ich denke es ist gut, das Teil in mehreren Post zu machen, Editieren macht weniger Traffik und der Thread macht keine elendlange Seiten.
 
Zuletzt bearbeitet:
Teil 3: Einrichtung der Umgebung (Fortsetzung)

7. Movable phantom

Ok, diese Einstellung macht bei der Brückenkonstruktion wenig Sinn, wir wollen nur was prüfen: Wir nehmen den Attribut "Movable phantom".

Bei dieser Einstellung passiert eine kleine Überaschung: Das Linkset, also die Brückenkonstruktion wird phantom und nicht begehar. Die Konstruktion übt auch keine Einflusse auf die Navmesh, genau wie die Einstellung "Movable obstacle". Das bedeutet wiederum, beim Wechsel zwischen diesen beiden Movables der Warnsymbol nicht aufspringt, beim Wechsel von einem der Movables zu den anderen Attributwerten (und zurück) aber schon.

Ich erwähne die Einstellung hier vollständigkeitshalber, und weil es durchaus möglich ist, dass man beim Optimieren unwisend/ungewollt diese Einstellung nehmen kann und dann etwa sein Haus nicht mehr betreten kann, bzw. von der Decke fällt. Immerhin kann man den Fehler leicht im Floater wieder korrigieren.

Ich werde aber noch überprüfen, inwiefern das Setzen auf Movable phantom sich von Phantomsetzen via Baufenster unterscheidet, und ob dabei andere Parameter sich ändern wie etwa Physikshape.
 
Zuletzt bearbeitet:
Teil 3: Einrichtung der Umgebung (Fortsetzung)

8. Ansatz 2: Walkable = Begehbar


Diese Einstelung ist eigentlich für Linksets vorgesehen, die durch Characters begehbar sein soll. Und diese setzen wir jetzt: Den Linksetfloater aufrufen, Brückenkonstruktion auswählen, und "Walkable" in der Liste unten wählen. Dann den "Apple Changes" Button im Floater, und sofern auftaucht, den "Rebake Region" am Bildschirm unten. Sobald dieser verschwindet, ist die Konstruktion begehbar gemacht. Das Fragenkatalog ist schon bekannt.

Frage 1: Was ist mit dem Navmesh passiert?

Öffnet man den View/Test - Floater (Build / Pathfinding / "View/Test"), erscheint die Navmesh jetzt ganz anders:

attachment.php

Hier habe ich wie vorhin die Ansicht auf das Linkset (diesmal ist sie mit dem Häckchen "Walkables" zu sehen) mit dem Sicht auf die Navmesh kombiniert, wobei das begehbare Lnkset in grün dargestellt wird und hier im Bild halbtransparent ist. Das Linkset stanzt ebenfalls löcher im Navmesh aus, die wegen Übermalung grün sind, allerdings sind die obere Flächen des Linksets selbst zu Navmesh geworden. Ist die Sicht auf reine Navmesh aktiv, erscheint sie noch spektakulärer, aber hier wäre das Bild unklar.

Frage 2: Kann man jetzt auch Pfade auf der Konstruktion per Viewer testen?

Tatsächlich - Man aktiviert nur die Weltansicht im Floater (Häckhen bei "World" nur aktiv) und wechselt zum "Test" Tab. Jetzt kann man prima die Start- und Endpunkte sowohl unter, als auch auf der Brücke setzen:

attachment.php

Oder den Pfad von unten nach oben über die rechte Rampe:

attachment.php

Oder über die linke Rampe, ob von unten nach oben oder umgekehrt:

attachment.php

Ich finde das sieht gut aus :)

Frage 3: Kann nun der Pendler die Wegpunkte endlich richtig ablaufen?

Das testen wir gleich: Den Pendler rezzen, und sobald er 4 Punkte meldet, per Klick los schicken. Der Rundlauf ist nun fast perfekt:

attachment.php

Ich habe erneut die vier Teipfade zu einem Bild zusammengefügt, wobei diesmal war das ohne Wirrwarr und Pfade möglich, die hinter Steinen versteckt wären.

  • Pfad A-B: Der Pendler hat den kürzesten Weg zu Beta genommen, der Weg läuft so nah am Rampenrand dass man Gefühl hat, der würde vom Rand fallen, tut das aber nicht.
  • Pfad B-G: Auch dieser Pfad über die Brücke ist schnurr-gerade. Also wie beabsichtigt war.
  • Pfad G-D (gelb): Hier kommt es zu einem seltsamen Fehler. Der Pendler nimmt nicht die Rampe, sondern läuft am Rand der Brücke, fällt halbwegs runter und dann am Boden zu Delta. Dieser Pfad entspricht nicht dem was der Viewer vorhin angezeigt hatte.
  • Pfad D-A: Der Pfad ist wie vorhin gerade zum Ziel und wie beabsichtigt.

Prozessorzeiten: Der Pendler läuft jetzt auf drei der Pfade mit konstanten 17 bis 19µs, das ist die Hälfte gegenüber 39µs die bei der unoptimierten/falsch konfigurierten Konstruktion war, und um 20% weniger als 23µs beim Lauf über den leeren Boden. Allerdings ist das nur bei den drei Pfaden, den orangenen die richtig sind. Beim gelben Pfad ist das anders: Vor dem Fall von der Brücke ist der Verbrauch ebenfalls 17µs, nach dem Fall steigt sie aber auf 40µs.

Das bedeutet für mich, dass an diesem Pfad etwas passiert, was die PF-Engine nicht berechnet hatte, so dass sie nach dem Fall dringend den neuen Pfad berechnen muss. Diesen Vorfall untersuche ich gerade, bzw. versuche einzuschränken, damit man den Bug finden kann. Weil der gelbe Teilpfad so nicht auftreten darf, wenn ich das Pathfinding richtig verstehe.

Pfadbereinigung (ansatzweise)

Nachtrag. Irgendwie fügt sich dieses (ungeplannte) Bug perfekt in den ganzen Ablauf ein, so dass ich kurz erkläre wie ich beim Untersuchen der Problemstelle vorgegangen bin, das wird der eine oder andere vielleicht auch so machen.

Als erstes wurde ja die Stelle mit einem falschen Ablauf festgestellt. Die Prozessorzeit hat auch die erhöhte Prozessorlast ermittelt, also müsste da etwas schief laufen.

Mit einem Skript aus llNavigateTo, oder auch llPatroolPoints kann man noch enschränken, dass der Fehllauf nicht am eigenen Characterskript liegt, sondern schon im Navigationsbefehl bzw. Pfadberechnung; ich habe mich so vergewissert, dass hier das Problem mit der Umgebung war, der Testcharacter lief dort genauso falsch.

Also muss die entsprechende Stelle analysiert werden. Diese habe ich im Navmesh angeschaut. So sah die Ecke bei genauern Betrachtung aus:

attachment.php

Man erkennt einen Dreieck in der Navmesh, der nahezu vertikal ausgerichtet ist. Damit man hier im Bild es sehen kann, habe ich das Triangle rot hinterlegt.Die Dreiecke im Navmesh sind sonst immer waagerecht oder geneigt ausgerichtet, also muss die Stelle ein Problem machen. Um es zu beseitigen, muss die Konstrukton abgeändert werden. Dazu kommen einige Ansätze in Frage

Eine funktionierende Lösng war, einen Abstand zwischen dem Übergang Brücke-Pfeiler und Pfeiler-Rampe zu machen, von etwa 50cm. Dazu kann man die Brücke um 1m einengen, oder die Pfeiler vergrößern und die Rampen nach außen um je 50cm zu verschieben. Ich habe nur die Brücke von 6m auf 5m eingeengt. Die Brücke zu verkürzen und abzusenken half nicht, es war trotzdem der Abstand erforderlich.

Eine andere Lösung bietet das Hinzufügen eines Exclusion Volume, das den Pfad über die Problemstelle verhindert, davon aber später. So sieht nun die Navmesh nachdem die Brücke eingeengt wurde:

attachment.php

Die Navmesh bildet jetzt ein anderes Dreieck, das auch nur geneigt ist und nicht mehr so steil. Lässt man nun den Pendler über die Konstruktion laufen, passiert er die Problemstelle jetzt richtig:

attachment.php

Und so sieht jetzt der Gesammtdurchlauf aus:

attachment.php

Also genau was unser Ziel war. Die Prozessorzeiten bestätigen das ebenfalls: Der Pendler verbraucht beim Abstieg jetzt 20µs, was zwar etwas höher als 17µs an anderen Stellen ist, aber wesentlich niedriger als 39µs wie vorher.

Anmerkung zum Bug: Ich werde die Konstruktion auf geeignete Weise vereinfachen und einen Post in Jira machen (falls nicht doch eines steht, aber keinen finde) und dann nachfragen was genauer passiert. Aber ich schätze, beim Einrichten der Umgebung sollte man allgemain auf Stellen achten wo die Navmesh steile Dreiecke macht und diese meiden/korrigiren, ich vermute da Schwierigkeiten bei der Navigation, was zu Prozessorlasten führen kann, auch wenn der Pfad einigermaßen passt.

Fortsetzung folgt, denke ich. Neben Bugbeseitigung wollte ich den Pfad durch Volumebereiche beeinflussen (also Material Volume und Exclusion volume), und evtl andere interessante Sachen damit anstellen.
 
Zuletzt bearbeitet:
sehr gute Pionierarbeit!
Danke Dir :)
Was mich hier sehr interessiert ist, wie stellt sich der Landimpakt ein, wenn mann mesh-körper oder sculpties benutzt?

Danke Dir auch JointVenture :)

Ich habe das selbst immer noch nicht gemessen, aber laut Feststellung von Amadeus und einem Beitrag in Jira, haben die Characters immer den Landimpakt von 15, weil die physikalische Kosten für Characters fix sind.
 
Zuletzt bearbeitet:
Ich habe das selbst immer noch nicht gemessen, aber laut Feststellung von Amadeus und einem Beitrag in Jira, haben die Characters immer den Landimpakt von 15, weil die physikalische Kosten für Characters fix sind.
Das gilt nur für Charaktere, deren Land Impact nicht durch Download- oder Serverkosten höher ausfallen, als der Physikwert von 15. Das heißt, wenn ein Charakter bei einem dieser beiden Berechnungen des Land Impact über 15 liegt, dann steigt auch der Primverbrauch des Charakters über 15.

Linden Lab sagt sich, wenn jemand einen Pathfinding Charakter verwendet, dann ist dessen Ressourcenverbrauch bei der Physikberechnung (Navmesh) eben mit 15 Prims Land Impact gleichzusetzen. Das sieht natürlich bei einem einfachen Würfel nicht unbedingt gerecht aus. Aber ich hoffe doch, dass in Zukunft nicht nur Würfel, Kugeln und Kegel über das Navmesh wandern werden.^^

Gutes Tutorial, Jenna!
 
Das gilt nur für Charaktere, deren Land Impact nicht durch Download- oder Serverkosten höher ausfallen, als der Physikwert von 15. Das heißt, wenn ein Charakter bei einem dieser beiden Berechnungen des Land Impact über 15 liegt, dann steigt auch der Primverbrauch des Charakters über 15.
...

Ja, sowas hab ich schon gedacht, aber da stellt ich noch eine Frage. Warum beeinflusst die Einstellung bei einem Mesh-Objekt auf "Prim oder None(im linkset)" das ganze nicht, wenn scripte im Spiel sind,, und noch eine.. den Physikwert kann mann beim hochladen einstellen, also kann ich ein komplexes mesh erstellen, die Physik mit wenigen Flächen, so das ich die (wieoderwasauchimmer) maximale Physikkosten und Downloadkosten erreicht habe, und, tada 15 Prims :p
Naja, ist wirklich massig viel Arbeit für den normal Benutzer. Vll sehen wir dann meisst doch erst mal nur normale Prims oder sculpties umherwandern.
*lacht
 
Ja, sowas hab ich schon gedacht, aber da stellt ich noch eine Frage. Warum beeinflusst die Einstellung bei einem Mesh-Objekt auf "Prim oder None(im linkset)" das ganze nicht, wenn scripte im Spiel sind,, und noch eine.. den Physikwert kann mann beim hochladen einstellen, also kann ich ein komplexes mesh erstellen, die Physik mit wenigen Flächen, so das ich die (wieoderwasauchimmer) maximale Physikkosten und Downloadkosten erreicht habe, und, tada 15 Prims :p
Naja, ist wirklich massig viel Arbeit für den normal Benutzer. Vll sehen wir dann meisst doch erst mal nur normale Prims oder sculpties umherwandern.
*lacht

Irgendwie versteh ich dein Problem nicht. Schon jetzt macht man einen Mesh ja in der Regel so, daß er einen vereinfachten Physikshape bekommt, um Kosten zu sparen. Und gerade bei Fahrzeugen ist es ja genau dieser wunderbare Effekt, der zum Beispiel 60Prim-Luftschiffe wunderschön physikalisch fahren läßt, da ihr Physikshape unter 32 bleibt.
Wenn diese Regelung auch für PF-Charaktere gilt, umso besser,da können sie detailiert werden, und nur die Physikgrenze zählt.
 
So viel unbekannt ist da nicht wirklich an Variablen, die Infos sind nur nicht sehr gut aufbereitet. Und die Wiki Seiten bisschen veraltet.

Grundsätzlich ist der LI immer noch das höhere aus Physik Cost, Streaming Cost und Server Weight.

Bei den Characters ist eben Physik immer fix auf 15,
die Streaming Cost hängt vor allem von der Größe des Objekts und den LOD (und indirekt von den Dreiecken) ab,
Siehe Mesh/Mesh Streaming Cost - Second Life Wiki
Server Weight von der Anzahl der Prims im Mesh und ob da Scripte drin sind in den Prims bzw. ob die dynamisch sind oder nicht
Siehe auch Mesh/Mesh Server Weight - Second Life Wiki
 
Ich muss gestehen, mit mesh kenn ich mich nicht so gut aus, ich kann höchtens lausig skulpten. Aber Ihr könnt ruhig diskutieren, habe ich auch am Anfang gesagt, man kanns :) Zur Not, wenn sich zuweit entfernt, können Moderatoren einen Teilpfaden lösen. Ich schreibe einfach immer im Titel des Posts "Teil X, Fortsetzung" oder so, wenn ich den Tutorial fortsetze. Und evtl. im Post davor einen Link auf die Nächste Fortsetzung für Schnell-Überflieger.
 

Users who are viewing this thread

Zurück
Oben Unten