root/cafu/trunk/CaSHL/Init2.cpp

Revision 455, 11.6 KB (checked in by Carsten, 4 months ago)

Updated copyright banners (in C++ files).

Line 
1/*
2=================================================================================
3This file is part of Cafu, the open-source game engine and graphics engine
4for multiplayer, cross-platform, real-time 3D action.
5Copyright (C) 2002-2012 Carsten Fuchs Software.
6
7Cafu is free software: you can redistribute it and/or modify it under the terms
8of the GNU General Public License as published by the Free Software Foundation,
9either version 3 of the License, or (at your option) any later version.
10
11Cafu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with Cafu. If not, see <http://www.gnu.org/licenses/>.
17
18For support and more information about Cafu, visit us at <http://www.cafu.de>.
19=================================================================================
20*/
21
22#if USE_NORMALMAPS
23
24// This function computes a normal vector for a patch by taking the surfaces normal-map into account.
25//
26// Dazu müssen wir eigentlich die Normal-Map dieser Face entlang des PatchPoly rasterizern, und dann den renomalisierten Mittelwert
27// der Normal-Map-Normalenvektoren im PatchPoly bilden. Allerdings ist ein PatchPoly üblicherweise *MINDESTENS* 200.0*200.0 world units groß,
28// während ein großer Normal-Map Texel idR nur (25.4*0.25)^2 world units groß ist.
29// Ein PatchPoly deckt also MINDESTENS (200.0)^2/(25.4*0.25)^2 == 6299 Normal-Map Texels ab!! Neben der Tatsache, daß das Rasterizing zur
30// Bestimmung dieser Normalen *sehr* aufwendig ist (und diese Normalen weiter aufwendig vom Tangent- in den Object-Space überführt werden müssen),
31// ergibt sich auch nahezu IMMER ein renomalisierter Mittelwert, der F.Plane.Normal entspricht. Sollte es dennoch Abweichungen geben, sind sie so klein,
32// daß man sie niemals wahrnimmt. (Die Rundungsfehler allein an anderer Stelle sind um Größenordnungen höher, z.B. die Komprimierung der Werte in "char"!!)
33// Daher würde   Patch.Normal=F.Plane.Normal;   normalerweise völlig ausreichen.
34void ComputePatchNormal(PatchT& Patch, const cf::SceneGraph::FaceNodeT::TexInfoT& TI, const BitmapT& NormalMap, const VectorT& SpanU, const VectorT& SpanV)
35{
36    const VectorT PlaneNormal=Patch.Normal;
37    const VectorT TI_U       =TI.U.AsVectorOfDouble();
38    const VectorT TI_V       =TI.V.AsVectorOfDouble();
39
40    Patch.Normal=VectorT();
41
42    const unsigned long NrOfSamples=20;
43
44    // Do not attempt to ACTUALLY RASTERIZE the normal-map along the dimensions of the patch: the effort is not proportional to the results.
45    // Simply taking some samples serves equally well, and saves us the huge overhead of a dedicated software rasterizer.
46    for (unsigned long SampleNr=0; SampleNr<NrOfSamples; SampleNr++)
47    {
48        const double  PatchRadius =cf::SceneGraph::FaceNodeT::SHLMapInfoT::PatchSize/2.0;
49        const double  OffsetU     =(2.0*double(rand())/double(RAND_MAX)-1.0)*PatchRadius;
50        const double  OffsetV     =(2.0*double(rand())/double(RAND_MAX)-1.0)*PatchRadius;
51        const VectorT SampleOrigin=Patch.Coord+scale(SpanU, OffsetU)+scale(SpanV, OffsetV);
52
53     // const double TexSizeX=TexDataSizeX[TI.TexDataNr];               // Texture size in X direction.
54     // const double TexSizeY=TexDataSizeY[TI.TexDataNr];               // Texture size in Y direction.
55        const double LengthU =length(TI_U);                       // Länge des U-Vektors (X-Richtung).
56        const double LengthV =length(TI_V);                       // Länge des V-Vektors (Y-Richtung).
57
58        double s=/*(*/ dot(SampleOrigin, TI_U)/(LengthU*LengthU)+TI.OffsetU;  // )/TexSizeX-SmallestS;
59        double t=/*(*/ dot(SampleOrigin, TI_V)/(LengthV*LengthV)+TI.OffsetV;  // )/TexSizeY-SmallestT;
60
61        // Do "modulo texsize" for s and t.
62        while (s<0.0) s+=NormalMap.SizeX; while (s>=NormalMap.SizeX) s-=NormalMap.SizeX;
63        while (t<0.0) t+=NormalMap.SizeY; while (t>=NormalMap.SizeY) t-=NormalMap.SizeY;
64
65        unsigned int s_=(unsigned int)(s+0.5); if (s_>=NormalMap.SizeX) s_=0;
66        unsigned int t_=(unsigned int)(t+0.5); if (t_>=NormalMap.SizeY) t_=0;
67
68        const uint32_t NormalRC=NormalMap.Data[s_+t_*NormalMap.SizeX];
69        const char     nxRC    =char(NormalRC >>  0);
70        const char     nyRC    =char(NormalRC >>  8);
71        const char     nzRC    =char(NormalRC >> 16);
72        const VectorT  Normal  =VectorT(2.0*(nxRC/255.0-0.5), 2.0*(nyRC/255.0-0.5), 2.0*(nzRC/255.0-0.5));
73
74        Patch.Normal=Patch.Normal+Normal;
75    }
76
77    try
78      {
79        Patch.Normal=normalize(Patch.Normal, 0.000001);
80      }
81    catch (const DivisionByZeroE& /*E*/)
82      {
83        printf("WARNING: Invalid patch normal occured!\n");
84        Patch.Normal=VectorT(0.0, 0.0, 1.0);
85      }
86
87    // Translate (rotate) the Patch.Normal from tangent into world space.
88    const VectorT R1=VectorT(SpanU.x, SpanV.x, PlaneNormal.x);
89    const VectorT R2=VectorT(SpanU.y, SpanV.y, PlaneNormal.y);
90    const VectorT R3=VectorT(SpanU.z, SpanV.z, PlaneNormal.z);
91
92    Patch.Normal=VectorT(dot(R1, Patch.Normal), dot(R2, Patch.Normal), dot(R3, Patch.Normal));
93}
94
95#endif
96
97
98void InitializePatches(const cf::SceneGraph::BspTreeNodeT& Map)
99{
100    printf("\n%-50s %s\n", "*** Initialize Patches ***", GetTimeSinceProgramStart());
101
102
103    // 1. Allokiere neuen Speicher für die ganzen Patches
104    Patches.Clear();
105    Patches.PushBackEmpty(Map.FaceChildren.Size());
106
107    unsigned long PatchCount=0;
108    unsigned long FaceNr;
109
110    for (FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
111    {
112        const cf::SceneGraph::FaceNodeT::SHLMapInfoT& SMI            =Map.FaceChildren[FaceNr]->SHLMapInfo;
113        const unsigned long                           NR_OF_SH_COEFFS=cf::SceneGraph::SHLMapManT::NrOfBands * cf::SceneGraph::SHLMapManT::NrOfBands;
114
115        Patches[FaceNr].PushBackEmpty(SMI.SizeS*SMI.SizeT);
116        PatchCount+=Patches[FaceNr].Size();
117
118        // Wir prüfen es besser hier, denn die Engine prüft es zur Zeit nicht! Sollte aber niemals vorkommen!
119        if (SMI.SizeS>cf::SceneGraph::SHLMapManT::SIZE_S || SMI.SizeT>cf::SceneGraph::SHLMapManT::SIZE_T) Error("SHLMAP OF FACE %u EXCEEDS LIMITS! ENGINE WILL DENY THIS MAP!", FaceNr);
120
121        // Für alle Patches auch die Coeffs allokieren.
122        for (unsigned long PatchNr=0; PatchNr<Patches[FaceNr].Size(); PatchNr++)
123        {
124            PatchT& P=Patches[FaceNr][PatchNr];
125
126            while (P.SHCoeffs_UnradiatedTransfer.Size()<NR_OF_SH_COEFFS) P.SHCoeffs_UnradiatedTransfer.PushBack(0.0);
127            while (P.SHCoeffs_TotalTransfer     .Size()<NR_OF_SH_COEFFS) P.SHCoeffs_TotalTransfer     .PushBack(0.0);
128        }
129    }
130    printf("# patches allocated:%10lu\n", PatchCount);
131
132
133    // 2. Bestimme, ob ein Patch zumindest ein bißchen innerhalb seiner Face liegt, und wenn ja, seinen Mittelpunkt.
134    //    Dieser wird wegen Rundungsfehlern etwas entlang seines Normalenvektors verschoben!
135
136    // Bilde zuerst ein LookUp-Array, das die Nummern aller Faces mit Radiosity-Sunlight Material enthält.
137    ArrayT<unsigned long> SkyFaces;
138
139    for (FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
140        if (length(Vector3T<double>(Map.FaceChildren[FaceNr]->Material->meta_SunLight_Irr))>0.1 &&
141            length(Vector3T<double>(Map.FaceChildren[FaceNr]->Material->meta_SunLight_Dir))>0.1) SkyFaces.PushBack(FaceNr);
142
143
144    for (FaceNr=0; FaceNr<Map.FaceChildren.Size(); FaceNr++)
145    {
146        printf("%5.1f%%\r", (double)FaceNr/Map.FaceChildren.Size()*100.0);
147        fflush(stdout);
148
149        const cf::SceneGraph::FaceNodeT* FN=Map.FaceChildren[FaceNr];
150        const Polygon3T<double>&         F =FN->Polygon;
151
152        // Bestimme die Spannvektoren
153        VectorT U;
154        VectorT V;
155
156        F.Plane.GetSpanVectors(U, V);
157
158        // Finde SmallestU und SmallestV
159        double SmallestU=dot(F.Vertices[0], U);
160        double SmallestV=dot(F.Vertices[0], V);
161
162        for (unsigned long VertexNr=1; VertexNr<F.Vertices.Size(); VertexNr++)
163        {
164            double u=dot(F.Vertices[VertexNr], U);
165            double v=dot(F.Vertices[VertexNr], V);
166
167            if (u<SmallestU) SmallestU=u;
168            if (v<SmallestV) SmallestV=v;
169        }
170
171        SmallestU=floor(SmallestU/cf::SceneGraph::FaceNodeT::SHLMapInfoT::PatchSize);
172        SmallestV=floor(SmallestV/cf::SceneGraph::FaceNodeT::SHLMapInfoT::PatchSize);
173
174        // Bereite folgende Schleife vor
175        const VectorT UV_Origin=scale(F.Plane.Normal, F.Plane.Dist);
176        const VectorT Safety   =scale(F.Plane.Normal, 0.1);
177
178        Polygon3T<double> PatchPoly;
179        PatchPoly.Plane=dot(F.Plane.Normal, cross(U, V))<0 ? F.Plane : F.Plane.GetMirror();
180
181#if USE_NORMALMAPS
182        BitmapT* NormalMapPtr=FN->Material->NormMapComp.GetBitmap();
183        BitmapT  NormalMap   =*NormalMapPtr;
184
185        delete NormalMapPtr;
186        NormalMapPtr=NULL;
187#endif
188
189        // Nun betrachte alle Patches
190        for (unsigned long t=0; t<FN->SHLMapInfo.SizeT; t++)
191            for (unsigned long s=0; s<FN->SHLMapInfo.SizeS; s++)
192            {
193                const double PATCH_SIZE=cf::SceneGraph::FaceNodeT::SHLMapInfoT::PatchSize;
194                PatchT&      Patch     =Patches[FaceNr][t*FN->SHLMapInfo.SizeS+s];
195
196                Patch.Coord     =VectorT(0, 0, 0);
197#if USE_NORMALMAPS
198                Patch.Normal    =F.Plane.Normal;    // Do a fail-safe init (also required for the ComputePatchNormal() function below!).
199#endif
200                Patch.InsideFace=false;
201
202                PatchPoly.Vertices.Clear();
203                PatchPoly.Vertices.PushBack(UV_Origin+scale(U, (SmallestU+s-1.0)*PATCH_SIZE)+scale(V, (SmallestV+t-1.0)*PATCH_SIZE));
204                PatchPoly.Vertices.PushBack(UV_Origin+scale(U, (SmallestU+s    )*PATCH_SIZE)+scale(V, (SmallestV+t-1.0)*PATCH_SIZE));
205                PatchPoly.Vertices.PushBack(UV_Origin+scale(U, (SmallestU+s    )*PATCH_SIZE)+scale(V, (SmallestV+t    )*PATCH_SIZE));
206                PatchPoly.Vertices.PushBack(UV_Origin+scale(U, (SmallestU+s-1.0)*PATCH_SIZE)+scale(V, (SmallestV+t    )*PATCH_SIZE));
207
208                if (!F.Overlaps(PatchPoly, false, MapT::RoundEpsilon)) continue;
209
210                if (!F.Encloses(PatchPoly, true, MapT::RoundEpsilon))
211                {
212                    ArrayT< Polygon3T<double> > NewPolygons;
213
214                    PatchPoly.GetChoppedUpAlong(F, MapT::RoundEpsilon, NewPolygons);
215                    if (NewPolygons.Size()==0) Error("PolygonChopUp failed.");
216
217                    PatchPoly=NewPolygons[NewPolygons.Size()-1];
218                    if (PatchPoly.Vertices.Size()==0) Error("PatchPoly.Vertices.Size()==0.");
219                }
220
221                for (unsigned long VertexNr=0; VertexNr<PatchPoly.Vertices.Size(); VertexNr++)
222                    Patch.Coord=Patch.Coord+PatchPoly.Vertices[VertexNr];
223
224                Patch.Coord     =scale(Patch.Coord, 1.0/double(PatchPoly.Vertices.Size()))+Safety;
225                Patch.InsideFace=true;
226
227#if USE_NORMALMAPS
228                // Zuletzt noch den Patch.Normal Vektor bestimmen.
229                // Siehe die Kommentare zur ComputePatchNormal Funktion für weitere Infos.
230                // Außerdem ist dieses Verfahren alles andere als effizient -- sollte die Normal-Map nicht für jede Face neu laden!
231                // Beachte: Die Patch.Normal muß mit der F.Plane.Normal initialisiert sein!
232                ComputePatchNormal(Patch, FN->TI, NormalMap, U, V);
233#endif
234            }
235    }
236    printf("Patch coords calculated.\n");
237}
Note: See TracBrowser for help on using the browser.