由于vox中存放的是每一个体素的xyz坐标,而用opengl渲染需要知道每一个顶点的坐标和索引,于是需要计算每个体素的顶点、法线,并且剔除不需要被渲染的面
存放剔除后的数据
class OptVoxel (
var palette: List<Long>,
val size: Int3,
val fronts: ByteArray,
val backs: ByteArray,
val lefts: ByteArray,
val rights: ByteArray,
val tops: ByteArray,
val bottoms: ByteArray
)
在VoxelChunk.kt中实现剔除方法
fun optimization(): OptVoxel {
var buffer: ByteArray? = ByteArray(size.dot) { 0 }
val fronts = ByteArray(size.dot){ 0 }
val backs = ByteArray(size.dot){ 0 }
val lefts = ByteArray(size.dot){ 0 }
val rights = ByteArray(size.dot){ 0 }
val tops = ByteArray(size.dot){ 0 }
val bottoms = ByteArray(size.dot){ 0 }
var i = 0
val temp = Int3(size.x, size.y, size.z)
size.y = temp.z
size.z = temp.y
// vox中z是高度,转成y
while(i<data.size){
val x = this[i++]
val z = temp.y-this[i++]-1
val y = this[i++]
val c = data[i++]
buffer!![size[x,y,z]] = c
}
val b0: Byte = 0
// 判断是否需要渲染对应的面
for(x in 0 until size.x) {
for(y in 0 until size.y){
for(z in 0 until size.z) {
val c = buffer!![size[x,y,z]]
if(c==b0)continue
if(y>1) {
if(buffer[size[x,y-1,z]]==b0){
bottoms[size[x,y,z]] = c
}
}else{
bottoms[size[x,y,z]] = c
}
if(y<size.y-1) {
if(buffer[size[x,y+1,z]]==b0){
tops[size[x,y,z]] = c
}
}else{
tops[size[x,y,z]] = c
}
if(x>1) {
if(buffer[size[x-1,y,z]]==b0){
lefts[size[x,y,z]] = c
}
}else{
lefts[size[x,y,z]] = c
}
if(x<size.x-1) {
if(buffer[size[x+1,y,z]]==b0){
rights[size[x,y,z]] = c
}
}else{
rights[size[x,y,z]] = c
}
if(z>1) {
if(buffer[size[x,y,z-1]]==b0){
backs[size[x,y,z]] = c
}
}else{
backs[size[x,y,z]] = c
}
if(z<size.z-1) {
if(buffer[size[x,y,z+1]]==b0){
fronts[size[x,y,z]] = c
}
}else{
fronts[size[x,y,z]] = c
}
}
}
}
buffer = null
size.y = temp.y
size.z = temp.z
return OptVoxel(
palette, Int3(size.x,size.z,size.y), fronts, backs, lefts, rights, tops, bottoms
)
}
operator fun get(i: Int): Int {
return data[i].toInt() and 0xFF
}
在OptVoxel.kt中实现转换成顶点数据和索引数据
fun rgbf(i: Int): Triple<Float, Float, Float> {
val hex = palette[i]
val r = ((hex shr 0) and 0xff) / 255f
val g = ((hex shr 8) and 0xff) / 255f
val b = ((hex shr 16) and 0xff) / 255f
return Triple(r,g,b)
}
fun rgbi(i: Int): Triple<Int, Int, Int> {
val hex = palette[i]
val r = ((hex shr 0) and 0xff).toInt()
val g = ((hex shr 8) and 0xff).toInt()
val b = ((hex shr 16) and 0xff).toInt()
return Triple(r,g,b)
}
fun buildArray(): Pair<FloatArray, IntArray> {
val vertices = mutableListOf<Float>()
val s1 = Int3(size.x+1,size.y+1,size.z+1)
val vertIndex = mutableMapOf<String, Int>()
val indices = mutableListOf<Int>()
val b0: Byte = 0
var nv = 0
for(x in 0 until size.x) {
for (y in 0 until size.y) {
for (z in 0 until size.z) {
if(tops[size[x,y,z]]!=b0) {
val c = tops[size[x,y,z]].toInt() and 0xFF
val (r,g,b) = rgbf(c)
val p1 = s1[x,y+1,z]
val p2 = s1[x+1,y+1,z]
val p3 = s1[x,y+1,z+1]
val p4 = s1[x+1,y+1,z+1]
if(vertIndex[0,p1,c]==-1){
vertices.add(x,y+1,z,0,1,0,r,g,b,1f)
vertIndex[0,p1,c] = nv++
}
if(vertIndex[0,p2,c]==-1){
vertices.add(x+1,y+1,z,0,1,0,r,g,b,1f)
vertIndex[0,p2,c] = nv++
}
if(vertIndex[0,p3,c]==-1){
vertices.add(x,y+1,z+1,0,1,0,r,g,b,1f)
vertIndex[0,p3,c] = nv++
}
if(vertIndex[0,p4,c]==-1){
vertices.add(x+1,y+1,z+1,0,1,0,r,g,b,1f)
vertIndex[0,p4,c] = nv++
}
indices.add(vertIndex[0,p1,c])
indices.add(vertIndex[0,p2,c])
indices.add(vertIndex[0,p3,c])
indices.add(vertIndex[0,p2,c])
indices.add(vertIndex[0,p4,c])
indices.add(vertIndex[0,p3,c])
}
if(bottoms[size[x,y,z]]!=b0) {
val c = bottoms[size[x,y,z]].toInt() and 0xFF
val (r,g,b) = rgbf(c)
val p1 = s1[x,y,z+1]
val p2 = s1[x+1,y,z+1]
val p3 = s1[x,y,z]
val p4 = s1[x+1,y,z]
if(vertIndex[1,p1,c]==-1){
vertices.add(x,y,z+1,0,-1,0,r,g,b,1f)
vertIndex[1,p1,c] = nv++
}
if(vertIndex[1,p2,c]==-1){
vertices.add(x+1,y,z+1,0,-1,0,r,g,b,1f)
vertIndex[1,p2,c] = nv++
}
if(vertIndex[1,p3,c]==-1){
vertices.add(x,y,z,0,-1,0,r,g,b,1f)
vertIndex[1,p3,c] = nv++
}
if(vertIndex[1,p4,c]==-1){
vertices.add(x+1,y,z,0,-1,0,r,g,b,1f)
vertIndex[1,p4,c] = nv++
}
indices.add(vertIndex[1,p1,c])
indices.add(vertIndex[1,p2,c])
indices.add(vertIndex[1,p3,c])
indices.add(vertIndex[1,p2,c])
indices.add(vertIndex[1,p4,c])
indices.add(vertIndex[1,p3,c])
}
if(lefts[size[x,y,z]]!=b0) {
val c = lefts[size[x,y,z]].toInt() and 0xFF
val (r,g,b) = rgbf(c)
val p1 = s1[x,y+1,z]
val p2 = s1[x,y+1,z+1]
val p3 = s1[x,y,z]
val p4 = s1[x,y,z+1]
if(vertIndex[2,p1,c]==-1){
vertices.add(x,y+1,z,-1,0,0,r,g,b,1f)
vertIndex[2,p1,c] = nv++
}
if(vertIndex[2,p2,c]==-1){
vertices.add(x,y+1,z+1,-1,0,0,r,g,b,1f)
vertIndex[2,p2,c] = nv++
}
if(vertIndex[2,p3,c]==-1){
vertices.add(x,y,z,-1,0,0,r,g,b,1f)
vertIndex[2,p3,c] = nv++
}
if(vertIndex[2,p4,c]==-1){
vertices.add(x,y,z+1,-1,0,0,r,g,b,1f)
vertIndex[2,p4,c] = nv++
}
indices.add(vertIndex[2,p1,c])
indices.add(vertIndex[2,p2,c])
indices.add(vertIndex[2,p3,c])
indices.add(vertIndex[2,p2,c])
indices.add(vertIndex[2,p4,c])
indices.add(vertIndex[2,p3,c])
}
if(rights[size[x,y,z]]!=b0) {
val c = rights[size[x,y,z]].toInt() and 0xFF
val (r,g,b) = rgbf(c)
val p1 = s1[x+1,y+1,z+1]
val p2 = s1[x+1,y+1,z]
val p3 = s1[x+1,y,z+1]
val p4 = s1[x+1,y,z]
if(vertIndex[3,p1,c]==-1){
vertices.add(x+1,y+1,z+1,1,0,0,r,g,b,1f)
vertIndex[3,p1,c] = nv++
}
if(vertIndex[3,p2,c]==-1){
vertices.add(x+1,y+1,z,1,0,0,r,g,b,1f)
vertIndex[3,p2,c] = nv++
}
if(vertIndex[3,p3,c]==-1){
vertices.add(x+1,y,z+1,1,0,0,r,g,b,1f)
vertIndex[3,p3,c] = nv++
}
if(vertIndex[3,p4,c]==-1){
vertices.add(x+1,y,z,1,0,0,r,g,b,1f)
vertIndex[3,p4,c] = nv++
}
indices.add(vertIndex[3,p1,c])
indices.add(vertIndex[3,p2,c])
indices.add(vertIndex[3,p3,c])
indices.add(vertIndex[3,p2,c])
indices.add(vertIndex[3,p4,c])
indices.add(vertIndex[3,p3,c])
}
if(fronts[size[x,y,z]]!=b0) {
val c = fronts[size[x,y,z]].toInt() and 0xFF
val (r,g,b) = rgbf(c)
val p1 = s1[x,y+1,z+1]
val p2 = s1[x+1,y+1,z+1]
val p3 = s1[x,y,z+1]
val p4 = s1[x+1,y,z+1]
if(vertIndex[4,p1,c]==-1){
vertices.add(x,y+1,z+1,0,0,1,r,g,b,1f)
vertIndex[4,p1,c] = nv++
}
if(vertIndex[4,p2,c]==-1){
vertices.add(x+1,y+1,z+1,0,0,1,r,g,b,1f)
vertIndex[4,p2,c] = nv++
}
if(vertIndex[4,p3,c]==-1){
vertices.add(x,y,z+1,0,0,1,r,g,b,1f)
vertIndex[4,p3,c] = nv++
}
if(vertIndex[4,p4,c]==-1){
vertices.add(x+1,y,z+1,0,0,1,r,g,b,1f)
vertIndex[4,p4,c] = nv++
}
indices.add(vertIndex[4,p1,c])
indices.add(vertIndex[4,p2,c])
indices.add(vertIndex[4,p3,c])
indices.add(vertIndex[4,p2,c])
indices.add(vertIndex[4,p4,c])
indices.add(vertIndex[4,p3,c])
}
if(backs[size[x,y,z]]!=b0) {
val c = backs[size[x,y,z]].toInt() and 0xFF
val (r,g,b) = rgbf(c)
val p1 = s1[x+1,y+1,z]
val p2 = s1[x,y+1,z]
val p3 = s1[x+1,y,z]
val p4 = s1[x,y,z]
if(vertIndex[5,p1,c]==-1){
vertices.add(x+1,y+1,z,0,0,-1,r,g,b,1f)
vertIndex[5,p1,c] = nv++
}
if(vertIndex[5,p2,c]==-1){
vertices.add(x,y+1,z,0,0,-1,r,g,b,1f)
vertIndex[5,p2,c] = nv++
}
if(vertIndex[5,p3,c]==-1){
vertices.add(x+1,y,z,0,0,-1,r,g,b,1f)
vertIndex[5,p3,c] = nv++
}
if(vertIndex[5,p4,c]==-1){
vertices.add(x,y,z,0,0,-1,r,g,b,1f)
vertIndex[5,p4,c] = nv++
}
indices.add(vertIndex[5,p1,c])
indices.add(vertIndex[5,p2,c])
indices.add(vertIndex[5,p3,c])
indices.add(vertIndex[5,p2,c])
indices.add(vertIndex[5,p4,c])
indices.add(vertIndex[5,p3,c])
}
}
}
}
println("顶点数:${vertices.size},索引数:${indices.size},点数:${vertices.size/10},面数:${indices.size/3}")
return vertices.toFloatArray() to indices.toIntArray()
}
fun MutableList<Float>.add(x: Int,y: Int,z: Int,nx: Int,ny: Int,nz: Int,r: Float,g: Float,b: Float,a: Float): MutableList<Float> {
this.add(x,y,z,nx,ny,nz).add(r,g,b,a)
return this
}
fun MutableList<Float>.add(vararg i: Int): MutableList<Float> {
i.forEach { add(it.toFloat()) }
return this
}
fun MutableList<Float>.add(vararg i: Float): MutableList<Float> {
i.forEach { add(it) }
return this
}
operator fun MutableMap<String, Int>.get(i: Int,j: Int,k: Int): Int {
return this["$i-$j-$k"]?:-1
}
operator fun MutableMap<String, Int>.set(i: Int,j: Int,k: Int, v: Int) {
this["$i-$j-$k"] = v
}
完整代码在github中