Revision b72b8a3b
Added by Leszek Koltunski almost 6 years ago
src/main/java/org/distorted/library/mesh/MeshSphere.java | ||
---|---|---|
75 | 75 |
// (level*level +4*level) because there are level*level little triangles, each requiring new vertex, |
76 | 76 |
// plus 2 extra vertices to start off a row and 2 to move to the next row (or the next face in case |
77 | 77 |
// of the last row) and there are 'level' rows. |
78 |
// |
|
79 |
// Now to this we need to add 6*(level-1) vertices for the internal seams in the three triangles |
|
80 |
// in the back ( 2,7,16 in the list above ): 3 triangles, level-1 rows of more than 1 triangle in |
|
81 |
// each, 2 extra seam vertices in each row. |
|
78 | 82 |
|
79 | 83 |
private void computeNumberOfVertices(int level) |
80 | 84 |
{ |
81 |
numVertices = NUMFACES*level*(level+4) -2; |
|
85 |
numVertices = NUMFACES*level*(level+4) -2 + 6*(level-1);
|
|
82 | 86 |
currentVert = 0; |
83 | 87 |
} |
84 | 88 |
|
85 | 89 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
86 |
// (longitude,latitude) - spherical coordinates of a point on a unit sphere. |
|
87 |
// Cartesian (0,0,1) - i.e. the point of the sphere closest to the camera - is spherical (0,0). |
|
88 | 90 |
|
89 |
private void addVertex( double longitude, double latitude, float[] attribs)
|
|
91 |
private int convertAng(double radian)
|
|
90 | 92 |
{ |
91 |
double sinLON = Math.sin(longitude); |
|
92 |
double cosLON = Math.cos(longitude); |
|
93 |
double sinLAT = Math.sin(latitude); |
|
94 |
double cosLAT = Math.cos(latitude); |
|
95 |
|
|
96 |
float x = (float)(cosLAT*sinLON / sqrt2); |
|
97 |
float y = (float)(sinLAT / sqrt2); |
|
98 |
float z = (float)(cosLAT*cosLON / sqrt2); |
|
99 |
|
|
100 |
double texX = 0.5 + longitude/(2*P); |
|
101 |
if( texX>=1.0 ) texX-=1.0; |
|
102 |
|
|
103 |
//android.util.Log.e("tex", "longitude = "+((int)(180.0*longitude/P))+" texX="+texX ); |
|
104 |
|
|
105 |
double texY = 0.5 + latitude/P; |
|
106 |
|
|
107 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB ] = x; // |
|
108 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB+1] = y; // |
|
109 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB+2] = z; // |
|
110 |
// In case of this Mesh so it happens that |
|
111 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB ] = x; // the vertex coords, normal vector, and |
|
112 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB+1] = y; // inflate vector have identical (x,y,z). |
|
113 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB+2] = z; // |
|
114 |
// TODO: think about some more efficient |
|
115 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB ] = x; // representation. |
|
116 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB+1] = y; // |
|
117 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB+2] = z; // |
|
118 |
|
|
119 |
attribs[VERT_ATTRIBS*currentVert + TEX_ATTRIB ] = (float)texX; |
|
120 |
attribs[VERT_ATTRIBS*currentVert + TEX_ATTRIB+1] = (float)texY; |
|
121 |
|
|
122 |
currentVert++; |
|
93 |
return (int)(radian*180.0/P); |
|
123 | 94 |
} |
124 | 95 |
|
125 |
|
|
126 | 96 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
127 | 97 |
|
128 |
private void repeatLast(float[] attribs)
|
|
98 |
private void repeatVertex(float[] attribs, int diff)
|
|
129 | 99 |
{ |
130 | 100 |
//android.util.Log.e("sphere", "repeat last!"); |
131 | 101 |
|
132 | 102 |
if( currentVert>0 ) |
133 | 103 |
{ |
134 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB ] = attribs[VERT_ATTRIBS*(currentVert-1) + POS_ATTRIB ];
|
|
135 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB+1] = attribs[VERT_ATTRIBS*(currentVert-1) + POS_ATTRIB+1];
|
|
136 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB+2] = attribs[VERT_ATTRIBS*(currentVert-1) + POS_ATTRIB+2];
|
|
104 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB ] = attribs[VERT_ATTRIBS*(currentVert-diff) + POS_ATTRIB ];
|
|
105 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB+1] = attribs[VERT_ATTRIBS*(currentVert-diff) + POS_ATTRIB+1];
|
|
106 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB+2] = attribs[VERT_ATTRIBS*(currentVert-diff) + POS_ATTRIB+2];
|
|
137 | 107 |
|
138 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB ] = attribs[VERT_ATTRIBS*(currentVert-1) + NOR_ATTRIB ];
|
|
139 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB+1] = attribs[VERT_ATTRIBS*(currentVert-1) + NOR_ATTRIB+1];
|
|
140 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB+2] = attribs[VERT_ATTRIBS*(currentVert-1) + NOR_ATTRIB+2];
|
|
108 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB ] = attribs[VERT_ATTRIBS*(currentVert-diff) + NOR_ATTRIB ];
|
|
109 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB+1] = attribs[VERT_ATTRIBS*(currentVert-diff) + NOR_ATTRIB+1];
|
|
110 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB+2] = attribs[VERT_ATTRIBS*(currentVert-diff) + NOR_ATTRIB+2];
|
|
141 | 111 |
|
142 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB ] = attribs[VERT_ATTRIBS*(currentVert-1) + INF_ATTRIB ];
|
|
143 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB+1] = attribs[VERT_ATTRIBS*(currentVert-1) + INF_ATTRIB+1];
|
|
144 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB+2] = attribs[VERT_ATTRIBS*(currentVert-1) + INF_ATTRIB+2];
|
|
112 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB ] = attribs[VERT_ATTRIBS*(currentVert-diff) + INF_ATTRIB ];
|
|
113 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB+1] = attribs[VERT_ATTRIBS*(currentVert-diff) + INF_ATTRIB+1];
|
|
114 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB+2] = attribs[VERT_ATTRIBS*(currentVert-diff) + INF_ATTRIB+2];
|
|
145 | 115 |
|
146 |
attribs[VERT_ATTRIBS*currentVert + TEX_ATTRIB ] = attribs[VERT_ATTRIBS*(currentVert-1) + TEX_ATTRIB ];
|
|
147 |
attribs[VERT_ATTRIBS*currentVert + TEX_ATTRIB+1] = attribs[VERT_ATTRIBS*(currentVert-1) + TEX_ATTRIB+1];
|
|
116 |
attribs[VERT_ATTRIBS*currentVert + TEX_ATTRIB ] = attribs[VERT_ATTRIBS*(currentVert-diff) + TEX_ATTRIB ];
|
|
117 |
attribs[VERT_ATTRIBS*currentVert + TEX_ATTRIB+1] = attribs[VERT_ATTRIBS*(currentVert-diff) + TEX_ATTRIB+1];
|
|
148 | 118 |
|
149 | 119 |
currentVert++; |
150 | 120 |
} |
... | ... | |
201 | 171 |
// ( 0, level-1, level) -> (lonV3,latV3 ) |
202 | 172 |
// (level-1, 0, level) -> (lonV2,latV12) |
203 | 173 |
|
204 |
private void newVertex(float[] attribs, int column, int row, int level,
|
|
205 |
double lonV1, double lonV2, double latV12, double latV3) |
|
174 |
private void addVertex(float[] attribs, int column, int row, int level,
|
|
175 |
double lonV1, double lonV2, double latV12, double latV3, boolean lastInRow)
|
|
206 | 176 |
{ |
207 | 177 |
double quotX = (double)column/level; |
208 | 178 |
double quotY = (double)row /level; |
... | ... | |
217 | 187 |
quotZ = (quotY==1.0 ? 0.0 : quotX / (1.0-quotY)); |
218 | 188 |
} |
219 | 189 |
|
220 |
double lonPoint = midLongitude(lonV1, lonV2, quotZ );
|
|
221 |
double latPoint = midLatitude(latV12, latV3, quotY );
|
|
190 |
double longitude = midLongitude(lonV1, lonV2, quotZ );
|
|
191 |
double latitude = midLatitude(latV12, latV3, quotY );
|
|
222 | 192 |
|
223 | 193 |
//android.util.Log.e("sphere", "newVertex: long:"+lonPoint+" lat:"+latPoint+" column="+column+" row="+row); |
224 | 194 |
|
225 |
addVertex(lonPoint,latPoint,attribs); |
|
195 |
double sinLON = Math.sin(longitude); |
|
196 |
double cosLON = Math.cos(longitude); |
|
197 |
double sinLAT = Math.sin(latitude); |
|
198 |
double cosLAT = Math.cos(latitude); |
|
199 |
|
|
200 |
float x = (float)(cosLAT*sinLON / sqrt2); |
|
201 |
float y = (float)(sinLAT / sqrt2); |
|
202 |
float z = (float)(cosLAT*cosLON / sqrt2); |
|
203 |
|
|
204 |
double texX = 0.5 + longitude/(2*P); |
|
205 |
if( texX>=1.0 ) texX-=1.0; |
|
206 |
|
|
207 |
//android.util.Log.e("tex", "longitude = "+((int)(180.0*longitude/P))+" texX="+texX ); |
|
208 |
|
|
209 |
double texY = 0.5 + latitude/P; |
|
210 |
|
|
211 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB ] = x; // |
|
212 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB+1] = y; // |
|
213 |
attribs[VERT_ATTRIBS*currentVert + POS_ATTRIB+2] = z; // |
|
214 |
// In case of this Mesh so it happens that |
|
215 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB ] = x; // the vertex coords, normal vector, and |
|
216 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB+1] = y; // inflate vector have identical (x,y,z). |
|
217 |
attribs[VERT_ATTRIBS*currentVert + NOR_ATTRIB+2] = z; // |
|
218 |
// TODO: think about some more efficient |
|
219 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB ] = x; // representation. |
|
220 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB+1] = y; // |
|
221 |
attribs[VERT_ATTRIBS*currentVert + INF_ATTRIB+2] = z; // |
|
222 |
|
|
223 |
attribs[VERT_ATTRIBS*currentVert + TEX_ATTRIB ] = (float)texX; |
|
224 |
attribs[VERT_ATTRIBS*currentVert + TEX_ATTRIB+1] = (float)texY; |
|
225 |
|
|
226 |
currentVert++; |
|
227 |
|
|
228 |
//////////////////////////////////////////////////////////////////////////////////////////////// |
|
229 |
// Problem: on the 'change of date' line in the back of the sphere, some triangles see texX |
|
230 |
// coords suddenly jump from 1-epsilon to 0+epsilon, which looks like a seam with a narrow copy |
|
231 |
// of the whole texture there. |
|
232 |
// Solution: each such 'jump' triangle, if it is the last in a row, should have the texX of its |
|
233 |
// last (and maybe forelast as well) vertex remapped to 1.0. |
|
234 |
// If such triangle is not the last in its row, we need to add two extra vertices between it and |
|
235 |
// the next one, remap the old ones' texX to 1.0, and set the two new ones' texX to 0.0. |
|
236 |
//////////////////////////////////////////////////////////////////////////////////////////////// |
|
237 |
|
|
238 |
if( currentVert>=3 ) |
|
239 |
{ |
|
240 |
double tex1 = attribs[VERT_ATTRIBS*(currentVert-2) + TEX_ATTRIB]; |
|
241 |
double tex2 = attribs[VERT_ATTRIBS*(currentVert-3) + TEX_ATTRIB]; |
|
242 |
double y1 = attribs[VERT_ATTRIBS*(currentVert-2) + INF_ATTRIB + 1]; |
|
243 |
double y2 = attribs[VERT_ATTRIBS*(currentVert-3) + INF_ATTRIB + 1]; |
|
244 |
|
|
245 |
if( tex1!=tex2 || y1!=y2 ) // if the triangle is not degenerate |
|
246 |
{ |
|
247 |
double diff1 = Math.abs(texX-tex1); |
|
248 |
double diff2 = Math.abs(texX-tex2); |
|
249 |
|
|
250 |
if( diff1>0.5 || diff2>0.5 ) // a jump in texture coords which can only happen along the |
|
251 |
{ // 'date change' line. Have to correct! |
|
252 |
if( lastInRow ) |
|
253 |
{ |
|
254 |
attribs[VERT_ATTRIBS*(currentVert-1) + TEX_ATTRIB] = 1.0f; |
|
255 |
if( tex1<tex2 ) attribs[VERT_ATTRIBS*(currentVert-2) + TEX_ATTRIB] = 1.0f; |
|
256 |
} |
|
257 |
else |
|
258 |
{ |
|
259 |
if( latitude> -A ) // top two triangles being corrected |
|
260 |
{ |
|
261 |
if (2*column+row-1 == level) // last such triangle in a row; have to introduce extra 2 vertices. |
|
262 |
{ |
|
263 |
/* |
|
264 |
android.util.Log.e("sphere", "LAST max diff exceeded: " + convertAng(longitude) + " " + convertAng(latitude) + " texX=" + texX); |
|
265 |
android.util.Log.d("sphere", " tex1=" + tex1 + " tex2=" + tex2 + " y1=" + y1 + " y2=" + y2); |
|
266 |
android.util.Log.d("sphere", " latV12=" + latV12 + " latV3=" + latV3); |
|
267 |
*/ |
|
268 |
repeatVertex(attribs, 2); |
|
269 |
repeatVertex(attribs, 2); |
|
270 |
|
|
271 |
attribs[VERT_ATTRIBS*(currentVert-1) + TEX_ATTRIB] = 0.0f; |
|
272 |
attribs[VERT_ATTRIBS*(currentVert-2) + TEX_ATTRIB] = 0.0f; |
|
273 |
attribs[VERT_ATTRIBS*(currentVert-3) + TEX_ATTRIB] = 1.0f; |
|
274 |
|
|
275 |
if (tex1 < tex2) attribs[VERT_ATTRIBS*(currentVert-4) + TEX_ATTRIB] = 1.0f; |
|
276 |
} |
|
277 |
if (2*column+row == level) // not the last; just remap current vertex' texX to 1.0. |
|
278 |
{ |
|
279 |
/* |
|
280 |
android.util.Log.e("sphere", "NOT LAST max diff exceeded: " + convertAng(longitude) + " " + convertAng(latitude) + " texX=" + texX); |
|
281 |
android.util.Log.d("sphere", " tex1=" + tex1 + " tex2=" + tex2 + " y1=" + y1 + " y2=" + y2); |
|
282 |
android.util.Log.d("sphere", " latV12=" + latV12 + " latV3=" + latV3); |
|
283 |
*/ |
|
284 |
attribs[VERT_ATTRIBS*(currentVert-1) + TEX_ATTRIB] = 1.0f; |
|
285 |
} |
|
286 |
} |
|
287 |
else // bottom triangle |
|
288 |
{ |
|
289 |
/* |
|
290 |
android.util.Log.e("sphere", "BOTTOM LAST max diff exceeded: " + convertAng(longitude) + " " + convertAng(latitude) + " texX=" + texX); |
|
291 |
android.util.Log.d("sphere", " tex1=" + tex1 + " tex2=" + tex2 + " y1=" + y1 + " y2=" + y2); |
|
292 |
android.util.Log.d("sphere", " latV12=" + latV12 + " latV3=" + latV3); |
|
293 |
*/ |
|
294 |
repeatVertex(attribs, 2); |
|
295 |
repeatVertex(attribs, 2); |
|
296 |
|
|
297 |
attribs[VERT_ATTRIBS*(currentVert-3) + TEX_ATTRIB] = 1.0f; |
|
298 |
} |
|
299 |
} |
|
300 |
} |
|
301 |
} |
|
302 |
} |
|
303 |
|
|
304 |
//////////////////////////////////////////////////////////////////////////////////////////////// |
|
305 |
// End problem |
|
306 |
//////////////////////////////////////////////////////////////////////////////////////////////// |
|
226 | 307 |
} |
227 | 308 |
|
228 | 309 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
... | ... | |
233 | 314 |
{ |
234 | 315 |
for (int column=0; column<level-row; column++) |
235 | 316 |
{ |
236 |
newVertex(attribs, column, row , level, lonV1, lonV2, latV12, latV3);
|
|
237 |
if (column==0 && !(face==0 && row==0 ) ) repeatLast(attribs);
|
|
238 |
newVertex(attribs, column, row+1, level, lonV1, lonV2, latV12, latV3);
|
|
317 |
addVertex(attribs, column, row , level, lonV1, lonV2, latV12, latV3, false);
|
|
318 |
if (column==0 && !(face==0 && row==0 ) ) repeatVertex(attribs,1);
|
|
319 |
addVertex(attribs, column, row+1, level, lonV1, lonV2, latV12, latV3, false);
|
|
239 | 320 |
} |
240 | 321 |
|
241 |
newVertex(attribs, level-row, row , level, lonV1, lonV2, latV12, latV3);
|
|
242 |
if( row!=level-1 || face!=NUMFACES-1 ) repeatLast(attribs);
|
|
322 |
addVertex(attribs, level-row, row , level, lonV1, lonV2, latV12, latV3, true);
|
|
323 |
if( row!=level-1 || face!=NUMFACES-1 ) repeatVertex(attribs,1);
|
|
243 | 324 |
} |
244 | 325 |
} |
245 | 326 |
|
Also available in: Unified diff
Fix (hopefully the last!) probelm with texturing the Sphere: the seam in the back.