More shadows tests
This commit is contained in:
parent
4198483974
commit
5c697c129e
@ -52,8 +52,8 @@ fun main() {
|
||||
var set = 0L
|
||||
var parse = 0L
|
||||
|
||||
for (chunkX in 0 .. 94) {
|
||||
for (chunkY in 0 .. 61) {
|
||||
for (chunkX in 17 .. 18) {
|
||||
for (chunkY in 21 .. 21) {
|
||||
var t = System.currentTimeMillis()
|
||||
val data = db.read(byteArrayOf(1, 0, chunkX.toByte(), 0, chunkY.toByte()))
|
||||
find += System.currentTimeMillis() - t
|
||||
@ -179,6 +179,7 @@ fun main() {
|
||||
client.gl.font.render("${ent.position}", y = 100f, scale = 0.25f)
|
||||
client.gl.font.render("${ent.movement.velocity}", y = 120f, scale = 0.25f)
|
||||
client.gl.font.render("${client.camera.pos} ${client.settings.zoom}", y = 140f, scale = 0.25f)
|
||||
client.gl.font.render("${ChunkPos.fromTilePosition(client.camera.pos.toDoubleVector())}", y = 160f, scale = 0.25f)
|
||||
}
|
||||
|
||||
client.onPreDrawWorld {
|
||||
|
@ -9,6 +9,7 @@ import ru.dbotthepony.kstarbound.client.gl.program.GLSoftLightGeometryProgram
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StatefulVertexBuilder
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.shadowLine
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.shadowQuad
|
||||
import ru.dbotthepony.kstarbound.client.render.ConfiguredStaticMesh
|
||||
import ru.dbotthepony.kstarbound.client.render.EntityRenderer
|
||||
@ -20,6 +21,7 @@ import ru.dbotthepony.kstarbound.world.*
|
||||
import ru.dbotthepony.kstarbound.world.entities.Entity
|
||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
|
||||
import ru.dbotthepony.kvector.util2d.intersectCircleRectangle
|
||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
||||
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
|
||||
@ -207,75 +209,89 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
||||
foregroundRenderer.autoUpload()
|
||||
}
|
||||
|
||||
private val hardShadowGeometry = StatefulVertexBuilder(state, LightRenderer.SHADOW_FORMAT, GeometryType.QUADS_AS_LINES)
|
||||
private var hardShadowGeometryRev = -1
|
||||
private val softShadowGeometry = StatefulVertexBuilder(state, LightRenderer.SHADOW_FORMAT_SOFT, GeometryType.QUADS_ALTERNATIVE)
|
||||
private var softShadowGeometryRev = -1
|
||||
private inner class ShadowGeometryTracker(val x: Int, val y: Int) : LightRenderer.ShadowGeometryRenderer {
|
||||
private val hardShadowGeometry = StatefulVertexBuilder(state, LightRenderer.SHADOW_FORMAT, GeometryType.LINES)
|
||||
private var hardShadowGeometryRev = -1
|
||||
private val softShadowGeometry = StatefulVertexBuilder(state, LightRenderer.SHADOW_FORMAT_SOFT, GeometryType.QUADS_ALTERNATIVE)
|
||||
private var softShadowGeometryRev = -1
|
||||
|
||||
val shadowGeometry: LightRenderer.ShadowGeometryRenderer get() {
|
||||
return object : LightRenderer.ShadowGeometryRenderer {
|
||||
override fun renderHardGeometry(
|
||||
renderer: LightRenderer,
|
||||
lightPosition: Vector2f,
|
||||
stack: Matrix4fStack,
|
||||
program: GLHardLightGeometryProgram
|
||||
) {
|
||||
if (hardShadowGeometryRev == tileChangeset) {
|
||||
program.localToWorldTransform.set(Matrix4f.IDENTITY.translateWithMultiplication(Vector3f(x = pos.x * CHUNK_SIZEf, y = pos.y * CHUNK_SIZEf)))
|
||||
hardShadowGeometry.draw(GL_LINES)
|
||||
return
|
||||
}
|
||||
private fun buildGeometry(builder: StatefulVertexBuilder, line: (StatefulVertexBuilder, Float, Float, Float, Float) -> Unit) {
|
||||
builder.begin()
|
||||
|
||||
hardShadowGeometryRev = tileChangeset
|
||||
for (x in this.x * SHADOW_GEOMETRY_SQUARE_SIZE until (this.x + 1) * SHADOW_GEOMETRY_SQUARE_SIZE) {
|
||||
for (y in this.y * SHADOW_GEOMETRY_SQUARE_SIZE until (this.y + 1) * SHADOW_GEOMETRY_SQUARE_SIZE) {
|
||||
if (foreground[x, y].material?.renderParameters?.lightTransparent == false) {
|
||||
if (x == 0 || foreground[x - 1, y].material?.renderParameters?.lightTransparent != true) {
|
||||
line(builder, x.toFloat(), y.toFloat(), x.toFloat(), y + 1f)
|
||||
}
|
||||
|
||||
val builder = hardShadowGeometry
|
||||
if (x == CHUNK_SIZE - 1 || foreground[x + 1, y].material?.renderParameters?.lightTransparent != true) {
|
||||
line(builder, x + 1f, y.toFloat(), x + 1f, y + 1f)
|
||||
}
|
||||
|
||||
builder.begin()
|
||||
if (y == 0 || foreground[x, y - 1].material?.renderParameters?.lightTransparent != true) {
|
||||
line(builder, x.toFloat(), y.toFloat(), x + 1f, y.toFloat())
|
||||
}
|
||||
|
||||
for (x in 0 until CHUNK_SIZE) {
|
||||
for (y in 0 until CHUNK_SIZE) {
|
||||
if (foreground[x, y].material != null) {
|
||||
builder.quad(x.toFloat(), y.toFloat(), x + 1f, y + 1f)
|
||||
if (y == CHUNK_SIZE - 1 || foreground[x, y + 1].material?.renderParameters?.lightTransparent != true) {
|
||||
line(builder, x.toFloat(), y + 1f, x + 1f, y + 1f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder.upload()
|
||||
|
||||
program.localToWorldTransform.set(Matrix4f.IDENTITY.translateWithMultiplication(Vector3f(x = pos.x * CHUNK_SIZEf, y = pos.y * CHUNK_SIZEf)))
|
||||
builder.draw(GL_LINES)
|
||||
}
|
||||
|
||||
override fun renderSoftGeometry(
|
||||
renderer: LightRenderer,
|
||||
lightPosition: Vector2f,
|
||||
stack: Matrix4fStack,
|
||||
program: GLSoftLightGeometryProgram
|
||||
) {
|
||||
if (softShadowGeometryRev == tileChangeset) {
|
||||
program.localToWorldTransform.set(Matrix4f.IDENTITY.translateWithMultiplication(Vector3f(x = pos.x * CHUNK_SIZEf, y = pos.y * CHUNK_SIZEf)))
|
||||
softShadowGeometry.draw(GL_TRIANGLES)
|
||||
return
|
||||
}
|
||||
builder.upload()
|
||||
}
|
||||
|
||||
softShadowGeometryRev = tileChangeset
|
||||
fun buildHardGeometry() {
|
||||
hardShadowGeometryRev = tileChangeset
|
||||
|
||||
val builder = softShadowGeometry
|
||||
buildGeometry(hardShadowGeometry) { it, x0, y0, x1, y1 ->
|
||||
it.vertex().pushVec2f(x0, y0)
|
||||
it.vertex().pushVec2f(x1, y1)
|
||||
}
|
||||
}
|
||||
|
||||
builder.begin()
|
||||
fun buildSoftGeometry() {
|
||||
softShadowGeometryRev = tileChangeset
|
||||
buildGeometry(softShadowGeometry, StatefulVertexBuilder::shadowLine)
|
||||
}
|
||||
|
||||
for (x in 0 until CHUNK_SIZE) {
|
||||
for (y in 0 until CHUNK_SIZE) {
|
||||
if (foreground[x, y].material != null) {
|
||||
builder.shadowQuad(x.toFloat(), y.toFloat(), x + 1f, y + 1f)
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun renderHardGeometry(
|
||||
renderer: LightRenderer,
|
||||
lightPosition: Vector2f,
|
||||
lightRadius: Float,
|
||||
stack: Matrix4fStack,
|
||||
program: GLHardLightGeometryProgram
|
||||
) {
|
||||
if (hardShadowGeometryRev != tileChangeset) {
|
||||
buildHardGeometry()
|
||||
}
|
||||
|
||||
builder.upload()
|
||||
hardShadowGeometry.draw(GL_LINES)
|
||||
}
|
||||
|
||||
program.localToWorldTransform.set(Matrix4f.IDENTITY.translateWithMultiplication(Vector3f(x = pos.x * CHUNK_SIZEf, y = pos.y * CHUNK_SIZEf)))
|
||||
builder.draw(GL_LINES)
|
||||
override fun renderSoftGeometry(
|
||||
renderer: LightRenderer,
|
||||
lightPosition: Vector2f,
|
||||
lightRadius: Float,
|
||||
stack: Matrix4fStack,
|
||||
program: GLSoftLightGeometryProgram
|
||||
) {
|
||||
if (softShadowGeometryRev != tileChangeset) {
|
||||
buildSoftGeometry()
|
||||
}
|
||||
|
||||
softShadowGeometry.draw(GL_TRIANGLES)
|
||||
}
|
||||
}
|
||||
|
||||
private val shadowGeometry = ArrayList<ShadowGeometryTracker>()
|
||||
|
||||
init {
|
||||
for (x in 0 until SHADOW_GEOMETRY_SUBDIVISION) {
|
||||
for (y in 0 until SHADOW_GEOMETRY_SUBDIVISION) {
|
||||
shadowGeometry.add(ShadowGeometryTracker(x, y))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -286,9 +302,81 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
||||
* Должен быть использован только один раз, после выкинут, иначе поведение
|
||||
* кода невозможно будет предсказать
|
||||
*/
|
||||
inner class OneShotRenderer constructor(val origin: ChunkPos = pos) : ILayeredRenderer {
|
||||
inner class OneShotRenderer constructor(val origin: ChunkPos = pos) : ILayeredRenderer, LightRenderer.ShadowGeometryRenderer {
|
||||
private val layerQueue = ArrayDeque<Pair<(Matrix4fStack) -> Unit, Int>>()
|
||||
|
||||
override fun renderHardGeometry(
|
||||
renderer: LightRenderer,
|
||||
lightPosition: Vector2f,
|
||||
lightRadius: Float,
|
||||
stack: Matrix4fStack,
|
||||
program: GLHardLightGeometryProgram
|
||||
) {
|
||||
if (!intersectCircleRectangle(lightPosition, lightRadius, origin.x * CHUNK_SIZEf, origin.y * CHUNK_SIZEf, (origin.x + 1) * CHUNK_SIZEf, (origin.y + 1) * CHUNK_SIZEf)) {
|
||||
return
|
||||
}
|
||||
|
||||
var setOnce = false
|
||||
|
||||
for (geometry in shadowGeometry) {
|
||||
if (intersectCircleRectangle(
|
||||
lightPosition,
|
||||
lightRadius,
|
||||
origin.x * CHUNK_SIZEf + geometry.x * SHADOW_GEOMETRY_SQUARE_SIZE,
|
||||
origin.y * CHUNK_SIZEf + geometry.y * SHADOW_GEOMETRY_SQUARE_SIZE,
|
||||
origin.x * CHUNK_SIZEf + (geometry.x + 1) * SHADOW_GEOMETRY_SQUARE_SIZE,
|
||||
origin.y * CHUNK_SIZEf + (geometry.y + 1) * SHADOW_GEOMETRY_SQUARE_SIZE)
|
||||
) {
|
||||
if (!setOnce) {
|
||||
program.localToWorldTransform.set(
|
||||
Matrix4f.IDENTITY.translateWithMultiplication(
|
||||
Vector3f(x = origin.x * CHUNK_SIZEf,
|
||||
y = origin.y * CHUNK_SIZEf)))
|
||||
|
||||
setOnce = true
|
||||
}
|
||||
|
||||
geometry.renderHardGeometry(renderer, lightPosition, lightRadius, stack, program)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderSoftGeometry(
|
||||
renderer: LightRenderer,
|
||||
lightPosition: Vector2f,
|
||||
lightRadius: Float,
|
||||
stack: Matrix4fStack,
|
||||
program: GLSoftLightGeometryProgram
|
||||
) {
|
||||
if (!intersectCircleRectangle(lightPosition, lightRadius, origin.x * CHUNK_SIZEf, origin.y * CHUNK_SIZEf, (origin.x + 1) * CHUNK_SIZEf, (origin.y + 1) * CHUNK_SIZEf)) {
|
||||
return
|
||||
}
|
||||
|
||||
var setOnce = false
|
||||
|
||||
for (geometry in shadowGeometry) {
|
||||
if (intersectCircleRectangle(
|
||||
lightPosition,
|
||||
lightRadius,
|
||||
origin.x * CHUNK_SIZEf + geometry.x * SHADOW_GEOMETRY_SQUARE_SIZE,
|
||||
origin.y * CHUNK_SIZEf + geometry.y * SHADOW_GEOMETRY_SQUARE_SIZE,
|
||||
origin.x * CHUNK_SIZEf + (geometry.x + 1) * SHADOW_GEOMETRY_SQUARE_SIZE,
|
||||
origin.y * CHUNK_SIZEf + (geometry.y + 1) * SHADOW_GEOMETRY_SQUARE_SIZE)
|
||||
) {
|
||||
if (!setOnce) {
|
||||
program.localToWorldTransform.set(
|
||||
Matrix4f.IDENTITY.translateWithMultiplication(
|
||||
Vector3f(x = origin.x * CHUNK_SIZEf,
|
||||
y = origin.y * CHUNK_SIZEf)))
|
||||
|
||||
setOnce = true
|
||||
}
|
||||
|
||||
geometry.renderSoftGeometry(renderer, lightPosition, lightRadius, stack, program)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
for ((baked, zLevel) in backgroundRenderer.bakedMeshes) {
|
||||
layerQueue.add(baked::renderStacked to (zLevel + Z_LEVEL_BACKGROUND))
|
||||
@ -414,4 +502,9 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
||||
renderer.close()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SHADOW_GEOMETRY_SUBDIVISION = 4
|
||||
const val SHADOW_GEOMETRY_SQUARE_SIZE = CHUNK_SIZE / SHADOW_GEOMETRY_SUBDIVISION
|
||||
}
|
||||
}
|
||||
|
@ -107,9 +107,10 @@ class ClientWorld(
|
||||
client.lightRenderer.begin()
|
||||
|
||||
for (chunk in collectPositionAware(size.encasingChunkPosAABB())) {
|
||||
determineRenderers.add(chunk.second.OneShotRenderer(chunk.first))
|
||||
val renderer = chunk.second.OneShotRenderer(chunk.first)
|
||||
determineRenderers.add(renderer)
|
||||
chunk.second.bake()
|
||||
client.lightRenderer.addShadowGeometry(chunk.second.shadowGeometry)
|
||||
client.lightRenderer.addShadowGeometry(renderer)
|
||||
}
|
||||
|
||||
renderLayeredList(client.gl.matrixStack, determineRenderers)
|
||||
@ -119,7 +120,7 @@ class ClientWorld(
|
||||
(client.screenToWorld(client.mouseCoordinatesF) + Vector2f(0.1f)) to Color.GREEN,
|
||||
(client.screenToWorld(client.mouseCoordinatesF) + Vector2f(-0.1f)) to Color.BLUE,
|
||||
)) {
|
||||
client.lightRenderer.renderSoftLight(lightPosition, color, radius = 100f)
|
||||
client.lightRenderer.renderSoftLight(lightPosition, color, radius = 20f, innerRadius = 1f)
|
||||
}
|
||||
|
||||
val old = client.gl.blendFunc
|
||||
|
@ -25,6 +25,7 @@ import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
||||
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.util.concurrent.locks.LockSupport
|
||||
|
||||
class StarboundClient : AutoCloseable {
|
||||
val window: Long
|
||||
@ -144,6 +145,9 @@ class StarboundClient : AutoCloseable {
|
||||
return Vector2f(relativeX, relativeY)
|
||||
}
|
||||
|
||||
var isRenderingGame = true
|
||||
private set
|
||||
|
||||
init {
|
||||
GLFWErrorCallback.create { error, description ->
|
||||
LOGGER.error("LWJGL error {}: {}", error, description)
|
||||
@ -166,6 +170,12 @@ class StarboundClient : AutoCloseable {
|
||||
input.installCallback(window)
|
||||
|
||||
GLFW.glfwSetFramebufferSizeCallback(window) { _, w, h ->
|
||||
if (w == 0 || h == 0) {
|
||||
isRenderingGame = false
|
||||
return@glfwSetFramebufferSizeCallback
|
||||
}
|
||||
|
||||
isRenderingGame = true
|
||||
viewportWidth = w
|
||||
viewportHeight = h
|
||||
viewportMatrixScreen = updateViewportMatrixScreen()
|
||||
@ -287,6 +297,13 @@ class StarboundClient : AutoCloseable {
|
||||
return false
|
||||
}
|
||||
|
||||
if (!isRenderingGame) {
|
||||
gl.cleanup()
|
||||
GLFW.glfwPollEvents()
|
||||
LockSupport.parkNanos(1_000_000L)
|
||||
return true
|
||||
}
|
||||
|
||||
val measure = GLFW.glfwGetTime()
|
||||
|
||||
if (frameRenderTime != 0.0 && Starbound.initialized)
|
||||
|
@ -43,6 +43,13 @@ class GLUniformLocation(val program: GLShaderProgram, val name: String, val poin
|
||||
return this
|
||||
}
|
||||
|
||||
fun set(value: Float): GLUniformLocation {
|
||||
program.state.ensureSameThread()
|
||||
glProgramUniform1f(program.pointer, pointer, value)
|
||||
checkForGLError()
|
||||
return this
|
||||
}
|
||||
|
||||
private val buff3x3: FloatBuffer by lazy { ByteBuffer.allocateDirect(4 * 3 * 3).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer() }
|
||||
private val buff4x4: FloatBuffer by lazy { ByteBuffer.allocateDirect(4 * 4 * 4).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer() }
|
||||
|
||||
|
@ -26,8 +26,8 @@ import ru.dbotthepony.kvector.vector.nfloat.Vector3f
|
||||
// https://slembcke.github.io/SuperFastSoftShadows
|
||||
class LightRenderer(val state: GLStateTracker) {
|
||||
interface ShadowGeometryRenderer {
|
||||
fun renderHardGeometry(renderer: LightRenderer, lightPosition: Vector2f, stack: Matrix4fStack, program: GLHardLightGeometryProgram)
|
||||
fun renderSoftGeometry(renderer: LightRenderer, lightPosition: Vector2f, stack: Matrix4fStack, program: GLSoftLightGeometryProgram)
|
||||
fun renderHardGeometry(renderer: LightRenderer, lightPosition: Vector2f, lightRadius: Float, stack: Matrix4fStack, program: GLHardLightGeometryProgram)
|
||||
fun renderSoftGeometry(renderer: LightRenderer, lightPosition: Vector2f, lightRadius: Float, stack: Matrix4fStack, program: GLSoftLightGeometryProgram)
|
||||
}
|
||||
|
||||
private val geometry = ArrayList<ShadowGeometryRenderer>()
|
||||
@ -169,7 +169,7 @@ class LightRenderer(val state: GLStateTracker) {
|
||||
state.blendFunc = BlendFunc.ONLY_ALPHA
|
||||
|
||||
for (renderer in geometry) {
|
||||
renderer.renderHardGeometry(this, position, stack, state.programs.hardLightGeometry)
|
||||
renderer.renderHardGeometry(this, position, radius, stack, state.programs.hardLightGeometry)
|
||||
}
|
||||
|
||||
state.programs.light.use()
|
||||
@ -224,11 +224,12 @@ class LightRenderer(val state: GLStateTracker) {
|
||||
state.programs.softLightGeometry.use()
|
||||
state.programs.softLightGeometry.transform.set(stack.last)
|
||||
state.programs.softLightGeometry.lightPositionAndSize.set(Vector3f(position, innerRadius))
|
||||
state.programs.softLightGeometry.lightPenetration.set(1f)
|
||||
|
||||
state.blendFunc = BlendFunc.ONLY_BLEND_ALPHA
|
||||
|
||||
for (renderer in geometry) {
|
||||
renderer.renderSoftGeometry(this, position, stack, state.programs.softLightGeometry)
|
||||
renderer.renderSoftGeometry(this, position, radius, stack, state.programs.softLightGeometry)
|
||||
}
|
||||
|
||||
state.programs.light.use()
|
||||
|
Loading…
Reference in New Issue
Block a user