1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/3d/zone_tgt_smoother.h"
20 #include "nel/misc/plane.h"
23 using namespace NLMISC
;
34 // ***************************************************************************
35 void CZoneTgtSmoother::makeVerticesCoplanar(std::vector
<CZoneInfo
> &zones
)
40 nlassert(zones
.size()>=1);
41 centerZoneId
= zones
[0].ZoneId
;
45 // First, make connectivity patch/vertex
46 for(i
=0;i
<(sint
)zones
[0].Patchs
.size();i
++)
48 CPatchInfo
&pa
= zones
[0].Patchs
[i
];
52 sint vtx
= pa
.BaseVertices
[j
];
54 pid
.ZoneId
= centerZoneId
;
58 VertexMap
[vtx
].Patchs
.push_back(pid
);
61 // Second, what vertices of this zone are one border?
62 for(i
=0;i
<(sint
)zones
[0].BorderVertices
.size();i
++)
64 CBorderVertex
&bv
= zones
[0].BorderVertices
[i
];
65 sint vtx
= bv
.CurrentVertex
;
66 VertexMap
[vtx
].OnBorder
= true;
71 map
<sint
, sint
> tempMap
;
72 for(numZone
= 1; numZone
<(sint
)zones
.size(); numZone
++)
74 sint adjZoneId
= zones
[numZone
].ZoneId
;
77 // Tests which vertices points on the center zone.
78 for(i
=0;i
<(sint
)zones
[numZone
].BorderVertices
.size();i
++)
80 CBorderVertex
&bv
= zones
[numZone
].BorderVertices
[i
];
82 if(bv
.NeighborZoneId
== centerZoneId
)
84 tempMap
[bv
.CurrentVertex
]= bv
.NeighborVertex
;
87 // Tests patchs which points on center zone.
88 for(i
=0;i
<(sint
)zones
[numZone
].Patchs
.size();i
++)
90 CPatchInfo
&pa
= zones
[numZone
].Patchs
[i
];
94 sint vtx
= pa
.BaseVertices
[j
];
95 if(tempMap
.find(vtx
)!=tempMap
.end())
98 pid
.ZoneId
= adjZoneId
;
102 // Fill the vertex of the center zone.
103 VertexMap
[tempMap
[vtx
]].Patchs
.push_back(pid
);
110 // 2. Process each vertex.
111 //========================
113 for(itVert
= VertexMap
.begin(); itVert
!=VertexMap
.end(); itVert
++)
115 CVertexInfo
&vert
= itVert
->second
;
117 // a. verify if coplanar is possible.
118 //===================================
120 // \todo yoyo: later: do it too on non border vertices if wanted (with a normal threshold...).
123 // \todo yoyo: later: formula with 3, 5 ... patchs around the vertex.
124 if(vert
.Patchs
.size()!=4)
127 // Test if there is no bind 1/x on this patch, around this vertex.
128 // \todo yoyo: later: binds should works...
129 std::list
<CPatchId
>::iterator itPatch
;
130 bool bindFound
= false;
131 for(itPatch
= vert
.Patchs
.begin(); itPatch
!= vert
.Patchs
.end(); itPatch
++)
133 // Tests the two edges around the vertex (before: e0, and after: e1).
134 sint e0
= (itPatch
->IdVert
+4-1)%4;
135 sint e1
= itPatch
->IdVert
;
137 if(itPatch
->Patch
->BindEdges
[e0
].NPatchs
!= 1 || itPatch
->Patch
->BindEdges
[e1
].NPatchs
!= 1)
148 // b. maps patchs on tangents.
149 //=========================
150 vector
<CTangentId
> tangents
;
151 for(itPatch
= vert
.Patchs
.begin(); itPatch
!= vert
.Patchs
.end(); itPatch
++)
153 CPatchInfo
&pa
= *(itPatch
->Patch
);
154 // The edges, before and after the veterx.
155 sint edgeNum
[2]= {(itPatch
->IdVert
+4-1)%4, itPatch
->IdVert
};
156 // The tangents, before and after the veterx.
157 sint tgtNum
[2]= {(itPatch
->IdVert
*2+8-1)%8, itPatch
->IdVert
*2 };
159 // For the 2 edges around this vertex.
160 for(sint ed
= 0; ed
<2;ed
++)
162 sint patchId
, zoneId
, edgeId
;
165 // get neighbor edge id.
166 zoneId
= pa
.BindEdges
[ edgeNum
[ed
] ].ZoneId
;
167 patchId
= pa
.BindEdges
[ edgeNum
[ed
] ].Next
[0];
168 edgeId
= pa
.BindEdges
[ edgeNum
[ed
] ].Edge
[0];
169 // Search if tangent already inserted, mapped to this "neighbor edge".
170 for(tgt
= 0; tgt
<(sint
)tangents
.size();tgt
++)
172 if(tangents
[tgt
].ZoneId
==zoneId
&& tangents
[tgt
].PatchId
==patchId
&& tangents
[tgt
].EdgeId
==edgeId
)
175 // If not found, add the tangent, and map ME to it.
176 if(tgt
==(sint
)tangents
.size())
180 tangent
.ZoneId
= itPatch
->ZoneId
;
181 tangent
.PatchId
= itPatch
->PatchId
;
182 tangent
.EdgeId
= edgeNum
[ed
];
183 // Get the tangent, before or after the vertex.
184 tangent
.Tangent
= pa
.Patch
.Tangents
[ tgtNum
[ed
] ];
185 // Which patchs this edge share. (0 is those which insert this tgt)
186 tangent
.Patchs
[0]= &pa
;
187 tangents
.push_back(tangent
);
191 // Which patchs this edge share. (0 is those which access this tgt)
192 tangents
[tgt
].Patchs
[1]= &pa
;
194 // Map the patch to this tangent.
195 itPatch
->Tangents
[ed
]= tgt
;
200 // There should be 4 tangents.
201 if (tangents
.size()!=4)
203 nlinfo ("ERROR: vertex %d should have 4 tangents. It got %d. (MAXINDICES +1!!)", itVert
->first
, tangents
.size());
208 // c. get the vertex.
209 //===================
211 itPatch
= vert
.Patchs
.begin();
212 vertexValue
= itPatch
->Patch
->Patch
.Vertices
[itPatch
->IdVert
];
215 // d. project the tangents.
216 //=========================
217 // better coplanar than Max... (with orthogonal angles: use p0/p1).
218 for(i
=0;i
<(sint
)tangents
.size();i
++)
220 // For following tangents, search the opposite.
221 // Begin at i+1 so we are sure to do this only one time.
222 for(j
=i
+1;j
<(sint
)tangents
.size();j
++)
224 if(tangents
[i
].isOppositeOf(tangents
[j
]))
226 CVector
&tgt0
= tangents
[i
].Tangent
;
227 CVector
&tgt1
= tangents
[j
].Tangent
;
228 // Colinear the tangents. Must keep the length of vectors.
229 float l0
= (tgt0
-vertexValue
).norm();
230 float l1
= (tgt1
-vertexValue
).norm();
231 // Average the tangents. Normalize them before, to keep much as possible the orientation.
232 CVector d0
= (vertexValue
-tgt0
).normed();
233 CVector d1
= (tgt1
-vertexValue
).normed();
234 CVector dir
= (d0
+d1
).normed();
237 tgt0
= vertexValue
-dir
*l0
;
238 tgt1
= vertexValue
+dir
*l1
;
244 // e. assign tangents to patchs, rebuild interior.
245 //==============================
246 for(itPatch
= vert
.Patchs
.begin(); itPatch
!= vert
.Patchs
.end(); itPatch
++)
248 CPatchInfo
&pa
= *(itPatch
->Patch
);
249 // The tangents, before and after the vertex.
250 sint tgtNum
[2]= {(itPatch
->IdVert
*2+8-1)%8, itPatch
->IdVert
*2 };
253 sint smoothEdge0
= pa
.getSmoothFlag (t0
/2);
254 sint smoothEdge1
= pa
.getSmoothFlag (t1
/2);
256 // Smooth this edge ?
258 pa
.Patch
.Tangents
[t0
]= tangents
[itPatch
->Tangents
[0]].Tangent
;
260 pa
.Patch
.Tangents
[t1
]= tangents
[itPatch
->Tangents
[1]].Tangent
;
262 // Setup the coplanared interior. just the sum of 2 vector tangents.
263 if (smoothEdge0
&&smoothEdge1
)
264 pa
.Patch
.Interiors
[itPatch
->IdVert
]= pa
.Patch
.Tangents
[t0
] + pa
.Patch
.Tangents
[t1
] - vertexValue
;
271 // OLD CODE FOR 3DS MAX LIKE COPLANAR.
272 // WORKS, BUT NOT AS GOOD AS REAL COPLANAR.
274 // b. build the plane.
275 //====================
276 CVector planeNormal(0,0,0);
278 for(itPatch= vert.Patchs.begin(); itPatch!= vert.Patchs.end(); itPatch++)
280 CPatchInfo &pa= *(itPatch->Patch);
281 CVector a,b,c, pvect;
282 sint t0= (itPatch->IdVert*2+8-1)%8;
283 sint t1= itPatch->IdVert*2;
286 a= pa.Patch.Tangents[t0];
287 b= pa.Patch.Vertices[itPatch->IdVert];
288 c= pa.Patch.Tangents[t1];
290 planeNormal+= pvect.normed();
292 // yes, done 4 times... :(
295 // Average of all normals...
296 planeNormal.normalize();
298 plane.make(planeNormal, planeCenter);
301 // c. projects the tangents, rebuild interior.
302 //============================================
303 for(itPatch= vert.Patchs.begin(); itPatch!= vert.Patchs.end(); itPatch++)
305 CPatchInfo &pa= *(itPatch->Patch);
306 sint t0= (itPatch->IdVert*2+8-1)%8;
307 sint t1= itPatch->IdVert*2;
308 pa.Patch.Tangents[t0]= plane.project(pa.Patch.Tangents[t0]);
309 pa.Patch.Tangents[t1]= plane.project(pa.Patch.Tangents[t1]);
311 // Setup the coplanared interior. just the sum of 2 vector tangents.
312 pa.Patch.Interiors[itPatch->IdVert]= pa.Patch.Tangents[t0] + pa.Patch.Tangents[t1] - planeCenter;