From 110005b8594bce9c5b1890e7c6722716d3c54970 Mon Sep 17 00:00:00 2001 From: saschawillems Date: Fri, 24 Mar 2017 17:58:25 +0100 Subject: [PATCH] Overhauled parallax mapping example with multiple modes --- data/shaders/parallax/generate-spirv.bat | 4 - data/shaders/parallax/normalmap.frag | 50 --- data/shaders/parallax/normalmap.frag.spv | Bin 3580 -> 0 bytes data/shaders/parallax/normalmap.vert | 65 ---- data/shaders/parallax/normalmap.vert.spv | Bin 6076 -> 0 bytes data/shaders/parallax/parallax.frag | 171 ++++++--- data/shaders/parallax/parallax.frag.spv | Bin 4592 -> 8336 bytes data/shaders/parallax/parallax.vert | 58 +-- data/shaders/parallax/parallax.vert.spv | Bin 6076 -> 4448 bytes parallaxmapping/parallaxmapping.cpp | 356 +++++------------- parallaxmapping/parallaxmapping.vcxproj | 5 + .../parallaxmapping.vcxproj.filters | 11 + 12 files changed, 245 insertions(+), 475 deletions(-) delete mode 100644 data/shaders/parallax/generate-spirv.bat delete mode 100644 data/shaders/parallax/normalmap.frag delete mode 100644 data/shaders/parallax/normalmap.frag.spv delete mode 100644 data/shaders/parallax/normalmap.vert delete mode 100644 data/shaders/parallax/normalmap.vert.spv diff --git a/data/shaders/parallax/generate-spirv.bat b/data/shaders/parallax/generate-spirv.bat deleted file mode 100644 index be825473..00000000 --- a/data/shaders/parallax/generate-spirv.bat +++ /dev/null @@ -1,4 +0,0 @@ -glslangvalidator -V parallax.vert -o parallax.vert.spv -glslangvalidator -V parallax.frag -o parallax.frag.spv -glslangvalidator -V normalmap.vert -o normalmap.vert.spv -glslangvalidator -V normalmap.frag -o normalmap.frag.spv \ No newline at end of file diff --git a/data/shaders/parallax/normalmap.frag b/data/shaders/parallax/normalmap.frag deleted file mode 100644 index 9c4c3bfc..00000000 --- a/data/shaders/parallax/normalmap.frag +++ /dev/null @@ -1,50 +0,0 @@ -#version 450 - -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable - -layout (binding = 1) uniform sampler2D sColorMap; -layout (binding = 2) uniform sampler2D sNormalHeightMap; - -layout (binding = 3) uniform UBO -{ - float scale; - float bias; - float lightRadius; - int usePom; - int displayNormalMap; -} ubo; - -layout (location = 0) in vec2 inUV; -layout (location = 1) in vec3 inLightVec; -layout (location = 2) in vec3 inLightVecB; -layout (location = 3) in vec3 inSpecular; -layout (location = 4) in vec3 inEyeVec; -layout (location = 5) in vec3 inLightDir; -layout (location = 6) in vec3 inViewVec; - -layout (location = 0) out vec4 outFragColor; - -void main(void) -{ - vec3 specularColor = vec3(0.0, 0.0, 0.0); - - float invRadius = 1.0/ubo.lightRadius; - float ambient = 0.5; - - vec3 rgb, normal; - - rgb = (ubo.displayNormalMap == 0) ? texture(sColorMap, inUV).rgb : texture(sNormalHeightMap, inUV).rgb; - normal = normalize((texture(sNormalHeightMap, inUV).rgb - 0.5) * 2.0); - - float distSqr = dot(inLightVecB, inLightVecB); - vec3 lVec = inLightVecB * inversesqrt(distSqr); - - vec3 nvViewVec = normalize(inViewVec); - float specular = pow(clamp(dot(reflect(-nvViewVec, normal), lVec), 0.0, 1.0), 4.0); - - float atten = clamp(1.0 - invRadius * sqrt(distSqr), 0.0, 1.0); - float diffuse = clamp(dot(lVec, normal), 0.0, 1.0); - - outFragColor = vec4((rgb * ambient + (diffuse * rgb + 0.5 * specular * specularColor.rgb)) * atten, 1.0); -} diff --git a/data/shaders/parallax/normalmap.frag.spv b/data/shaders/parallax/normalmap.frag.spv deleted file mode 100644 index f02b933829fa8be1d4f1795da9956df70fac2a32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3580 zcmZ9NX>$}+6o%VuYym`eQA|J)1tTILifmy?)Bu4<5K%)<(j*O&nJ_Z}abYRTDnI$j zU*XU2Pq|cC<@5CP!G@kXbo#k{9@`OdciOXG78hPLegrKrxO@ zOihfmJ98t44j)jlF6k|VYSt%flRidmG0htW_G8~;XR#l!AF+qnMQj0kk@@OZV!ix& z82=zyU$QD0o0vI$Wpt*UEv2orlg+dj(z&cP)2!XjW;^X?HH7lU{7gM<%rB?&+03DX z2bR*=J4rv8s`d1d>uKvuv)*ih`}wV9%p3QvkZPIqFul~5Bv(f-F{{7u zfk}Hdt!IqEx%XP0It6Z^(7BI#KEKc@vxU~vT5e~P%|*2<3$69d_m?*&oHd=zjux76xH^cT&|F|_+?&p``(4ty zyyv{}EO!|$&L6kPb%QbObTXU9^=piC`K?==6?mZNmF9Bid@G%gD}(PZdh7qXx^>uR zd1I=);Vx(2<&AR>vP!-7VLA6~P7{oi&-?b--5s8C-m#o_6*})&&fX2Kx8w#ZoO9Hf zd#vm!=Z=xh``v~41RlmWkJx*y#>K|1$GCUA6Y~*!$5p*peXQp_st@e_hzBs|FO-;} zz`nc2V?EDS9QApwV)y9$hb8W3+{h}fGmKij{uVsf8p5`s=YvyV<3nK2Qcl|kR=XPW z*$f7Qk~}`SnfQ9VAFn`AgiCXK(sO4jPdCezkndDYo?>Oe&h5f`i%AdfTYy8)eJB2Ur zdpuaqKaFqBbJ!`&y6t88*psod6@0$LzmeD88pG7cJAbs~V*V%Kn6Lg*OpP^&Kf|nH z2s0M-PT)J&xOsht8sD1Y9IoN3mmj2e-P;$K^Zni$Uyb=5n&0@Bm~neW?RCt${T>)|Ep=aE zYb*F`{OTEg12&KEsj;8SyP3gvu5o+ATsJXmFcx*D_)+Ig{HW7fZh(!)zGv~>ci=gE z&n(U%!&f68`ETJze&f~rHL&r>m*aaLvG?2f+py@1JNRnkLsQ2$Pvls{H%H8A;LE9t zIZb@eInHVc-}gv9^4!H=g+-ngzMR@8<$Kk}H@~sqI{4OUEY@4b_bemVJ$!ZYm&?1k qk1y{N+_(60o?mbeO0I`-l3p5N{0?)zdgI=)_qV`k>|Zh*#r^}TVho7@ diff --git a/data/shaders/parallax/normalmap.vert b/data/shaders/parallax/normalmap.vert deleted file mode 100644 index a559ee51..00000000 --- a/data/shaders/parallax/normalmap.vert +++ /dev/null @@ -1,65 +0,0 @@ -#version 450 - -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable - -layout (location = 0) in vec3 inPos; -layout (location = 1) in vec2 inUV; -layout (location = 2) in vec3 inNormal; -layout (location = 3) in vec3 inTangent; -layout (location = 4) in vec3 inBiTangent; - -layout (binding = 0) uniform UBO -{ - mat4 projection; - mat4 model; - mat4 normal; - vec4 lightPos; - vec4 cameraPos; -} ubo; - -layout (location = 0) out vec2 outUV; -layout (location = 1) out vec3 outLightVec; -layout (location = 2) out vec3 outLightVecB; -layout (location = 3) out vec3 outSpecular; -layout (location = 4) out vec3 outEyeVec; -layout (location = 5) out vec3 outLightDir; -layout (location = 6) out vec3 outViewVec; - -void main(void) -{ - vec3 vertexPosition = vec3(ubo.model * vec4(inPos, 1.0)); - outLightDir = normalize(ubo.lightPos.xyz - vertexPosition); - - // Setup (t)angent-(b)inormal-(n)ormal matrix for converting - // object coordinates into tangent space - mat3 tbnMatrix; - tbnMatrix[0] = mat3(ubo.normal) * inTangent; - tbnMatrix[1] = mat3(ubo.normal) * inBiTangent; - tbnMatrix[2] = mat3(ubo.normal) * inNormal; - - outEyeVec = vec3(-vertexPosition) * tbnMatrix; - - outLightVec.xyz = vec3(ubo.lightPos.xyz - vertexPosition.xyz) * tbnMatrix; - - vec3 lightDist = ubo.lightPos.xyz - inPos.xyz; - outLightVecB.x = dot(inTangent.xyz, lightDist); - outLightVecB.y = dot(inBiTangent.xyz, lightDist); - outLightVecB.z = dot(inNormal, lightDist); - - vec3 camPos = vec3(ubo.normal * ubo.cameraPos); - - vec3 camVec = camPos - inPos.xyz; - outViewVec.x = dot(inTangent, camVec); - outViewVec.y = dot(inBiTangent, camVec); - outViewVec.z = dot(inNormal, camVec); - - vec3 reflectVec = reflect(-camVec, inNormal); - vec3 outViewVec = outLightDir; - float specIntensity = pow(max(dot(reflectVec, outViewVec), 0.0), 8.0); - outSpecular = vec3(specIntensity * 0.3); - - outUV = inUV; - - gl_Position = ubo.projection * ubo.model * vec4(inPos, 1.0); -} diff --git a/data/shaders/parallax/normalmap.vert.spv b/data/shaders/parallax/normalmap.vert.spv deleted file mode 100644 index 8561f391a001ef12ecf5b7906c73c1f36ce51038..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6076 zcmZXX`FoUC6~|v731zVbE2Y+oA*ou$21Ht`wKN23K+_VMg1hMuhA=dl#L1+ExhiRq?;@7oW$^=bd}vHC~=C_nhzf-gEBy4lJ18y|5_e z@#nnapGB)JFXrPH#gd|-PJA$eP|sOTRU-gHyn@KklO(x^16!&Cbz zd#a7$iQW6FBTW+K8bY=D=smyO+p3Lb^}yi7 zRIOQ?VCL=AUJAdnZ##;P(#9<&8xvM5H65tbxc2dhJ=HP#;GB1TqA^~9jPdT&SZ#D) zlQNjIyz?2Uj8_|#R>0cl!%gp=DCg@Q*6I;!FZXI)1nZ<(jtC zrdl;R%5%+heMnHY6%Wv}&T=98CtH45z+9d`<95}mx6g8?;TqMwW9<1X_t5|8I*Nzk zrY5T++v?3~okKi`Z_b&Pc8JjQSjD|+EAJn5cJ3-QZRP!})k~LnNAXMe(XrvdYGYS< zD{#xRlD8R)i_%dnEcM=jlCRa9L$y1q>LND3727;kn{<~d^^xjq%sauj&C_FJvoX)# zcVKf3z6Ug|$!yzF&hcD}+g5MogDr}!tj+sqYX@8TJN)jF{a=p9UMwqht#Pg)AE)oQ zUJ$wD=8kiH`8a*Y9R@K@?!V(&^K$L#&VbPQ7UW!ie|m$C?PqPii7sFZe|5_(ec#Ed z%vY=L+|>6b-@5v~1>@G#_Z{d*J>Nhc_x|g<2kMU`KlI*T;~gnJll-XXch9)Z@qQO0 zpX-nNwWL(E_C(Hla`vIKrkuHh)0S(kXF-`S=H?wT7JG3n`Ofu1R;+F{+03DR5tgw| zu#$|Poxbr-{PXDLgz?4n#;tuZe_KmVe-$e4py<^IQpv;_!9qS7W)Z(Cc?4F6wnBU;Sm+)^q-@ zbq&2^V{e|9eEAsPgKZ0cEw(vgKI;wAV!plD&NqDTYVPmNeCN9#SYN%qcQyCDtNQNe zyXZTC&HDOxm!5oEaSygy_bK8>vFBy}{n#;o&*ud2tfT%ZY;&0JJM`{P~X^sQaX9G1{u2;}wE zUIctwI~e1hUYt0(S?;Ncb00!?N#fjtK{C0APXmruZ`?O}jJ(D!1=dy*Ii8+)x>?Te zsoK2OGZNRT<*%~mRTPd_Z+s&s;C^=k*Y6vDCUE`T!1X$hX94-`oRE2*oj7@$b*&To zb2+wo?;@xA=K#mZFJ;H%o(mjzJuvQEy6ENOEY@K=m$e|y;`!L}JILeSzW~TZ3w{Gc z@YV_b%8Yl;!C#elwYK12h;1JEJkQk`pXYf|;^l0S=f&9Okt^C&nvL!p3f`cbG&-v)?7pX2H>2Irgz`KRx9ru_tVR{hRf)iz&q3p%(0k$8py}* z!EK3?w>dZG66?Gj+jYk8!2xW?$j7=4V$0ity8~M;U+Wtam#_6raE@1RJl6VV?0l_n z!B;EqTBqpcVy%a<=dSfmIQdxXTe0PY&AH`ky$gQ@h_${A+cEOiJVY-Sd-Hbe-pqdo zwwn9c{|@?h0yXl^^B($lgCpQ>U`~B?k@G#+emlZ{FLs{uefVnRBj+(}a~=ie)K?cd z?#1@LhyQ-;Jm-D*YUCs52e8d~KQO1hI^)afKM36KwZObf=#K+=HQv7u0W~Lp8t>nS zf&4Kv`X2#~laIUe(Ztiuavw{aXBN5#6XzMmx8UR0j#vL6aPAM#%g6dZfh`yQC$aN$ z{}jF&dB>lmmka%;v3oQBGuUe4+&_!0Mn3lQbJ(XqoV&id$oYBf{M^5QpXdA{z8d++ z`6X;~#<}aOi=1D^&d>cT_<7E+;;WI5oL|E>XPmpfy2$x;Y;(kS?;F^15&tH(HJ9=) zlZEu(0-jkvP;1;hJxy;c#(f*RE5#n7*N@nDvDJtFJ#00x-`~epBX8Xf`X2!6UJi_} z2NC-rwy{fqx--BzJxp)RI_CHhkUPR%)&Ftg9-)u>_LIaL6Xuzrmp9L&^gjn@fw9Mu z?|%D^ehqvhJwUzh=r=$2ac0h5oJjjsg9sO=m6E3m#A=llfy-@xO*b-8YRb^m7PuLl1Cn>7;P diff --git a/data/shaders/parallax/parallax.frag b/data/shaders/parallax/parallax.frag index c002f196..4787bbf2 100644 --- a/data/shaders/parallax/parallax.frag +++ b/data/shaders/parallax/parallax.frag @@ -1,66 +1,143 @@ #version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable - layout (binding = 1) uniform sampler2D sColorMap; layout (binding = 2) uniform sampler2D sNormalHeightMap; layout (binding = 3) uniform UBO { - float scale; - float bias; - float lightRadius; - int usePom; - int displayNormalMap; + float heightScale; + float parallaxBias; + float numLayers; + int mappingMode; } ubo; layout (location = 0) in vec2 inUV; -layout (location = 1) in vec3 inLightVec; -layout (location = 2) in vec3 inLightVecB; -layout (location = 3) in vec3 inSpecular; -layout (location = 4) in vec3 inEyeVec; -layout (location = 5) in vec3 inLightDir; -layout (location = 6) in vec3 inViewVec; +layout (location = 1) in vec3 inTangentLightPos; +layout (location = 2) in vec3 inTangentViewPos; +layout (location = 3) in vec3 inTangentFragPos; -layout (location = 0) out vec4 outFragColor; +layout (location = 0) out vec4 outColor; + +vec2 parallax_uv(vec2 uv, vec3 view_dir, int type) +{ + if (type == 2) { + // Parallax mapping + float depth = 1.0 - texture(sNormalHeightMap, uv).a; + vec2 p = view_dir.xy * (depth * (ubo.heightScale * 0.5) + ubo.parallaxBias) / view_dir.z; + return uv - p; + } else { + float layer_depth = 1.0 / ubo.numLayers; + float cur_layer_depth = 0.0; + vec2 delta_uv = view_dir.xy * ubo.heightScale / (view_dir.z * ubo.numLayers); + vec2 cur_uv = uv; + + float depth_from_tex = 1.0 - texture(sNormalHeightMap, cur_uv).a; + + for (int i = 0; i < 32; i++) { + cur_layer_depth += layer_depth; + cur_uv -= delta_uv; + depth_from_tex = 1.0 - texture(sNormalHeightMap, cur_uv).a; + if (depth_from_tex < cur_layer_depth) { + break; + } + } + + if (type == 3) { + // Steep parallax mapping + return cur_uv; + } else { + // Parallax occlusion mapping + vec2 prev_uv = cur_uv + delta_uv; + float next = depth_from_tex - cur_layer_depth; + float prev = 1.0 - texture(sNormalHeightMap, prev_uv).a - cur_layer_depth + layer_depth; + float weight = next / (next - prev); + return mix(cur_uv, prev_uv, weight); + } + } +} + +vec2 parallaxMapping(vec2 uv, vec3 viewDir) +{ + float height = 1.0 - texture(sNormalHeightMap, uv).a; + vec2 p = viewDir.xy * (height * (ubo.heightScale * 0.5) + ubo.parallaxBias) / viewDir.z; + return uv - p; +} + +vec2 steepParallaxMapping(vec2 uv, vec3 viewDir) +{ + float layerDepth = 1.0 / ubo.numLayers; + float currLayerDepth = 0.0; + vec2 deltaUV = viewDir.xy * ubo.heightScale / (viewDir.z * ubo.numLayers); + vec2 currUV = uv; + float height = 1.0 - texture(sNormalHeightMap, currUV).a; + for (int i = 0; i < ubo.numLayers; i++) { + currLayerDepth += layerDepth; + currUV -= deltaUV; + height = 1.0 - texture(sNormalHeightMap, currUV).a; + if (height < currLayerDepth) { + break; + } + } + return currUV; +} + +vec2 parallaxOcclusionMapping(vec2 uv, vec3 viewDir) +{ + float layerDepth = 1.0 / ubo.numLayers; + float currLayerDepth = 0.0; + vec2 deltaUV = viewDir.xy * ubo.heightScale / (viewDir.z * ubo.numLayers); + vec2 currUV = uv; + float height = 1.0 - texture(sNormalHeightMap, currUV).a; + for (int i = 0; i < ubo.numLayers; i++) { + currLayerDepth += layerDepth; + currUV -= deltaUV; + height = 1.0 - texture(sNormalHeightMap, currUV).a; + if (height < currLayerDepth) { + break; + } + } + vec2 prevUV = currUV + deltaUV; + float nextDepth = height - currLayerDepth; + float prevDepth = 1.0 - texture(sNormalHeightMap, prevUV).a - currLayerDepth + layerDepth; + return mix(currUV, prevUV, nextDepth / (nextDepth - prevDepth)); +} void main(void) { - vec3 specularColor = vec3(0.0, 0.0, 0.0); + vec3 V = normalize(inTangentViewPos - inTangentFragPos); + vec2 uv = inUV; - float invRadius = 1.0/ubo.lightRadius; - float ambient = 0.5; + if (ubo.mappingMode == 0) { + // Color only + outColor = texture(sColorMap, inUV); + } else { + switch(ubo.mappingMode) { + case 2: + uv = parallaxMapping(inUV, V); + break; + case 3: + uv = steepParallaxMapping(inUV, V); + break; + case 4: + uv = parallaxOcclusionMapping(inUV, V); + break; + } - vec3 rgb, normal, eyeVecTs; - vec2 UV = inUV; + // Discard fragments at texture border + if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) { + discard; + } - // Get new scaled and biased texture coordinates - // Height info is stored in alpha channel of normal map - vec2 height_bump = vec2(texture(sNormalHeightMap, inUV).a * ubo.scale + ubo.bias, 0.0); + vec3 N = normalize(texture(sNormalHeightMap, uv).rgb * 2.0 - 1.0); + vec3 L = normalize(inTangentLightPos - inTangentFragPos); + vec3 R = reflect(-L, N); + vec3 H = normalize(L + V); + + vec3 color = texture(sColorMap, uv).rgb; + vec3 ambient = 0.2 * color; + vec3 diffuse = max(dot(L, N), 0.0) * color; + vec3 specular = vec3(0.15) * pow(max(dot(N, H), 0.0), 32.0); - // If parallax mapping is enabled, offset texture coordinates - if (ubo.usePom == 1) - { - UV = inUV + (height_bump.x * normalize(inEyeVec).xy); - } - - rgb = (ubo.displayNormalMap == 0) ? texture(sColorMap, UV).rgb : texture(sNormalHeightMap, UV).rgb; - - normal = normalize((texture(sNormalHeightMap, UV).rgb - 0.5) * 2.0); - - eyeVecTs = normalize(inLightVec).xyz; - height_bump.y = min(dot(normal, eyeVecTs.xyz), 1.0); - height_bump.y = pow(height_bump.y, 8.0); - - float distSqr = dot(inLightVecB, inLightVecB); - vec3 lVec = inLightVecB * inversesqrt(distSqr); - - vec3 nvViewVec = normalize(inViewVec); - float specular = pow(clamp(dot(reflect(-nvViewVec, normal), lVec), 0.0, 1.0), 4.0); - - float atten = clamp(1.0 - invRadius * sqrt(distSqr), 0.0, 1.0); - float diffuse = clamp(dot(lVec, normal), 0.0, 1.0); - - outFragColor = vec4((rgb * ambient + (diffuse * rgb + 0.5 * specular * specularColor.rgb)) * atten, 1.0); + outColor = vec4(ambient + diffuse + specular, 1.0f); + } } diff --git a/data/shaders/parallax/parallax.frag.spv b/data/shaders/parallax/parallax.frag.spv index b63863190d789dfe848839b24cee56e16a35f00e..ccad474ef5d1b2e6df8ba61620db5446395c26fa 100644 GIT binary patch literal 8336 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 Q@2h#4i+28gsq^>ie<=SMt^fc4 literal 4592 zcmZ9O2X|CO7>2J&Hi8rz*iczOMFkNNu%JLeDlrB-E?-WI6X;D<8My#Thbn9CmqO1GB4@Q=DvX) z18bVC(KYKgtkq*-(wRBxb7rz2>0%ZWX|=B5QZNRl!7rc}{0a_%kHA^P>pur{^4G!q zJIT6|xk=x^P|x<>p=M<&ZKSQrP;*Z@T4@YT4nJ8LX*K`vgQ;2{AF8GG@#%EDGPHi( z+NpG8Z&D&tv7Qq9n9CZ?smjQ7Ep6O3S(|Jim-t)2T&?flPO53rqv@o+B-z=!ji^$_ z5tHUfTB|UJ&b<#;Q$x^oXMXOZRvq8d%Cm*9-I{Jz1}7)>f@|x9)7D<8d9(m$Lg>t?$ThN_&sq z-MrS@t6ZFZ{JbNM747Mi&U>NG^9?`mg*xwh=sI)V{DRIH{mk8$-$P^j$mX3`4jdsb zgPTX$Hzyp*o_o<>S^vn_3)kN@_4llc{>u8hAMKv0{vmsQ%8}1=QSJu%`_7de%6gNG<0psj<Y`C@Rvx!(`&q4Q&`16K`P!>;z2_D+Ujw)1)gWqK16TiI9(OI=SoINi9o#tIP{gf+ zt3Q&*T@N=_{UAE`v>vGUyXU^j%<9bRo4Wy+*SBb1-`|Zu{YiX$hd1Xs*ZzYXw=g^Y z#$Veepw7D~j~?9$w@0q!S#JSluo=W2w!+mbd(O9kUNE22Q@$Pe7VZGrwxM-j%G!iO zpX2$S?}TgL3ha&keZYFO#rdlHi<+Z$=jh8laQou7B>FM{S08=37p~5;v@hG39ri`r zePAcBFLLvEm+l9Cla#G(JGdCcUD^THNBuTlxqWy5s22|R+X38*Z&bT`u?E+3-B@oI zym)taBNx|u5LqAfvED;)^};cGJ?+KyT-Wui^hcI^S{NdCuHAQef;8z`LPt1gIYdamPmC=Jd{Jw{E|4>SIsi@G%fE zd*BhH&6oeyfe(|BJW}NArNPC1a2PB^Dr>xAhY_2c^E?e&>-~tf$;#0Uj>Z3oO z!OasnK8KqlV!nW@(=TGagxlxn)mL!8C0~Nb^EG@fh&aC;fKet_$zKK^(35w6}5x}V_c>|f|k=DH5%L2l|w=AVJ_`fK-$J-?5bwf#ee G8^OQehHrfU diff --git a/data/shaders/parallax/parallax.vert b/data/shaders/parallax/parallax.vert index ec8473d9..1d6e9bdc 100644 --- a/data/shaders/parallax/parallax.vert +++ b/data/shaders/parallax/parallax.vert @@ -1,8 +1,5 @@ #version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable - layout (location = 0) in vec3 inPos; layout (location = 1) in vec2 inUV; layout (location = 2) in vec3 inNormal; @@ -12,54 +9,29 @@ layout (location = 4) in vec3 inBiTangent; layout (binding = 0) uniform UBO { mat4 projection; + mat4 view; mat4 model; - mat4 normal; vec4 lightPos; vec4 cameraPos; } ubo; layout (location = 0) out vec2 outUV; -layout (location = 1) out vec3 outLightVec; -layout (location = 2) out vec3 outLightVecB; -layout (location = 3) out vec3 outSpecular; -layout (location = 4) out vec3 outEyeVec; -layout (location = 5) out vec3 outLightDir; -layout (location = 6) out vec3 outViewVec; +layout (location = 1) out vec3 outTangentLightPos; +layout (location = 2) out vec3 outTangentViewPos; +layout (location = 3) out vec3 outTangentFragPos; void main(void) { - vec3 vertexPosition = vec3(ubo.model * vec4(inPos, 1.0)); - outLightDir = normalize(ubo.lightPos.xyz - vertexPosition); + gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPos, 1.0f); + outTangentFragPos = vec3(ubo.model * vec4(inPos, 1.0)); + outUV = inUV; + + vec3 T = normalize(mat3(ubo.model) * inTangent); + vec3 B = normalize(mat3(ubo.model) * inBiTangent); + vec3 N = normalize(mat3(ubo.model) * inNormal); + mat3 TBN = transpose(mat3(T, B, N)); - // Setup (t)angent-(b)inormal-(n)ormal matrix for converting - // object coordinates into tangent space - mat3 tbnMatrix; - tbnMatrix[0] = mat3(ubo.normal) * inTangent; - tbnMatrix[1] = mat3(ubo.normal) * inBiTangent; - tbnMatrix[2] = mat3(ubo.normal) * inNormal; - - outEyeVec = vec3(-vertexPosition) * tbnMatrix; - - outLightVec.xyz = vec3(ubo.lightPos.xyz - vertexPosition.xyz) * tbnMatrix; - - vec3 lightDist = ubo.lightPos.xyz - inPos.xyz; - outLightVecB.x = dot(inTangent.xyz, lightDist); - outLightVecB.y = dot(inBiTangent.xyz, lightDist); - outLightVecB.z = dot(inNormal, lightDist); - - vec3 camPos = vec3(ubo.normal * ubo.cameraPos); - - vec3 camVec = camPos - inPos.xyz; - outViewVec.x = dot(inTangent, camVec); - outViewVec.y = dot(inBiTangent, camVec); - outViewVec.z = dot(inNormal, camVec); - - vec3 reflectVec = reflect(-camVec, inNormal); - vec3 outViewVec = outLightDir; - float specIntensity = pow(max(dot(reflectVec, outViewVec), 0.0), 8.0); - outSpecular = vec3(specIntensity * 0.3); - - outUV = inUV; - - gl_Position = ubo.projection * ubo.model * vec4(inPos, 1.0); + outTangentLightPos = TBN * ubo.lightPos.xyz; + outTangentViewPos = TBN * ubo.cameraPos.xyz; + outTangentFragPos = TBN * outTangentFragPos; } diff --git a/data/shaders/parallax/parallax.vert.spv b/data/shaders/parallax/parallax.vert.spv index 8561f391a001ef12ecf5b7906c73c1f36ce51038..9c99a660f4c17c43b8249c248b63aabcd5947ff0 100644 GIT binary patch literal 4448 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 diff --git a/parallaxmapping/parallaxmapping.cpp b/parallaxmapping/parallaxmapping.cpp index 4fbc22c2..e98912c0 100644 --- a/parallaxmapping/parallaxmapping.cpp +++ b/parallaxmapping/parallaxmapping.cpp @@ -30,20 +30,12 @@ class VulkanExample : public VulkanExampleBase { public: - bool splitScreen = false; - struct { vks::Texture2D colorMap; - // Normals and height are combined in one texture (height = alpha channel) + // Normals and height are combined into one texture (height = alpha channel) vks::Texture2D normalHeightMap; } textures; - struct { - VkPipelineVertexInputStateCreateInfo inputState; - std::vector bindingDescriptions; - std::vector attributeDescriptions; - } vertices; - // Vertex layout for the models vks::VertexLayout vertexLayout = vks::VertexLayout({ vks::VERTEX_COMPONENT_POSITION, @@ -66,52 +58,44 @@ public: struct { glm::mat4 projection; + glm::mat4 view; glm::mat4 model; - glm::mat4 normal; - glm::vec4 lightPos = glm::vec4(0.0f); + glm::vec4 lightPos = glm::vec4(0.0f, -2.0f, 0.0f, 1.0f); glm::vec4 cameraPos; } vertexShader; struct { - // Scale and bias control the parallax offset effect - // They need to be tweaked for each material - // Getting them wrong destroys the depth effect - float scale = 0.06f; - float bias = -0.04f; - float lightRadius = 1.0f; - int32_t usePom = 1; - int32_t displayNormalMap = 0; + float heightScale = 0.1f; + // Basic parallax mapping needs a bias to look any good (and is hard to tweak) + float parallaxBias = -0.02f; + // Number of layers for steep parallax and parallax occlusion (more layer = better result for less performance) + float numLayers = 48.0f; + // (Parallax) mapping mode to use + int32_t mappingMode = 4; } fragmentShader; } ubos; - struct { - VkPipeline parallaxMapping; - VkPipeline normalMapping; - } pipelines; - VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; + VkPipeline pipeline; VkDescriptorSetLayout descriptorSetLayout; + VkDescriptorSet descriptorSet; VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) { - zoom = -2.7f; - rotation = glm::vec3(56.0f, 0.0f, 0.0f); - rotationSpeed = 0.25f; - enableTextOverlay = true; - timerSpeed *= 0.25f; - paused = true; title = "Vulkan Example - Parallax Mapping"; + enableTextOverlay = true; + timerSpeed *= 0.5f; + camera.type = Camera::CameraType::firstperson; + camera.setPosition(glm::vec3(0.0f, 1.25f, 1.5f)); + camera.setRotation(glm::vec3(-45.0f, 180.0f, 0.0f)); + camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f); } ~VulkanExample() { - // Clean up used Vulkan resources - // Note : Inherited destructor cleans up resources stored in base class - vkDestroyPipeline(device, pipelines.parallaxMapping, nullptr); - vkDestroyPipeline(device, pipelines.normalMapping, nullptr); - + vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); @@ -127,6 +111,7 @@ public: void loadAssets() { models.quad.loadFromFile(getAssetPath() + "models/plane_z.obj", vertexLayout, 0.1f, vulkanDevice, queue); + // Textures textures.normalHeightMap.loadFromFile(getAssetPath() + "textures/rocks_normal_height_rgba.dds", VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue); if (vulkanDevice->features.textureCompressionBC) { @@ -141,17 +126,6 @@ public: else { vks::tools::exitFatal("Device does not support any compressed texture format!", "Error"); } - - } - - void reBuildCommandBuffers() - { - if (!checkCommandBuffers()) - { - destroyCommandBuffers(); - createCommandBuffers(); - } - buildCommandBuffers(); } void buildCommandBuffers() @@ -180,7 +154,7 @@ public: vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - VkViewport viewport = vks::initializers::viewport((splitScreen) ? (float)width / 2.0f : (float)width, (float)height, 0.0f, 1.0f); + VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); @@ -192,82 +166,16 @@ public: vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &models.quad.vertices.buffer, offsets); vkCmdBindIndexBuffer(drawCmdBuffers[i], models.quad.indices.buffer, 0, VK_INDEX_TYPE_UINT32); - // Parallax enabled vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.parallaxMapping); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdDrawIndexed(drawCmdBuffers[i], models.quad.indexCount, 1, 0, 0, 1); - // Normal mapping - if (splitScreen) - { - viewport.x = (float)width / 2.0f; - vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.normalMapping); - vkCmdDrawIndexed(drawCmdBuffers[i], models.quad.indexCount, 1, 0, 0, 1); - } - vkCmdEndRenderPass(drawCmdBuffers[i]); VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); } } - void setupVertexDescriptions() - { - // Binding description - vertices.bindingDescriptions.resize(1); - vertices.bindingDescriptions[0] = - vks::initializers::vertexInputBindingDescription( - VERTEX_BUFFER_BIND_ID, - vertexLayout.stride(), - VK_VERTEX_INPUT_RATE_VERTEX); - - // Attribute descriptions - // Describes memory layout and shader positions - vertices.attributeDescriptions.resize(5); - // Location 0 : Position - vertices.attributeDescriptions[0] = - vks::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - 0, - VK_FORMAT_R32G32B32_SFLOAT, - 0); - // Location 1 : Texture coordinates - vertices.attributeDescriptions[1] = - vks::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - 1, - VK_FORMAT_R32G32_SFLOAT, - sizeof(float) * 3); - // Location 2 : Normal - vertices.attributeDescriptions[2] = - vks::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - 2, - VK_FORMAT_R32G32B32_SFLOAT, - sizeof(float) * 5); - // Location 3 : Tangent - vertices.attributeDescriptions[3] = - vks::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - 3, - VK_FORMAT_R32G32B32_SFLOAT, - sizeof(float) * 8); - // Location 4 : Bitangent - vertices.attributeDescriptions[4] = - vks::initializers::vertexInputAttributeDescription( - VERTEX_BUFFER_BIND_ID, - 4, - VK_FORMAT_R32G32B32_SFLOAT, - sizeof(float) * 11); - - vertices.inputState = vks::initializers::pipelineVertexInputStateCreateInfo(); - vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size(); - vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data(); - vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size(); - vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data(); - } - void setupDescriptorPool() { // Example uses two ubos and two image sampler @@ -278,44 +186,22 @@ public: }; VkDescriptorPoolCreateInfo descriptorPoolInfo = - vks::initializers::descriptorPoolCreateInfo( - poolSizes.size(), - poolSizes.data(), - 4); + vks::initializers::descriptorPoolCreateInfo(poolSizes, 2); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); } void setupDescriptorSetLayout() { - std::vector setLayoutBindings = - { - // Binding 0 : Vertex shader uniform buffer - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - VK_SHADER_STAGE_VERTEX_BIT, - 0), - // Binding 1 : Fragment shader color map image sampler - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - VK_SHADER_STAGE_FRAGMENT_BIT, - 1), - // Binding 2 : Fragment combined normal and heightmap - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - VK_SHADER_STAGE_FRAGMENT_BIT, - 2), - // Binding 3 : Fragment shader uniform buffer - vks::initializers::descriptorSetLayoutBinding( - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - VK_SHADER_STAGE_FRAGMENT_BIT, - 3) + std::vector setLayoutBindings = { + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), // Binding 0: Vertex shader uniform buffer + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1), // Binding 1: Fragment shader color map image sampler + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 2), // Binding 2: Fragment combined normal and heightmap + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 3), // Binding 3: Fragment shader uniform buffer }; VkDescriptorSetLayoutCreateInfo descriptorLayout = - vks::initializers::descriptorSetLayoutCreateInfo( - setLayoutBindings.data(), - setLayoutBindings.size()); + vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); @@ -337,99 +223,52 @@ public: VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); - std::vector writeDescriptorSets = - { - // Binding 0 : Vertex shader uniform buffer - vks::initializers::writeDescriptorSet( - descriptorSet, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 0, - &uniformBuffers.vertexShader.descriptor), - // Binding 1 : Fragment shader image sampler - vks::initializers::writeDescriptorSet( - descriptorSet, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - 1, - &textures.colorMap.descriptor), - // Binding 2 : Combined normal and heightmap - vks::initializers::writeDescriptorSet( - descriptorSet, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - 2, - &textures.normalHeightMap.descriptor), - // Binding 3 : Fragment shader uniform buffer - vks::initializers::writeDescriptorSet( - descriptorSet, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 3, - &uniformBuffers.fragmentShader.descriptor) + std::vector writeDescriptorSets = { + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.vertexShader.descriptor), // Binding 0: Vertex shader uniform buffer + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &textures.colorMap.descriptor), // Binding 1: Fragment shader image sampler + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, &textures.normalHeightMap.descriptor), // Binding 2: Combined normal and heightmap + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3, &uniformBuffers.fragmentShader.descriptor), // Binding 3: Fragment shader uniform buffer }; - vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); } void preparePipelines() { VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = - vks::initializers::pipelineInputAssemblyStateCreateInfo( - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - 0, - VK_FALSE); + vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); VkPipelineRasterizationStateCreateInfo rasterizationState = - vks::initializers::pipelineRasterizationStateCreateInfo( - VK_POLYGON_MODE_FILL, - VK_CULL_MODE_NONE, - VK_FRONT_FACE_COUNTER_CLOCKWISE, - 0); + vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE); VkPipelineColorBlendAttachmentState blendAttachmentState = - vks::initializers::pipelineColorBlendAttachmentState( - 0xf, - VK_FALSE); + vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); VkPipelineColorBlendStateCreateInfo colorBlendState = - vks::initializers::pipelineColorBlendStateCreateInfo( - 1, - &blendAttachmentState); + vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); VkPipelineDepthStencilStateCreateInfo depthStencilState = - vks::initializers::pipelineDepthStencilStateCreateInfo( - VK_TRUE, - VK_TRUE, - VK_COMPARE_OP_LESS_OR_EQUAL); + vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); VkPipelineViewportStateCreateInfo viewportState = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); VkPipelineMultisampleStateCreateInfo multisampleState = - vks::initializers::pipelineMultisampleStateCreateInfo( - VK_SAMPLE_COUNT_1_BIT, - 0); + vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT); std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamicState = - vks::initializers::pipelineDynamicStateCreateInfo( - dynamicStateEnables.data(), - dynamicStateEnables.size(), - 0); + vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); - // Parallax mapping pipeline // Load shaders std::array shaderStages; - shaderStages[0] = loadShader(getAssetPath() + "shaders/parallax/parallax.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getAssetPath() + "shaders/parallax/parallax.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); VkGraphicsPipelineCreateInfo pipelineCreateInfo = - vks::initializers::pipelineCreateInfo( - pipelineLayout, - renderPass, - 0); + vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass); - pipelineCreateInfo.pVertexInputState = &vertices.inputState; pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCreateInfo.pRasterizationState = &rasterizationState; pipelineCreateInfo.pColorBlendState = &colorBlendState; @@ -437,15 +276,32 @@ public: pipelineCreateInfo.pViewportState = &viewportState; pipelineCreateInfo.pDepthStencilState = &depthStencilState; pipelineCreateInfo.pDynamicState = &dynamicState; - pipelineCreateInfo.stageCount = shaderStages.size(); + pipelineCreateInfo.stageCount = static_cast(shaderStages.size()); pipelineCreateInfo.pStages = shaderStages.data(); - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.parallaxMapping)); + // Vertex bindings an attributes + std::vector vertexInputBindings = { + vks::initializers::vertexInputBindingDescription(0, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX), + }; + std::vector vertexInputAttributes = { + vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Location 0: Position + vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 1, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 3), // Location 1: Texture coordinates + vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 2, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 5), // Location 2: Normal + vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 3, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 8), // Location 3: Tangent + vks::initializers::vertexInputAttributeDescription(VERTEX_BUFFER_BIND_ID, 4, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 11), // Location 4: Bitangent + }; + VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); + vertexInputState.vertexBindingDescriptionCount = static_cast(vertexInputBindings.size()); + vertexInputState.pVertexBindingDescriptions = vertexInputBindings.data(); + vertexInputState.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); + vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data(); - // Normal mapping (no parallax effect) - shaderStages[0] = loadShader(getAssetPath() + "shaders/parallax/normalmap.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getAssetPath() + "shaders/parallax/normalmap.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.normalMapping)); + pipelineCreateInfo.pVertexInputState = &vertexInputState; + + // Parallax mapping modes pipeline + shaderStages[0] = loadShader(getAssetPath() + "shaders/parallax/parallax.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getAssetPath() + "shaders/parallax/parallax.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); } void prepareUniformBuffers() @@ -474,25 +330,17 @@ public: void updateUniformBuffers() { // Vertex shader - glm::mat4 viewMatrix = glm::mat4(); - ubos.vertexShader.projection = glm::perspective(glm::radians(45.0f), (float)(width* ((splitScreen) ? 0.5f : 1.0f)) / (float)height, 0.001f, 256.0f); - viewMatrix = glm::translate(viewMatrix, glm::vec3(0.0f, 0.0f, zoom)); + ubos.vertexShader.projection = camera.matrices.perspective; + ubos.vertexShader.view = camera.matrices.view; + ubos.vertexShader.model = glm::rotate(glm::mat4(), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));; + ubos.vertexShader.model = glm::rotate(ubos.vertexShader.model, glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f));; - ubos.vertexShader.model = glm::mat4(); - ubos.vertexShader.model = viewMatrix * glm::translate(ubos.vertexShader.model, cameraPos); - ubos.vertexShader.model = glm::rotate(ubos.vertexShader.model, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); - ubos.vertexShader.model = glm::rotate(ubos.vertexShader.model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); - ubos.vertexShader.model = glm::rotate(ubos.vertexShader.model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); - - ubos.vertexShader.normal = glm::inverseTranspose(ubos.vertexShader.model); - - if (!paused) - { - ubos.vertexShader.lightPos.x = sin(glm::radians(timer * 360.0f)) * 0.5f; - ubos.vertexShader.lightPos.y = cos(glm::radians(timer * 360.0f)) * 0.5f; + if (!paused) { + ubos.vertexShader.lightPos.x = sin(glm::radians(timer * 360.0f)) * 1.5f; + ubos.vertexShader.lightPos.z = cos(glm::radians(timer * 360.0f)) * 1.5f; } - ubos.vertexShader.cameraPos = glm::vec4(0.0, 0.0, zoom, 0.0); + ubos.vertexShader.cameraPos = glm::vec4(camera.position, -1.0f) * -1.0f; memcpy(uniformBuffers.vertexShader.mapped, &ubos.vertexShader, sizeof(ubos.vertexShader)); @@ -503,14 +351,9 @@ public: void draw() { VulkanExampleBase::prepareFrame(); - - // Command buffer to be sumitted to the queue submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; - - // Submit to queue VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - VulkanExampleBase::submitFrame(); } @@ -518,7 +361,6 @@ public: { VulkanExampleBase::prepare(); loadAssets(); - setupVertexDescriptions(); prepareUniformBuffers(); setupDescriptorSetLayout(); preparePipelines(); @@ -544,54 +386,36 @@ public: updateUniformBuffers(); } - void toggleParallaxOffset() - { - ubos.fragmentShader.usePom = !ubos.fragmentShader.usePom; + void toggleMappingMode() + { + ubos.fragmentShader.mappingMode++; + if (ubos.fragmentShader.mappingMode > 4) { + ubos.fragmentShader.mappingMode = 0; + }; updateUniformBuffers(); - } - - void toggleNormalMapDisplay() - { - ubos.fragmentShader.displayNormalMap = !ubos.fragmentShader.displayNormalMap; - updateUniformBuffers(); - } - - void toggleSplitScreen() - { - splitScreen = !splitScreen; - updateUniformBuffers(); - reBuildCommandBuffers(); + updateTextOverlay(); } virtual void keyPressed(uint32_t keyCode) { switch (keyCode) { - case KEY_O: + case KEY_SPACE: case GAMEPAD_BUTTON_A: - toggleParallaxOffset(); - break; - case KEY_N: - case GAMEPAD_BUTTON_X: - toggleNormalMapDisplay(); - break; - case KEY_S: - case GAMEPAD_BUTTON_Y: - toggleSplitScreen(); + toggleMappingMode(); break; } } virtual void getOverlayText(VulkanTextOverlay *textOverlay) { + const std::vector mappingModes = { + "Color only", "Normal mapping", "Parallax mapping", "Steep parallax mapping", "Parallax occlusion mapping", + }; #if defined(__ANDROID__) - textOverlay->addText("Press \"Button A\" to toggle parallax", 5.0f, 85.0f, VulkanTextOverlay::alignLeft); - textOverlay->addText("Press \"Button X\" to toggle normals", 5.0f, 100.0f, VulkanTextOverlay::alignLeft); - textOverlay->addText("Press \"Button Y\" to toggle splitscreen", 5.0f, 115.0f, VulkanTextOverlay::alignLeft); -#else - textOverlay->addText("Press \"o\" to toggle parallax", 5.0f, 85.0f, VulkanTextOverlay::alignLeft); - textOverlay->addText("Press \"n\" to toggle normals", 5.0f, 100.0f, VulkanTextOverlay::alignLeft); - textOverlay->addText("Press \"s\" to toggle splitscreen", 5.0f, 115.0f, VulkanTextOverlay::alignLeft); + textOverlay->addText("Mode: " + mappingModes[ubos.fragmentShader.mappingMode] + " (\"Button A\")", 5.0f, 85.0f, VulkanTextOverlay::alignLeft); +#else + textOverlay->addText("Mode: " + mappingModes[ubos.fragmentShader.mappingMode] + " (\"Space\")", 5.0f, 85.0f, VulkanTextOverlay::alignLeft); #endif } }; diff --git a/parallaxmapping/parallaxmapping.vcxproj b/parallaxmapping/parallaxmapping.vcxproj index d8b6f71a..8fc77887 100644 --- a/parallaxmapping/parallaxmapping.vcxproj +++ b/parallaxmapping/parallaxmapping.vcxproj @@ -21,6 +21,10 @@ + + + + {3DB08441-72C9-4172-8BA9-ECEE032387BA} parallaxmapping @@ -54,6 +58,7 @@ Disabled true /FS %(AdditionalOptions) + Level3 ..\libs\vulkan\vulkan-1.lib;..\libs\assimp\assimp.lib;%(AdditionalDependencies) diff --git a/parallaxmapping/parallaxmapping.vcxproj.filters b/parallaxmapping/parallaxmapping.vcxproj.filters index 37cebe3e..730b9045 100644 --- a/parallaxmapping/parallaxmapping.vcxproj.filters +++ b/parallaxmapping/parallaxmapping.vcxproj.filters @@ -13,6 +13,9 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + {d4e5cf47-9778-4a8e-8ef1-632080b554d6} + @@ -39,4 +42,12 @@ Header Files + + + Shaders + + + Shaders + + \ No newline at end of file