Skip to content

Commit 800adbb

Browse files
committed
Multisampling and specialization constants
1 parent ffc6918 commit 800adbb

18 files changed

+348
-25
lines changed

booksamples/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
.idea/
2+
.gradle/
23
.settings/
34
*.iml
45
.classpath
56
.factorypath
67
.project
78
target/
9+
build/
810
*.log

booksamples/chapter-12/resources/shaders/lighting_fragment.glsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// developed by Joey de Vries, https://twitter.com/JoeyDeVriez, and licensed under the terms of the CC BY-NC 4.0,
44
// https://creativecommons.org/licenses/by-nc/4.0/legalcode
55

6-
const int MAX_LIGHTS = 10;
6+
layout (constant_id = 0) const int MAX_LIGHTS = 10;
77
const float PI = 3.14159265359;
88

99
// Always use vec4 (minimum alighnment)
Binary file not shown.
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#version 450
2+
// CREDITS: Most of the functions here have been obtained from this link: https://learnopengl.com/PBR
3+
// developed by Joey de Vries, https://twitter.com/JoeyDeVriez, and licensed under the terms of the CC BY-NC 4.0,
4+
// https://creativecommons.org/licenses/by-nc/4.0/legalcode
5+
6+
layout (constant_id = 0) const int MAX_LIGHTS = 10;
7+
layout (constant_id = 1) const int NUM_SAMPLES = 8;
8+
const float PI = 3.14159265359;
9+
10+
// Always use vec4 (minimum alighnment)
11+
struct Light {
12+
vec4 position;
13+
vec4 color;
14+
};
15+
16+
layout(location = 0) in vec2 inTextCoord;
17+
18+
layout(location = 0) out vec4 outFragColor;
19+
20+
layout(set = 0, binding = 0) uniform sampler2DMS albedoSampler;
21+
layout(set = 0, binding = 1) uniform sampler2DMS normalsSampler;
22+
layout(set = 0, binding = 2) uniform sampler2DMS pbrSampler;
23+
layout(set = 0, binding = 3) uniform sampler2DMS depthSampler;
24+
layout(set = 1, binding = 0) uniform UBO {
25+
vec4 ambientLightColor;
26+
uint count;
27+
Light lights[MAX_LIGHTS];
28+
} lights;
29+
layout(set = 2, binding = 0) uniform ProjUniform {
30+
mat4 invProjectionMatrix;
31+
} projUniform;
32+
33+
vec4 resolve(sampler2DMS tex, ivec2 uv)
34+
{
35+
vec4 result = vec4(0.0);
36+
for (int i = 0; i < NUM_SAMPLES; i++)
37+
{
38+
vec4 val = texelFetch(tex, uv, i);
39+
result += val;
40+
}
41+
// Average resolved samples
42+
return result / float(NUM_SAMPLES);
43+
}
44+
45+
vec3 fresnelSchlick(float cosTheta, vec3 F0)
46+
{
47+
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
48+
}
49+
50+
float DistributionGGX(vec3 N, vec3 H, float roughness)
51+
{
52+
float a = roughness*roughness;
53+
float a2 = a*a;
54+
float NdotH = max(dot(N, H), 0.0);
55+
float NdotH2 = NdotH*NdotH;
56+
57+
float num = a2;
58+
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
59+
denom = PI * denom * denom;
60+
61+
return num / denom;
62+
}
63+
64+
float GeometrySchlickGGX(float NdotV, float roughness)
65+
{
66+
float r = (roughness + 1.0);
67+
float k = (r*r) / 8.0;
68+
69+
float num = NdotV;
70+
float denom = NdotV * (1.0 - k) + k;
71+
72+
return num / denom;
73+
}
74+
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
75+
{
76+
float NdotV = max(dot(N, V), 0.0);
77+
float NdotL = max(dot(N, L), 0.0);
78+
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
79+
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
80+
81+
return ggx1 * ggx2;
82+
}
83+
84+
vec3 calculateLight(Light light, vec3 lightDirection, vec3 position, vec3 normal, vec3 albedo,
85+
float metallic, float roughness, float attenuation) {
86+
vec3 result;
87+
88+
vec3 N = normalize(normal);
89+
vec3 L = normalize(lightDirection);
90+
vec3 V = normalize(-position);
91+
vec3 H = normalize(L + V);
92+
93+
vec3 F0 = vec3(0.04);
94+
F0 = mix(F0, albedo, metallic);
95+
96+
vec3 Lo = vec3(0.0);
97+
vec3 radiance = light.color.rgb * attenuation;
98+
99+
// cook-torrance brdf
100+
float NDF = DistributionGGX(N, H, roughness);
101+
float G = GeometrySmith(N, V, L, roughness);
102+
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
103+
104+
vec3 kS = F;
105+
vec3 kD = vec3(1.0) - kS;
106+
kD *= 1.0 - metallic;
107+
108+
vec3 numerator = NDF * G * F;
109+
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
110+
vec3 specular = numerator / max(denominator, 0.001);
111+
112+
// add to outgoing radiance Lo
113+
float NdotL = max(dot(N, L), 0.0);
114+
Lo += (kD * albedo / PI + specular) * radiance * NdotL;
115+
116+
return Lo;
117+
}
118+
119+
vec3 calculateDirectionalLight(Light light, vec3 position, vec3 normal, vec3 color,
120+
float metallic, float roughness) {
121+
float attenuation = 1.0;
122+
return calculateLight(light, light.position.xyz, position, normal, color, metallic, roughness,
123+
attenuation);
124+
}
125+
126+
vec3 calculatePointLight(Light light, vec3 position, vec3 normal, vec3 color,
127+
float metallic, float roughness) {
128+
vec3 lightDirection = light.position.xyz - position;
129+
float dist = length(lightDirection) * 0.005;
130+
float attenuation = 1.0 / (dist * dist);
131+
return calculateLight(light, lightDirection, position, normal, color, metallic, roughness,
132+
attenuation);
133+
}
134+
135+
void main() {
136+
ivec2 textSize = textureSize(albedoSampler);
137+
ivec2 uv = ivec2(inTextCoord * textSize);
138+
139+
vec3 albedo = resolve(albedoSampler, uv).rgb;
140+
vec3 normal = normalize(2.0 * resolve(normalsSampler, uv).rgb - 1.0);
141+
vec3 pbrSampledValue = resolve(pbrSampler, uv).rgb;
142+
float ao = pbrSampledValue.r;
143+
float roughness = pbrSampledValue.g;
144+
float metallic = pbrSampledValue.b;
145+
146+
// Retrieve position from depth
147+
vec4 clip = vec4(inTextCoord.x * 2.0 - 1.0, inTextCoord.y * -2.0 + 1.0, resolve(depthSampler, uv).x, 1.0);
148+
vec4 world_w = projUniform.invProjectionMatrix * clip;
149+
vec3 pos = world_w.xyz / world_w.w;
150+
151+
// Calculate lighting
152+
vec3 lightColor = vec3(0.0);
153+
vec3 ambientColor = vec3(0.5);
154+
for (uint i = 0U; i < lights.count; i++)
155+
{
156+
Light light = lights.lights[i];
157+
if (light.position.w == 0)
158+
{
159+
lightColor += calculateDirectionalLight(light, pos, normal, albedo, metallic, roughness);
160+
}
161+
else
162+
{
163+
lightColor += calculatePointLight(light, pos, normal, albedo, metallic, roughness);
164+
}
165+
}
166+
167+
vec3 ambient = lights.ambientLightColor.rgb * albedo * ao;
168+
169+
outFragColor = vec4(pow(ambient + lightColor, vec3(0.4545)), 1.0);
170+
}
Binary file not shown.

booksamples/chapter-12/src/main/java/org/vulkanb/eng/EngineProperties.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
public class EngineProperties {
99
private static final float DEFAULT_FOV = 60.0f;
1010
private static final int DEFAULT_MAX_MATERIALS = 500;
11+
private static final int DEFAULT_MULTISAMPLING = 1;
1112
private static final int DEFAULT_REQUESTED_IMAGES = 3;
1213
private static final int DEFAULT_UPS = 30;
1314
private static final float DEFAULT_Z_FAR = 100.f;
@@ -18,6 +19,7 @@ public class EngineProperties {
1819
private String defaultTexturePath;
1920
private float fov;
2021
private int maxMaterials;
22+
private int multiSampling;
2123
private String physDeviceName;
2224
private int requestedImages;
2325
private boolean shaderRecompilation;
@@ -44,6 +46,7 @@ private EngineProperties() {
4446
zFar = Float.parseFloat(props.getOrDefault("zFar", DEFAULT_Z_FAR).toString());
4547
defaultTexturePath = props.getProperty("defaultTexturePath");
4648
maxMaterials = Integer.parseInt(props.getOrDefault("maxMaterials", DEFAULT_MAX_MATERIALS).toString());
49+
multiSampling = Integer.parseInt(props.getOrDefault("multiSampling", DEFAULT_MULTISAMPLING).toString());
4750
} catch (IOException excp) {
4851
LOGGER.error("Could not read [{}] properties file", FILENAME, excp);
4952
}
@@ -68,6 +71,10 @@ public int getMaxMaterials() {
6871
return maxMaterials;
6972
}
7073

74+
public int getMultiSampling() {
75+
return multiSampling;
76+
}
77+
7178
public String getPhysDeviceName() {
7279
return physDeviceName;
7380
}

booksamples/chapter-12/src/main/java/org/vulkanb/eng/graph/geometry/GeometryAttachments.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,33 @@ public class GeometryAttachments {
1515
private int height;
1616
private int width;
1717

18-
public GeometryAttachments(Device device, int width, int height) {
18+
public GeometryAttachments(Device device, int width, int height, int numSamples) {
1919
this.width = width;
2020
this.height = height;
2121
attachments = new Attachment[NUMBER_ATTACHMENTS];
2222

2323
int i = 0;
2424
// Albedo attachment
2525
Attachment attachment = new Attachment(device, width, height,
26-
VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
26+
VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, numSamples);
2727
attachments[i] = attachment;
2828
i++;
2929

3030
// Normals attachment
3131
attachment = new Attachment(device, width, height,
32-
VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
32+
VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, numSamples);
3333
attachments[i] = attachment;
3434
i++;
3535

3636
// PBR attachment
3737
attachment = new Attachment(device, width, height,
38-
VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
38+
VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, numSamples);
3939
attachments[i] = attachment;
4040
i++;
4141

4242
// Depth attachment
4343
attachment = new Attachment(device, width, height,
44-
VK_FORMAT_D32_SFLOAT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
44+
VK_FORMAT_D32_SFLOAT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, numSamples);
4545
attachments[i] = attachment;
4646
depthAttachmentPos = i;
4747
}

booksamples/chapter-12/src/main/java/org/vulkanb/eng/graph/geometry/GeometryFrameBuffer.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,21 @@
33
import org.apache.logging.log4j.*;
44
import org.lwjgl.system.MemoryStack;
55
import org.lwjgl.vulkan.VkExtent2D;
6+
import org.vulkanb.eng.EngineProperties;
67
import org.vulkanb.eng.graph.vk.*;
78

89
import java.nio.LongBuffer;
910

11+
import static org.lwjgl.vulkan.VK10.VK_SAMPLE_COUNT_1_BIT;
12+
1013
public class GeometryFrameBuffer {
1114

1215
private static final Logger LOGGER = LogManager.getLogger();
1316

1417
private FrameBuffer frameBuffer;
1518
private GeometryAttachments geometryAttachments;
1619
private GeometryRenderPass geometryRenderPass;
20+
private int numSamples;
1721

1822
public GeometryFrameBuffer(SwapChain swapChain) {
1923
LOGGER.debug("Creating GeometryFrameBuffer");
@@ -33,7 +37,17 @@ private void createAttachments(SwapChain swapChain) {
3337
VkExtent2D extent2D = swapChain.getSwapChainExtent();
3438
int width = extent2D.width();
3539
int height = extent2D.height();
36-
geometryAttachments = new GeometryAttachments(swapChain.getDevice(), width, height);
40+
41+
numSamples = VK_SAMPLE_COUNT_1_BIT;
42+
EngineProperties engProps = EngineProperties.getInstance();
43+
int requestedSamples = engProps.getMultiSampling();
44+
Device device = swapChain.getDevice();
45+
if (requestedSamples > 0 && device.isSampleRateShading()) {
46+
numSamples = device.getPhysicalDevice().supportsSampleCount(requestedSamples) ? requestedSamples : VK_SAMPLE_COUNT_1_BIT;
47+
}
48+
LOGGER.debug("Requested [{}] samples, using [{}]", requestedSamples, numSamples);
49+
50+
geometryAttachments = new GeometryAttachments(swapChain.getDevice(), width, height, numSamples);
3751
}
3852

3953
private void createFrameBuffer(SwapChain swapChain) {
@@ -58,6 +72,10 @@ public FrameBuffer getFrameBuffer() {
5872
return frameBuffer;
5973
}
6074

75+
public int getNumSamples() {
76+
return numSamples;
77+
}
78+
6179
public GeometryRenderPass getRenderPass() {
6280
return geometryRenderPass;
6381
}
@@ -68,4 +86,8 @@ public void resize(SwapChain swapChain) {
6886
createAttachments(swapChain);
6987
createFrameBuffer(swapChain);
7088
}
89+
90+
public void setNumSamples(int numSamples) {
91+
this.numSamples = numSamples;
92+
}
7193
}

booksamples/chapter-12/src/main/java/org/vulkanb/eng/graph/geometry/GeometryRenderActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ private void createPipeline() {
134134
Pipeline.PipeLineCreationInfo pipeLineCreationInfo = new Pipeline.PipeLineCreationInfo(
135135
geometryFrameBuffer.getRenderPass().getVkRenderPass(), shaderProgram, GeometryAttachments.NUMBER_COLOR_ATTACHMENTS,
136136
true, true, GraphConstants.MAT4X4_SIZE,
137-
new VertexBufferStructure(), geometryDescriptorSetLayouts);
137+
new VertexBufferStructure(), geometryDescriptorSetLayouts, geometryFrameBuffer.getNumSamples());
138138
pipeLine = new Pipeline(pipelineCache, pipeLineCreationInfo);
139139
pipeLineCreationInfo.cleanup();
140140
}

booksamples/chapter-12/src/main/java/org/vulkanb/eng/graph/geometry/GeometryRenderPass.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
public class GeometryRenderPass {
1313

14-
private static final int MAX_SAMPLES = 1;
1514
private Device device;
1615
private long vkRenderPass;
1716

@@ -28,7 +27,7 @@ public GeometryRenderPass(Device device, Attachment[] attachments) {
2827
.storeOp(VK_ATTACHMENT_STORE_OP_STORE)
2928
.stencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE)
3029
.stencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE)
31-
.samples(MAX_SAMPLES)
30+
.samples(attachments[i].getSamples())
3231
.initialLayout(VK_IMAGE_LAYOUT_UNDEFINED);
3332
if (attachments[i].isDepthAttachment()) {
3433
depthAttachmentPos = i;

0 commit comments

Comments
 (0)