Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
c47017f
Chore: Add shaders to version control
brenocq Mar 22, 2025
e7eb44c
Fix: Normal not normalized in PBR fragment shader
brenocq Mar 22, 2025
fd383b5
Feat: Environment light HDR texture selection
brenocq Mar 22, 2025
2321742
Feat: Skybox shader
brenocq Mar 22, 2025
0601e95
Feat: Basic skybox pipeline
brenocq Apr 6, 2025
fcf919a
Refactor: Implement renderQuad/renderCube in pipeline base class
brenocq Apr 6, 2025
ace010d
Refactor: Remove quad shader
brenocq Apr 6, 2025
5b77389
Chore: Move grid shader to common folder
brenocq Apr 6, 2025
a9c4cad
Chore: Move drawer shaders to common folder
brenocq Apr 6, 2025
e205e8a
Chore: Remove old entity click shaders
brenocq Apr 6, 2025
a1ecf65
Feat: EquiToCubemap compute shader
brenocq Apr 6, 2025
217e624
Fix: Vulkan cubemap image creation
brenocq Apr 6, 2025
e458843
Fix: Do not allow to use HDR images in materials
brenocq Apr 6, 2025
883b6c7
Feat: Only render skybox if there is an environment light
brenocq Apr 6, 2025
5a2355c
Feat: Store cubemap images in gfx manager
brenocq Apr 6, 2025
b633ac3
Feat: OpenGL framebuffer set cubemap layer
brenocq Apr 6, 2025
5587e5b
Feat: Create vulkan image view for each cubemap layer
brenocq Apr 6, 2025
f804d05
Feat: Recreate vulkan framebuffer with selected cubemap layer
brenocq Apr 6, 2025
5f7315a
Feat: Set proj and view matrices for equiToCubemap
brenocq Apr 6, 2025
6c9194a
Fix: Vulkan samplerCube bindings
brenocq Apr 6, 2025
8165ae4
Fix: Vulkan default cubemap image binding
brenocq Apr 6, 2025
e749f5e
Feat: Write data to OpenGL/Vulkan cubemap images
brenocq Apr 7, 2025
3907a42
Fix: OpenGL cubemap image creation with data
brenocq Apr 7, 2025
bfd2c13
Merge branch 'main' into pbr-renderer
brenocq Mar 8, 2026
77c4712
Feat: Drawer and grid shaders
brenocq Mar 8, 2026
09d714e
Fix: Vulkan transition error
brenocq Mar 8, 2026
08b84ad
Fix: Render skybox from HDR image
brenocq Mar 9, 2026
1f564c9
Fix: Vulkan warnings
brenocq Mar 9, 2026
a8548dc
Feat: Convert PBR shaders into ASL
brenocq Mar 9, 2026
e8e83f4
Feat: PBR shader with irradiance map
brenocq Mar 9, 2026
caa5dfd
Feat: PBR shader with BRDF LUT
brenocq Mar 9, 2026
d0688c4
Feat: Full IBL pipeline implemented
brenocq Mar 9, 2026
5bf67fa
Feat: Directional light shadows
brenocq Mar 10, 2026
51c4b3a
Fix: Specular IBL with OpenGL API
brenocq Mar 10, 2026
8c43eae
Fix: Directional light shadows with OpenGL API
brenocq Mar 10, 2026
57ea44c
Refactor: Remove omni shadow mapping
brenocq Mar 10, 2026
8a44a1c
Fix: Wrong phong renderer mesh transform
brenocq Mar 10, 2026
df5097a
Fix: Phong renderer materials too white
brenocq Mar 10, 2026
3e5c5ca
Chore: Apply clang-format
brenocq Mar 10, 2026
f100d47
Merge remote-tracking branch 'origin/main' into pbr-renderer
github-actions[bot] Mar 10, 2026
05f0ec8
Chore: Bump version to 0.3.11
github-actions[bot] Mar 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@

# Build
/build/
/scripts/local_*.sh
/projects/
/resources/

# Resources
/resources/fonts/
/resources/icons/
/resources/meshes/
/resources/textures/

# Visual Studio
/.vs
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.14)

