📄 202f0d37e0c5001d1cd1e38dc83e3a87
字号:
p3x = centerX-width-w2;
p3z = centerZ-w2;
break;
case 3: p1x = centerX-w2;
p1z = centerZ-w2;
p2x = centerX+width+w2;
p2z = centerZ-w2;
p3x = centerX-w2;
p3z = centerZ+width+w2;
break;
}
//--- propagate to 3 parents -----------------------------
float d2K_EMthis = D2K * em[centerZ * Width + centerX];
//--- to real father -------------------------------------
p1 = p1z * Width + p1x;
em[p1] = Math.max(em[p1], d2K_EMthis);
//--- other 2 "parents" ----------------------------------
if (p2x >= 0 && p2x < Width &&
p2z >= 0 && p2z < Width ) {
p2 = p2z * Width + p2x;
em[p2] = Math.max(em[p2], d2K_EMthis);
}
if (p3x >= 0 && p3x < Width &&
p3z >= 0 && p3z < Width ) {
p3 = p3z * Width + p3x;
em[p3] = Math.max(em[p3], d2K_EMthis);
}
centerZ += width; // advance zPos
}
centerX += width; // advance xPos
}
width *= 2;
steps /= 2;
}
}
//=== Triangulation ========================================================================================
private void triangulateMeshRec(int c, int width, int level) {
if (level > Level) { return; }
//--- check view frustum --------------------------------------------------------------
if (level <= Level - 2) {
getVertex(c, Point);
BoundsSphere.setCenter(Point);
BoundsSphere.setRadius((double)(width/2) * (double)VertexSpacing * 15f);
if (!ViewFrustum.intersect(BoundsSphere)) { return; }
}
//--- go on ---------------------------------------------------------------------------
float subDiv = calcSubDiv(c, width);
int w2 = width / 2;
int w4 = width / 4;
int r = w4 * Width;
int nw = c - r - w4;
int ne = c - r + w4;
int sw = c + r - w4;
int se = c + r + w4;
if (subDiv >= 1.0f) {
//--- NOT to be drawn --------------------
deleteNode(c, width);
return;
}
else {
//--- leaf or parent? ---------------------
QuadMatrix[c] = calcBlend(subDiv);
triangulateMeshRec(nw, w2, level+1);
triangulateMeshRec(ne, w2, level+1);
triangulateMeshRec(sw, w2, level+1);
triangulateMeshRec(se, w2, level+1);
return;
}
}
private float calcSubDiv(int nodeIndex, int width) {
//--- calculate the eye distance to each node, using L1-Norm --------------
float eyeDist = Math.abs(Vertices[nodeIndex*3 ] - EyePos.x) +
Math.abs(HeightAboveGround) +
Math.abs(Vertices[nodeIndex*3 + 2] - EyePos.z);
//--- calc subdiv value ---------------------------------------------------
return eyeDist / ((width * VertexSpacing) * MinGlobalRes *
Math.max(DesiredRes * ErrorMatrix[nodeIndex], 1.0f));
}
private float calcBlend(float subDiv) {
//--- calc blend factor ----------------------
float blend = 2 * (1.0f - subDiv);
if (blend > 1.0f) { blend = 1.0f; }
return blend;
}
private void deleteNode(int index, int width) {
//--- init vars ---------------------------------------
width /= 2;
int rx = width / 2;
int rz = rx * Width;
//--- delete this node and descend --------------------
QuadMatrix[index] = MAX_F; // C (this)
if (width > 2) {
deleteNode(index - rz - rx, width); // NW
deleteNode(index - rz + rx, width); // NE
deleteNode(index + rz - rx, width); // SW
deleteNode(index + rz + rx, width); // SE
}
}
private float getHeightAboveGround() {
//--- init needed vars --------------------------------------------------
float ex = EyePos.x;
float ez = EyePos.z;
float ulx = Vertices[0]; // upper left x coord.
float ulz = Vertices[2]; // upper left z coord.
float lrx = Vertices[Vertices.length - 3]; // lower right...
float lrz = Vertices[Vertices.length - 1]; // ...
//--- determine height above ground -------------------------------------
if (ex < ulx) { ex = ulx; }
else if (ex > lrx) { ex = lrx; }
if (ez < ulz) { ez = ulz; }
else if (ez > lrz) { ez = lrz; }
int x = (int) ((ex - ulx) / VertexSpacing);
int z = (int) ((ez - ulz) / VertexSpacing);
if (x > Width - 1) { x = Width - 1; }
if (z > Width - 1) { z = Width - 1; }
float ground = Vertices[((z * Width) + x) * 3 + 1];
return EyePos.y - ground;
}
//=== Render Terrain-Mesh ==================================================================================
private boolean renderMeshRec(int x, int z, int width, int level, int dirToFather,
float rhNW, float rhNE, float rhSW, float rhSE) {
// returns true if caller has to draw this corner
int c = z * Width + x; // center
if (QuadMatrix[c] == MAX_F) { return true; } // STOP RECURSION
int w2 = width / 2;
int w4 = width / 4;
//--- check view frustum ---------------------------------------------------------------------------
if (level <= Level-2) {
getVertex(c, Point);
BoundsSphere.setCenter(Point);
BoundsSphere.setRadius((double) w2 * (double) VertexSpacing * 5f);
if (!ViewFrustum.intersect(BoundsSphere)) { return false; }
}
//--- init necessary vars --------------------------------------------------------------------------
int rx = width / 2; // radius offset in x direction
int rz = rx * Width; // radius offset in z direction
int n = c - rz; // northern vertex
int w = c - rx; // western
int s = c + rz; // southern
int e = c + rx; // eastern
int nw = n - rx;
int sw = s - rx;
int se = s + rx;
int ne = n + rx;
//--- get all 9 heights ----------------------------------------------------------------------------
float blend = QuadMatrix[c];
float hC = getHeight(c, width, dirToFather, C, blend, rhNW, rhNE, rhSW, rhSE);
float hN = getHeight(n, width, dirToFather, N, blend, rhNW, rhNE, rhSW, rhSE);
float hS = getHeight(s, width, dirToFather, S, blend, rhNW, rhNE, rhSW, rhSE);
float hW = getHeight(w, width, dirToFather, W, blend, rhNW, rhNE, rhSW, rhSE);
float hE = getHeight(e, width, dirToFather, E, blend, rhNW, rhNE, rhSW, rhSE);
//--- check if node has children -------------------------------------------------------------------
boolean[] corners = { true, true, true, true, true, true, true, true };
boolean isLeaf = false;
if (level < Level) {
corners[NW] = renderMeshRec(x-w4, z-w4, w2, level+1, SE, rhNW, hN, hW, hC );
corners[NE] = renderMeshRec(x+w4, z-w4, w2, level+1, SW, hN, rhNE, hC, hE );
corners[SW] = renderMeshRec(x-w4, z+w4, w2, level+1, NE, hW, hC, rhSW, hS );
corners[SE] = renderMeshRec(x+w4, z+w4, w2, level+1, NW, hC, hE, hS, rhSE);
}
else {
isLeaf = true;
}
if (corners[NW] || corners[SW] || corners[SE] || corners[NE]) {
if (corners[NW] && corners[SW] && corners[SE] && corners[NE]) { isLeaf = true; }
//--- determine 'corners' to be drawn ------------------------------------------------------
float[] qm = QuadMatrix; // shortcut
// check array bounds and whether the neighbor exists
if ((z-width >= 0 ) && (qm[c-(Width*width)] == MAX_F)) { corners[N] = false; }
if ((x+width < Width) && (qm[c+width] == MAX_F)) { corners[E] = false; }
if ((z+width < Width) && (qm[c+(Width*width)] == MAX_F)) { corners[S] = false; }
if ((x-width >= 0 ) && (qm[c-width] == MAX_F)) { corners[W] = false; }
createFanAround(x, z, width, corners, isLeaf, hC, hN, hS, hW, hE, rhNW, rhNE, rhSW, rhSE);
}
return false;
}
private void createFanAround(int x, int z, int width, boolean[] corners, boolean isLeaf,
float hC, float hN, float hS, float hW, float hE,
float hNW, float hNE, float hSW, float hSE) {
//--- init necessary vars -------------------------------------------------
int rx = width / 2; // radius offset in x direction
int rz = rx * Width; // radius offset in z direction
int c = z * Width + x; // center vertex
int n = c - rz; // northern vertex
int w = c - rx; // western
int s = c + rz; // southern
int e = c + rx; // eastern
int nw = n - rx;
int sw = s - rx;
int se = s + rx;
int ne = n + rx;
//--- resize geometry array size (maybe) ----------------------------------
if ((VNum + 24) * FLOATS_PER_VERTEX > Interleaved.length) {
float[] temp = new float[Interleaved.length * 2];
System.arraycopy(Interleaved, 0, temp, 0, Interleaved.length);
Interleaved = temp;
CreateNewTA = true;
}
//--- pre-check corners array ---------------------------------------------
if (!isLeaf) {
if (!corners[NW] && !corners[SW]) { corners[W] = false; }
if (!corners[SW] && !corners[SE]) { corners[S] = false; }
if (!corners[SE] && !corners[NE]) { corners[E] = false; }
if (!corners[NE] && !corners[NW]) { corners[N] = false; }
}
//--- check western quarter -----------------------------------------------
if (corners[NW]) {
setInterleaved(nw, hNW);
if (corners[W]) {
setInterleaved(w, hW);
if (corners[SW]) {
setInterleaved(c, hC );
setInterleaved(w, hW );
setInterleaved(sw, hSW);
}
}
else {
if (corners[SW]) { setInterleaved(sw, hSW); }
else { setInterleaved(w, hW ); }
}
setInterleaved(c, hC);
}
else if (corners[W] || corners[SW]) {
setInterleaved(w, hW );
setInterleaved(sw, hSW);
setInterleaved(c, hC );
}
//--- check southern quarter ----------------------------------------------
if (corners[SW]) {
setInterleaved(sw, hSW);
if (corners[S]) {
setInterleaved(s, hS);
if (corners[SE]) {
setInterleaved(c, hC );
setInterleaved(s, hS );
setInterleaved(se, hSE);
}
}
else {
if (corners[SE]) { setInterleaved(se, hSE); }
else { setInterleaved(s, hS ); }
}
setInterleaved(c, hC);
}
else if (corners[S] || corners[SE]) {
setInterleaved(s, hS );
setInterleaved(se, hSE);
setInterleaved(c, hC );
}
//--- check eastern quarter -----------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -