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) } }