project(atta VERSION 0.3.10 LANGUAGES CXX C)
project(atta VERSION 0.3.11 LANGUAGES CXX C)

option(ATTA_BUILD_TESTS "Set to ON to build also the test executables" ON)
option(ATTA_BUILD_DOCS "Build the documentation" OFF)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[project]
attaVersion = "0.3.7"
attaVersion = "0.3.10"
name = "material-resource"

[config]
Expand Down Expand Up @@ -166,3 +166,8 @@ transform.position = vec3(0.000000, 0.000000, 2.548024)
transform.orientation = quat(0.000000, 0.000000, 0.000000, 1.000000)
transform.scale = vec3(1.000000, 1.000000, 1.000000)

[node]
id = 9
environmentLight.sid = "environment/suburban_soccer_park_2k.hdr"
name.name = "Environment light"

18 changes: 18 additions & 0 deletions resources/shaders/common/depth.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
perFrame mat4 uView;
perFrame mat4 uProjection;
perDraw mat4 uModel;
perDraw vec4 uColor;
// uniform sampler2D uDepthMap;

perVertex vec3 vUV;

vec4 vertex(vec3 iVertex, vec3 iNormal, vec3 iUV) {
vUV = iUV;
return uProjection * uView * uModel * vec4(iVertex, 1.0f);
}

vec4 fragment() {
// float depthValue = texture(depthMap, vUV).r;
// return vec4(vec3(depthValue), 1.0f);
return vec4(0, 0, 0, 1);
}
12 changes: 12 additions & 0 deletions resources/shaders/common/drawerLine.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
perFrame mat4 uView;
perFrame mat4 uProjection;

perVertex vec4 vColor;

vec4 vertex(vec3 iPos, vec4 iColor) {
vec4 pos = uProjection * uView * vec4(iPos, 1.0);
vColor = iColor;
return vec4(pos.xyz, pos.w);
}

void fragment(out vec4 color) { color = vColor; }
14 changes: 14 additions & 0 deletions resources/shaders/common/drawerPoint.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
perFrame mat4 uView;
perFrame mat4 uProjection;

perVertex vec4 vColor;

vec4 vertex(vec3 iPos, vec4 iColor) {
vec4 pos = uProjection * uView * vec4(iPos, 1.0);
vColor = iColor;
gl_PointSize = 5.0;
return pos;
}

void fragment(out vec4 color) { color = vColor; }

28 changes: 28 additions & 0 deletions resources/shaders/common/grid.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
perFrame mat4 uView;
perFrame mat4 uProjection;
perFrame vec3 uCamPos;

perVertex vec4 vColor;
perVertex vec3 vFragPos;

vec4 vertex(vec3 iPos, vec4 iColor, float iWidth) {
vec4 pos = uProjection * uView * vec4(iPos, 1.0);
vColor = iColor;
vFragPos = iPos;
return vec4(pos.xyz, pos.w);
}

void fragment(out vec4 color) {
float dist = length(uCamPos - vFragPos) + 0.0001;
color = vColor;

// Parameters for controlling the fade effect
float fadeStart = 20.0; // Distance where the fading starts
float fadeEnd = 50.0; // Distance where the grid is fully faded/transparent

// Clamped ratio between where fading starts and where it ends
float fadeRatio = clamp((dist - fadeStart) / (fadeEnd - fadeStart), 0.0, 1.0);

// Apply fade falloff
color.a *= 1.0 - fadeRatio;
}
8 changes: 8 additions & 0 deletions resources/shaders/common/selected.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
perFrame mat4 uView;
perFrame mat4 uProjection;
perDraw mat4 uModel;
perDraw vec4 uColor;

vec4 vertex(vec3 iVertex, vec3 iNormal, vec3 iUV) { return uProjection * uView * uModel * vec4(iVertex, 1.0f); }

vec4 fragment() { return uColor; }
20 changes: 20 additions & 0 deletions resources/shaders/common/skybox.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
perFrame mat4 uProjection;
perFrame mat4 uView;
perFrame samplerCube uEnvironmentMap;

perVertex vec3 vTexCoords;

