|
@@ -0,0 +1,477 @@
|
|
|
+package h3d.scene.pbr.terrain;
|
|
|
+
|
|
|
+class Tile extends h3d.scene.Mesh {
|
|
|
+
|
|
|
+ public var tileX (default, null) : Int;
|
|
|
+ public var tileY (default, null) : Int;
|
|
|
+ public var heightMap(default, set) : h3d.mat.Texture;
|
|
|
+ public var surfaceIndexMap : h3d.mat.Texture;
|
|
|
+ public var surfaceCount = 0;
|
|
|
+ public var surfaceWeights : Array<h3d.mat.Texture> = [];
|
|
|
+ var shader : h3d.shader.pbr.Terrain;
|
|
|
+ public var surfaceWeightArray (default, null) : h3d.mat.TextureArray;
|
|
|
+ public var grid (default, null) : h3d.prim.Grid;
|
|
|
+ public var needAlloc = false;
|
|
|
+ var heightmapPixels : hxd.Pixels.PixelsFloat;
|
|
|
+ public var needNewPixelCapture = false;
|
|
|
+
|
|
|
+ public function new(x : Int, y : Int , ?parent){
|
|
|
+ super(null, null, parent);
|
|
|
+ this.tileX = x;
|
|
|
+ this.tileY = y;
|
|
|
+ shader = new h3d.shader.pbr.Terrain();
|
|
|
+ material.mainPass.addShader(shader);
|
|
|
+ material.mainPass.culling = None;
|
|
|
+ this.x = x * getTerrain().tileSize;
|
|
|
+ this.y = y * getTerrain().tileSize;
|
|
|
+ this.surfaceCount = getTerrain().surfaces.length;
|
|
|
+ refreshMesh();
|
|
|
+ }
|
|
|
+
|
|
|
+ function set_heightMap(v){
|
|
|
+ shader.heightMap = v;
|
|
|
+ return heightMap = v;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getHeightPixels(){
|
|
|
+ if(needNewPixelCapture || heightmapPixels == null)
|
|
|
+ heightmapPixels = heightMap.capturePixels();
|
|
|
+ needNewPixelCapture = false;
|
|
|
+ return heightmapPixels;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function refreshMesh(){
|
|
|
+ if(grid == null || grid.width != getTerrain().cellCount || grid.height != getTerrain().cellCount || grid.cellWidth != getTerrain().cellSize || grid.cellHeight != getTerrain().cellSize){
|
|
|
+ if(grid != null) grid.dispose();
|
|
|
+ grid = new h3d.prim.Grid( getTerrain().cellCount, getTerrain().cellCount, getTerrain().cellSize, getTerrain().cellSize);
|
|
|
+ primitive = grid;
|
|
|
+ grid.addUVs();
|
|
|
+ }
|
|
|
+ computeNormals();
|
|
|
+ }
|
|
|
+
|
|
|
+ public function blendEdges(?propagate = false){
|
|
|
+ computeEdgesHeight();
|
|
|
+ computeEdgesNormals();
|
|
|
+ }
|
|
|
+
|
|
|
+ public function refresh(){
|
|
|
+ if(heightMap == null || heightMap.width != getTerrain().heightMapResolution + 1){
|
|
|
+ var oldHeightMap = heightMap;
|
|
|
+ heightMap = new h3d.mat.Texture(getTerrain().heightMapResolution + 1, getTerrain().heightMapResolution + 1, [Target], RGBA32F );
|
|
|
+ heightMap.wrap = Clamp;
|
|
|
+ heightMap.filter = Linear;
|
|
|
+ if(oldHeightMap != null){
|
|
|
+ getTerrain().copyPass.apply(oldHeightMap, heightMap);
|
|
|
+ oldHeightMap.dispose();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(surfaceIndexMap == null || surfaceIndexMap.width != getTerrain().weightMapResolution){
|
|
|
+ var oldSurfaceIndexMap = surfaceIndexMap;
|
|
|
+ surfaceIndexMap = new h3d.mat.Texture(getTerrain().weightMapResolution, getTerrain().weightMapResolution, [Target], RGBA);
|
|
|
+ surfaceIndexMap.filter = Nearest;
|
|
|
+ if(oldSurfaceIndexMap != null){
|
|
|
+ getTerrain().copyPass.apply(oldSurfaceIndexMap, surfaceIndexMap);
|
|
|
+ oldSurfaceIndexMap.dispose();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(surfaceWeights.length != surfaceCount || surfaceWeights[0].width != getTerrain().weightMapResolution){
|
|
|
+ var oldArray = surfaceWeights;
|
|
|
+ surfaceWeights = new Array<h3d.mat.Texture>();
|
|
|
+ surfaceWeights.resize(surfaceCount);
|
|
|
+ for(i in 0 ... surfaceWeights.length){
|
|
|
+ surfaceWeights[i] = new h3d.mat.Texture(getTerrain().weightMapResolution, getTerrain().weightMapResolution, [Target], R8);
|
|
|
+ surfaceWeights[i].wrap = Clamp;
|
|
|
+ if(i < oldArray.length && oldArray[i] != null)
|
|
|
+ getTerrain().copyPass.apply(oldArray[i], surfaceWeights[i]);
|
|
|
+ }
|
|
|
+ for(i in 0 ... oldArray.length)
|
|
|
+ if( oldArray[i] != null) oldArray[i].dispose();
|
|
|
+ generateWeightArray();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function generateWeightArray(){
|
|
|
+ if(surfaceWeightArray == null || surfaceWeightArray.width != getTerrain().weightMapResolution || surfaceWeightArray.get_layerCount() != surfaceWeights.length){
|
|
|
+ if(surfaceWeightArray != null) surfaceWeightArray.dispose();
|
|
|
+ surfaceWeightArray = new h3d.mat.TextureArray(getTerrain().weightMapResolution, getTerrain().weightMapResolution, surfaceWeights.length, [Target], R8);
|
|
|
+ surfaceWeightArray.wrap = Clamp;
|
|
|
+ }
|
|
|
+ for(i in 0 ... surfaceWeights.length)
|
|
|
+ if(surfaceWeights[i] != null) getTerrain().copyPass.apply(surfaceWeights[i], surfaceWeightArray, None, null, i);
|
|
|
+ }
|
|
|
+
|
|
|
+ public function computeEdgesHeight(){
|
|
|
+ if(heightMap == null) return;
|
|
|
+ var pixels : hxd.Pixels.PixelsFloat = getHeightPixels();
|
|
|
+ var adjTileX = getTerrain().getTile(tileX + 1, tileY);
|
|
|
+ var adjHeightMapX = adjTileX != null ? adjTileX.heightMap : null;
|
|
|
+ if(adjHeightMapX != null){
|
|
|
+ var adjpixels : hxd.Pixels.PixelsFloat = adjTileX.getHeightPixels();
|
|
|
+ for( i in 0 ... heightMap.height - 1){
|
|
|
+ pixels.setPixelF(heightMap.width - 1, i, adjpixels.getPixelF(0,i) );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var adjTileY = getTerrain().getTile(tileX, tileY + 1);
|
|
|
+ var adjHeightMapY = adjTileY != null ? adjTileY.heightMap : null;
|
|
|
+ if(adjHeightMapY != null){
|
|
|
+ var adjpixels : hxd.Pixels.PixelsFloat = adjTileY.getHeightPixels();
|
|
|
+ for( i in 0 ... heightMap.width - 1){
|
|
|
+ pixels.setPixelF(i, heightMap.height - 1, adjpixels.getPixelF(i,0) );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var adjTileXY = getTerrain().getTile(tileX + 1, tileY + 1);
|
|
|
+ var adjHeightMapXY = adjTileXY != null ? adjTileXY.heightMap : null;
|
|
|
+ if(adjHeightMapXY != null){
|
|
|
+ var adjpixels : hxd.Pixels.PixelsFloat = adjTileXY.getHeightPixels();
|
|
|
+ pixels.setPixelF(heightMap.width - 1, heightMap.height - 1, adjpixels.getPixelF(0,0));
|
|
|
+ }
|
|
|
+ heightmapPixels = pixels;
|
|
|
+ heightMap.uploadPixels(pixels);
|
|
|
+ }
|
|
|
+
|
|
|
+ public function computeEdgesNormals(){
|
|
|
+ if(grid.normals == null) return;
|
|
|
+ var t0 = new h3d.col.Point(); var t1 = new h3d.col.Point(); var t2 = new h3d.col.Point();
|
|
|
+ var triCount = Std.int(grid.triCount() / grid.width);
|
|
|
+ var vertexCount = grid.width + 1;
|
|
|
+ var step = hxd.Math.floor(grid.normals.length / grid.width) - 1;
|
|
|
+ var s = hxd.Math.floor(grid.normals.length - grid.normals.length / grid.width + 2);
|
|
|
+ var istep = triCount * 3 - 6;
|
|
|
+ var i0, i1, i2 : Int = 0;
|
|
|
+
|
|
|
+ inline function computeVertexPos(tile : Tile){
|
|
|
+ var pixels : hxd.Pixels.PixelsFloat = tile.getHeightPixels();
|
|
|
+ t0.load(tile.grid.points[i0]); t1.load(tile.grid.points[i1]); t2.load(tile.grid.points[i2]);
|
|
|
+ t0.z += tile.getHeight(t0.x / getTerrain().tileSize, t0.y / getTerrain().tileSize, pixels);
|
|
|
+ t1.z += tile.getHeight(t1.x / getTerrain().tileSize, t1.y / getTerrain().tileSize, pixels);
|
|
|
+ t2.z += tile.getHeight(t2.x / getTerrain().tileSize, t2.y / getTerrain().tileSize, pixels);
|
|
|
+ }
|
|
|
+
|
|
|
+ inline function computeNormal() : h3d.col.Point {
|
|
|
+ var n1 = t1.sub(t0);
|
|
|
+ n1.normalize();
|
|
|
+ var n2 = t2.sub(t0);
|
|
|
+ n2.normalize();
|
|
|
+ return n1.cross(n2);
|
|
|
+ }
|
|
|
+
|
|
|
+ var adjUpTile = getTerrain().getTile(tileX, tileY + 1);
|
|
|
+ var adjUpGrid = adjUpTile != null ? adjUpTile.grid: null;
|
|
|
+ var adjDownTile = getTerrain().getTile(tileX, tileY - 1);
|
|
|
+ var adjDownGrid = adjDownTile != null ? adjDownTile.grid: null;
|
|
|
+ var adjLeftTile = getTerrain().getTile(tileX + 1, tileY);
|
|
|
+ var adjLeftGrid = adjLeftTile != null ? adjLeftTile.grid: null;
|
|
|
+ var adjRightTile = getTerrain().getTile(tileX - 1, tileY);
|
|
|
+ var adjRightGrid = adjRightTile != null ? adjRightTile.grid: null;
|
|
|
+ var adjUpRightTile = getTerrain().getTile(tileX - 1, tileY + 1);
|
|
|
+ var adjUpRightGrid = adjUpRightTile != null ? adjUpRightTile.grid: null;
|
|
|
+ var adjUpLeftTile = getTerrain().getTile(tileX + 1, tileY + 1);
|
|
|
+ var adjUpLeftGrid = adjUpLeftTile != null ? adjUpLeftTile.grid: null;
|
|
|
+ var adjDownLeftTile = getTerrain().getTile(tileX + 1, tileY - 1);
|
|
|
+ var adjDownLeftGrid = adjDownLeftTile != null ? adjDownLeftTile.grid: null;
|
|
|
+ var adjDownRightTile = getTerrain().getTile(tileX - 1, tileY - 1);
|
|
|
+ var adjDownRightGrid = adjDownRightTile != null ? adjDownRightTile.grid: null;
|
|
|
+
|
|
|
+ if(adjUpGrid != null && adjUpGrid.normals != null){
|
|
|
+ var pos = 0;
|
|
|
+ for( i in 0 ... vertexCount)
|
|
|
+ adjUpGrid.normals[i].set(0,0,0);
|
|
|
+ for( i in 0 ... triCount ) {
|
|
|
+ i0 = adjUpGrid.idx[pos++]; i1 = adjUpGrid.idx[pos++]; i2 = adjUpGrid.idx[pos++];
|
|
|
+ computeVertexPos(adjUpTile);
|
|
|
+ var n = computeNormal();
|
|
|
+ if(i0 <= adjUpGrid.width){ adjUpGrid.normals[i0].x += n.x; adjUpGrid.normals[i0].y += n.y; adjUpGrid.normals[i0].z += n.z;}
|
|
|
+ if(i1 <= adjUpGrid.width){ adjUpGrid.normals[i1].x += n.x; adjUpGrid.normals[i1].y += n.y; adjUpGrid.normals[i1].z += n.z;}
|
|
|
+ if(i2 <= adjUpGrid.width){ adjUpGrid.normals[i2].x += n.x; adjUpGrid.normals[i2].y += n.y; adjUpGrid.normals[i2].z += n.z;}
|
|
|
+ }
|
|
|
+ for( i in 0 ... vertexCount)
|
|
|
+ adjUpGrid.normals[i].normalize();
|
|
|
+ for( i in 1 ... vertexCount - 1){
|
|
|
+ var n = grid.normals[s + i].add(adjUpGrid.normals[i]);
|
|
|
+ n.normalize();
|
|
|
+ grid.normals[s + i].load(n);
|
|
|
+ adjUpGrid.normals[i].load(n);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(adjDownGrid != null && adjDownGrid.normals != null){
|
|
|
+ var pos = triCount * (adjDownGrid.width - 1) * 3;
|
|
|
+ for( i in 0 ... vertexCount)
|
|
|
+ adjDownGrid.normals[s + i].set(0,0,0);
|
|
|
+ for( i in 0 ... triCount ) {
|
|
|
+ i0 = adjDownGrid.idx[pos++]; i1 = adjDownGrid.idx[pos++]; i2 = adjDownGrid.idx[pos++];
|
|
|
+ computeVertexPos(adjDownTile);
|
|
|
+ var n = computeNormal();
|
|
|
+ if(i0 >= (adjDownGrid.width * adjDownGrid.height + adjDownGrid.height)){ adjDownGrid.normals[i0].x += n.x; adjDownGrid.normals[i0].y += n.y; adjDownGrid.normals[i0].z += n.z;}
|
|
|
+ if(i1 >= (adjDownGrid.width * adjDownGrid.height + adjDownGrid.height)){ adjDownGrid.normals[i1].x += n.x; adjDownGrid.normals[i1].y += n.y; adjDownGrid.normals[i1].z += n.z;}
|
|
|
+ if(i2 >= (adjDownGrid.width * adjDownGrid.height + adjDownGrid.height)){ adjDownGrid.normals[i2].x += n.x; adjDownGrid.normals[i2].y += n.y; adjDownGrid.normals[i2].z += n.z;}
|
|
|
+ }
|
|
|
+ for( i in 1 ... vertexCount - 1)
|
|
|
+ adjDownGrid.normals[s + i].normalize();
|
|
|
+ for( i in 1 ... vertexCount - 1){
|
|
|
+ var n = grid.normals[i].add(adjDownGrid.normals[s + i]);
|
|
|
+ n.normalize();
|
|
|
+ grid.normals[i].load(n);
|
|
|
+ adjDownGrid.normals[s + i].load(n);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(adjLeftGrid != null && adjLeftGrid.normals != null){
|
|
|
+ var pos = 0;
|
|
|
+ var istep = triCount * 3 - 6;
|
|
|
+ var needStep = false;
|
|
|
+ for( i in 0 ... vertexCount)
|
|
|
+ adjLeftGrid.normals[i * step].set(0,0,0);
|
|
|
+ for( i in 0 ... triCount ) {
|
|
|
+ i0 = adjLeftGrid.idx[pos++]; i1 = adjLeftGrid.idx[pos++]; i2 = adjLeftGrid.idx[pos++];
|
|
|
+ computeVertexPos(adjLeftTile);
|
|
|
+ var n = computeNormal();
|
|
|
+ if(i0 % (adjLeftGrid.width + 1) == 0){ adjLeftGrid.normals[i0].x += n.x; adjLeftGrid.normals[i0].y += n.y; adjLeftGrid.normals[i0].z += n.z;}
|
|
|
+ if(i1 % (adjLeftGrid.width + 1) == 0){ adjLeftGrid.normals[i1].x += n.x; adjLeftGrid.normals[i1].y += n.y; adjLeftGrid.normals[i1].z += n.z;}
|
|
|
+ if(i2 % (adjLeftGrid.width + 1) == 0){ adjLeftGrid.normals[i2].x += n.x; adjLeftGrid.normals[i2].y += n.y; adjLeftGrid.normals[i2].z += n.z;}
|
|
|
+ if(needStep) pos += istep;
|
|
|
+ needStep = !needStep;
|
|
|
+ }
|
|
|
+ for( i in 0 ... vertexCount)
|
|
|
+ adjLeftGrid.normals[i * step].normalize();
|
|
|
+ for( i in 1 ... vertexCount - 1){
|
|
|
+ var n = grid.normals[i * step + (step - 1)].add(adjLeftGrid.normals[i * step]);
|
|
|
+ n.normalize();
|
|
|
+ grid.normals[i * step + (step - 1)].load(n);
|
|
|
+ adjLeftGrid.normals[i * step].load(n);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(adjRightGrid != null && adjRightGrid.normals != null){
|
|
|
+ var pos = (triCount - 2) * 3;
|
|
|
+ var istep = (triCount - 2) * 3;
|
|
|
+ var needStep = false;
|
|
|
+ for( i in 0 ... vertexCount)
|
|
|
+ adjRightGrid.normals[i * step + (step - 1)].set(0,0,0);
|
|
|
+ for( i in 0 ... triCount ) {
|
|
|
+ i0 = adjRightGrid.idx[pos++]; i1 = adjRightGrid.idx[pos++]; i2 = adjRightGrid.idx[pos++];
|
|
|
+ computeVertexPos(adjRightTile);
|
|
|
+ var n = computeNormal();
|
|
|
+ if((i0 + 1) % (adjRightGrid.width + 1) == 0){ adjRightGrid.normals[i0].x += n.x; adjRightGrid.normals[i0].y += n.y; adjRightGrid.normals[i0].z += n.z;}
|
|
|
+ if((i1 + 1) % (adjRightGrid.width + 1) == 0){ adjRightGrid.normals[i1].x += n.x; adjRightGrid.normals[i1].y += n.y; adjRightGrid.normals[i1].z += n.z;}
|
|
|
+ if((i2 + 1) % (adjRightGrid.width + 1) == 0){ adjRightGrid.normals[i2].x += n.x; adjRightGrid.normals[i2].y += n.y; adjRightGrid.normals[i2].z += n.z;}
|
|
|
+ if(needStep) pos += istep;
|
|
|
+ needStep = !needStep;
|
|
|
+ }
|
|
|
+ for( i in 0 ... vertexCount)
|
|
|
+ adjRightGrid.normals[i * step + (step - 1)].normalize();
|
|
|
+ for( i in 1 ... vertexCount - 1){
|
|
|
+ var n = grid.normals[i * step].add(adjRightGrid.normals[i * step + (step - 1)]);
|
|
|
+ n.normalize();
|
|
|
+ grid.normals[i * step].load(n);
|
|
|
+ adjRightGrid.normals[i * step + (step - 1)].load(n);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var topLeft = grid.points.length - 1;
|
|
|
+ var downLeft= step - 1;
|
|
|
+ var downRight = 0;
|
|
|
+ var upRight = step * grid.height;
|
|
|
+
|
|
|
+ var n = new h3d.col.Point();
|
|
|
+ if(adjUpRightGrid != null && adjUpRightGrid.normals != null){
|
|
|
+ var pos = (triCount) * 3 - 6;
|
|
|
+ i0 = adjUpRightGrid.idx[pos++]; i1 = adjUpRightGrid.idx[pos++]; i2 = adjUpRightGrid.idx[pos++];
|
|
|
+ computeVertexPos(adjUpRightTile);
|
|
|
+ n = computeNormal();
|
|
|
+ i0 = adjUpRightGrid.idx[pos++]; i1 = adjUpRightGrid.idx[pos++]; i2 = adjUpRightGrid.idx[pos++];
|
|
|
+ computeVertexPos(adjUpRightTile);
|
|
|
+ n = n.add(computeNormal());
|
|
|
+ n.normalize();
|
|
|
+ }
|
|
|
+ if(adjRightGrid != null && adjRightGrid.normals != null) n = n.add(adjRightGrid.normals[topLeft]);
|
|
|
+ if(adjUpGrid != null && adjUpGrid.normals != null) n = n.add(adjUpGrid.normals[downRight]);
|
|
|
+ n = n.add(grid.normals[upRight]);
|
|
|
+ n.normalize();
|
|
|
+ if(adjUpRightGrid != null && adjUpRightGrid.normals != null) adjUpRightGrid.normals[downLeft].load(n);
|
|
|
+ if(adjRightGrid != null && adjRightGrid.normals != null) adjRightGrid.normals[topLeft].load(n);
|
|
|
+ if(adjUpGrid != null && adjUpGrid.normals != null) adjUpGrid.normals[downRight].load(n);
|
|
|
+ grid.normals[upRight].load(n);
|
|
|
+
|
|
|
+ n.set(0,0,0);
|
|
|
+ if(adjUpLeftGrid != null && adjUpLeftGrid.normals != null){
|
|
|
+ var pos = 0;
|
|
|
+ i0 = adjUpLeftGrid.idx[pos++]; i1 = adjUpLeftGrid.idx[pos++]; i2 = adjUpLeftGrid.idx[pos++];
|
|
|
+ computeVertexPos(adjUpLeftTile);
|
|
|
+ n = computeNormal();
|
|
|
+ n.normalize();
|
|
|
+ }
|
|
|
+ if(adjLeftGrid != null && adjLeftGrid.normals != null) n = n.add(adjLeftGrid.normals[upRight]);
|
|
|
+ if(adjUpGrid != null && adjUpGrid.normals != null) n = n.add(adjUpGrid.normals[downLeft]);
|
|
|
+ n = n.add(grid.normals[topLeft]);
|
|
|
+ n.normalize();
|
|
|
+ if(adjUpLeftGrid != null && adjUpLeftGrid.normals != null) adjUpLeftGrid.normals[downRight].load(n);
|
|
|
+ if(adjLeftGrid != null && adjLeftGrid.normals != null) adjLeftGrid.normals[upRight].load(n);
|
|
|
+ if(adjUpGrid != null && adjUpGrid.normals != null) adjUpGrid.normals[downLeft].load(n);
|
|
|
+ grid.normals[topLeft].load(n);
|
|
|
+
|
|
|
+ n.set(0,0,0);
|
|
|
+ if(adjDownLeftGrid != null && adjDownLeftGrid.normals != null){
|
|
|
+ var pos = (triCount) * 3 * (adjDownLeftGrid.height - 1) ;
|
|
|
+ i0 = adjDownLeftGrid.idx[pos++]; i1 = adjDownLeftGrid.idx[pos++]; i2 = adjDownLeftGrid.idx[pos++];
|
|
|
+ computeVertexPos(adjDownLeftTile);
|
|
|
+ n = computeNormal();
|
|
|
+ i0 = adjDownLeftGrid.idx[pos++]; i1 = adjDownLeftGrid.idx[pos++]; i2 = adjDownLeftGrid.idx[pos++];
|
|
|
+ computeVertexPos(adjDownLeftTile);
|
|
|
+ n = n.add(computeNormal());
|
|
|
+ n.normalize();
|
|
|
+ }
|
|
|
+ if(adjLeftGrid != null && adjLeftGrid.normals != null) n = n.add(adjLeftGrid.normals[downRight]);
|
|
|
+ if(adjDownGrid != null && adjDownGrid.normals != null) n = n.add(adjDownGrid.normals[topLeft]);
|
|
|
+ n = n.add(grid.normals[downLeft]);
|
|
|
+ n.normalize();
|
|
|
+ if(adjDownLeftGrid != null && adjDownLeftGrid.normals != null) adjDownLeftGrid.normals[upRight].load(n);
|
|
|
+ if(adjLeftGrid != null && adjLeftGrid.normals != null) adjLeftGrid.normals[downRight].load(n);
|
|
|
+ if(adjDownGrid != null && adjDownGrid.normals != null) adjDownGrid.normals[topLeft].load(n);
|
|
|
+ grid.normals[downLeft].load(n);
|
|
|
+
|
|
|
+ n.set(0,0,0);
|
|
|
+ if(adjDownRightGrid != null && adjDownRightGrid.normals != null){
|
|
|
+ var pos = triCount * 3 * adjDownRightGrid.width - 3;
|
|
|
+ i0 = adjDownRightGrid.idx[pos++]; i1 = adjDownRightGrid.idx[pos++]; i2 = adjDownRightGrid.idx[pos++];
|
|
|
+ computeVertexPos(adjDownRightTile);
|
|
|
+ n = computeNormal();
|
|
|
+ n.normalize();
|
|
|
+ }
|
|
|
+ if(adjRightGrid != null && adjRightGrid.normals != null) n = n.add(adjRightGrid.normals[downLeft]);
|
|
|
+ if(adjDownGrid != null && adjDownGrid.normals != null) n = n.add(adjDownGrid.normals[upRight]);
|
|
|
+ n = n.add(grid.normals[downRight]);
|
|
|
+ n.normalize();
|
|
|
+ if(adjDownRightGrid != null && adjDownRightGrid.normals != null) adjDownRightGrid.normals[topLeft].load(n);
|
|
|
+ if(adjRightGrid != null && adjRightGrid.normals != null) adjRightGrid.normals[downLeft].load(n);
|
|
|
+ if(adjDownGrid != null && adjDownGrid.normals != null) adjDownGrid.normals[upRight].load(n);
|
|
|
+ grid.normals[downRight].load(n);
|
|
|
+
|
|
|
+ if(adjUpTile != null) adjUpTile.needAlloc = true;
|
|
|
+ if(adjDownTile != null) adjDownTile.needAlloc = true;
|
|
|
+ if(adjLeftTile != null) adjLeftTile.needAlloc = true;
|
|
|
+ if(adjRightTile != null) adjRightTile.needAlloc = true;
|
|
|
+ if(adjUpLeftTile != null) adjUpLeftTile.needAlloc = true;
|
|
|
+ if(adjDownLeftTile != null) adjDownLeftTile.needAlloc = true;
|
|
|
+ if(adjUpRightTile != null) adjUpRightTile.needAlloc = true;
|
|
|
+ if(adjDownRightTile != null) adjDownRightTile.needAlloc = true;
|
|
|
+ needAlloc = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function computeNormals(){
|
|
|
+ var pixels : hxd.Pixels.PixelsFloat = null;
|
|
|
+ if(heightMap != null)
|
|
|
+ pixels = getHeightPixels();
|
|
|
+ if(grid.normals == null) grid.normals = new Array();
|
|
|
+ grid.normals.resize(grid.points.length);
|
|
|
+ for( i in 0 ... grid.points.length){
|
|
|
+ if(grid.normals[i] == null) grid.normals[i] = new h3d.col.Point();
|
|
|
+ grid.normals[i].x = 0; grid.normals[i].y = 0; grid.normals[i].z = 0;
|
|
|
+ }
|
|
|
+ var t0 = new h3d.col.Point();
|
|
|
+ var t1 = new h3d.col.Point();
|
|
|
+ var t2 = new h3d.col.Point();
|
|
|
+ var pos = 0;
|
|
|
+ for( i in 0...grid.triCount() ) {
|
|
|
+ var i0, i1, i2;
|
|
|
+ if( grid.idx == null ) {
|
|
|
+ i0 = pos++;
|
|
|
+ i1 = pos++;
|
|
|
+ i2 = pos++;
|
|
|
+ } else {
|
|
|
+ i0 = grid.idx[pos++];
|
|
|
+ i1 = grid.idx[pos++];
|
|
|
+ i2 = grid.idx[pos++];
|
|
|
+ }
|
|
|
+ t0.load(grid.points[i0]);
|
|
|
+ t1.load(grid.points[i1]);
|
|
|
+ t2.load(grid.points[i2]);
|
|
|
+ if(pixels != null){
|
|
|
+ t0.z += getHeight(t0.x / getTerrain().tileSize, t0.y / getTerrain().tileSize, pixels);
|
|
|
+ t1.z += getHeight(t1.x / getTerrain().tileSize, t1.y / getTerrain().tileSize, pixels);
|
|
|
+ t2.z += getHeight(t2.x / getTerrain().tileSize, t2.y / getTerrain().tileSize, pixels);
|
|
|
+ }
|
|
|
+ var n1 = t1.sub(t0);
|
|
|
+ n1.normalize();
|
|
|
+ var n2 = t2.sub(t0);
|
|
|
+ n2.normalize();
|
|
|
+ var n = n1.cross(n2);
|
|
|
+ grid.normals[i0].x += n.x; grid.normals[i0].y += n.y; grid.normals[i0].z += n.z;
|
|
|
+ grid.normals[i1].x += n.x; grid.normals[i1].y += n.y; grid.normals[i1].z += n.z;
|
|
|
+ grid.normals[i2].x += n.x; grid.normals[i2].y += n.y; grid.normals[i2].z += n.z;
|
|
|
+ }
|
|
|
+ for( n in grid.normals )
|
|
|
+ n.normalize();
|
|
|
+
|
|
|
+ needAlloc = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ function getHeight(u : Float, v : Float, pixels : hxd.Pixels.PixelsFloat ){
|
|
|
+ if(heightMap.filter == Linear){
|
|
|
+ var coordsX = hxd.Math.max(0, u * (heightMap.width - 1) - 0.5);
|
|
|
+ var coordsY = hxd.Math.max(0, v * (heightMap.width - 1) - 0.5);
|
|
|
+ var x = hxd.Math.floor(coordsX);
|
|
|
+ var y = hxd.Math.floor(coordsY);
|
|
|
+ var ratioX = coordsX - x;
|
|
|
+ var ratioY = coordsY - y;
|
|
|
+ var oppositeU = 1 - ratioX;
|
|
|
+ var oppositeV = 1 - ratioY;
|
|
|
+ var result = (pixels.getPixelF(x, y).r * oppositeU + pixels.getPixelF( Std.int(hxd.Math.min(x + 1, pixels.width)), y).r * ratioX) * oppositeV +
|
|
|
+ (pixels.getPixelF(x, Std.int(hxd.Math.min(y + 1, pixels.height))).r * oppositeU +
|
|
|
+ pixels.getPixelF(Std.int(hxd.Math.min(x + 1, pixels.width)), Std.int(hxd.Math.min(y + 1, pixels.height))).r * ratioX) * ratioY;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ var x = hxd.Math.floor(u * (heightMap.width - 2));
|
|
|
+ var y = hxd.Math.floor(v * (heightMap.height - 2));
|
|
|
+ return pixels.getPixelF(x, y).r;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public override function dispose() {
|
|
|
+ if(heightMap != null) heightMap.dispose();
|
|
|
+ if(surfaceIndexMap != null) surfaceIndexMap.dispose();
|
|
|
+ for(i in 0 ... surfaceWeights.length)
|
|
|
+ if( surfaceWeights[i] != null) surfaceWeights[i].dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ override function emit(ctx:RenderContext){
|
|
|
+ if( getTerrain().surfaceArray == null) return;
|
|
|
+ var bounds = getBounds();
|
|
|
+ if(bounds != null){
|
|
|
+ if(ctx.camera.getFrustum().hasBounds(bounds))
|
|
|
+ super.emit(ctx);
|
|
|
+ }else
|
|
|
+ super.emit(ctx);
|
|
|
+ }
|
|
|
+
|
|
|
+ override function sync(ctx:RenderContext) {
|
|
|
+ if( getTerrain().surfaceArray == null) return;
|
|
|
+ shader.heightMap = heightMap;
|
|
|
+ shader.heightMapSize = heightMap.width;
|
|
|
+ shader.primSize = getTerrain().tileSize;
|
|
|
+ shader.cellSize = getTerrain().cellSize;
|
|
|
+ shader.showGrid = getTerrain().showGrid;
|
|
|
+ shader.surfaceIndexMap = surfaceIndexMap;
|
|
|
+ shader.albedoTextures = getTerrain().surfaceArray.albedo;
|
|
|
+ shader.normalTextures = getTerrain().surfaceArray.normal;
|
|
|
+ shader.pbrTextures = getTerrain().surfaceArray.pbr;
|
|
|
+ shader.weightTextures = surfaceWeightArray;
|
|
|
+ shader.weightCount = surfaceCount;
|
|
|
+ shader.surfaceParams = getTerrain().surfaceArray.params;
|
|
|
+ shader.secondSurfaceParams = getTerrain().surfaceArray.secondParams;
|
|
|
+ shader.tileIndex = new h3d.Vector(tileX, tileY);
|
|
|
+ shader.parallaxAmount = getTerrain().parallaxAmount;
|
|
|
+ shader.minStep = getTerrain().parallaxMinStep;
|
|
|
+ shader.maxStep = getTerrain().parallaxMaxStep;
|
|
|
+ shader.heightBlendStrength = getTerrain().heightBlendStrength;
|
|
|
+ shader.heightBlendSharpness = getTerrain().heightBlendSharpness;
|
|
|
+ }
|
|
|
+
|
|
|
+ inline function getTerrain(){
|
|
|
+ return Std.instance(parent, Terrain);
|
|
|
+ }
|
|
|
+}
|