00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #include <cstdlib>
00051 #include <cstdio>
00052 #include <sstream>
00053
00054 #include <OSGConfig.h>
00055
00056 #include "OSGQuadTreeTerrain.h"
00057 #include "OSGImage.h"
00058 #include "OSGRenderAction.h"
00059 #include "OSGMaterial.h"
00060 #include <OSGChunkMaterial.h>
00061 #include <OSGTextureObjChunk.h>
00062 #include <OSGTextureEnvChunk.h>
00063 #include <OSGSHLParameterChunk.h>
00064 #include "OSGTypedGeoIntegralProperty.h"
00065
00066 OSG_USING_NAMESPACE
00067
00068
00069 static const Real32 MinGlobalRes = 10.0f;
00070 static const UInt32
00071 NW = 0,
00072 W = 1,
00073 SW = 2,
00074 S = 3,
00075 SE = 4,
00076 E = 5,
00077 NE = 6,
00078 N = 7,
00079 C = 8;
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 void QuadTreeTerrain::initMethod(InitPhase ePhase)
00101 {
00102 Inherited::initMethod(ePhase);
00103
00104 if(ePhase == TypeObject::SystemPost)
00105 {
00106 RenderAction::registerEnterDefault(
00107 getClassType(),
00108 reinterpret_cast<Action::Callback>(&QuadTreeTerrain::renderEnter));
00109 }
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 QuadTreeTerrain::QuadTreeTerrain(void) :
00124 Inherited()
00125 {
00126 }
00127
00128 QuadTreeTerrain::QuadTreeTerrain(const QuadTreeTerrain &source) :
00129 Inherited(source)
00130 {
00131 }
00132
00133 QuadTreeTerrain::~QuadTreeTerrain(void)
00134 {
00135 }
00136
00137 Real32 QuadTreeTerrain::getHeightDataScaled (UInt32 i) const
00138 {
00139 switch(getHeightData()->getDataType())
00140 {
00141 default:
00142 case Image::OSG_INVALID_IMAGEDATATYPE:
00143 case Image::OSG_UINT8_IMAGEDATA:
00144
00145 return
00146 ((UInt8*) getHeightData()->getData())[i] /
00147 Real32(TypeTraits<UInt8>::getMax());
00148
00149 case Image::OSG_UINT16_IMAGEDATA:
00150
00151 return
00152 ((UInt16*)getHeightData()->getData())[i] /
00153 Real32(TypeTraits<UInt16>::getMax());
00154
00155 case Image::OSG_UINT32_IMAGEDATA:
00156 return
00157 ((UInt32*)getHeightData()->getData())[i] /
00158 Real32(TypeTraits<UInt32>::getMax());
00159
00160 case Image::OSG_FLOAT16_IMAGEDATA:
00161 return ((Real16*)getHeightData()->getData())[i];
00162
00163 case Image::OSG_FLOAT32_IMAGEDATA:
00164 return ((Real32*)getHeightData()->getData())[i];
00165 };
00166 }
00167
00168 void QuadTreeTerrain::getVertex(UInt32 i, Pnt3f &point) const
00169 {
00170 GeoPnt3fPropertyPtr pos =
00171 dynamic_cast<GeoPnt3fPropertyPtr>(getHeightVertices());
00172
00173 point.setValue(pos->getField()[i]);
00174 }
00175 const Pnt3f &QuadTreeTerrain::getVertex(UInt32 i) const
00176 {
00177 GeoPnt3fPropertyPtr pos =
00178 dynamic_cast<GeoPnt3fPropertyPtr>(getHeightVertices());
00179
00180 return pos->getField()[i];
00181 }
00182 UInt32 QuadTreeTerrain::getNumVertices(void) const
00183 {
00184 GeoPnt3fPropertyPtr pos =
00185 dynamic_cast<GeoPnt3fPropertyPtr>(getHeightVertices());
00186
00187 return pos->getField().size();
00188 }
00189
00190
00191
00192
00193 static std::string _vp_program =
00194 "const vec3 planenormal = vec3 (0.0, 0.0, 1.0);\n"
00195 "const vec3 planebinormal = vec3 (0.0, 1.0, 0.0);\n"
00196 "const vec3 planetangent = vec3 (1.0, 0.0, 0.0);\n"
00197 "varying vec3 lightDir; // interpolated surface local coordinate light direction\n"
00198 "varying vec3 viewDir; // interpolated surface local coordinate view direction\n"
00199
00200 "void main(void)\n"
00201 "{\n"
00202 " // Do standard vertex stuff\n"
00203
00204 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
00205 " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
00206
00207 " // Compute the binormal\n"
00208 " vec3 n = normalize(gl_NormalMatrix * planenormal);\n"
00209 " vec3 t = normalize(gl_NormalMatrix * planetangent);\n"
00210 " vec3 b = cross(n, t);\n"
00211
00212 " // Transform light position into surface local coordinates\n"
00213 " vec3 LightPosition = gl_LightSource[0].position.xyz;\n"
00214
00215 " vec3 v;\n"
00216 " v.x = dot(LightPosition, t);\n"
00217 " v.y = dot(LightPosition, b);\n"
00218 " v.z = dot(LightPosition, n);\n"
00219
00220 " lightDir = normalize(v);\n"
00221
00222 " vec3 pos = vec3 (gl_ModelViewMatrix * gl_Vertex);\n"
00223 " v.x = dot(pos, t);\n"
00224 " v.y = dot(pos, b);\n"
00225 " v.z = dot(pos, n);\n"
00226
00227 " viewDir = normalize(v);\n"
00228 "\n"
00229 "}\n";
00230
00231
00232 static std::string _fp_program =
00233 "uniform sampler2D texSampler;\n"
00234 "uniform sampler2D nmapSampler;\n"
00235 "uniform float offsetS;\n"
00236 "uniform float offsetT;\n"
00237 "uniform float scaleS;\n"
00238 "uniform float scaleT;\n"
00239 "uniform float specularExponent;\n"
00240 "uniform float diffuseFactor;\n"
00241 "uniform float specularFactor;\n"
00242 "uniform vec3 basecolor;\n"
00243 "varying vec3 lightDir; // interpolated surface local coordinate light direction\n"
00244 "varying vec3 viewDir; // interpolated surface local coordinate view direction\n"
00245
00246 "void main (void)\n"
00247 "{\n"
00248 " vec3 norm;\n"
00249 " vec3 r;\n"
00250 " vec3 color;\n"
00251 " vec3 texcolor;\n"
00252 " float intensity;\n"
00253 " float spec;\n"
00254 " float d;\n"
00255 " // Fetch normal from normal map\n"
00256 " vec2 nmapST = vec2 (gl_TexCoord[0])*vec2(scaleS, scaleT) + vec2(offsetS, offsetT);\n"
00257 " norm = vec3(texture2D(nmapSampler, nmapST));\n"
00258 " norm = (norm - 0.5) * 2.0;\n"
00259 " // Compute diffuse reflection\n"
00260 " d = dot(lightDir, norm);\n"
00261 " intensity = max(d, 0.0) * diffuseFactor;\n"
00262 " // Compute specular reflection\n"
00263 " d = 2.0 * d;\n"
00264 " r = d * norm;\n"
00265 " r = lightDir - r;\n"
00266 " spec = pow(max(dot(r, viewDir), 0.0), specularExponent) * specularFactor;\n"
00267 " intensity += min (spec, 1.0);\n"
00268 " // mix texture color and lighting color\n"
00269 " texcolor = vec3(texture2D(texSampler, vec2 (gl_TexCoord[0])));\n"
00270 " color = clamp(texcolor * basecolor * intensity, 0.0, 1.0);\n"
00271 " // Write out final fragment color\n"
00272 " gl_FragColor = vec4 (color, 1.0);\n"
00273 "\n"
00274 "}\n";
00275
00276
00277 static SHLChunkPtr s_shlChunk;
00278
00279 SHLChunkPtr QuadTreeTerrain::createSHLChunk () const
00280 {
00281 SHLChunkPtr shl = SHLChunk::create();
00282
00283 shl->setVertexProgram (_vp_program);
00284 shl->setFragmentProgram(_fp_program);
00285
00286
00287
00288
00289 addRef(shl);
00290
00291 return shl;
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 static std::string _avp_program =
00303 "!!ARBvp1.0\n"
00304 "PARAM mv[4] = { state.matrix.modelview };\n"
00305 "PARAM mvp[4] = { state.matrix.mvp };\n"
00306 "PARAM mvinv[4] = { state.matrix.modelview.invtrans };\n"
00307 "PARAM light0 = state.light[0].position;\n"
00308 "TEMP R0;\n"
00309 "TEMP R1;\n"
00310 "TEMP R2;\n"
00311 "TEMP R3;\n"
00312 "TEMP R4;\n"
00313 "TEMP R5;\n"
00314 "MOV result.texcoord[0], vertex.texcoord[0];\n"
00315 "MUL R0, vertex.position.y, mvp[1];\n"
00316 "//MUL R3.xyz, vertex.position.y, mv[1];\n"
00317 "//MOV R2.xyz, mvinv[0];\n"
00318 "//MOV R1.xyz, mvinv[2];\n"
00319 "//DP3 R1.w, mvinv[2], R1;\n"
00320 "//DP3 R2.x, mvinv[0], R2;\n"
00321 "//MAD R1.xyz, vertex.position.x, mv[0], R3;\n"
00322 "MAD R0, vertex.position.x, mvp[0], R0;\n"
00323 "MAD R0, vertex.position.z, mvp[2], R0;\n"
00324 "//MAD R1.xyz, vertex.position.z, mv[2], R1;\n"
00325 "//RSQ R2.x, R2.x;\n"
00326 "//MAD R4.xyz, vertex.position.w, mv[3], R1;\n"
00327 "//RSQ R1.x, R1.w;\n"
00328 "//MUL R2.xyz, R2.x, mvinv[0];\n"
00329 "//MUL R1.xyz, R1.x, mvinv[2];\n"
00330 "//DP3 R5.z, R4, R1;\n"
00331 "//DP3 R5.x, R4, R2;\n"
00332 "//DP3 R1.w, R1, light0;\n"
00333 "//MUL R3.xyz, R1.zxyw, R2.yzxw;\n"
00334 "//MAD R3.xyz, R1.yzxw, R2.zxyw, -R3;\n"
00335 "//DP3 R1.x, R2, light0;\n"
00336 "//DP3 R1.y, R3, light0;\n"
00337 "//DP3 R5.y, R4, R3;\n"
00338 "//DP3 R1.z, R1.xyww, R1.xyww;\n"
00339 "//DP3 R2.x, R5, R5;\n"
00340 "//RSQ R1.z, R1.z;\n"
00341 "MAD result.position, vertex.position.w, mvp[3], R0;\n"
00342 "//RSQ R0.x, R2.x;\n"
00343 "//MUL result.texcoord[1].xyz, R1.z, R1.xyww;\n"
00344 "//MUL result.texcoord[2].xyz, R0.x, R5;\n"
00345 "END\n"
00346 "# 31 instructions, 6 R-regs\n";
00347
00348 VertexProgramChunkPtr QuadTreeTerrain::createVPChunk () const
00349 {
00350 std::istringstream vpcode(_avp_program.c_str());
00351
00352 VertexProgramChunkPtr vp = VertexProgramChunk::create();
00353 vp->read(vpcode);
00354
00355
00356
00357 addRef(vp);
00358
00359 return vp;
00360 }
00361
00362 static std::string _afp_program =
00363 "!!ARBfp1.0\n"
00364 "PARAM c[9] = { program.local[0..4], { 0.5, 2, 0, 1 }, program.local[6..8] };\n"
00365 "TEMP R0;\n"
00366 "TEMP R1;\n"
00367 "MOV R0.w, c[4].x;\n"
00368 "MOV R0.z, c[3].x;\n"
00369 "MOV R0.x, c[1];\n"
00370 "MOV R0.y, c[2].x;\n"
00371 "MAD R0.xy, fragment.texcoord[0], R0, R0.zwzw;\n"
00372 "TEX R0.xyz, R0, texture[1], 2D;\n"
00373 "ADD R0.xyz, R0, -c[5].x;\n"
00374 "MUL R1.xyz, R0, c[5].y;\n"
00375 "DP3 R0.x, fragment.texcoord[1], R1;\n"
00376 "MUL R1.xyz, R0.x, R1;\n"
00377 "MAD R1.xyz, -R1, c[5].y, fragment.texcoord[1];\n"
00378 "DP3 R0.y, R1, fragment.texcoord[2];\n"
00379 "MAX R0.y, R0, c[5].z;\n"
00380 "POW R0.y, R0.y, c[7].x;\n"
00381 "MUL R0.y, R0, c[8].x;\n"
00382 "MIN R1.x, R0.y, c[5].w;\n"
00383 "MAX R0.w, R0.x, c[5].z;\n"
00384 "TEX R0.xyz, fragment.texcoord[0], texture[0], 2D;\n"
00385 "MAD R0.w, R0, c[6].x, R1.x;\n"
00386 "MUL R0.xyz, R0, c[0];\n"
00387 "MUL_SAT result.color.xyz, R0, R0.w;\n"
00388 "MOV result.color.w, c[5];\n"
00389 "MOV result.color, c[5];\n"
00390 "END\n"
00391 "# 22 instructions, 2 R-regs\n";
00392
00393 FragmentProgramChunkPtr QuadTreeTerrain::createFPChunk () const
00394 {
00395 std::istringstream fpcode(_afp_program.c_str());
00396
00397 FragmentProgramChunkPtr fp = FragmentProgramChunk::create();
00398
00399 fp->read(fpcode);
00400
00401 fp->addParameter("offsetS",
00402 3,
00403 Vec4f(1.0f/getTexSpacing(),
00404 1.0f/getTexSpacing(),
00405 1.0f/getTexSpacing(),
00406 1.0f/getTexSpacing()));
00407
00408 fp->addParameter("scaleS", 1,
00409 Vec4f(-getOriginTexX()/getTexSpacing(),
00410 -getOriginTexX()/getTexSpacing(),
00411 -getOriginTexX()/getTexSpacing(),
00412 -getOriginTexX()/getTexSpacing()));
00413
00414 if(getTexYSpacing() != 1.0f)
00415 {
00416 fp->addParameter("offsetT",
00417 4,
00418 Vec4f(-getOriginTexY()/getTexYSpacing(),
00419 -getOriginTexY()/getTexYSpacing(),
00420 -getOriginTexY()/getTexYSpacing(),
00421 -getOriginTexY()/getTexYSpacing()));
00422
00423 fp->addParameter("scaleT",
00424 2,
00425 Vec4f(1.0f/getTexYSpacing(),
00426 1.0f/getTexYSpacing(),
00427 1.0f/getTexYSpacing(),
00428 1.0f/getTexYSpacing()));
00429 }
00430 else
00431 {
00432 fp->addParameter("offsetT",
00433 4, Vec4f(-getOriginTexY()/getTexSpacing(),
00434 -getOriginTexY()/getTexSpacing(),
00435 -getOriginTexY()/getTexSpacing(),
00436 -getOriginTexY()/getTexSpacing()));
00437
00438 fp->addParameter("scaleT",
00439 2,
00440 Vec4f(1.0f/getTexSpacing(),
00441 1.0f/getTexSpacing(),
00442 1.0f/getTexSpacing(),
00443 1.0f/getTexSpacing()));
00444 }
00445
00446 fp->addParameter("diffuseFactor", 6, Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
00447 fp->addParameter("specularExponent", 7, Vec4f(6.0f, 6.0f, 6.0f, 6.0f));
00448 fp->addParameter("specularFactor", 8, Vec4f(0.2f, 0.2f, 0.2f, 0.2f));
00449 fp->addParameter("basecolor", 0, Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
00450
00451 addRef(fp);
00452
00453 return fp;
00454 }
00455
00456 void QuadTreeTerrain::addMaterialChunks(void) const
00457 {
00458 #if 1
00459 #ifndef WITH_SINGLE_SHLCHUNK
00460
00461 SHLParameterChunkPtr shlp = SHLParameterChunk::create();
00462
00463 shlp->setSHLChunk(s_shlChunk);
00464 shlp->setUniformParameter("texSampler", 0);
00465 shlp->setUniformParameter("nmapSampler", 1);
00466
00467 shlp->setUniformParameter("offsetS", -getOriginTexX()/getTexSpacing());
00468 shlp->setUniformParameter("scaleS", 1.0f/getTexSpacing());
00469
00470 if(getTexYSpacing() != 1.0f)
00471 {
00472 shlp->setUniformParameter("offsetT", -getOriginTexY()/getTexYSpacing());
00473 shlp->setUniformParameter("scaleT", 1.0f/getTexYSpacing());
00474 }
00475 else
00476 {
00477 shlp->setUniformParameter("offsetT", -getOriginTexY()/getTexSpacing());
00478 shlp->setUniformParameter("scaleT", 1.0f/getTexSpacing());
00479 }
00480
00481 shlp->setUniformParameter("diffuseFactor", 1.0f);
00482 shlp->setUniformParameter("specularFactor", 0.2f);
00483 shlp->setUniformParameter("specularExponent", 6.0f);
00484 shlp->setUniformParameter("basecolor", Vec3f(1.0, 1.0, 1.0));
00485
00486 #else
00487
00488 SHLChunkPtr shl = SHLChunk::create();
00489
00490 shl->setVertexProgram (_vp_program);
00491 shl->setFragmentProgram(_fp_program);
00492 shl->setUniformParameter("texSampler", 0);
00493 shl->setUniformParameter("nmapSampler", 1);
00494
00495
00496 shl->setUniformParameter("offsetS", -getOriginTexX()/getTexSpacing());
00497 shl->setUniformParameter("scaleS", 1.0f/getTexSpacing());
00498
00499 if(getTexYSpacing() != 1.0f)
00500 {
00501 shl->setUniformParameter("offsetT", -getOriginTexY()/getTexYSpacing());
00502 shl->setUniformParameter("scaleT", 1.0f/getTexYSpacing());
00503 }
00504 else
00505 {
00506 shl->setUniformParameter("offsetT", -getOriginTexY()/getTexSpacing());
00507 shl->setUniformParameter("scaleT", 1.0f/getTexSpacing());
00508 }
00509
00510 shl->setUniformParameter("diffuseFactor", 1.0f);
00511 shl->setUniformParameter("specularFactor", 0.2f);
00512 shl->setUniformParameter("specularExponent", 6.0f);
00513 shl->setUniformParameter("basecolor", Vec3f(1.0, 1.0, 1.0));
00514
00515 #endif
00516
00517 #else
00518 VertexProgramChunkPtr vp = createVPChunk();
00519 FragmentProgramChunkPtr fp = createFPChunk();
00520 #endif
00521
00522 ImagePtr normal_map_img = createNormalMap();
00523 TextureObjChunkPtr tex_normal_map = TextureObjChunk::create();
00524
00525 tex_normal_map->setImage(normal_map_img);
00526 tex_normal_map->setMinFilter(GL_LINEAR);
00527 tex_normal_map->setMagFilter(GL_LINEAR);
00528 tex_normal_map->setWrapS(GL_CLAMP);
00529 tex_normal_map->setWrapT(GL_CLAMP);
00530
00531
00532 ChunkMaterialPtr mat = dynamic_cast<ChunkMaterialPtr>(getMaterial());
00533
00534 #if 1
00535
00536 #ifndef WITH_SINGLE_SHLCHUNK
00537 StateChunkPtr oldSHL = mat->find(SHLChunk::getClassType());
00538
00539 if(oldSHL == NullFC)
00540 {
00541 mat->addChunk(s_shlChunk);
00542 }
00543
00544 StateChunkPtr oldSHLP = mat->find(SHLParameterChunk::getClassType());
00545
00546 if(oldSHLP != NullFC)
00547 {
00548 mat->subChunk(oldSHLP);
00549 }
00550
00551 mat->addChunk(shlp);
00552 #else
00553 StateChunkPtr oldSHL = mat->find(SHLChunk::getClassType());
00554
00555 if(oldSHL != NullFC)
00556 {
00557 mat->subChunk(oldSHL);
00558 }
00559
00560 mat->addChunk(shl);
00561 #endif
00562
00563 #else
00564 StateChunkPtr oldVP = mat->find(VertexProgramChunk::getClassType());
00565
00566 if(oldVP != NullFC)
00567 {
00568 mat->subChunk(oldVP);
00569 }
00570
00571 mat->addChunk(vp);
00572
00573 StateChunkPtr oldFP = mat->find(FragmentProgramChunk::getClassType());
00574 if(oldFP != NullFC)
00575 {
00576 mat->subChunk(oldFP);
00577 }
00578
00579 mat->addChunk(fp);
00580 #endif
00581
00582 StateChunkPtr oldTEX = mat->find(TextureObjChunk::getClassType(), 1);
00583
00584 if(oldTEX != NullFC)
00585 {
00586 mat->subChunk(oldTEX);
00587 }
00588
00589 mat->addChunk(tex_normal_map, 1);
00590 }
00591
00592 ImagePtr QuadTreeTerrain::createNormalMap () const
00593 {
00594 ImagePtr out = Image::create();
00595
00596 out->set(Image::OSG_RGB_PF, getWidth()-1, getWidth()-1, 1,
00597 1, 1, 0.0f, NULL, Image::OSG_UINT8_IMAGEDATA);
00598
00599 UInt8* outData = (UInt8*) out->editData();
00600
00601 GeoPnt3fPropertyPtr pos = dynamic_cast<GeoPnt3fPropertyPtr>(getPositions());
00602
00603 const Real32 maxData = 0.5f*TypeTraits<UInt8>::getMax();
00604
00605 UInt32 vnum, inum;
00606
00607 vnum = inum = 0;
00608
00609 for(UInt32 z = 0; z < getWidth(); z++)
00610 {
00611 for (UInt32 x = 0; x < getWidth(); x++, vnum++)
00612 {
00613 Vec3f tanx, tany, norm;
00614
00615 if(x == 0 || z == 0)
00616 {
00617 continue;
00618 }
00619
00620
00621 tanx = pos->getValue(vnum) - pos->getValue(vnum-1);
00622
00623
00624
00625
00626 tany = pos->getValue(vnum) - pos->getValue(vnum-getWidth());
00627
00628
00629
00630
00631 norm.setValue(tany.cross(tanx)); norm.normalize();
00632 outData[inum] = UInt8(maxData*(norm[0]+1.0f));
00633 outData[inum+1] = UInt8(maxData*(norm[1]+1.0f));
00634 outData[inum+2] = UInt8(maxData*(norm[2]+1.0f));
00635 inum += 3;
00636 }
00637 }
00638 return out;
00639 }
00640
00641
00642 void QuadTreeTerrain::calcD2ErrorMatrix()
00643 {
00644
00645 calcD2ErrorMatrixRec(getWidth() / 2, getWidth() / 2, getWidth(), 1);
00646
00647
00648 propagateD2Errors();
00649 }
00650
00651 void QuadTreeTerrain::calcD2ErrorMatrixRec(Int32 centerX,
00652 Int32 centerZ,
00653 Int32 width,
00654 Int32 level)
00655 {
00656 if(level <= getLevel())
00657 {
00658 Int32 w2 = width / 2;
00659 Int32 w4 = width / 4;
00660
00661
00662 Int32 nodeIndex = centerZ * getWidth() + centerX;
00663
00664 if(level == getLevel()-getBorderDetail() &&
00665 ( centerX <= w2 ||
00666 (getWidth()-centerX) <= w2+1 ||
00667 centerZ <= w2 ||
00668 (getWidth()-centerZ) <= w2+1 ) )
00669 {
00670
00671 editHeightError(nodeIndex) =
00672 (getBoundMax()[1]-getBoundMin()[1]) /
00673 ((Real32) width * getVertexSpacing());
00674 }
00675 else if(level > getLevel()-getBorderDetail() &&
00676 ( centerX <= w2 ||
00677 (getWidth()-centerX) <= w2+1 ||
00678 centerZ <= w2 ||
00679 (getWidth()-centerZ) <= w2+1 ) )
00680 {
00681 editHeightError(nodeIndex) = 0.0f;
00682 }
00683 else
00684 {
00685 editHeightError(nodeIndex) = calcD2Value(centerX, centerZ, width);
00686 }
00687
00688
00689
00690 calcD2ErrorMatrixRec(centerX - w4, centerZ + w4, w2, level + 1);
00691
00692 calcD2ErrorMatrixRec(centerX + w4, centerZ + w4, w2, level + 1);
00693
00694 calcD2ErrorMatrixRec(centerX + w4, centerZ - w4, w2, level + 1);
00695
00696 calcD2ErrorMatrixRec(centerX - w4, centerZ - w4, w2, level + 1);
00697 }
00698 }
00699
00700 Real32 QuadTreeTerrain::calcD2Value (Int32 centerX,
00701 Int32 centerZ,
00702 Int32 width)
00703 {
00704
00705 Int32 rx = width / 2;
00706 Int32 rz = rx * getWidth();
00707
00708 Int32 c = centerZ * getWidth() + centerX;
00709 Int32 n = c - rz;
00710 Int32 w = c - rx;
00711 Int32 s = c + rz;
00712 Int32 e = c + rx;
00713 Int32 nw = n - rx;
00714 Int32 sw = s - rx;
00715 Int32 se = s + rx;
00716 Int32 ne = n + rx;
00717
00718
00719 const GeoPnt3fProperty::StoredFieldType &v =
00720 dynamic_cast<GeoPnt3fPropertyPtr>(getHeightVertices())->getField();
00721
00722
00723 Real32 nErr = osgAbs( v[n][1] - (v[nw][1] + v[ne][1]) / 2.0f);
00724 Real32 eErr = osgAbs( v[e][1] - (v[ne][1] + v[se][1]) / 2.0f);
00725 Real32 sErr = osgAbs( v[s][1] - (v[se][1] + v[sw][1]) / 2.0f);
00726 Real32 wErr = osgAbs( v[w][1] - (v[sw][1] + v[nw][1]) / 2.0f);
00727
00728
00729
00730
00731 Real32 d1Err = osgAbs( v[c][1] - (v[nw][1] + v[se][1]) / 2.0f);
00732 Real32 d2Err = osgAbs( v[c][1] - (v[ne][1] + v[sw][1]) / 2.0f);
00733
00734
00735
00736 Real32 maxErr = osgMax(osgMax(nErr, eErr),
00737 osgMax(osgMax(sErr, wErr), osgMax(d1Err, d2Err)));
00738
00739 return (maxErr / ((Real32) width * getVertexSpacing()));
00740 }
00741
00742
00743
00744 void QuadTreeTerrain::propagateD2Errors()
00745 {
00746 const Real32 D2K = MinGlobalRes / (2.0f * (MinGlobalRes - 1.0f));
00747
00748
00749
00750
00751 Int32 steps = getWidth() / 2;
00752 Int32 width = 2;
00753
00754 Int32 centerX, centerZ;
00755
00756 Int32 w2;
00757 Int32 p1, p2, p3;
00758 Int32
00759 p1x = 0, p1z = 0,
00760 p2x = 0, p2z = 0,
00761 p3x = 0, p3z = 0;
00762
00763 MFReal32 &em = editHeightError();
00764
00765
00766
00767 while(steps > 1)
00768 {
00769 w2 = width / 2;
00770 centerX = w2;
00771
00772 for(Int32 i = 0; i < steps; i++)
00773 {
00774 centerZ = w2;
00775 for(Int32 j = 0; j < steps; j++)
00776 {
00777
00778 switch ((centerX/width)%2 + 2*((centerZ/width)%2))
00779 {
00780 case 0:
00781 p1x = centerX+w2;
00782 p1z = centerZ+w2;
00783 p2x = centerX-width-w2;
00784 p2z = centerZ+w2;
00785 p3x = centerX+w2;
00786 p3z = centerZ-width-w2;
00787 break;
00788 case 1:
00789 p1x = centerX-w2;
00790 p1z = centerZ+w2;
00791 p2x = centerX-w2;
00792 p2z = centerZ-width-w2;
00793 p3x = centerX+width+w2;
00794 p3z = centerZ+w2;
00795 break;
00796 case 2:
00797 p1x = centerX+w2;
00798 p1z = centerZ-w2;
00799 p2x = centerX+w2;
00800 p2z = centerZ+width+w2;
00801 p3x = centerX-width-w2;
00802 p3z = centerZ-w2;
00803 break;
00804 case 3:
00805 p1x = centerX-w2;
00806 p1z = centerZ-w2;
00807 p2x = centerX+width+w2;
00808 p2z = centerZ-w2;
00809 p3x = centerX-w2;
00810 p3z = centerZ+width+w2;
00811 break;
00812 }
00813
00814
00815
00816 Real32 d2K_EMthis = D2K * em[centerZ * getWidth() + centerX];
00817
00818
00819
00820 p1 = p1z * getWidth() + p1x;
00821 em[p1] = osgMax(em[p1], d2K_EMthis);
00822
00823
00824
00825 if(p2x >= 0 &&
00826 p2x < getWidth() &&
00827 p2z >= 0 &&
00828 p2z < getWidth() )
00829 {
00830 p2 = p2z * getWidth() + p2x;
00831 em[p2] = osgMax(em[p2], d2K_EMthis);
00832 }
00833
00834 if(p3x >= 0 &&
00835 p3x < getWidth() &&
00836 p3z >= 0 &&
00837 p3z < getWidth() )
00838 {
00839 p3 = p3z * getWidth() + p3x;
00840 em[p3] = osgMax(em[p3], d2K_EMthis);
00841 }
00842
00843 centerZ += width;
00844 }
00845 centerX += width;
00846 }
00847 width *= 2;
00848 steps /= 2;
00849 }
00850 }
00851
00852 Real32 QuadTreeTerrain::calcSubDiv(Int32 nodeIndex, Int32 width)
00853 {
00854
00855
00856 const Pnt3f& v = getVertex(nodeIndex);
00857
00858 Real32 eyeDist =
00859 osgAbs(v[0] - getEyePoint()[0]) +
00860 osgAbs(getEyeHeight()) +
00861 osgAbs(v[2] - getEyePoint()[2]);
00862
00863
00864 return
00865 eyeDist / ((width * getVertexSpacing()) * MinGlobalRes *
00866 osgMax(getDetail() * getHeightError(nodeIndex), 1.0f));
00867 }
00868
00869 void QuadTreeTerrain::triangulateMeshRec(const FrustumVolume &frustum,
00870 Int32 c,
00871 Int32 width,
00872 Int32 level)
00873 {
00874 if(level > getLevel())
00875 {
00876 return;
00877 }
00878
00879
00880 #if 1
00881 if(level <= getLevel() - 2)
00882 {
00883 Pnt3f point;
00884 getVertex(c, point);
00885
00886 SphereVolume current(point,
00887 (0.5f*width) * getVertexSpacing() * 15.0f);
00888
00889 if(!OSG::intersect(frustum, current))
00890 {
00891 return;
00892 }
00893 }
00894 #endif
00895
00896
00897
00898 Real32 subDiv = calcSubDiv(c, width);
00899
00900 Int32 w2 = width / 2;
00901 Int32 w4 = width / 4;
00902 Int32 r = w4 * getWidth();
00903
00904 Int32 nw = c - r - w4;
00905 Int32 ne = c - r + w4;
00906 Int32 sw = c + r - w4;
00907 Int32 se = c + r + w4;
00908
00909 if(subDiv >= 1.0f)
00910 {
00911 deleteNode(c, width);
00912 return;
00913 }
00914 else
00915 {
00916 editHeightQuad(c) = calcBlend(subDiv);
00917
00918 triangulateMeshRec(frustum, nw, w2, level+1);
00919 triangulateMeshRec(frustum, ne, w2, level+1);
00920 triangulateMeshRec(frustum, sw, w2, level+1);
00921 triangulateMeshRec(frustum, se, w2, level+1);
00922
00923 return;
00924 }
00925 }
00926
00927
00928 bool QuadTreeTerrain::renderMeshRec(const FrustumVolume &frustum,
00929 Int32 x,
00930 Int32 z,
00931 Int32 width,
00932 Int32 level,
00933 Int32 dirToFather,
00934 Real32 rhNW,
00935 Real32 rhNE,
00936 Real32 rhSW,
00937 Real32 rhSE )
00938 {
00939
00940 Int32 c = z * getWidth() + x;
00941
00942 if(getHeightQuad(c) == TypeTraits<Real32>::getMax())
00943 {
00944 return true;
00945 }
00946
00947 Int32 w2 = width / 2;
00948 Int32 w4 = width / 4;
00949
00950
00951
00952
00953 #if 1
00954 if(level <= getLevel()-2)
00955 {
00956 Pnt3f point;
00957 getVertex(c, point);
00958
00959 SphereVolume current;
00960 current.setCenter(point);
00961 current.setRadius((Real32) w2 * (Real32) getVertexSpacing() * 5.0f);
00962
00963 if(!OSG::intersect(frustum, current))
00964 {
00965 return false;
00966 }
00967 }
00968 #endif
00969
00970
00971
00972 Int32 rx = width / 2;
00973 Int32 rz = rx * getWidth();
00974
00975 Int32 n = c - rz;
00976 Int32 w = c - rx;
00977 Int32 s = c + rz;
00978 Int32 e = c + rx;
00979 Int32 nw = n - rx;
00980 Int32 sw = s - rx;
00981 Int32 se = s + rx;
00982 Int32 ne = n + rx;
00983
00984
00985
00986 Real32 blend = getHeightQuad(c);
00987
00988 Real32 hC = getHeight(c,
00989 width,
00990 dirToFather,
00991 C,
00992 blend,
00993 rhNW,
00994 rhNE,
00995 rhSW,
00996 rhSE);
00997
00998 Real32 hN = getHeight(n,
00999 width,
01000 dirToFather,
01001 N,
01002 blend,
01003 rhNW,
01004 rhNE,
01005 rhSW,
01006 rhSE);
01007
01008 Real32 hS = getHeight(s,
01009 width,
01010 dirToFather,
01011 S,
01012 blend,
01013 rhNW,
01014 rhNE,
01015 rhSW,
01016 rhSE);
01017
01018 Real32 hW = getHeight(w,
01019 width,
01020 dirToFather,
01021 W,
01022 blend,
01023 rhNW,
01024 rhNE,
01025 rhSW,
01026 rhSE);
01027 Real32 hE = getHeight(e,
01028 width,
01029 dirToFather,
01030 E,
01031 blend,
01032 rhNW,
01033 rhNE,
01034 rhSW,
01035 rhSE);
01036
01037
01038
01039 bool corners[] = { true, true, true, true, true, true, true, true };
01040 bool isLeaf = false;
01041
01042 if(level < getLevel())
01043 {
01044 corners[NW] = renderMeshRec(frustum,
01045 x-w4,
01046 z-w4,
01047 w2,
01048 level+1,
01049 SE,
01050 rhNW,
01051 hN,
01052 hW,
01053 hC );
01054
01055 corners[NE] = renderMeshRec(frustum,
01056 x+w4,
01057 z-w4,
01058 w2,
01059 level+1,
01060 SW,
01061 hN,
01062 rhNE,
01063 hC,
01064 hE );
01065
01066 corners[SW] = renderMeshRec(frustum,
01067 x-w4,
01068 z+w4,
01069 w2,
01070 level+1,
01071 NE,
01072 hW,
01073 hC,
01074 rhSW,
01075 hS );
01076
01077 corners[SE] = renderMeshRec(frustum,
01078 x+w4,
01079 z+w4,
01080 w2,
01081 level+1,
01082 NW,
01083 hC,
01084 hE,
01085 hS,
01086 rhSE);
01087 }
01088 else
01089 {
01090 isLeaf = true;
01091 }
01092
01093 if(corners[NW] || corners[SW] || corners[SE] || corners[NE])
01094 {
0109