Light renderer dispatcher
This commit is contained in:
parent
0614158a9c
commit
7eeb5f8a12
@ -5,18 +5,23 @@ import org.lwjgl.Version
|
||||
import org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose
|
||||
import org.lwjgl.opengl.GL11.GL_LINES
|
||||
import org.lwjgl.opengl.GL11.GL_RGBA
|
||||
import org.lwjgl.opengl.GL11.GL_SCISSOR_TEST
|
||||
import org.lwjgl.opengl.GL11.glDisable
|
||||
import org.lwjgl.opengl.GL11.glEnable
|
||||
import org.lwjgl.opengl.GL11.glScissor
|
||||
import org.lwjgl.opengl.GL46
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.client.gl.BlendFunc
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLFrameBuffer
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLTexture2D
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
||||
import ru.dbotthepony.kstarbound.client.render.LightRenderer
|
||||
import ru.dbotthepony.kstarbound.io.*
|
||||
import ru.dbotthepony.kstarbound.world.ChunkPos
|
||||
import ru.dbotthepony.kstarbound.world.entities.PlayerEntity
|
||||
import ru.dbotthepony.kvector.vector.Color
|
||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.DataInputStream
|
||||
import java.io.File
|
||||
@ -180,88 +185,40 @@ fun main() {
|
||||
client.gl.font.render("${client.camera.pos} ${client.settings.zoom}", y = 140f, scale = 0.25f)
|
||||
}
|
||||
|
||||
val lightmap = GLFrameBuffer(client.gl)
|
||||
|
||||
lightmap.reattachTexture(client.viewportWidth, client.viewportHeight, GL_RGBA)
|
||||
|
||||
client.onViewportChanged { width, height -> lightmap.reattachTexture(width, height, GL_RGBA) }
|
||||
|
||||
client.onPostDrawWorld {
|
||||
lightmap.bind()
|
||||
GL46.glClear(GL46.GL_COLOR_BUFFER_BIT or GL46.GL_DEPTH_BUFFER_BIT)
|
||||
//client.gl.programs.colorQuad.clearAlpha()
|
||||
|
||||
client.gl.programs.light.use()
|
||||
client.gl.programs.light.transform.set(client.gl.matrixStack.last)
|
||||
// client.gl.programs.light.transform.set(Matrix4f.IDENTITY)
|
||||
client.gl.programs.light.baselineColor.set(Color.WHITE)
|
||||
|
||||
var builder = client.gl.programs.light.builder
|
||||
|
||||
val (rX, rY) = client.screenToWorld(client.mouseCoordinatesF)
|
||||
|
||||
builder.begin()
|
||||
|
||||
//val size = 20f / client.settings.scale
|
||||
val size = 10f
|
||||
|
||||
builder.quad(rX - size, rY - size, rX + size, rY + size, QuadTransformers.uv())
|
||||
|
||||
builder.upload()
|
||||
|
||||
//client.gl.blendFunc = BlendFunc(
|
||||
// BlendFunc.Func.DST_ALPHA,
|
||||
// BlendFunc.Func.ONE_MINUS_DST_ALPHA
|
||||
//)
|
||||
|
||||
builder.draw()
|
||||
client.gl.blendFunc = BlendFunc.ALPHA_TEST
|
||||
|
||||
client.gl.programs.lightOccluder.use()
|
||||
client.gl.programs.lightOccluder.transform.set(client.gl.matrixStack.last)
|
||||
|
||||
builder = client.gl.programs.lightOccluder.builder
|
||||
|
||||
builder.begin()
|
||||
|
||||
val lightPosition = client.screenToWorld(client.mouseCoordinatesF)
|
||||
|
||||
builder.quad(0f, 0f, 2f, 2f)
|
||||
builder.quad(-6f, 0f, -2f, 2f)
|
||||
|
||||
client.gl.programs.lightOccluder.lightPosition.set(lightPosition)
|
||||
|
||||
builder.upload()
|
||||
|
||||
client.gl.blendFunc = BlendFunc.ONLY_ALPHA
|
||||
builder.draw(GL_LINES)
|
||||
client.gl.blendFunc = BlendFunc.ALPHA_TEST
|
||||
|
||||
lightmap.unbind()
|
||||
|
||||
client.gl.activeTexture = 0
|
||||
client.gl.texture2D = lightmap.texture
|
||||
client.gl.programs.textureQuad.run(0)
|
||||
|
||||
client.gl.programs.flat.use()
|
||||
client.gl.programs.flat.color.set(Color.BLACK)
|
||||
client.gl.programs.flat.transform.set(client.gl.matrixStack.last)
|
||||
builder = client.gl.programs.flat.builder
|
||||
|
||||
builder.begin()
|
||||
|
||||
builder.quad(0f, 0f, 2f, 2f)
|
||||
builder.quad(-6f, 0f, -2f, 2f)
|
||||
|
||||
builder.upload()
|
||||
builder.draw()
|
||||
}
|
||||
|
||||
client.onPreDrawWorld {
|
||||
//client.camera.pos.x = ent.pos.x.toFloat()
|
||||
//client.camera.pos.y = ent.pos.y.toFloat()
|
||||
}
|
||||
|
||||
val lightRenderer = LightRenderer(client.gl)
|
||||
|
||||
lightRenderer.resizeFramebuffer(client.viewportWidth, client.viewportHeight)
|
||||
client.onViewportChanged(lightRenderer::resizeFramebuffer)
|
||||
|
||||
lightRenderer.addShadowGeometry { _, _ ->
|
||||
val builder = client.gl.programs.lightOccluder.builder
|
||||
|
||||
builder.begin()
|
||||
builder.quad(0f, 0f, 2f, 2f)
|
||||
builder.quad(-6f, 0f, -2f, 2f)
|
||||
builder.upload()
|
||||
builder.draw(GL_LINES)
|
||||
}
|
||||
|
||||
client.onPostDrawWorld {
|
||||
lightRenderer.begin()
|
||||
|
||||
for ((lightPosition, color) in listOf(
|
||||
(client.screenToWorld(client.mouseCoordinatesF) + Vector2f(-2f)) to Color.RED,
|
||||
(client.screenToWorld(client.mouseCoordinatesF) + Vector2f(2f)) to Color.GREEN,
|
||||
(client.screenToWorld(client.mouseCoordinatesF) + Vector2f(y = -2f)) to Color.BLUE,
|
||||
)) {
|
||||
lightRenderer.renderLight(lightPosition, color)
|
||||
}
|
||||
|
||||
lightRenderer.renderOutputAdditive()
|
||||
}
|
||||
|
||||
client.gl.box2dRenderer.drawShapes = false
|
||||
client.gl.box2dRenderer.drawPairs = false
|
||||
client.gl.box2dRenderer.drawAABB = false
|
||||
|
@ -133,6 +133,16 @@ class StarboundClient : AutoCloseable {
|
||||
return screenToWorld(value.x, value.y)
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразует мировые координаты в экранные
|
||||
*/
|
||||
fun worldToScreen(x: Float, y: Float): Vector2f {
|
||||
val relativeX = (x - camera.pos.x) * PIXELS_IN_STARBOUND_UNITf * settings.zoom + viewportWidth / 2f
|
||||
val relativeY = (camera.pos.y - y) * PIXELS_IN_STARBOUND_UNITf * settings.zoom + viewportHeight / 2f
|
||||
|
||||
return Vector2f(relativeX, relativeY)
|
||||
}
|
||||
|
||||
init {
|
||||
GLFWErrorCallback.create { error, description ->
|
||||
LOGGER.error("LWJGL error {}: {}", error, description)
|
||||
@ -205,7 +215,7 @@ class StarboundClient : AutoCloseable {
|
||||
gl.clearColor = Color.SLATE_GREY
|
||||
|
||||
gl.blend = true
|
||||
gl.blendFunc = BlendFunc.ALPHA_TEST
|
||||
gl.blendFunc = BlendFunc.MULTIPLY_WITH_ALPHA
|
||||
}
|
||||
|
||||
var frameRenderTime = 0.0
|
||||
|
@ -2,7 +2,6 @@ package ru.dbotthepony.kstarbound.client.gl
|
||||
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.lwjgl.opengl.GL
|
||||
import org.lwjgl.opengl.GL14
|
||||
import org.lwjgl.opengl.GL46.*
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.client.freetype.FreeType
|
||||
@ -25,7 +24,6 @@ import ru.dbotthepony.kvector.util2d.AABB
|
||||
import ru.dbotthepony.kvector.vector.Color
|
||||
import java.io.FileNotFoundException
|
||||
import java.lang.ref.Cleaner
|
||||
import java.util.*
|
||||
import java.util.concurrent.ThreadFactory
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
@ -109,7 +107,8 @@ data class BlendFunc(
|
||||
|
||||
companion object {
|
||||
val DEFAULT = BlendFunc()
|
||||
val ALPHA_TEST = BlendFunc(Func.SRC_ALPHA, Func.ONE_MINUS_SRC_ALPHA)
|
||||
val MULTIPLY_WITH_ALPHA = BlendFunc(Func.SRC_ALPHA, Func.ONE_MINUS_SRC_ALPHA)
|
||||
val ADDITIVE = BlendFunc(Func.ONE, Func.ONE)
|
||||
|
||||
val ONLY_ALPHA = BlendFunc(
|
||||
Func.ZERO,
|
||||
|
@ -0,0 +1,181 @@
|
||||
package ru.dbotthepony.kstarbound.client.render
|
||||
|
||||
import org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT
|
||||
import org.lwjgl.opengl.GL11.GL_RGBA
|
||||
import org.lwjgl.opengl.GL11.glClear
|
||||
import ru.dbotthepony.kstarbound.client.gl.BlendFunc
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLFrameBuffer
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLTexture2D
|
||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||
import ru.dbotthepony.kvector.vector.Color
|
||||
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
||||
|
||||
// https://slembcke.github.io/SuperFastHardShadows
|
||||
class LightRenderer(val state: GLStateTracker) {
|
||||
fun interface ShadowGeometryRenderer {
|
||||
fun render(lightPosition: Vector2f, stack: Matrix4fStack)
|
||||
}
|
||||
|
||||
private val geometry = ArrayList<ShadowGeometryRenderer>()
|
||||
|
||||
fun addShadowGeometry(geometry: ShadowGeometryRenderer): LightRenderer {
|
||||
this.geometry.add(geometry)
|
||||
return this
|
||||
}
|
||||
|
||||
fun removeShadowGeometry(geometry: ShadowGeometryRenderer): Boolean {
|
||||
return this.geometry.remove(geometry)
|
||||
}
|
||||
|
||||
/**
|
||||
* Сюда происходит рендер маски света и самого света
|
||||
*/
|
||||
private val framebufferRender = GLFrameBuffer(state)
|
||||
|
||||
/**
|
||||
* Сюда накапливается отрисованный свет
|
||||
*/
|
||||
private val framebufferAccumulator = GLFrameBuffer(state)
|
||||
|
||||
val outputTexture: GLTexture2D? get() = framebufferAccumulator.texture
|
||||
|
||||
fun resizeFramebuffer(width: Int, height: Int) {
|
||||
framebufferRender.reattachTexture(width, height, GL_RGBA)
|
||||
framebufferAccumulator.reattachTexture(width, height, GL_RGBA)
|
||||
}
|
||||
|
||||
fun begin() {
|
||||
state.ensureSameThread()
|
||||
|
||||
if (!framebufferRender.isComplete || !framebufferAccumulator.isComplete) {
|
||||
return
|
||||
}
|
||||
|
||||
val old = state.clearColor
|
||||
state.clearColor = Color.BLACK
|
||||
|
||||
framebufferRender.bind()
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
checkForGLError()
|
||||
framebufferAccumulator.bind()
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
checkForGLError()
|
||||
state.clearColor = old
|
||||
|
||||
framebufferAccumulator.unbind()
|
||||
}
|
||||
|
||||
/**
|
||||
* Отрисовывает результат на весь текущий framebuffer в режиме additive
|
||||
*/
|
||||
fun renderOutputAdditive() {
|
||||
val oldFunc = state.blendFunc
|
||||
|
||||
try {
|
||||
state.activeTexture = 0
|
||||
state.texture2D = outputTexture
|
||||
state.blendFunc = BlendFunc.ADDITIVE
|
||||
state.programs.textureQuad.run(0)
|
||||
} finally {
|
||||
state.blendFunc = oldFunc
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Отрисовывает результат на весь текущий framebuffer в режиме additive
|
||||
*/
|
||||
fun renderOutputMultiplicative() {
|
||||
val oldFunc = state.blendFunc
|
||||
|
||||
try {
|
||||
state.activeTexture = 0
|
||||
state.texture2D = outputTexture
|
||||
state.blendFunc = BlendFunc.MULTIPLY_WITH_ALPHA
|
||||
state.programs.textureQuad.run(0)
|
||||
} finally {
|
||||
state.blendFunc = oldFunc
|
||||
}
|
||||
}
|
||||
|
||||
fun renderLight(
|
||||
position: Vector2f,
|
||||
color: Color = Color.WHITE,
|
||||
radius: Float = 10f,
|
||||
stack: Matrix4fStack = state.matrixStack
|
||||
) {
|
||||
state.ensureSameThread()
|
||||
|
||||
if (!framebufferRender.isComplete || !framebufferAccumulator.isComplete) {
|
||||
return
|
||||
}
|
||||
|
||||
val oldFunc = state.blendFunc
|
||||
|
||||
// отрисовка
|
||||
try {
|
||||
framebufferRender.bind()
|
||||
|
||||
// state.programs.colorQuad.clearAlpha()
|
||||
|
||||
// Геометрия
|
||||
val old = state.clearColor
|
||||
state.clearColor = Color.BLACK
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
checkForGLError()
|
||||
state.clearColor = old
|
||||
|
||||
state.programs.lightOccluder.use()
|
||||
state.programs.lightOccluder.transform.set(stack.last)
|
||||
state.programs.lightOccluder.lightPosition.set(position)
|
||||
|
||||
state.blendFunc = BlendFunc.ONLY_ALPHA
|
||||
|
||||
for (renderer in geometry) {
|
||||
renderer.render(position, stack)
|
||||
}
|
||||
|
||||
state.programs.light.use()
|
||||
state.programs.light.transform.set(stack.last)
|
||||
state.programs.light.baselineColor.set(color)
|
||||
|
||||
// Свет
|
||||
val builder = state.programs.light.builder
|
||||
|
||||
builder.begin()
|
||||
builder.quad(position.x - radius, position.y - radius, position.x + radius, position.y + radius, QuadTransformers.uv())
|
||||
builder.upload()
|
||||
|
||||
state.blendFunc = BLEND_MODE
|
||||
builder.draw()
|
||||
} finally {
|
||||
state.blendFunc = oldFunc
|
||||
framebufferRender.unbind()
|
||||
}
|
||||
|
||||
// накопление
|
||||
try {
|
||||
framebufferAccumulator.bind()
|
||||
|
||||
state.blendFunc = BlendFunc.ADDITIVE
|
||||
state.activeTexture = 0
|
||||
state.texture2D = framebufferRender.texture
|
||||
state.programs.textureQuad.run(0)
|
||||
} finally {
|
||||
state.blendFunc = oldFunc
|
||||
framebufferAccumulator.unbind()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val BLEND_MODE = BlendFunc(
|
||||
BlendFunc.Func.DST_ALPHA,
|
||||
BlendFunc.Func.ZERO,
|
||||
BlendFunc.Func.ZERO,
|
||||
BlendFunc.Func.ONE,
|
||||
)
|
||||
}
|
||||
}
|
@ -7,5 +7,5 @@ out vec4 resultColor;
|
||||
uniform vec4 baselineColor;
|
||||
|
||||
void main() {
|
||||
resultColor = vec4(baselineColor) * smoothstep(0.0, 1.0, 1.0 - sqrt(pow(oUVCoords.x - 0.5, 2.0) + pow(oUVCoords.y - 0.5, 2.0)) * 2.0);
|
||||
resultColor = vec4(baselineColor.rgb * smoothstep(0.0, 1.0, 1.0 - sqrt(pow(oUVCoords.x - 0.5, 2.0) + pow(oUVCoords.y - 0.5, 2.0)) * 2.0), baselineColor.a);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user