public static RayCastResult rayCast(Vector3 startPos, Vector3 dir, RayCastManager rtm, float length, RayCastBlockType mask) { DirInfo dirInfo = new DirInfo(dir); Vector3 startPosInner = startPos; float hitTime = 0; float startOffset = 0; bool bHitBounds = true;//能击中总区域,或者在内部 if (startPos.x >= 0 && startPos.x < rtm.getSizeX() && startPos.y >= 0 && startPos.y < rtm.getSizeY() && startPos.z >= 0 && startPos.z < rtm.getSizeZ()) { bHitBounds = true; } else { bHitBounds = Misc.rayHitAABB(startPos, dir, new Vector3(0, 0, 0), rtm.getSize(), ref hitTime); if (hitTime > 0) { startOffset = hitTime; } startPosInner = startPos + dir * startOffset - dir * 0.01f; } if (bHitBounds) { RayCastResult rlt = rayTraceSmall(startPosInner, dirInfo, rtm, Face.FNI_Unknown, length - startOffset, mask); rlt.hitLength += startOffset; return(rlt); } else { return(new RayCastResult(false, 0, 0, 0, Face.FNI_Unknown, 0)); } }
public static void SetExtendAo(List <MeshTool.BlockSurface> surface, RayCastManager scene, int normalIndex, VecInt3 gpos) { for (int i = 0; i < surface.Count; i++) { VecInt3 pos = surface[i].pos; VecInt3 adjPos = new VecInt3(); adjPos.x = pos.x + Const.AdjacencyOffsetV[normalIndex].x + gpos.x; adjPos.y = pos.y + Const.AdjacencyOffsetV[normalIndex].y + gpos.y; adjPos.z = pos.z + Const.AdjacencyOffsetV[normalIndex].z + gpos.z; for (int v = 0; v < 4; v++) { int curLight = scene.getLight(adjPos.x, adjPos.y, adjPos.z); int num = 1; for (int b = 0; b < 3; b++) { int sx = Const.VertexSharedOffset[normalIndex, v, b, 0]; int sy = Const.VertexSharedOffset[normalIndex, v, b, 1]; int sz = Const.VertexSharedOffset[normalIndex, v, b, 2]; if (!scene.testBlock(adjPos.x + sx, adjPos.y + sy, adjPos.z + sz, RayCastBlockType.Opacity)) { curLight += scene.getLight(adjPos.x + sx, adjPos.y + sy, adjPos.z + sz); num++; } } surface[i].extendAo[v] = curLight / (Const.MaxLightIteration * num * 1.0f); } } }
static float calcDirectSunLight(RayCastManager rayTraceManager, Vector3 sunDir, int globalX, int globalY, int globalZ, int faceIndex) { //计算ao Vector3 faceNormal = Const.getFaceNormal(faceIndex); float faceLightFactor = Vector3.Dot(faceNormal, -sunDir); if (faceLightFactor < 0) { return(0); } else { Vector3 startPos = (new Vector3(globalX, globalY, globalZ) + Vector3.one * 0.5f + faceNormal * 0.501f) * Const.BlockSize; float rayLength = 100.0f; //float brightness = 0.0f; RayCastRestult rlt = rayTraceManager.rayCast(startPos, -sunDir, rayLength, RayCastBlockType.All); if (rlt.bHit) { return(0); } else { return(faceLightFactor); } } }
static float calcAo(RayCastManager rayTraceManager, Vector3[] rays, int globalX, int globalY, int globalZ, int faceIndex) { //计算ao Vector3 startPos = (new Vector3(globalX, globalY, globalZ) + Vector3.one * 0.5f + Const.getFaceNormal(faceIndex) * 0.51f) * Const.BlockSize; float rayLength = 16; float brightness = 0.0f; Vector3[] startPosArray = new Vector3[rays.Length]; float[] rayLenghtArray = new float[rays.Length]; for (int i = 0; i < startPosArray.Length; i++) { startPosArray[i] = startPos; rayLenghtArray[i] = rayLength; } RayCastRestult[] rlts = rayTraceManager.batchRayCast(startPosArray, rays, rayLenghtArray, RayCastBlockType.Opacity); for (uint i = 0; i < rays.Length; i++) { RayCastRestult rlt = rlts[i];//rayTraceManager.rayCast(startPos, rays[i], rayLength); if (rlt.bHit && rlt.hitLength < rayLength) { float a = ((rlt.hitLength) / rayLength); brightness += (a / rays.Length); } else { brightness += 1.0f / rays.Length; } } brightness = Mathf.Clamp(brightness, 0.0f, 1.0f); return(Mathf.Pow(brightness, 0.8f) * 0.9f + 0.1f); }
public static void calcLight(BlockManager blockManager, RayCastManager rayTraceManager, Vector3[][] rays, Vector3 sunDir) { ////射线求交方式计算AO //blockManager.forEachChunk((BlockChunk chunk, int i, int j, int k) => { // if (!chunk.isEmpty()) { // calcChunkLight(chunk, i, j, k, rayTraceManager, rays, sunDir); // } //}); }
private static Texture3D Create3DTexture(RayCastManager rtc) { Texture3D voxelTexture = new Texture3D(rtc.getSizeX(), rtc.getSizeY() / 8, rtc.getSizeZ(), TextureFormat.Alpha8, false); voxelTexture.filterMode = FilterMode.Point; voxelTexture.wrapMode = TextureWrapMode.Clamp; voxelTexture.SetPixels(ToColorsA(rtc, 8)); voxelTexture.Apply(); return(voxelTexture); }
public static Color[] ToColorsA(RayCastManager rtc, int bits) { int dgx = rtc.getSizeX(); int dgy = rtc.getSizeY(); int dgz = rtc.getSizeZ(); Color[,,] colors = new Color[dgx, (dgy / bits), dgz]; for (int gx = 0; gx < dgx; gx++) { for (int gy = 0; gy < dgy / bits; gy++) { for (int gz = 0; gz < dgz; gz++) { int iv = 0; for (int n = 0; n < bits; n++) { iv |= rtc.testBlock(gx, gy * bits + n, gz, RayCastBlockType.Opacity) ? (1 << n) : 0; } float a = iv / (float)((1 << bits) - 1); colors[gx, gy, gz] = new Color(0, 0, 0, a); } } } int sizeX = colors.GetLength(0); int sizeY = colors.GetLength(1); int sizeZ = colors.GetLength(2); Color[] rlt = new Color[sizeX * sizeY * sizeZ]; for (int x = 0; x < sizeX; x++) { for (int y = 0; y < sizeY; y++) { for (int z = 0; z < sizeZ; z++) { rlt[z * sizeY * sizeX + y * sizeX + x] = colors[x, y, z]; } } } return(rlt); }
public void DoGenerate() { float startTime = Time.realtimeSinceStartup; bm.create(numX * Const.ChunkSize, numY * Const.ChunkSize, numZ * Const.ChunkSize, new BlockTypeFun()); for (int x = 0; x < bm.SizeX; x++) { for (int y = 0; y < bm.SizeY; y++) { for (int z = 0; z < bm.SizeZ; z++) { //bm.setBlock(x, y, z, (short)(z < y ? Block.BlockTypeEnum.Air : Block.BlockTypeEnum.Sand)); bm.setBlock(x, y, z, (short)(y < 10 || (x == 20 && z > 10 && z <= 15) ? Block.BlockTypeEnum.Sand : Block.BlockTypeEnum.Air)); } } } rtm = new Block.RayCastManager(); rtm.create(numX, numY, numZ); for (int x = 0; x < bm.SizeX; x++) { for (int y = 0; y < bm.SizeY; y++) { for (int z = 0; z < bm.SizeZ; z++) { rtm.setBlock(x, y, z, bm.getBlock(x, y, z) != 0 ? RayCastBlockType.All : RayCastBlockType.Nothing); } } } rma = new Block.RayMarchingAo(); rma.Init(rtm); viewVoxel.SetVexelTex(rma.GetVoxelTexture()); Debug.Log("生成完体素数据," + (Time.realtimeSinceStartup - startTime)); StartCoroutine(GenerateMesh()); }
public static void calcChunkLight(BlockChunk chunk, int cx, int cy, int cz, RayCastManager rayTraceManager, Vector3[][] rays, Vector3 sunDir) { //List<VecInt3>[] surfaces = chunk.calcSurfaceList(); //for (int f = 0; f < 6; f++) { // List<VecInt3> surs = surfaces[f]; // for (int i = 0; i < surs.Count; i++) { // VecInt3 surface = surs[i]; // int gx = cx * Const.ChunkSize + surface.x; // int gy = cy * Const.ChunkSize + surface.y; // int gz = cz * Const.ChunkSize + surface.z; // Vector3 faceNormal = Const.getFaceNormal(f); // float faceLightFactor = Vector3.Dot(faceNormal, -sunDir); // Vector3 startPos = (new Vector3(gx, gy, gz) + Vector3.one * 0.5f + faceNormal * 0.51f) * Const.BlockSize; // // float directionLight = 0; // float aoLight = 0; // float aoLenght = 8.0f; // if(faceLightFactor > 0){ // RayCastRestult rlt = rayTraceManager.rayCast(startPos, -sunDir, 30); // directionLight += rlt.bHit ? 0 : faceLightFactor; // } // for (int r = 0; r < rays[f].Length; r++) { // RayCastRestult rlt = rayTraceManager.rayCast(startPos, rays[f][r], aoLenght); // if (rlt.bHit && rlt.hitLength < aoLenght) { // float a = ((rlt.hitLength) / aoLenght); // aoLight += (a / rays[f].Length); // } // else { // aoLight += 1.0f / rays[f].Length; // } // } // float brightness = directionLight * 0.35f + aoLight * 0.45f + 0.2f; // brightness = Mathf.Clamp(brightness, 0, 1); // chunk.setBrightness(surface.x, surface.y, surface.z, f, (Byte)(brightness * Const.MaxBrightness)); // } //} }
public void Init(RayCastManager rtc) { constValueTexture = CreateConstValueTexture(); texVoxel3D = Create3DTexture(rtc); calcAoMaterial = new Material(Shader.Find("Hidden/RaytraceAo")); }
public static RayCastResult rayTraceSmall(Vector3 startPos, DirInfo dirInfo, RayCastManager rtm, Face faceIn, float maxLength, RayCastBlockType mask) { int X = (int)(startPos.x + dirInfo.stepX * 0.0001f); int Y = (int)(startPos.y + dirInfo.stepY * 0.0001f); int Z = (int)(startPos.z + dirInfo.stepZ * 0.0001f); float tMaxX = (dirInfo.stepX > 0 ? (1 - (startPos.x - X)) : (startPos.x - X)) * dirInfo.tDeltaX;//沿射线走多远才能跳到下一个X格 float tMaxY = (dirInfo.stepY > 0 ? (1 - (startPos.y - Y)) : (startPos.y - Y)) * dirInfo.tDeltaY; float tMaxZ = (dirInfo.stepZ > 0 ? (1 - (startPos.z - Z)) : (startPos.z - Z)) * dirInfo.tDeltaZ; int outSizeX = dirInfo.stepX > 0 ? rtm.getSizeX() : -1; int outSizeY = dirInfo.stepY > 0 ? rtm.getSizeY() : -1; int outSizeZ = dirInfo.stepZ > 0 ? rtm.getSizeZ() : -1; while (true) { if (tMaxX < tMaxY) { if (tMaxX < tMaxZ) { X += dirInfo.stepX; if (X == outSizeX) { return(new RayCastResult(false, X, Y, Z, dirInfo.stepX > 0 ? Face.FNI_x0 : Face.FNI_x1, tMaxX)); } else { if (tMaxX > maxLength) { return(new RayCastResult(false, X, Y, Z, Face.FNI_OutOfLength, tMaxX)); } else if (rtm.testBlock(X, Y, Z, mask)) { return(new RayCastResult(true, X, Y, Z, dirInfo.stepX > 0 ? Face.FNI_x0 : Face.FNI_x1, tMaxX)); } } tMaxX += dirInfo.tDeltaX; } else { Z += dirInfo.stepZ; if (Z == outSizeZ) { return(new RayCastResult(false, X, Y, Z, dirInfo.stepZ > 0 ? Face.FNI_z0 : Face.FNI_z1, tMaxZ)); } else { if (tMaxZ > maxLength) { return(new RayCastResult(false, X, Y, Z, Face.FNI_OutOfLength, tMaxZ)); } else if (rtm.testBlock(X, Y, Z, mask)) { return(new RayCastResult(true, X, Y, Z, dirInfo.stepZ > 0 ? Face.FNI_z0 : Face.FNI_z1, tMaxZ)); } } tMaxZ += dirInfo.tDeltaZ; } } else { if (tMaxY < tMaxZ) { Y += dirInfo.stepY; if (Y == outSizeY) { return(new RayCastResult(false, X, Y, Z, dirInfo.stepY > 0 ? Face.FNI_y0 : Face.FNI_y1, tMaxY)); } else { if (tMaxY > maxLength) { return(new RayCastResult(false, X, Y, Z, Face.FNI_OutOfLength, tMaxY)); } else if (rtm.testBlock(X, Y, Z, mask)) { return(new RayCastResult(true, X, Y, Z, dirInfo.stepY > 0 ? Face.FNI_y0 : Face.FNI_y1, tMaxY)); } } tMaxY += dirInfo.tDeltaY; } else { Z += dirInfo.stepZ; if (Z == outSizeZ) { return(new RayCastResult(false, X, Y, Z, dirInfo.stepZ > 0 ? Face.FNI_z0 : Face.FNI_z1, tMaxZ)); } else { if (tMaxZ > maxLength) { return(new RayCastResult(false, X, Y, Z, Face.FNI_OutOfLength, tMaxZ)); } else if (rtm.testBlock(X, Y, Z, mask)) { return(new RayCastResult(true, X, Y, Z, dirInfo.stepZ > 0 ? Face.FNI_z0 : Face.FNI_z1, tMaxZ)); } } tMaxZ += dirInfo.tDeltaZ; } } } }
void Start() { SimpleModelFactory.CreateAll(); texturePacker = new TexturePacker(); Block.BlockManager bm = new Block.BlockManager(); for (int i = 0; i < (int)Game.BlockType.Num; i++) { for (int f = 0; f < 6; f++) { Game.BlockType block = (Game.BlockType)i; texturePacker.AddTexture(block, f, TextureNameConfig.GetTextureName(block, f)); } } texturePacker.Pack(); packedTexture = texturePacker.GetPackedTexture(); BlockTypeFun blockTypeFun = new BlockTypeFun(); blockTypeFun.texturePacker = texturePacker; //float startTime = Time.realtimeSinceStartup; int WorldSizeX = 1; int WorldSizeY = 1; int WorldSizeZ = 1; //申请内存 bm.create(WorldSizeX * Const.ChunkSize, WorldSizeY * Const.ChunkSize, WorldSizeZ * Const.ChunkSize, blockTypeFun); bm.setBlock(3, 4, 4, (int)Game.BlockType.StairLeft); bm.setBlock(5, 4, 4, (int)Game.BlockType.StairRight); bm.setBlock(4, 4, 3, (int)Game.BlockType.StairBack); bm.setBlock(4, 4, 5, (int)Game.BlockType.StairFront); //光线追踪初始化 Block.RayCastManager rtm = new Block.RayCastManager(); rtm.create(bm.SizeX, bm.SizeY, bm.SizeZ); for (int x = 0; x < bm.SizeX; x++) { for (int y = 0; y < bm.SizeY; y++) { for (int z = 0; z < bm.SizeZ; z++) { rtm.setBlock(x, y, z, bm.getBlock(x, y, z) != 0 ? RayCastBlockType.All : RayCastBlockType.Nothing); } } } //初始化AO计算 rma = new Block.RayMarchingAo(); rma.Init(rtm); ViewVoxel viewVoxel = GameObject.FindObjectOfType <ViewVoxel>(); if (viewVoxel) { Texture3D voxelTex3D = rma.GetVoxelTexture(); viewVoxel.SetVexelTex(voxelTex3D); } Material mat = GlobalResources.getBlockMaterial(); mat.mainTexture = texturePacker.GetPackedTexture(); GameObject root = this.gameObject; if (root == null) { root = new GameObject("Root"); } //创建网格 for (int i = 0; i < WorldSizeX; i++) { for (int k = 0; k < WorldSizeZ; k++) { for (int j = 0; j < WorldSizeY; j++) { Block.BlockChunk chunk = new BlockChunk(bm, i * Const.ChunkSize, j * Const.ChunkSize, k * Const.ChunkSize); //TerrainTool.calcChunkLight(chunk, i, j, k, rtm, rays, sunDir); //Mesh mesh = MeshTool.createMesh(chunk, blockTypeFun, 0, 0, 0); for (int f = 0; f < 6; f++) { List <Block.MeshTool.BlockSurface> surface = Block.MeshTool.getChunkSurface(chunk, blockTypeFun, f); Texture2D texSurface = Block.MeshTool.SurfacePointsToTexture(surface, f); RenderTexture targetAoResult = rma.RenderByCalcShader(texSurface, new Vector3(i, j, k) * Block.Const.ChunkSize, f); //回读亮度数据 RenderTexture.active = targetAoResult; Texture2D readback = new Texture2D(targetAoResult.width, targetAoResult.height); readback.ReadPixels(new Rect(0, 0, targetAoResult.width, targetAoResult.width), 0, 0); Block.MeshTool.SetRaytraceAo(surface, readback); Mesh mesh = Block.MeshTool.createMesh2(surface, f, blockTypeFun); if (mesh != null) { GameObject obj = new GameObject("Chunk", typeof(MeshRenderer), typeof(MeshFilter)); obj.isStatic = true; obj.GetComponent <Renderer>().material = mat; obj.GetComponent <MeshFilter>().mesh = mesh; obj.transform.SetParent(root.transform); obj.transform.position = new Vector3(i * Block.Const.ChunkSize * Block.Const.BlockSize, j * Block.Const.ChunkSize * Block.Const.BlockSize, k * Block.Const.ChunkSize * Block.Const.BlockSize); } } } } } }