2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
7 // Initialisiert die FacePVS-Matrix, für die nach Ausführung dieser Funktion folgende Eigenschaften gelten:
9 // 1) FacePVS[i][j]== NO_VISIBILITY iff Face[i] can NOT see Face[j]
10 // FacePVS[i][j]==PARTIAL_VISIBILITY iff Face[i] can (PARTIALLY) see Face[j]
11 // FacePVS[i][j]== FULL_VISIBILITY iff Face[i] can FULLY see Face[j]
13 // 2) FacePVS[i][i]==NO_VISIBILITY für alle i (NO_VISIBILITY auf der Diagonalen), d.h. keine Face kann sich selbst sehen!
15 // 3) FacePVS[i][j]==FacePVS[j][i], d.h. die FacePVS-Matrix ist symmetrisch
17 void InitializeFacePVSMatrix(const CaSHLWorldT
& CaSHLWorld
, const bool UseFullVis
)
19 const cf::SceneGraph::BspTreeNodeT
& Map
=CaSHLWorld
.GetBspTree();
21 printf("\n%-50s %s\n", "*** Initialize FacePVS matrix ***", GetTimeSinceProgramStart());
24 // 1. Allokiere neuen Speicher für die FacePVS-Matrix
26 FacePVS
.PushBackEmpty(Map
.FaceChildren
.Size());
28 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++) FacePVS
[Face1Nr
].PushBackEmpty(Map
.FaceChildren
.Size());
30 printf("Faces (n): %10lu\n", Map
.FaceChildren
.Size());
31 printf("Bytes allocated for FacePVS matrix (n^2): %10lu\n", Map
.FaceChildren
.Size()*Map
.FaceChildren
.Size());
34 // 2. Initialisiere alle Elemente mit NO_VISIBILITY
35 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++)
36 for (unsigned long Face2Nr
=0; Face2Nr
<Map
.FaceChildren
.Size(); Face2Nr
++)
37 FacePVS
[Face1Nr
][Face2Nr
]=NO_VISIBILITY
;
40 // 3. Setze nun die aus dem Map.PVS abgeleiteten Werte ein.
41 // Für alle Leaves L, markiere also alle Faces aller Leaves im PVS von L als sichtbar von allen Faces von L aus.
42 // Wichtig: Dies handhabt auch diejenigen Faces richtig, die größer sind als ein Leaf, also mehrere Leaves begrenzen!
43 ArrayT
<bool> FaceSetBool
;
44 FaceSetBool
.PushBackEmpty(Map
.FaceChildren
.Size());
46 for (unsigned long Leaf1Nr
=0; Leaf1Nr
<Map
.Leaves
.Size(); Leaf1Nr
++)
48 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++) FaceSetBool
[Face1Nr
]=false;
50 // Setze für alle Faces F aller Leaves im PVS von Leaf1Nr FaceSetBool[F] auf true.
51 // Wichtig: Auch Leaf1Nr liegt im (eigenen) PVS von Leaf1Nr!
52 for (unsigned long Leaf2Nr
=0; Leaf2Nr
<Map
.Leaves
.Size(); Leaf2Nr
++)
54 unsigned long PVSTotalBitNr
=Leaf1Nr
*Map
.Leaves
.Size()+Leaf2Nr
;
55 unsigned long PVS_W32_Nr
=PVSTotalBitNr
>> 5;
57 if ((Map
.PVS
[PVS_W32_Nr
] >> (PVSTotalBitNr
& 31)) & 1)
58 for (unsigned long Face2Nr
=0; Face2Nr
<Map
.Leaves
[Leaf2Nr
].FaceChildrenSet
.Size(); Face2Nr
++)
59 FaceSetBool
[Map
.Leaves
[Leaf2Nr
].FaceChildrenSet
[Face2Nr
]]=true;
62 ArrayT
<unsigned long> FaceSetList
;
63 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++) if (FaceSetBool
[Face1Nr
]) FaceSetList
.PushBack(Face1Nr
);
65 // Markiere für alle Faces F im Leaf1Nr, daß alle Faces F' aller Leaves im PVS von Leaf1Nr von F aus sichtbar sind,
66 // aber auch die umgekehrte Sichtbarkeit, also daß F von F' aus sichtbar ist, um Symmetrie zu garantieren.
67 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.Leaves
[Leaf1Nr
].FaceChildrenSet
.Size(); Face1Nr
++)
68 for (unsigned long Face2Nr
=0; Face2Nr
<FaceSetList
.Size(); Face2Nr
++)
70 FacePVS
[Map
.Leaves
[Leaf1Nr
].FaceChildrenSet
[Face1Nr
]][FaceSetList
[Face2Nr
]]=PARTIAL_VISIBILITY
;
71 FacePVS
[FaceSetList
[Face2Nr
]][Map
.Leaves
[Leaf1Nr
].FaceChildrenSet
[Face1Nr
]]=PARTIAL_VISIBILITY
;
76 // 4. Für die Statistik: Zähle die Anzahl der PARTIAL_VISIBILITY-Elemente in der FacePVS-Matrix
77 unsigned long VisCount
=0;
79 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++)
80 for (unsigned long Face2Nr
=0; Face2Nr
<Map
.FaceChildren
.Size(); Face2Nr
++)
81 if (FacePVS
[Face1Nr
][Face2Nr
]==PARTIAL_VISIBILITY
) VisCount
++;
83 if (VisCount
==Map
.FaceChildren
.Size()*Map
.FaceChildren
.Size())
85 printf("\nWARNING: NON-TRIVIAL PVS INFORMATION REQUIRED FOR SENSIBLE LIGHTING!\n");
86 printf(" [You may choose to ignore this warning, but lighting will take much longer.]\n\n");
88 printf("# matrix elements set to 'PARTIAL': %10lu (%7.3f%%)\n", VisCount
, 100.0*double(VisCount
)/double(Map
.FaceChildren
.Size()*Map
.FaceChildren
.Size()));
91 // 5. Optimierung der FacePVS-Matrix, Teil 1:
92 // Beim Map.PVS handelt es sich um den Leaf-Allgemeinfall. Nutze hier den Spezialfall aus, daß wir nur die Sichtbarkeit
93 // von einer *Face* aus bestimmen wollen und die Tatsache, daß alles unterhalb oder in der Ebene einer Face F nicht von
94 // F aus sichtbar sein kann! (Das heißt insbesondere auch, daß F sich nicht selbst sehen kann!)
95 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++)
97 // Zuerst (wegen oben) muß eine Face sich noch selbst sehen können
98 if (FacePVS
[Face1Nr
][Face1Nr
]==NO_VISIBILITY
) printf("WARNING: FacePVS[i][i]==NO_VISIBILITY\n");
99 FacePVS
[Face1Nr
][Face1Nr
]=NO_VISIBILITY
;
101 for (unsigned long Face2Nr
=Face1Nr
+1; Face2Nr
<Map
.FaceChildren
.Size(); Face2Nr
++)
102 if (FacePVS
[Face1Nr
][Face2Nr
]==PARTIAL_VISIBILITY
|| FacePVS
[Face2Nr
][Face1Nr
]==PARTIAL_VISIBILITY
)
104 Polygon3T
<double>::SideT Side1
=Map
.FaceChildren
[Face2Nr
]->Polygon
.WhatSideSimple(Map
.FaceChildren
[Face1Nr
]->Polygon
.Plane
, MapT::RoundEpsilon
);
105 Polygon3T
<double>::SideT Side2
=Map
.FaceChildren
[Face1Nr
]->Polygon
.WhatSideSimple(Map
.FaceChildren
[Face2Nr
]->Polygon
.Plane
, MapT::RoundEpsilon
);
107 if (FacePVS
[Face1Nr
][Face2Nr
]!=FacePVS
[Face2Nr
][Face1Nr
]) printf("WARNING: FacePVS[i][j]!=FacePVS[j][i]\n");
109 if (Side1
!=Polygon3T
<double>::Front
&& Side1
!=Polygon3T
<double>::Both
&&
110 Side2
!=Polygon3T
<double>::Front
&& Side2
!=Polygon3T
<double>::Both
)
112 FacePVS
[Face1Nr
][Face2Nr
]=NO_VISIBILITY
;
113 FacePVS
[Face2Nr
][Face1Nr
]=NO_VISIBILITY
;
119 // 6. Zähle die Anzahl der PARTIAL_VISIBILITY-Elemente in der FacePVS-Matrix nach erster Optimierung
122 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++)
123 for (unsigned long Face2Nr
=0; Face2Nr
<Map
.FaceChildren
.Size(); Face2Nr
++)
124 if (FacePVS
[Face1Nr
][Face2Nr
]==PARTIAL_VISIBILITY
) VisCount
++;
126 printf("Still 'PARTIAL' after 1st optimization pass: %10lu (%7.3f%%)\n", VisCount
, 100.0*double(VisCount
)/double(Map
.FaceChildren
.Size()*Map
.FaceChildren
.Size()));
129 // 7. Optimierung der FacePVS-Matrix, Teil 2:
130 // Faces ohne Lightmap (z.B. mit Sky-Materials) emitieren kein Licht (Initialisierung des Sonnenlichts folgt unten)
131 // und reflektieren auch keins. Deshalb können sie als "unsichtbar" aus dem FacePVS entfernt werden!
132 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++)
134 if (!Map
.FaceChildren
[Face1Nr
]->Material
->UsesGeneratedSHLMap())
136 printf("WARNING: Got a patch mesh that doesn't use a generated SHL map! Material name is \"%s\".\n", Map
.FaceChildren
[Face1Nr
]->Material
->Name
.c_str());
138 for (unsigned long Face2Nr
=0; Face2Nr
<Map
.FaceChildren
.Size(); Face2Nr
++)
140 FacePVS
[Face1Nr
][Face2Nr
]=NO_VISIBILITY
;
141 FacePVS
[Face2Nr
][Face1Nr
]=NO_VISIBILITY
;
147 // 8. Zähle die Anzahl der PARTIAL_VISIBILITY-Elemente in der FacePVS-Matrix nach zweiter Optimierung
150 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++)
151 for (unsigned long Face2Nr
=0; Face2Nr
<Map
.FaceChildren
.Size(); Face2Nr
++)
152 if (FacePVS
[Face1Nr
][Face2Nr
]==PARTIAL_VISIBILITY
) VisCount
++;
154 printf("Still 'PARTIAL' after 2nd optimization pass: %10lu (%7.3f%%)\n", VisCount
, 100.0*double(VisCount
)/double(Map
.FaceChildren
.Size()*Map
.FaceChildren
.Size()));
155 printf(" (%.2f faces visible in average from each face.)\n", double(VisCount
)/double(Map
.FaceChildren
.Size()));
158 // 9. BIS JETZT: Nur NO_VISIBILITY- und PARTIAL_VISIBILITY-Einträge.
159 // JETZT NEU: Bestimme, welche der PARTIAL_VISIBILITY-Einträge sogar FULL_VISIBILITY-Einträge sind.
160 ArrayT
< BoundingBox3T
<double> > FaceBBs
;
162 // Zuerst mal Bounding-Boxes für alle Faces erstellen.
163 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++)
164 FaceBBs
.PushBack(BoundingBox3T
<double>(Map
.FaceChildren
[Face1Nr
]->Polygon
.Vertices
));
166 for (unsigned long Face1Nr
=UseFullVis
? 0 : Map
.FaceChildren
.Size(); Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++)
168 printf("%5.1f%%\r", (double)Face1Nr
/Map
.FaceChildren
.Size()*100.0);
171 for (unsigned long Face2Nr
=Face1Nr
+1; Face2Nr
<Map
.FaceChildren
.Size(); Face2Nr
++)
173 // Faces, die sich nicht mal teilweise sehen können, können sich erst recht nicht komplett sehen.
174 if (FacePVS
[Face1Nr
][Face2Nr
]==NO_VISIBILITY
) continue;
176 // Faces, die sich "schon aus sich heraus" (T-artige Anordnung) nur teilweise sehen können, können sich nicht komplett sehen.
177 if (Map
.FaceChildren
[Face1Nr
]->Polygon
.WhatSideSimple(Map
.FaceChildren
[Face2Nr
]->Polygon
.Plane
, MapT::RoundEpsilon
)!=Polygon3T
<double>::Front
) continue;
178 if (Map
.FaceChildren
[Face2Nr
]->Polygon
.WhatSideSimple(Map
.FaceChildren
[Face1Nr
]->Polygon
.Plane
, MapT::RoundEpsilon
)!=Polygon3T
<double>::Front
) continue;
180 // Faces, zwischen denen möglicherweise ein Terrain liegt, können sich nicht komplett sehen.
181 BoundingBox3T
<double> ConvexHullBB(Map
.FaceChildren
[Face1Nr
]->Polygon
.Vertices
);
182 ConvexHullBB
.Insert(Map
.FaceChildren
[Face2Nr
]->Polygon
.Vertices
);
183 ConvexHullBB
=ConvexHullBB
.GetEpsilonBox(-MapT::RoundEpsilon
);
185 // Bilde die ConvexHull über die Faces Face1Nr und Face2Nr,
186 // wobei alle Normalenvektoren dieser ConvexHull nach *INNEN* zeigen!
187 ArrayT
< Plane3T
<double> > ConvexHull
;
189 // Auf diese HullPlanes können wir nicht verzichten -- im Occluders-Array werden wir Occluder haben,
190 // die von Face[Face1Nr] ODER Face[Face2Nr] aus mindestens PARTIAL sichbar sind!
191 ConvexHull
.PushBack(Map
.FaceChildren
[Face1Nr
]->Polygon
.Plane
);
192 ConvexHull
.PushBack(Map
.FaceChildren
[Face2Nr
]->Polygon
.Plane
);
194 // Teil 1: Planes von der einen Seite aus anlegen
195 for (unsigned long Vertex1Nr
=0; Vertex1Nr
<Map
.FaceChildren
[Face1Nr
]->Polygon
.Vertices
.Size(); Vertex1Nr
++)
197 // Beuge degenerierten und mehrfach vorkommenden HullPlanes vor
198 if (fabs(Map
.FaceChildren
[Face2Nr
]->Polygon
.Plane
.GetDistance(Map
.FaceChildren
[Face1Nr
]->Polygon
.Vertices
[Vertex1Nr
]))<0.1) continue;
200 for (unsigned long Vertex2Nr
=0; Vertex2Nr
<Map
.FaceChildren
[Face2Nr
]->Polygon
.Vertices
.Size(); Vertex2Nr
++)
202 // Dieser try/catch-Block sollte trotz obigem Test nicht entfernt werden, denn es gibt keine Garantieen!
205 Plane3T
<double> HullPlane(Map
.FaceChildren
[Face2Nr
]->Polygon
.Vertices
[Vertex2Nr
], Map
.FaceChildren
[Face1Nr
]->Polygon
.Vertices
[Vertex1Nr
],
206 Map
.FaceChildren
[Face2Nr
]->Polygon
.Vertices
[Vertex2Nr
+1<Map
.FaceChildren
[Face2Nr
]->Polygon
.Vertices
.Size() ? Vertex2Nr
+1 : 0], MapT::RoundEpsilon
);
208 if (Map
.FaceChildren
[Face1Nr
]->Polygon
.WhatSideSimple(HullPlane
, MapT::RoundEpsilon
)!=Polygon3T
<double>::Front
) continue;
209 if (Map
.FaceChildren
[Face2Nr
]->Polygon
.WhatSideSimple(HullPlane
, MapT::RoundEpsilon
)!=Polygon3T
<double>::Front
) continue;
211 ConvexHull
.PushBack(HullPlane
);
213 catch (const DivisionByZeroE
&) {}
217 // Teil 2: Planes von der anderen Seite aus anlegen (Notwendig! Betrachte gegenüberstehendes Dreieck und Quadrat!)
218 for (unsigned long Vertex2Nr
=0; Vertex2Nr
<Map
.FaceChildren
[Face2Nr
]->Polygon
.Vertices
.Size(); Vertex2Nr
++)
220 // Beuge degenerierten und mehrfach vorkommenden HullPlanes vor
221 if (fabs(Map
.FaceChildren
[Face1Nr
]->Polygon
.Plane
.GetDistance(Map
.FaceChildren
[Face2Nr
]->Polygon
.Vertices
[Vertex2Nr
]))<0.1) continue;
223 for (unsigned long Vertex1Nr
=0; Vertex1Nr
<Map
.FaceChildren
[Face1Nr
]->Polygon
.Vertices
.Size(); Vertex1Nr
++)
225 // Dieser try/catch-Block sollte trotz obigem Test nicht entfernt werden, denn es gibt keine Garantieen!
228 Plane3T
<double> HullPlane(Map
.FaceChildren
[Face1Nr
]->Polygon
.Vertices
[Vertex1Nr
], Map
.FaceChildren
[Face2Nr
]->Polygon
.Vertices
[Vertex2Nr
],
229 Map
.FaceChildren
[Face1Nr
]->Polygon
.Vertices
[Vertex1Nr
+1<Map
.FaceChildren
[Face1Nr
]->Polygon
.Vertices
.Size() ? Vertex1Nr
+1 : 0], MapT::RoundEpsilon
);
231 if (Map
.FaceChildren
[Face2Nr
]->Polygon
.WhatSideSimple(HullPlane
, MapT::RoundEpsilon
)!=Polygon3T
<double>::Front
) continue;
232 if (Map
.FaceChildren
[Face1Nr
]->Polygon
.WhatSideSimple(HullPlane
, MapT::RoundEpsilon
)!=Polygon3T
<double>::Front
) continue;
234 ConvexHull
.PushBack(HullPlane
);
236 catch (const DivisionByZeroE
&) {}
240 // Bilde ein Array der in Frage kommenden Occluder.
241 ArrayT
< Polygon3T
<double> > Occluders
;
243 for (unsigned long FaceNr
=0; FaceNr
<Map
.FaceChildren
.Size(); FaceNr
++)
245 if (!ConvexHullBB
.Intersects(FaceBBs
[FaceNr
])) continue;
247 // TODO: if (Face[FaceNr].Alpha<255 || Face[FaceNr].RenderMode==Masked) continue;
249 if ((FacePVS
[Face1Nr
][FaceNr
]!=NO_VISIBILITY
) ||
250 (FacePVS
[Face2Nr
][FaceNr
]!=NO_VISIBILITY
)) Occluders
.PushBack(Map
.FaceChildren
[FaceNr
]->Polygon
);
253 // Clippe die Occluder gegen die ConvexHull.
254 for (unsigned long HullPlaneNr
=0; HullPlaneNr
<ConvexHull
.Size(); HullPlaneNr
++)
255 for (unsigned long OccluderNr
=0; OccluderNr
<Occluders
.Size(); OccluderNr
++)
256 switch (Occluders
[OccluderNr
].WhatSideSimple(ConvexHull
[HullPlaneNr
], MapT::RoundEpsilon
))
258 case Polygon3T
<double>::Both
:
259 // Occluder splitten und Front-Teil behalten.
260 Occluders
[OccluderNr
]=Occluders
[OccluderNr
].GetSplits(ConvexHull
[HullPlaneNr
], MapT::RoundEpsilon
)[0];
263 case Polygon3T
<double>::Front
:
264 // Occluder bleibt unverändert in der Liste.
268 // Diesen Occluder aus der Liste löschen.
269 Occluders
[OccluderNr
]=Occluders
[Occluders
.Size()-1];
270 Occluders
.DeleteBack();
275 // Es sind noch Occluder in der ConvexHull, keine gegenseitige komplette Sichtbarkeit.
276 if (Occluders
.Size()) continue;
278 // Die Faces Face1Nr und Face2Nr können sich gegenseitig komplett sehen!
279 FacePVS
[Face1Nr
][Face2Nr
]=FULL_VISIBILITY
;
280 FacePVS
[Face2Nr
][Face1Nr
]=FULL_VISIBILITY
;
285 // 10. Zähle die Anzahl der FULL_VISIBILITY-Elemente in der FacePVS-Matrix.
286 unsigned long PartialVisCount
=VisCount
;
289 for (unsigned long Face1Nr
=0; Face1Nr
<Map
.FaceChildren
.Size(); Face1Nr
++)
290 for (unsigned long Face2Nr
=0; Face2Nr
<Map
.FaceChildren
.Size(); Face2Nr
++)
291 if (FacePVS
[Face1Nr
][Face2Nr
]==FULL_VISIBILITY
) VisCount
++;
293 printf("Number of 'FULL' visibility entries: %10lu (%7.3f%%)\n", VisCount
, 100.0*double(VisCount
)/double(Map
.FaceChildren
.Size()*Map
.FaceChildren
.Size()));
294 printf(" (These are %.2f%% of the 'PARTIAL' entries!)\n", 100.0*double(VisCount
)/double(PartialVisCount
));