zworld/engine/render/pass/deferred_geometry.go

150 lines
3.8 KiB
Go
Raw Permalink Normal View History

2024-01-14 22:56:06 +08:00
package pass
import (
"github.com/vkngwrapper/core/v2/core1_0"
"zworld/engine/object"
"zworld/engine/object/mesh"
"zworld/engine/renderapi"
"zworld/engine/renderapi/color"
"zworld/engine/renderapi/command"
"zworld/engine/renderapi/framebuffer"
"zworld/engine/renderapi/material"
"zworld/engine/renderapi/renderpass"
"zworld/engine/renderapi/renderpass/attachment"
"zworld/engine/renderapi/vulkan"
"zworld/plugins/math/shape"
)
const (
DiffuseAttachment attachment.Name = "diffuse"
NormalsAttachment attachment.Name = "normals"
PositionAttachment attachment.Name = "position"
OutputAttachment attachment.Name = "output"
)
type DeferredGeometryPass struct {
target vulkan.Target
gbuffer GeometryBuffer
app vulkan.App
pass renderpass.T
fbuf framebuffer.Array
materials MaterialCache
meshQuery *object.Query[mesh.Mesh]
}
func NewDeferredGeometryPass(
app vulkan.App,
depth vulkan.Target,
gbuffer GeometryBuffer,
) *DeferredGeometryPass {
pass := renderpass.New(app.Device(), renderpass.Args{
Name: "Deferred Geometry",
ColorAttachments: []attachment.Color{
{
Name: DiffuseAttachment,
LoadOp: core1_0.AttachmentLoadOpClear,
StoreOp: core1_0.AttachmentStoreOpStore,
FinalLayout: core1_0.ImageLayoutShaderReadOnlyOptimal,
Image: attachment.FromImageArray(gbuffer.Diffuse()),
},
{
Name: NormalsAttachment,
LoadOp: core1_0.AttachmentLoadOpLoad,
StoreOp: core1_0.AttachmentStoreOpStore,
FinalLayout: core1_0.ImageLayoutShaderReadOnlyOptimal,
Image: attachment.FromImageArray(gbuffer.Normal()),
},
{
Name: PositionAttachment,
LoadOp: core1_0.AttachmentLoadOpLoad,
StoreOp: core1_0.AttachmentStoreOpStore,
FinalLayout: core1_0.ImageLayoutShaderReadOnlyOptimal,
Image: attachment.FromImageArray(gbuffer.Position()),
},
},
DepthAttachment: &attachment.Depth{
LoadOp: core1_0.AttachmentLoadOpLoad,
StencilLoadOp: core1_0.AttachmentLoadOpLoad,
StoreOp: core1_0.AttachmentStoreOpStore,
FinalLayout: core1_0.ImageLayoutShaderReadOnlyOptimal,
Image: attachment.FromImageArray(depth.Surfaces()),
},
Subpasses: []renderpass.Subpass{
{
Name: MainSubpass,
Depth: true,
ColorAttachments: []attachment.Name{DiffuseAttachment, NormalsAttachment, PositionAttachment},
},
},
})
fbuf, err := framebuffer.NewArray(gbuffer.Frames(), app.Device(), "deferred-geometry", gbuffer.Width(), gbuffer.Height(), pass)
if err != nil {
panic(err)
}
app.Textures().Fetch(color.White)
return &DeferredGeometryPass{
gbuffer: gbuffer,
app: app,
pass: pass,
fbuf: fbuf,
materials: NewDeferredMaterialCache(app, pass, gbuffer.Frames()),
meshQuery: object.NewQuery[mesh.Mesh](),
}
}
func (p *DeferredGeometryPass) Record(cmds command.Recorder, args renderapi.Args, scene object.Component) {
cmds.Record(func(cmd command.Buffer) {
cmd.CmdBeginRenderPass(p.pass, p.fbuf[args.Frame])
})
frustum := shape.FrustumFromMatrix(args.VP)
objects := p.meshQuery.
Reset().
Where(isDrawDeferred).
Where(frustumCulled(&frustum)).
Collect(scene)
cam := CameraFromArgs(args)
groups := MaterialGroups(p.materials, args.Frame, objects)
groups.Draw(cmds, cam, nil)
cmds.Record(func(cmd command.Buffer) {
cmd.CmdEndRenderPass()
})
}
func (p *DeferredGeometryPass) Name() string {
return "Deferred"
}
func (p *DeferredGeometryPass) Destroy() {
p.materials.Destroy()
p.materials = nil
p.fbuf.Destroy()
p.fbuf = nil
p.pass.Destroy()
p.pass = nil
}
func isDrawDeferred(m mesh.Mesh) bool {
if mat := m.Material(); mat != nil {
return mat.Pass == material.Deferred
}
return false
}
func frustumCulled(frustum *shape.Frustum) func(mesh.Mesh) bool {
return func(m mesh.Mesh) bool {
bounds := m.BoundingSphere()
return frustum.IntersectsSphere(&bounds)
}
}