vec4 vertex(vec3 iVertex, vec3 iNormal, vec2 iUV) {
vTexCoords = iVertex;
// Add small dependency between vertex and normal/uv to avoid compilation error
vTexCoords += iNormal / 10000.0f + vec3(iUV,0) / 10000.0f;

// Remove translation from the view matrix (so the skybox remains centered)
mat4 rotView = mat4(mat3(uView));
return uProjection * rotView * vec4(iVertex, 1.0);
}

void fragment(out vec4 color) {
// Sample the cubemap using the normalized direction
color = texture(uEnvironmentMap, normalize(vTexCoords));
}
92 changes: 92 additions & 0 deletions resources/shaders/compute/brdf.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
perVertex vec2 uv;

vec4 vertex(vec2 iVertex, vec2 iUV) {
uv = iUV;
return vec4(iVertex, 0.0, 1.0);
}

const float PI = 3.14159265359;

float RadicalInverse_VdC(uint bits) {
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return float(bits) * 2.3283064365386963e-10;
}

vec2 Hammersley(uint i, uint N) {
return vec2(float(i) / float(N), RadicalInverse_VdC(i));
}

vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) {
float a = roughness * roughness;

float phi = 2.0 * PI * Xi.x;
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);

vec3 H;
H.x = cos(phi) * sinTheta;
H.y = sin(phi) * sinTheta;
H.z = cosTheta;

vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 tangent = normalize(cross(up, N));
vec3 bitangent = cross(N, tangent);

return normalize(tangent * H.x + bitangent * H.y + N * H.z);
}

float GeometrySchlickGGX(float NdotV, float roughness) {
float a = roughness;
float k = (a * a) / 2.0;
return NdotV / (NdotV * (1.0 - k) + k);
}

float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
return GeometrySchlickGGX(NdotV, roughness) * GeometrySchlickGGX(NdotL, roughness);
}

vec2 IntegrateBRDF(float NdotV, float roughness) {
vec3 V;
V.x = sqrt(1.0 - NdotV * NdotV);
V.y = 0.0;
V.z = NdotV;

float A = 0.0;
float B = 0.0;

vec3 N = vec3(0.0, 0.0, 1.0);

const uint SAMPLE_COUNT = 1024u;
for (uint i = 0u; i < SAMPLE_COUNT; ++i) {
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
vec3 L = normalize(2.0 * dot(V, H) * H - V);

float NdotL = max(L.z, 0.0);
float NdotH = max(H.z, 0.0);
float VdotH = max(dot(V, H), 0.0);

if (NdotL > 0.0) {
float G = GeometrySmith(N, V, L, roughness);
float G_Vis = (G * VdotH) / (NdotH * NdotV);
float Fc = pow(1.0 - VdotH, 5.0);

A += (1.0 - Fc) * G_Vis;
B += Fc * G_Vis;
}
}
A /= float(SAMPLE_COUNT);
B /= float(SAMPLE_COUNT);
return vec2(A, B);
}

void fragment(out vec4 color) {
vec2 integratedBRDF = IntegrateBRDF(uv.x, uv.y);
color = vec4(integratedBRDF, 0.0, 1.0);
}
8 changes: 8 additions & 0 deletions resources/shaders/compute/entityClick.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
perFrame mat4 projection;
perFrame mat4 view;
perDraw mat4 model;
perDraw int entityId;

vec4 vertex(vec3 inPos, vec3 inNormal, vec2 inUV) { return projection * view * model * vec4(inPos, 1.0f); }

void fragment(out int eid) { eid = entityId; }
26 changes: 26 additions & 0 deletions resources/shaders/compute/equiToCubemap.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
perFrame mat4 uProjection;
perFrame mat4 uView;
perFrame sampler2D uEquirectangularMap;

perVertex vec3 localPos;

vec4 vertex(vec3 iPos, vec3 iNormal, vec2 iUV) {
localPos = iPos;
// Add small dependency between vertex and normal/uv to avoid compilation error
localPos += iNormal / 10000.0f + vec3(iUV,0) / 10000.0f;
return uProjection * uView * vec4(localPos, 1.0);
}

