zworld/engine/render/pass/forward.go
2024-01-14 22:56:06 +08:00

132 lines
3.2 KiB
Go

package pass
import (
"github.com/vkngwrapper/core/v2/core1_0"
"zworld/engine/object"
"zworld/engine/object/light"
"zworld/engine/object/mesh"
"zworld/engine/renderapi"
"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"
)
type ForwardPass struct {
target vulkan.Target
app vulkan.App
pass renderpass.T
fbuf framebuffer.Array
materials MaterialCache
meshQuery *object.Query[mesh.Mesh]
lightQuery *object.Query[light.T]
}
var _ Pass = &ForwardPass{}
func NewForwardPass(
app vulkan.App,
target vulkan.Target,
depth vulkan.Target,
shadows Shadow,
) *ForwardPass {
pass := renderpass.New(app.Device(), renderpass.Args{
Name: "Forward",
ColorAttachments: []attachment.Color{
{
Name: OutputAttachment,
LoadOp: core1_0.AttachmentLoadOpLoad,
StoreOp: core1_0.AttachmentStoreOpStore,
FinalLayout: core1_0.ImageLayoutShaderReadOnlyOptimal,
Blend: attachment.BlendMultiply,
Image: attachment.FromImageArray(target.Surfaces()),
},
},
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{OutputAttachment},
},
},
})
fbuf, err := framebuffer.NewArray(target.Frames(), app.Device(), "forward", target.Width(), target.Height(), pass)
if err != nil {
panic(err)
}
return &ForwardPass{
target: target,
app: app,
pass: pass,
fbuf: fbuf,
materials: NewForwardMaterialCache(app, pass, target.Frames(), shadows.Shadowmap),
meshQuery: object.NewQuery[mesh.Mesh](),
lightQuery: object.NewQuery[light.T](),
}
}
func (p *ForwardPass) Record(cmds command.Recorder, args renderapi.Args, scene object.Component) {
cam := CameraFromArgs(args)
lights := p.lightQuery.Reset().Collect(scene)
cmds.Record(func(cmd command.Buffer) {
cmd.CmdBeginRenderPass(p.pass, p.fbuf[args.Frame])
})
// opaque pass
opaque := p.meshQuery.
Reset().
Where(isDrawForward(false)).
Collect(scene)
groups := MaterialGroups(p.materials, args.Frame, opaque)
groups.Draw(cmds, cam, lights)
// transparent pass
transparent := p.meshQuery.
Reset().
Where(isDrawForward(true)).
Where(func(m mesh.Mesh) bool { return m.Material().Transparent }).
Collect(scene)
groups = DepthSortGroups(p.materials, args.Frame, cam, transparent)
groups.Draw(cmds, cam, lights)
cmds.Record(func(cmd command.Buffer) {
cmd.CmdEndRenderPass()
})
}
func (p *ForwardPass) Name() string {
return "Forward"
}
func (p *ForwardPass) Destroy() {
p.fbuf.Destroy()
p.pass.Destroy()
p.materials.Destroy()
}
func isDrawForward(transparent bool) func(m mesh.Mesh) bool {
return func(m mesh.Mesh) bool {
if mat := m.Material(); mat != nil {
return mat.Pass == material.Forward && m.Material().Transparent == transparent
}
return false
}
}