Skip to content

kotlin voxel解析 二

Published:

由于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


Previous Post
kotlin voxel解析 三
Next Post
kotlin voxel解析 一