147 lines
3.6 KiB
Go
147 lines
3.6 KiB
Go
package pass
|
|
|
|
import (
|
|
"github.com/vkngwrapper/core/v2/core1_0"
|
|
"zworld/engine/object"
|
|
"zworld/engine/object/light"
|
|
"zworld/engine/renderapi"
|
|
"zworld/engine/renderapi/cache"
|
|
"zworld/engine/renderapi/color"
|
|
"zworld/engine/renderapi/command"
|
|
"zworld/engine/renderapi/framebuffer"
|
|
"zworld/engine/renderapi/renderpass"
|
|
"zworld/engine/renderapi/renderpass/attachment"
|
|
"zworld/engine/renderapi/vertex"
|
|
"zworld/engine/renderapi/vulkan"
|
|
)
|
|
|
|
const LightingSubpass renderpass.Name = "lighting"
|
|
|
|
type DeferredLightPass struct {
|
|
app vulkan.App
|
|
target vulkan.Target
|
|
gbuffer GeometryBuffer
|
|
ssao vulkan.Target
|
|
quad vertex.Mesh
|
|
pass renderpass.T
|
|
light LightShader
|
|
fbuf framebuffer.Array
|
|
samplers []cache.SamplerCache
|
|
shadows []*ShadowCache
|
|
lightbufs []*LightBuffer
|
|
lightQuery *object.Query[light.T]
|
|
}
|
|
|
|
func NewDeferredLightingPass(
|
|
app vulkan.App,
|
|
target vulkan.Target,
|
|
gbuffer GeometryBuffer,
|
|
shadows Shadow,
|
|
occlusion vulkan.Target,
|
|
) *DeferredLightPass {
|
|
pass := renderpass.New(app.Device(), renderpass.Args{
|
|
Name: "Deferred Lighting",
|
|
ColorAttachments: []attachment.Color{
|
|
{
|
|
Name: OutputAttachment,
|
|
Image: attachment.FromImageArray(target.Surfaces()),
|
|
Samples: 0,
|
|
LoadOp: core1_0.AttachmentLoadOpClear,
|
|
StoreOp: core1_0.AttachmentStoreOpStore,
|
|
InitialLayout: 0,
|
|
FinalLayout: core1_0.ImageLayoutShaderReadOnlyOptimal,
|
|
Clear: color.T{},
|
|
Blend: attachment.BlendAdditive,
|
|
},
|
|
},
|
|
Subpasses: []renderpass.Subpass{
|
|
{
|
|
Name: LightingSubpass,
|
|
|
|
ColorAttachments: []attachment.Name{OutputAttachment},
|
|
},
|
|
},
|
|
})
|
|
|
|
fbuf, err := framebuffer.NewArray(target.Frames(), app.Device(), "deferred-lighting", target.Width(), target.Height(), pass)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
quad := vertex.ScreenQuad("geometry-pass-quad")
|
|
|
|
lightsh := NewLightShader(app, pass, gbuffer, occlusion)
|
|
|
|
samplers := make([]cache.SamplerCache, target.Frames())
|
|
lightbufs := make([]*LightBuffer, target.Frames())
|
|
shadowmaps := make([]*ShadowCache, target.Frames())
|
|
for i := range lightbufs {
|
|
samplers[i] = cache.NewSamplerCache(app.Textures(), lightsh.Descriptors(i).Shadow)
|
|
shadowmaps[i] = NewShadowCache(samplers[i], shadows.Shadowmap)
|
|
lightbufs[i] = NewLightBuffer(256)
|
|
}
|
|
|
|
return &DeferredLightPass{
|
|
target: target,
|
|
gbuffer: gbuffer,
|
|
app: app,
|
|
quad: quad,
|
|
light: lightsh,
|
|
pass: pass,
|
|
fbuf: fbuf,
|
|
shadows: shadowmaps,
|
|
lightbufs: lightbufs,
|
|
lightQuery: object.NewQuery[light.T](),
|
|
}
|
|
}
|
|
|
|
func (p *DeferredLightPass) Record(cmds command.Recorder, args renderapi.Args, scene object.Component) {
|
|
camera := CameraFromArgs(args)
|
|
|
|
desc := p.light.Descriptors(args.Frame)
|
|
desc.Camera.Set(camera)
|
|
|
|
lightbuf := p.lightbufs[args.Frame]
|
|
shadows := p.shadows[args.Frame]
|
|
lightbuf.Reset()
|
|
|
|
// todo: perform frustum culling on light volumes
|
|
lights := p.lightQuery.Reset().Collect(scene)
|
|
for _, lit := range lights {
|
|
lightbuf.Store(lit.LightData(shadows))
|
|
}
|
|
|
|
lightbuf.Flush(desc.Lights)
|
|
shadows.Flush()
|
|
|
|
quad := p.app.Meshes().Fetch(p.quad)
|
|
cmds.Record(func(cmd command.Buffer) {
|
|
cmd.CmdBeginRenderPass(p.pass, p.fbuf[args.Frame])
|
|
|
|
p.light.Bind(cmd, args.Frame)
|
|
|
|
quad.Draw(cmd, 0)
|
|
|
|
cmd.CmdEndRenderPass()
|
|
})
|
|
}
|
|
|
|
func (p *DeferredLightPass) Name() string {
|
|
return "Deferred Lighting"
|
|
}
|
|
|
|
func (p *DeferredLightPass) Destroy() {
|
|
for _, cache := range p.samplers {
|
|
cache.Destroy()
|
|
}
|
|
p.samplers = nil
|
|
p.lightbufs = nil
|
|
|
|
p.fbuf.Destroy()
|
|
p.fbuf = nil
|
|
p.pass.Destroy()
|
|
p.pass = nil
|
|
p.light.Destroy()
|
|
p.light = nil
|
|
}
|