keid-render-basic 0.1.9.0 → 0.1.10.0
raw patch · 15 files changed
+90/−86 lines, 15 filesdep ~geomancydep ~keid-core
Dependency ranges changed: geomancy, keid-core
Files
- ChangeLog.md +6/−0
- keid-render-basic.cabal +5/−5
- src/Render/Code/Lit.hs +20/−15
- src/Render/Debug/Code.hs +4/−4
- src/Render/DescSets/Set0.hs +1/−1
- src/Render/DescSets/Sun.hs +19/−31
- src/Render/ForwardMsaa.hs +1/−1
- src/Render/Lit/Colored/Pipeline.hs +5/−0
- src/Render/Lit/Material/Pipeline.hs +1/−1
- src/Render/Lit/Textured/Pipeline.hs +4/−2
- src/Render/ShadowMap/Pipeline.hs +2/−2
- src/Render/ShadowMap/RenderPass.hs +1/−1
- src/Render/Skybox/Code.hs +8/−7
- src/Render/Unlit/Colored/Code.hs +2/−3
- src/Stage/Loader/UI.hs +11/−13
ChangeLog.md view
@@ -1,5 +1,11 @@ # Changelog for keid-render-basic +## 0.1.10.0++- Update to follow the changes in keid-core-0.1.11 and geomancy-0.3.+- Fix lit pipelines by removing spurious sign flips.+- Require LitColored to participate in the depth pre-pass.+ ## 0.1.9.0 - Moved to geomancy-layout.
keid-render-basic.cabal view
@@ -1,17 +1,17 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.35.2.+-- This file has been generated from package.yaml by hpack version 0.38.1. -- -- see: https://github.com/sol/hpack name: keid-render-basic-version: 0.1.9.0+version: 0.1.10.0 synopsis: Basic rendering programs for Keid engine. category: Game Engine homepage: https://keid.haskell-game.dev author: IC Rainbow maintainer: keid@aenor.ru-copyright: 2023 IC Rainbow+copyright: 2025 IC Rainbow license: BSD3 license-file: LICENSE build-type: Simple@@ -132,10 +132,10 @@ , derive-storable , derive-storable-plugin , file-embed >=0.0.10- , geomancy+ , geomancy >=0.3.0.0 , geomancy-layout , gl-block- , keid-core >=0.1.9.0+ , keid-core >=0.1.11.0 , keid-geometry , neat-interpolation , resourcet
src/Render/Code/Lit.hs view
@@ -127,10 +127,10 @@ baseColor.rgb; vec3 F0 = mix(vec3(0.04), albedo, metallic); - vec3 ray = scene.viewPosition.xyz - fPosition.xyz;- vec3 rayDir = normalize(ray); // V- float quadrance = dot(ray, ray);- float distance = sqrt(quadrance);+ vec3 rayDir = normalize(scene.viewPosition.xyz - fPosition.xyz); // V+ // vec3 rayDir = normalize(ray); // V+ // float quadrance = dot(ray, ray);+ // float viewDistance = sqrt(quadrance); // XXX: not used for directional lights // XXX: provided by caller // vec3 normal = normalize(fNormal); // N@@ -138,7 +138,7 @@ vec3 Lo = vec3(0.0); for (int l = 0; l < scene.numLights; l++) { // XXX: directional lights' hit angle doesn't depend on fragment position- vec3 lightDir = normalize(lights[l].direction.xyz); // L+ vec3 lightDir = lights[l].direction.xyz; // L, pre-normalized float shade = 1.0; // XXX: 0 - occluded, 1 - lit if (lights[l].shadow.z > -1) {@@ -147,12 +147,13 @@ // TODO: pick on specialization constant shade = filterPCF(shadowCoord.xyz, lights[l].shadow.z);- // shade = shadow_factor(shadowCoord.xyz, lights[l].shadow.z, vec2(0));+ // shade = shadow_factor(shadowCoord.xyz, lights[l].shadow.z, vec2(0)); // looks like crap+ // TODO: VSM shadows } Lo += brdfSpecular(- lightDir,- ray,+ -lightDir, // XXX: according to PBR convention+ rayDir, normal, F0, metallic,@@ -162,7 +163,8 @@ ) * shade; } - vec3 reflection = prefilteredReflection(reflect(rayDir, normal), roughness).rgb;+ vec3 R = reflect(-rayDir, normal);+ vec3 reflection = prefilteredReflection(R, roughness).rgb; // IBL vec3 irradiance = vec3(0);@@ -172,7 +174,7 @@ cubes[nonuniformEXT(scene.envCubeId)], samplers[0] ),- -normal,+ normal * vec3(1, -1, 1), IRRADIANCE_LOD ).rgb; }@@ -208,12 +210,13 @@ vec3 color = Lo + ambient; // Tone mapping+ // TODO: make configurable color = Uncharted2Tonemap(color * 4.5) / Uncharted2Tonemap(vec3(11.2)); // White point // Gamma correction- // XXX: not needed, we're in linear already+ // XXX: not needed, we're in sRGB after tonemap // color = pow(color, vec3(1.0/2.2)); // Happily ever after@@ -257,8 +260,9 @@ vec3 prefilteredReflection(vec3 R, float roughness) { vec3 color = vec3(0);+ vec3 R_cube = R * vec3(1, -1, 1); - if (scene.envCubeId > -1) {+ if (scene.envCubeId > -1) { // TODO: wrap the whole call float lod = roughness * MAX_REFLECTION_LOD; float lodf = floor(lod); float lodc = ceil(lod);@@ -268,7 +272,7 @@ cubes[nonuniformEXT(scene.envCubeId)], samplers[0] ),- R,+ R_cube, lodf ).rgb; @@ -277,7 +281,7 @@ cubes[nonuniformEXT(scene.envCubeId)], samplers[0] ),- R,+ R_cube, lodc ).rgb; @@ -302,6 +306,7 @@ float dotNH = clamp(dot(N, H), 0.0, 1.0); float dotNV = clamp(dot(N, V), 0.0, 1.0); float dotNL = clamp(dot(N, L), 0.0, 1.0);+ float dotVH = clamp(dot(V, H), 0.0, 1.0); vec3 color = vec3(0.0); @@ -312,7 +317,7 @@ float rroughness = max(0.05, roughness); float G = G_SchlicksmithGGX(dotNL, dotNV, rroughness); // F = Fresnel factor (Reflectance depending on angle of incidence)- vec3 F = F_Schlick(dotNV, F0);+ vec3 F = F_Schlick(dotVH, F0); vec3 spec = D * F * G / (4.0 * dotNL * dotNV + 0.001); vec3 kD = (vec3(1.0) - F) * (1.0 - metallic); color += (kD * ALBEDO / 3.1415926535897932384626433832795 + spec) * dotNL * lightColor;
src/Render/Debug/Code.hs view
@@ -86,28 +86,28 @@ break; case 2:- float d0 = 1.0;+ float d0 = 0.0; if ((shadow_mask & 1) == 1) d0 = texture( shadowmaps, vec3(fTexCoord, 0.0) ).x; - float d1 = 1.0;+ float d1 = 0.0; if ((shadow_mask & 2) == 2) d1 = texture( shadowmaps, vec3(fTexCoord, 1.0) ).x; - float d2 = 1.0;+ float d2 = 0.0; if ((shadow_mask & 4) == 4) d2 = texture( shadowmaps, vec3(fTexCoord, 2.0) ).x; - texel = vec4(1-d0, 1-d1, 1-d2, 1.0);+ texel = vec4(d0, d1, d2, 1.0); break; default:
src/Render/DescSets/Set0.hs view
@@ -258,7 +258,7 @@ , Vk.magFilter = shadowFilter , Vk.minFilter = shadowFilter , Vk.compareEnable = True- , Vk.compareOp = Vk.COMPARE_OP_LESS+ , Vk.compareOp = Vk.COMPARE_OP_GREATER } let ifor = flip Vector.imapM
src/Render/DescSets/Sun.hs view
@@ -33,6 +33,7 @@ import Geomancy (Vec3, Vec4, vec3, vec4) import Geomancy.Transform (Transform) import Geomancy.Transform qualified as Transform+import Geomancy.Quaternion qualified as Quaternion import Geomancy.Vec4 qualified as Vec4 import Vulkan.Core10 qualified as Vk import Vulkan.CStruct.Extends (SomeStruct(..))@@ -173,7 +174,7 @@ , siRadius = Camera.PROJECTION_FAR / 2 , siTarget = 0 - , siDepthRange = Camera.PROJECTION_FAR+ , siDepthRange = Camera.PROJECTION_FAR -- TODO: use explicit near/far , siSize = 512 , siShadowIx = -1 }@@ -192,7 +193,7 @@ mkSun SunInput{..} = ( bbTransform , Sun- { sunViewProjection = mconcat vp+ { sunViewProjection = pv , sunShadow = vec4 0 0 siShadowIx siSize , sunPosition = Vec4.fromVec3 position 0 , sunDirection = Vec4.fromVec3 direction 0@@ -200,39 +201,26 @@ } ) where- vp =- [ Transform.rotateY (-siAzimuth)- , Transform.rotateX (-siInclination)-- , Transform.translate 0 0 siRadius-- -- XXX: some area beyond the near plane receives light, but not shadows- , Transform.scale3- (1 / siSize)- (1 / siSize)- (1 / siDepthRange)- ]-- position = Transform.apply (vec3 0 0 siRadius) rotation-- direction = Transform.apply (vec3 0 0 $ -1) rotation+ pv = p <> v+ p = -- just a scaled ortho box+ Transform.scale3+ (1 / siSize)+ (1 / siSize)+ (1 / siDepthRange)+ v =+ Transform.dirPos+ (Quaternion.extrinsic (-siAzimuth) (-siInclination) 0)+ (vec3 0 0 siRadius) bbTransform = mconcat- [ -- XXX: orient wire box "green/near -> far/red"- Transform.rotateX (τ/4)- -- XXX: the rest must be matched with VP flipped- , Transform.translate 0 0 0.5 -- XXX: shift origin to the near face-- -- XXX: reverse light transform- , Transform.scale3 siSize siSize siDepthRange -- XXX: size to projection volume- , Transform.translate 0 0 (-siRadius) -- XXX: translate near face to radius- , rotation -- XXX: apply sphere coords+ [ Transform.inverse pv+ , Transform.translate 0 0 0.5 -- shift origin to the near face+ , Transform.rotateX (τ/4) -- put the green side towards the light ] - rotation = mconcat- [ Transform.rotateX siInclination- , Transform.rotateY siAzimuth- ]+ position = rotation `Quaternion.rotate` vec3 0 0 siRadius+ direction = rotation `Quaternion.rotate` vec3 0 0 (-1)+ rotation = Quaternion.intrinsic 0 (siInclination) (siAzimuth) type Observer = Worker.ObserverIO (VectorS.Vector ("bounding box" ::: Transform))
src/Render/ForwardMsaa.hs view
@@ -78,7 +78,7 @@ } clear = Vector.fromList [ clearColor- , Vk.DepthStencil (Vk.ClearDepthStencilValue 1.0 0)+ , Vk.DepthStencil (Vk.ClearDepthStencilValue 0.0 0) , clearColor ] clearColor = Vk.Color zero
src/Render/Lit/Colored/Pipeline.hs view
@@ -65,11 +65,16 @@ { Graphics.cDescLayouts = Tagged @'[Scene] [set0] , Graphics.cStages = stageSpirv , Graphics.cVertexInput = Graphics.vertexInput @Pipeline+ , Graphics.cDepthWrite = False -- XXX: Lit pipelines require depth pre-pass+ , Graphics.cDepthCompare = Vk.COMPARE_OP_EQUAL } configBlend :: Tagged Scene DsLayoutBindings -> Config configBlend tset0 = (config tset0) { Graphics.cBlend = True+ , Graphics.cDepthCompare =+ -- XXX: blended objects aren't a part of depth prepass+ Vk.COMPARE_OP_GREATER_OR_EQUAL } stageCode :: Graphics.StageCode
src/Render/Lit/Material/Pipeline.hs view
@@ -75,7 +75,7 @@ True , Graphics.cDepthCompare = -- XXX: blended objects aren't a part of depth prepass- Vk.COMPARE_OP_LESS_OR_EQUAL+ Vk.COMPARE_OP_GREATER_OR_EQUAL } stageCode :: Graphics.StageCode
src/Render/Lit/Textured/Pipeline.hs view
@@ -71,8 +71,10 @@ configBlend :: Tagged Scene DsLayoutBindings -> Config configBlend tset0 = (config tset0)- { Graphics.cBlend = True- , Graphics.cDepthCompare = Vk.COMPARE_OP_LESS_OR_EQUAL+ { Graphics.cBlend = True+ , Graphics.cDepthCompare =+ -- XXX: blended objects aren't a part of depth prepass+ Vk.COMPARE_OP_GREATER_OR_EQUAL } stageCode :: Graphics.StageCode
src/Render/ShadowMap/Pipeline.hs view
@@ -37,8 +37,8 @@ defaults :: Settings defaults = Settings- { cull = Vk.CULL_MODE_BACK_BIT- , depthBias = Just (2.0, 2.5)+ { cull = Vk.CULL_MODE_FRONT_BIT+ , depthBias = Just (-2.0, -2.5) } allocate
src/Render/ShadowMap/RenderPass.hs view
@@ -87,7 +87,7 @@ } clear = Vector.fromList- [ Vk.DepthStencil (Vk.ClearDepthStencilValue 1.0 0)+ [ Vk.DepthStencil (Vk.ClearDepthStencilValue 0.0 0) ] -- ** Render pass
src/Render/Skybox/Code.hs view
@@ -15,21 +15,20 @@ ${set0binding0} - layout(location = 0) out vec3 fragUVW;+ layout(location = 0) out vec3 fUVW; - float farZ = 0.9999; // 1 - 1e-7;+ float farZ = 5.960464478e-8; // FLT_EPS void main() { vec4 pos = vec4(0.0); switch(gl_VertexIndex) { case 0: pos = vec4(-1.0, 3.0, farZ, 1.0); break;- case 1: pos = vec4(-1.0, -1.0, farZ, 1.0); break; // XXX: swapped with 2. culling?+ case 1: pos = vec4(-1.0, -1.0, farZ, 1.0); break; case 2: pos = vec4( 3.0, -1.0, farZ, 1.0); break; } vec3 unProjected = (scene.invProjection * pos).xyz;- unProjected *= -1;- fragUVW = mat3(scene.invView) * unProjected;+ fUVW = mat3(scene.invView) * unProjected; gl_Position = pos; }@@ -46,18 +45,20 @@ ${set0binding1} ${set0binding3} - layout(location = 0) in vec3 fragUVW;+ layout(location = 0) in vec3 fUVW; layout(location = 0) out vec4 outColor; void main() { if (scene.envCubeId > -1) {+ vec3 dir = fUVW;+ dir.y *= -1; // TODO: make customizable outColor = texture( samplerCube( cubes[nonuniformEXT(scene.envCubeId)], samplers[3] // XXX: linear ),- fragUVW+ dir ); } }
src/Render/Unlit/Colored/Code.hs view
@@ -40,11 +40,10 @@ [glsl| #version 450 - layout(location = 0) in vec4 fragColor;-+ layout(location = 0) in vec4 fColor; layout(location = 0) out vec4 outColor; void main() {- outColor = fragColor;+ outColor = fColor; } |]
src/Stage/Loader/UI.hs view
@@ -13,7 +13,7 @@ import Control.Monad.Trans.Resource (ResourceT) import Control.Monad.Trans.Resource qualified as Resource-import Geomancy (vec4)+import Geomancy (vec4, withVec2) import Geomancy.Layout qualified as Layout import Geomancy.Layout.Alignment qualified as Alignment import Geomancy.Layout.Box qualified as Box@@ -119,24 +119,22 @@ -- Spinner spinnerTransformTimeP <-- Worker.spawnTimed_ True 100 mempty do- t <- getMonotonicTime- pure $ Transform.rotateZ (realToFrac t)-- spinnerTransformBoxP <-- Worker.spawnMerge1- (Box.mkTransform) -- FIXME: . Layout.boxFitScale 64)- subtitleBoxP+ Worker.spawnTimed_ True 100 0.0 Engine.secondsSinceStart spinnerP <- Worker.spawnMerge2- ( \place turn ->- UnlitTextured.stores1+ ( \box time ->+ withVec2 box.position \x y ->+ withVec2 box.size \w h ->+ UnlitTextured.stores1 (Samplers.linear Samplers.indices) spinnerIx- [turn, place]+ [ Transform.translate x y 0+ , Transform.rotateZ time+ , Transform.scale (min 256 $ min w h)+ ] )- spinnerTransformBoxP+ subtitleBoxP spinnerTransformTimeP -- Models