mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-13 09:26:11 -04:00
optimize Mat4 math, skeletal: reduce memory allocations
This commit is contained in:
parent
8c61605c88
commit
d0ea37e93a
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -24,7 +24,7 @@ class DummyFloatUniformBuffer(
|
||||
) : FloatUniformBuffer {
|
||||
override val bindingIndex: Int = 0
|
||||
|
||||
override fun upload(range: IntRange) {
|
||||
override fun upload(start: Int, end: Int) {
|
||||
}
|
||||
|
||||
override fun upload() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -23,7 +23,7 @@ class DummyIntUniformBuffer(
|
||||
) : IntUniformBuffer {
|
||||
override val bindingIndex: Int = 0
|
||||
|
||||
override fun upload(range: IntRange) {
|
||||
override fun upload(start: Int, end: Int) {
|
||||
}
|
||||
|
||||
override fun upload() {
|
||||
|
@ -36,7 +36,7 @@ class ChestAnimation(
|
||||
transform.value
|
||||
.translateAssign(transform.pivot)
|
||||
.rotateRadAssign(rotation)
|
||||
.translateAssign(-transform.pivot)
|
||||
.translateAssign(transform.nPivot)
|
||||
}
|
||||
|
||||
|
||||
|
@ -37,7 +37,7 @@ class ShulkerAnimation(
|
||||
.translateAssign(translation)
|
||||
.translateAssign(transform.pivot)
|
||||
.rotateRadAssign(rotation)
|
||||
.translateAssign(-transform.pivot)
|
||||
.translateAssign(transform.nPivot)
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,6 +24,7 @@ class SkeletalManager(
|
||||
) {
|
||||
private val uniformBuffer = context.system.createFloatUniformBuffer(memAllocFloat(MAX_TRANSFORMS * Mat4.length))
|
||||
val shader = context.system.createShader(minosoft("skeletal")) { SkeletalShader(it, uniformBuffer) }
|
||||
private val temp = Mat4()
|
||||
|
||||
fun init() {
|
||||
uniformBuffer.init()
|
||||
@ -36,8 +37,8 @@ class SkeletalManager(
|
||||
}
|
||||
|
||||
fun upload(instance: SkeletalInstance) {
|
||||
instance.transform.pack(uniformBuffer.buffer, instance.position, Mat4())
|
||||
uniformBuffer.upload(0 until instance.model.transformCount * Mat4.length)
|
||||
instance.transform.pack(uniformBuffer.buffer, instance.position, temp)
|
||||
uniformBuffer.upload(0, instance.model.transformCount * Mat4.length)
|
||||
}
|
||||
|
||||
fun draw(instance: SkeletalInstance, light: Int) {
|
||||
|
@ -23,6 +23,7 @@ class TransformInstance(
|
||||
val pivot: Vec3,
|
||||
val children: Map<String, TransformInstance>,
|
||||
) {
|
||||
val nPivot = -pivot
|
||||
val value = Mat4()
|
||||
|
||||
|
||||
|
@ -36,7 +36,7 @@ data class RotateKeyframe(
|
||||
override fun instance() = object : Vec3KeyframeInstance(data, loop, interpolation) {
|
||||
override fun apply(value: Vec3, transform: TransformInstance) {
|
||||
transform.value
|
||||
.translateAssign(-transform.pivot)
|
||||
.translateAssign(transform.nPivot)
|
||||
.rotateRadAssign(value)
|
||||
.translateAssign(transform.pivot)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -19,7 +19,7 @@ import de.bixilon.minosoft.gui.rendering.system.base.shader.NativeShader
|
||||
interface UniformBuffer : RenderableBuffer {
|
||||
val bindingIndex: Int
|
||||
|
||||
fun upload(range: IntRange)
|
||||
fun upload(start: Int, end: Int)
|
||||
|
||||
fun use(shader: NativeShader, bufferName: String)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -42,13 +42,13 @@ class FloatOpenGLUniformBuffer(renderSystem: OpenGLRenderSystem, bindingIndex: I
|
||||
unbind()
|
||||
}
|
||||
|
||||
override fun upload(range: IntRange) {
|
||||
override fun upload(start: Int, end: Int) {
|
||||
check(initialSize == size) { "Can not change buffer size!" }
|
||||
if (range.first < 0 || range.last >= size) {
|
||||
throw IndexOutOfBoundsException(range.first)
|
||||
if (start < 0 || end >= size) {
|
||||
throw IndexOutOfBoundsException(start)
|
||||
}
|
||||
bind()
|
||||
nglBufferSubData(type.gl, range.first * 4L, Integer.toUnsignedLong(((range.last + 1) - range.first) * 4), MemoryUtil.memAddress(buffer, range.first))
|
||||
nglBufferSubData(type.gl, start * 4L, Integer.toUnsignedLong(((end + 1) - start) * 4), MemoryUtil.memAddress(buffer, start))
|
||||
unbind()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -37,5 +37,5 @@ class IntOpenGLUniformBuffer(renderSystem: OpenGLRenderSystem, bindingIndex: Int
|
||||
unbind()
|
||||
}
|
||||
|
||||
override fun upload(range: IntRange) = TODO("Unsupported")
|
||||
override fun upload(start: Int, end: Int) = TODO("Unsupported")
|
||||
}
|
||||
|
@ -13,12 +13,10 @@
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.util.mat.mat4
|
||||
|
||||
import de.bixilon.kotlinglm.GLM
|
||||
import de.bixilon.kotlinglm.func.rad
|
||||
import de.bixilon.kotlinglm.mat4x4.Mat4
|
||||
import de.bixilon.kotlinglm.vec3.Vec3
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.X
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.Y
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.Z
|
||||
|
||||
object Mat4Util {
|
||||
private val empty = Mat4()
|
||||
@ -26,16 +24,16 @@ object Mat4Util {
|
||||
val Mat4.Companion.EMPTY_INSTANCE get() = empty
|
||||
|
||||
fun Mat4.rotateDegreesAssign(rotation: Vec3): Mat4 {
|
||||
if (rotation.x != 0.0f) rotateAssign(rotation.x.rad, Vec3.X)
|
||||
if (rotation.y != 0.0f) rotateAssign(rotation.y.rad, Vec3.Y)
|
||||
if (rotation.z != 0.0f) rotateAssign(rotation.z.rad, Vec3.Z)
|
||||
if (rotation.x != 0.0f) rotateX(this, rotation.x.rad)
|
||||
if (rotation.y != 0.0f) rotateY(this, rotation.y.rad)
|
||||
if (rotation.z != 0.0f) rotateZ(this, rotation.z.rad)
|
||||
return this
|
||||
}
|
||||
|
||||
fun Mat4.rotateRadAssign(rotation: Vec3): Mat4 {
|
||||
if (rotation.x != 0.0f) rotateAssign(rotation.x, Vec3.X)
|
||||
if (rotation.y != 0.0f) rotateAssign(rotation.y, Vec3.Y)
|
||||
if (rotation.z != 0.0f) rotateAssign(rotation.z, Vec3.Z)
|
||||
if (rotation.x != 0.0f) rotateX(this, rotation.x)
|
||||
if (rotation.y != 0.0f) rotateY(this, rotation.y)
|
||||
if (rotation.z != 0.0f) rotateZ(this, rotation.z)
|
||||
return this
|
||||
}
|
||||
|
||||
@ -53,9 +51,123 @@ object Mat4Util {
|
||||
|
||||
fun Mat4.reset() {
|
||||
val array = this.array
|
||||
array[0] = 1.0f; array[1] = 0.0f;array[2] = 0.0f;array[3] = 0.0f
|
||||
array[4] = 0.0f; array[5] = 1.0f;array[6] = 0.0f;array[7] = 0.0f
|
||||
array[8] = 0.0f; array[9] = 0.0f;array[10] = 1.0f;array[11] = 0.0f
|
||||
array[12] = 0.0f; array[13] = 0.0f;array[14] = 0.0f;array[15] = 1.0f
|
||||
System.arraycopy(empty.array, 0, array, 0, Mat4.length)
|
||||
}
|
||||
|
||||
fun rotateX(m: Mat4, angle: Float) {
|
||||
val c = GLM.cos(angle)
|
||||
val s = GLM.sin(angle)
|
||||
|
||||
val dot = angle * angle
|
||||
val inv = GLM.inverseSqrt(dot)
|
||||
|
||||
val aX = angle * inv
|
||||
|
||||
val tempX = (1f - c) * aX
|
||||
|
||||
val rotate00 = c + tempX * aX
|
||||
|
||||
val rotate12 = s * aX
|
||||
val rotate11 = c
|
||||
|
||||
val rotate21 = -s * aX
|
||||
|
||||
m[0, 0] = m[0, 0] * rotate00
|
||||
m[0, 1] = m[0, 1] * rotate00
|
||||
m[0, 2] = m[0, 2] * rotate00
|
||||
m[0, 3] = m[0, 3] * rotate00
|
||||
|
||||
val res1x = m[1, 0] * rotate11 + m[2, 0] * rotate12
|
||||
val res1y = m[1, 1] * rotate11 + m[2, 1] * rotate12
|
||||
val res1z = m[1, 2] * rotate11 + m[2, 2] * rotate12
|
||||
val res1w = m[1, 3] * rotate11 + m[2, 3] * rotate12
|
||||
|
||||
m[2, 0] = m[1, 0] * rotate21 + m[2, 0] * c
|
||||
m[2, 1] = m[1, 1] * rotate21 + m[2, 1] * c
|
||||
m[2, 2] = m[1, 2] * rotate21 + m[2, 2] * c
|
||||
m[2, 3] = m[1, 3] * rotate21 + m[2, 3] * c
|
||||
|
||||
m[1, 0] = res1x
|
||||
m[1, 1] = res1y
|
||||
m[1, 2] = res1z
|
||||
m[1, 3] = res1w
|
||||
}
|
||||
|
||||
fun rotateY(m: Mat4, angle: Float) {
|
||||
val c = GLM.cos(angle)
|
||||
val s = GLM.sin(angle)
|
||||
|
||||
val dot = angle * angle
|
||||
val inv = GLM.inverseSqrt(dot)
|
||||
|
||||
val aY = angle * inv
|
||||
|
||||
val tempY = (1f - c) * aY
|
||||
|
||||
val rotate02 = -s * aY
|
||||
|
||||
val rotate11 = c + tempY * aY
|
||||
|
||||
val rotate20 = s * aY
|
||||
|
||||
|
||||
val res0x = m[0, 0] * c + m[2, 0] * rotate02
|
||||
val res0y = m[0, 1] * c + m[2, 1] * rotate02
|
||||
val res0z = m[0, 2] * c + m[2, 2] * rotate02
|
||||
val res0w = m[0, 3] * c + m[2, 3] * rotate02
|
||||
|
||||
m[1, 0] = m[1, 0] * rotate11
|
||||
m[1, 1] = m[1, 1] * rotate11
|
||||
m[1, 2] = m[1, 2] * rotate11
|
||||
m[1, 3] = m[1, 3] * rotate11
|
||||
|
||||
m[2, 0] = m[0, 0] * rotate20 + m[2, 0] * c
|
||||
m[2, 1] = m[0, 1] * rotate20 + m[2, 1] * c
|
||||
m[2, 2] = m[0, 2] * rotate20 + m[2, 2] * c
|
||||
m[2, 3] = m[0, 3] * rotate20 + m[2, 3] * c
|
||||
|
||||
m[0, 0] = res0x
|
||||
m[0, 1] = res0y
|
||||
m[0, 2] = res0z
|
||||
m[0, 3] = res0w
|
||||
}
|
||||
|
||||
fun rotateZ(m: Mat4, angle: Float) {
|
||||
val c = GLM.cos(angle)
|
||||
val s = GLM.sin(angle)
|
||||
|
||||
val dot = angle * angle
|
||||
val inv = GLM.inverseSqrt(dot)
|
||||
|
||||
val aZ = angle * inv
|
||||
|
||||
val tempZ = (1f - c) * aZ
|
||||
|
||||
val rotate01 = s * aZ
|
||||
|
||||
val rotate10 = -s * aZ
|
||||
|
||||
val rotate22 = c + tempZ * aZ
|
||||
|
||||
|
||||
val res0x = m[0, 0] * c + m[1, 0] * rotate01
|
||||
val res0y = m[0, 1] * c + m[1, 1] * rotate01
|
||||
val res0z = m[0, 2] * c + m[1, 2] * rotate01
|
||||
val res0w = m[0, 3] * c + m[1, 3] * rotate01
|
||||
|
||||
m[1, 0] = m[0, 0] * rotate10 + m[1, 0] * c
|
||||
m[1, 1] = m[0, 1] * rotate10 + m[1, 1] * c
|
||||
m[1, 2] = m[0, 2] * rotate10 + m[1, 2] * c
|
||||
m[1, 3] = m[0, 3] * rotate10 + m[1, 3] * c
|
||||
|
||||
m[2, 0] = m[2, 0] * rotate22
|
||||
m[2, 1] = m[2, 1] * rotate22
|
||||
m[2, 2] = m[2, 2] * rotate22
|
||||
m[2, 3] = m[2, 3] * rotate22
|
||||
|
||||
m[0, 0] = res0x
|
||||
m[0, 1] = res0y
|
||||
m[0, 2] = res0z
|
||||
m[0, 3] = res0w
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.util.mat.mat4
|
||||
|
||||
import de.bixilon.kotlinglm.func.rad
|
||||
import de.bixilon.kotlinglm.mat4x4.Mat4
|
||||
import de.bixilon.kotlinglm.vec3.Vec3
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class Mat4UtilTest {
|
||||
|
||||
@Test
|
||||
fun `custom rotateX`() {
|
||||
val expected = Mat4().rotateAssign(12.0f.rad, Vec3(1, 0, 0))
|
||||
val actual = Mat4().apply { Mat4Util.rotateX(this, 12.0f.rad) }
|
||||
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `custom rotateY`() {
|
||||
val expected = Mat4().rotateAssign(12.0f.rad, Vec3(0, 1, 0))
|
||||
val actual = Mat4().apply { Mat4Util.rotateY(this, 12.0f.rad) }
|
||||
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `custom rotateZ`() {
|
||||
val expected = Mat4().rotateAssign(12.0f.rad, Vec3(0, 0, 1))
|
||||
val actual = Mat4().apply { Mat4Util.rotateZ(this, 12.0f.rad) }
|
||||
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user