const vec2 invAtan = vec2(0.1591, 0.3183);
vec2 sampleSphericalMap(vec3 v) {
// Z-up convention: azimuth in XY plane, elevation along Z axis
vec2 uv = vec2(atan(v.y, v.x), asin(v.z));
uv *= invAtan;
uv += 0.5;
return uv;
}

void fragment(out vec4 color) {
vec2 uv = sampleSphericalMap(normalize(localPos));
color = vec4(texture(uEquirectangularMap, uv).rgb, 1.0);
}
38 changes: 38 additions & 0 deletions resources/shaders/compute/irradiance.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
perFrame mat4 uProjection;
perFrame mat4 uView;
perFrame samplerCube uEnvironmentMap;

perVertex vec3 localPos;

vec4 vertex(vec3 iPos, vec3 iNormal, vec2 iUV) {
localPos = iPos;
localPos += iNormal / 10000.0f + vec3(iUV, 0) / 10000.0f;
return uProjection * uView * vec4(localPos, 1.0);
}

const float PI = 3.14159265359;

void fragment(out vec4 color) {
vec3 N = normalize(localPos);

vec3 irradiance = vec3(0.0);

vec3 up = vec3(0.0, 1.0, 0.0);
vec3 right = normalize(cross(up, N));
up = normalize(cross(N, right));

float sampleDelta = 0.025;
float nrSamples = 0.0;
for (float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta) {
for (float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta) {
vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N;

irradiance += texture(uEnvironmentMap, sampleVec).rgb * cos(theta) * sin(theta);
nrSamples++;
}
}
irradiance = PI * irradiance * (1.0 / float(nrSamples));

color = vec4(irradiance, 1.0);
}
70 changes: 70 additions & 0 deletions resources/shaders/compute/prefilter.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
perFrame mat4 uProjection;
perFrame mat4 uView;
perFrame samplerCube uEnvironmentMap;
perFrame float uRoughness;

perVertex vec3 localPos;

vec4 vertex(vec3 iPos, vec3 iNormal, vec2 iUV) {
localPos = iPos;
localPos += iNormal / 10000.0f + vec3(iUV, 0) / 10000.0f;
return uProjection * uView * vec4(localPos, 1.0);
}

const float PI = 3.14159265359;

float RadicalInverse_VdC(uint bits) {
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return float(bits) * 2.3283064365386963e-10;
}

vec2 Hammersley(uint i, uint N) {
return vec2(float(i) / float(N), RadicalInverse_VdC(i));
}

vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) {
float a = roughness * roughness;

float phi = 2.0 * PI * Xi.x;
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);

vec3 H;
H.x = cos(phi) * sinTheta;
H.y = sin(phi) * sinTheta;
H.z = cosTheta;

vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 tangent = normalize(cross(up, N));
vec3 bitangent = cross(N, tangent);

return normalize(tangent * H.x + bitangent * H.y + N * H.z);
}

void fragment(out vec4 color) {
vec3 N = normalize(localPos);
vec3 R = N;
vec3 V = R;

const uint SAMPLE_COUNT = 1024u;
float totalWeight = 0.0;
vec3 prefilteredColor = vec3(0.0);
for (uint i = 0u; i < SAMPLE_COUNT; ++i) {
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
vec3 H = ImportanceSampleGGX(Xi, N, uRoughness);
vec3 L = normalize(2.0 * dot(V, H) * H - V);

float NdotL = max(dot(N, L), 0.0);
if (NdotL > 0.0) {
prefilteredColor += texture(uEnvironmentMap, L).rgb * NdotL;
totalWeight += NdotL;
}
}
prefilteredColor = prefilteredColor / totalWeight;

color = vec4(prefilteredColor, 1.0);
}
12 changes: 12 additions & 0 deletions resources/shaders/drawer/line.asl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
perFrame mat4 uView;
perFrame mat4 uProjection;

perVertex vec4 vColor;

vec4 vertex(vec3 iPos, vec4 iColor) {
vec4 pos = uProjection * uView * vec4(iPos, 1.0);
vColor = iColor;
return vec4(pos.xyz, pos.w);
}

void fragment(out vec4 color) { color = vColor; }
Loading