Compare commits

...
Sign in to create a new pull request.

62 commits

Author SHA1 Message Date
Halbear
9424b29d0a Jarvis, Optimise my shit 2026-09-25 23:37:22 +01:00
Halbear
d1abde919d structures, also they're a little broken, they need to check for neighbouring YZones as well 2026-09-20 22:43:42 +01:00
Halbear
a0b00b0f1c voxel biomes and CPU pushed blocks 2026-09-20 17:57:19 +01:00
7fda2614d7 fixed intel graphical issues 2026-09-18 13:56:17 +01:00
95a27cfd50 formatting changes in voxel generation shader 2026-09-18 08:55:43 +01:00
Halbear
0074bf1d1f voxel texture mapping 2026-09-17 21:48:04 +01:00
4565188f15 Improved island generation 2026-09-17 11:31:52 +01:00
Halbear
8c301d0ac1 update GitIgnore 2026-09-16 20:39:56 +01:00
Halbear
ce7051d8ca i did a little memory optimisation (19GB of VRAM -> 2.6GB of VRAM), lost some FPS in vertex rendering as a result but i'll figure it out 2026-09-16 20:38:37 +01:00
Halbear
bf9af81f38 what if minecraft ran on the GPU exclusively? glad you asked! because now it can 2026-09-15 20:49:24 +01:00
Halbear
fa7bf893e7 refactoring stuff 2026-09-15 11:38:44 +01:00
Halbear
04befce27d HDR, Bloom and SSR 2026-09-04 00:23:48 +01:00
Halbear
577836a03f SSAO, performance sucks and it flickers so tweaking is needed, also more material support 2026-09-01 03:33:26 +01:00
Halbear
5b231d6920 OpenGL works again, Vulkan can be switched to, fixed most of the vulkan validation errors, better shadows, soft shadows, emissive lighting, and multiple different opacity rendering methods 2026-08-31 14:13:59 +01:00
Halbear
0d41f3e15b Shadows, broke OpenGL, broke graphics settings, Exception raised when closing software 2026-08-30 01:06:23 +01:00
Halbear
f7127e0878 OpenGL lighting 2026-08-29 19:42:11 +01:00
Halbear
5518dae1d7 more OpenGL support, cameras and 3D projection and it now shares 3D models with vulkan, OpenGL does not work if launched, and switching to vulkan from OpenGL does not work 2026-08-29 04:24:05 +01:00
Halbear
5ea45890c8 Separated packet management to it's own thread, optimised the physics to only test bodies with mass, added 2D Noise, fixed pivot points 2026-08-26 16:33:02 +01:00
Halbear
c9ef43a2a0 NIO networking transition is now functional, has some issues with usernames not syncing properly and some latency issues on real world testing 2026-08-21 19:25:58 +01:00
Halbear
3e886e5ba8 2D Sprite Renderer and sprite framework, Began additional OpenGL Renderer, started transitioning multiplayer networking to use Java NIO 2026-08-20 03:03:03 +01:00
Halbear
5a05b9d65e 2D rendering (big feature) 2026-08-14 22:22:03 +01:00
Halbear
6d7ea4ebc5 delete logs from being in the repo 2026-07-11 15:27:42 +01:00
Halbear
bf11da6799 Shooting 2026-07-11 15:27:06 +01:00
Halbear
0d8f23cb1f Fixing issues, preparing more multiplayer stuff, added credits 2026-07-11 02:04:55 +01:00
4af61ca2c8 changed weapon fire from SFX to WEAPONS 2026-07-10 14:42:09 +01:00
1284a9835a sfx GunCock, ambient crickets, fire sound 2026-07-10 14:38:23 +01:00
Halbear
9723a3567c Sound Effects 2026-07-10 13:13:42 +01:00
Halbear
59c5486299 Fixed some volume related issues, separated options into its own menu with tabs, added a visualised collision actor (dual pass graphics required), added a player model, started shooting mechanics 2026-07-10 01:01:13 +01:00
f3aee6cb84 Item record, tried to fix swapping 2026-07-09 16:52:36 +01:00
92fb49191b Merge remote-tracking branch 'origin/main' 2026-07-09 14:57:32 +01:00
ffb7b842af Visualised Collisions & broken as hell player model 2026-07-09 14:57:19 +01:00
0f8fa9c9f9 added audio settings and aiming with right click 2026-07-09 13:31:07 +01:00
Halbear
aff4c2a57a removed now unnecessary logging 2026-07-09 00:27:23 +01:00
Halbear
3fbf3485b1 Fixed merge issues 2026-07-09 00:23:24 +01:00
Halbear
745d38fb09 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	LastSession.t4jlog
2026-07-09 00:18:55 +01:00
Halbear
f3c83bea80 Multiplayer networking + broke a bunch of things, we'll need to redo gun switching 2026-07-09 00:18:29 +01:00
2e929abf46 Merge remote-tracking branch 'origin/main' 2026-07-08 15:36:28 +01:00
1c5f6d41ad Added a start menu, if you dont press R or M before anything it crashes but idk how to fix. 2026-07-08 15:36:18 +01:00
Halbear
c270a049b5 fixed revolver actor rolling around 2026-07-08 13:57:42 +01:00
Halbear
613e31658f changing BGM to main menu music 2026-07-08 13:54:55 +01:00
Halbear
db4de8f791 audio instance changes 2026-07-08 13:46:00 +01:00
Halbear
d49ff709e2 Fixed the Weapon switching, added some boilerplate classes which may be useful in the future, added music files 2026-07-08 13:42:45 +01:00
7bad787477 stuck on getting revolver and musket to switch idk why it wouldnt let me push earlier 2026-07-07 20:57:33 +01:00
94858a7cad Merge remote-tracking branch 'origin/main' 2026-07-07 14:07:54 +01:00
f2174e4364 removed flying added double jump :) 2026-07-07 14:07:22 +01:00
Halbear
9c08fb6248 added weapon models 2026-07-07 12:53:31 +01:00
Halbear
42fc70100d Fixed movement Input 2026-07-07 12:50:02 +01:00
Halbear
8a92f99474 physics are on fun evil mode 2026-07-06 23:00:07 +01:00
Halbear
8ab8c06f9c Gun + the physics are on evil mode 2026-07-06 22:41:47 +01:00
Halbear
605c96362b correction 2026-07-06 13:25:11 +01:00
Halbear
d05c5d0171 More Physics corrections and Forward Renderer physics 2026-07-06 13:03:42 +01:00
Halbear
eb09963e3a Physics corrections 2026-07-05 17:56:47 +01:00
Halbear
2b0344630e Physics Adjustments 2026-07-05 13:42:40 +01:00
Halbear
e746462295 Fixes on the super janky collision 2026-07-05 01:19:29 +01:00
Halbear
b817940716 super janky rigid body collisions 2026-07-05 01:12:42 +01:00
Halbear
c02b9ed2ca Physics, toggle the collision mesh preview with F2, collision is hella buggy 2026-07-01 21:38:10 +01:00
6b51c9b680 Collision & Engine refactor 2026-06-30 16:02:08 +01:00
f135d99d74 Skyboxes 2026-06-23 13:20:43 +01:00
Halbear
eb01ec4877 Better lighting 2026-06-20 02:13:47 +01:00
8d219d2a35 Deferred Lighting 2026-06-19 13:04:15 +01:00
Halbear
441bd95ddd Deferred Rendering 2026-06-15 18:17:11 +01:00
Halbear
2d37c574d6 non functional deferred rendering and also camera paths and instanced GUIs 2026-06-14 13:39:49 +01:00
536 changed files with 30120 additions and 159168 deletions

10
.gitignore vendored
View file

@ -27,7 +27,9 @@ build/
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
*.t4jlog
*.spv
*.spv.options
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
@ -84,3 +86,9 @@ fabric.properties
/.idea/
/.gradle/buildOutputCleanup/
/.gradle/
/resources/models/bistrohd/
/resources/models/Cafe/
/resources/models/Forest/
/resources/models/tree/
/resources/models/woman/
/docs/

View file

@ -1,8 +1,25 @@
import org.gradle.internal.os.OperatingSystem
plugins {
id 'application'
id 'java'
buildscript {
repositories {
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id 'application'
id 'java'
id 'com.gradleup.shadow' version '9.2.0'
}
jar {
manifest {
attributes(
'Main-Class': 'net.halbear.Executable.Launcher'
)
}
}
project.ext.lwjglVersion = "3.4.1"
project.ext.jomlVersion = "1.10.8"
project.ext.jomlprimitivesVersion = "1.10.0"
@ -11,37 +28,20 @@ project.ext.steamworks4jVersion = "1.9.0"
project.ext.steamworks4jserverVersion = "1.9.0"
project.ext.imguiVersion = "1.92.0"
switch (OperatingSystem.current()) {
case OperatingSystem.LINUX:
project.ext.lwjglNatives = "natives-linux"
def osArch = System.getProperty("os.arch")
if (osArch.startsWith("arm") || osArch.startsWith("aarch64")) {
project.ext.lwjglNatives += osArch.contains("64") || osArch.startsWith("armv8") ? "-arm64" : "-arm32"
} else if (osArch.startsWith("ppc")) {
project.ext.lwjglNatives += "-ppc64le"
} else if (osArch.startsWith("riscv")) {
project.ext.lwjglNatives += "-riscv64"
}
break
case OperatingSystem.MAC_OS:
project.ext.lwjglNatives = System.getProperty("os.arch").startsWith("aarch64") ? "natives-macos-arm64" : "natives-macos"
break
case OperatingSystem.WINDOWS:
def osArch = System.getProperty("os.arch")
project.ext.lwjglNatives = osArch.contains("64")
? "natives-windows${osArch.startsWith("aarch64") ? "-arm64" : ""}"
: "natives-windows-x86"
break
}
repositories {
mavenCentral()
}
application {
mainClass.set('net.halbear.Executable.Launcher')
}
dependencies {
implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion")
implementation 'org.tinylog:tinylog-api:2.7.0'
implementation 'org.tinylog:tinylog-impl:2.7.0'
// Core LWJGL modules
implementation "org.lwjgl:lwjgl"
implementation "org.lwjgl:lwjgl-assimp"
implementation "org.lwjgl:lwjgl-fmod"
@ -59,22 +59,29 @@ dependencies {
implementation "org.lwjgl:lwjgl-stb"
implementation "org.lwjgl:lwjgl-vma"
implementation "org.lwjgl:lwjgl-vulkan"
implementation "org.lwjgl:lwjgl::$lwjglNatives"
implementation "org.lwjgl:lwjgl-assimp::$lwjglNatives"
implementation "org.lwjgl:lwjgl-freetype::$lwjglNatives"
implementation "org.lwjgl:lwjgl-glfw::$lwjglNatives"
implementation "org.lwjgl:lwjgl-jemalloc::$lwjglNatives"
implementation "org.lwjgl:lwjgl-llvm::$lwjglNatives"
implementation "org.lwjgl:lwjgl-lmdb::$lwjglNatives"
implementation "org.lwjgl:lwjgl-meshoptimizer::$lwjglNatives"
implementation "org.lwjgl:lwjgl-openal::$lwjglNatives"
implementation "org.lwjgl:lwjgl-rpmalloc::$lwjglNatives"
implementation "org.lwjgl:lwjgl-remotery:${lwjglVersion}"
runtimeOnly "org.lwjgl:lwjgl-remotery:${lwjglVersion}:${lwjglNatives}"
implementation "org.lwjgl:lwjgl-shaderc::$lwjglNatives"
implementation "org.lwjgl:lwjgl-stb::$lwjglNatives"
implementation "org.lwjgl:lwjgl-vma::$lwjglNatives"
if (lwjglNatives == "natives-macos" || lwjglNatives == "natives-macos-arm64") implementation "org.lwjgl:lwjgl-vulkan::$lwjglNatives"
// Define targeted native platforms explicitly
def targetNatives = ["natives-windows", "natives-linux"]
// Loop through and bundle natives for both Windows and Linux
targetNatives.each { target ->
runtimeOnly "org.lwjgl:lwjgl::$target"
runtimeOnly "org.lwjgl:lwjgl-assimp::$target"
runtimeOnly "org.lwjgl:lwjgl-freetype::$target"
runtimeOnly "org.lwjgl:lwjgl-glfw::$target"
runtimeOnly "org.lwjgl:lwjgl-jemalloc::$target"
runtimeOnly "org.lwjgl:lwjgl-llvm::$target"
runtimeOnly "org.lwjgl:lwjgl-lmdb::$target"
runtimeOnly "org.lwjgl:lwjgl-meshoptimizer::$target"
runtimeOnly "org.lwjgl:lwjgl-openal::$target"
runtimeOnly "org.lwjgl:lwjgl-rpmalloc::$target"
runtimeOnly "org.lwjgl:lwjgl-remotery:${lwjglVersion}:$target"
runtimeOnly "org.lwjgl:lwjgl-shaderc::$target"
runtimeOnly "org.lwjgl:lwjgl-stb::$target"
runtimeOnly "org.lwjgl:lwjgl-vma::$target"
}
implementation "org.joml:joml:${jomlVersion}"
implementation "org.joml:joml-primitives:${jomlprimitivesVersion}"
implementation "org.lwjglx:lwjgl3-awt:${lwjgl3awtVersion}"
@ -82,13 +89,18 @@ dependencies {
implementation "com.code-disaster.steamworks4j:steamworks4j-server:${steamworks4jserverVersion}"
implementation 'com.google.code.gson:gson:2.14.0'
implementation "org.jcommander:jcommander:3.0"
['', '-opengl', '-glfw'].each {
implementation "org.lwjgl:lwjgl$it:$lwjglVersion"
implementation "org.lwjgl:lwjgl$it::natives-windows"
runtimeOnly "org.lwjgl:lwjgl$it::natives-windows"
runtimeOnly "org.lwjgl:lwjgl$it::natives-linux"
}
// ImGui Setup
implementation "io.github.spair:imgui-java-binding:$imguiVersion"
implementation "io.github.spair:imgui-java-lwjgl3:$imguiVersion"
implementation "io.github.spair:imgui-java-natives-windows:$imguiVersion"
}
// ImGui Natives for both OS environments
runtimeOnly "io.github.spair:imgui-java-natives-windows:$imguiVersion"
runtimeOnly "io.github.spair:imgui-java-natives-linux:$imguiVersion"
}

View file

@ -0,0 +1,10 @@
def validationRun = System.currentTimeMillis()
gradle.projectsEvaluated {
allprojects {
tasks.withType(Test).configureEach {
binaryResultsDirectory.set(layout.buildDirectory.dir("renderer-validation/${validationRun}/binary"))
reports.junitXml.outputLocation.set(layout.buildDirectory.dir("renderer-validation/${validationRun}/xml"))
reports.html.outputLocation.set(layout.buildDirectory.dir("renderer-validation/${validationRun}/html"))
}
}
}

View file

@ -1,7 +1,6 @@
#Thu Jun 18 13:00:38 BST 2026
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View file

@ -0,0 +1,13 @@
#version 330
in vec2 fragTextCoords;
in vec4 fragColour;
uniform sampler2D textureSampler;
out vec4 outColour;
void main()
{
outColour = fragColour * texture(textureSampler, fragTextCoords);
}

View file

@ -0,0 +1,17 @@
#version 330
layout (location=0) in vec2 inPos;
layout (location=1) in vec2 inTextCoords;
layout (location=2) in vec4 inColour;
out vec2 fragTextCoords;
out vec4 fragColour;
uniform vec2 scale;
void main()
{
fragTextCoords = inTextCoords;
fragColour = inColour;
gl_Position = vec4(inPos * scale + vec2(-1.0, 1.0), 0.0, 1.0);
}

View file

@ -0,0 +1,172 @@
#version 450
#extension GL_EXT_scalar_block_layout: require
// CREDITS: functions obtained from this link: https://github.com/SaschaWillems/Vulkan
// developed by Sascha Willems, https://twitter.com/JoeyDeVriez, licensed under MIT License (MIT)
// also Vulkan Book https://github.com/lwjglgamedev/vulkanbook/blob/master/bookcontents/chapter-15/chapter-15.md
const int MAX_LIGHTS = 32;
const float PI = 3.14159265359;
struct Light {
vec3 position;
uint directional;
float intensity;
vec3 color;
};
in vec2 inTextCoord;
out vec4 outFragColor;
uniform sampler2D outAlbedo;
uniform sampler2D outPosition;
uniform sampler2D outNormals;
uniform sampler2D outPBR;
struct Attenuation
{
float constant;
float linear;
float exponent;
};
struct Light {
vec3 position;
int lightType;
float intensity;
vec3 color;
vec3 conedir;
float cutoff;
Attenuation attenuation;
};
uniform Light lights[MAX_LIGHTS];
struct SceneInfo {
vec3 camPos;
float ambientLightIntensity;
vec3 ambientLightColor;
int LightCount;
};
uniform SceneInfo sceneInfo;
float distributionGGX(vec3 N, vec3 H, float roughness) {
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH * NdotH;
float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / denom;
}
float geometrySchlickGGX(float NdotV, float roughness) {
float r = (roughness + 1.0);
float k = (r * r) / 8.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
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);
float ggx2 = geometrySchlickGGX(NdotV, roughness);
float ggx1 = geometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
vec3 calculatePointLight(Light light, vec3 worldPos, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness) {
vec3 tmpSub = light.position - worldPos;
vec3 L = normalize(tmpSub);
vec3 H = normalize(V + L);
// Calculate distance and attenuation
float distance = length(tmpSub);
float attenuation = 1.0 / (distance * distance);
float intensity = 10.0f;
vec3 radiance = light.color * light.intensity * attenuation;
// Cook-Torrance BRDF
float NDF = distributionGGX(N, H, roughness);
float G = geometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
vec3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
vec3 specular = numerator / denominator;
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;
float NdotL = max(dot(N, L), 0.0);
return (kD * albedo / PI + specular) * radiance * NdotL;
}
vec3 calculateDirectionalLight(Light light, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness) {
vec3 L = normalize(-light.position);
vec3 H = normalize(V + L);
vec3 radiance = light.color * light.intensity;
// Cook-Torrance BRDF
float NDF = distributionGGX(N, H, roughness);
float G = geometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
vec3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
vec3 specular = numerator / denominator;
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;
float NdotL = max(dot(N, L), 0.0);
return (kD * albedo / PI + specular) * radiance * NdotL;
}
void main() {
vec3 albedo = texture(outAlbedo, inTextCoord).rgb;
vec3 normal = texture(outNormals, inTextCoord).rgb;
vec3 worldPos = texture(outPosition, inTextCoord).rgb;
vec3 pbr = texture(outPBR, inTextCoord).rgb;
float roughness = pbr.g;
float metallic = pbr.b;
vec3 N = normalize(normal);
vec3 V = normalize(sceneInfo.camPos - worldPos);
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic);
vec3 Lo = vec3(0.0);
for (uint i = 0; i < sceneInfo.LightCount; i++) {
Light light = lights[i];
if (light.lightType == 1) {
Lo += calculateDirectionalLight(light, V, N, F0, albedo, metallic, roughness);
} else {
Lo += calculatePointLight(light, worldPos, V, N, F0, albedo, metallic, roughness);
}
}
vec3 ambient = sceneInfo.ambientLightColor * albedo * sceneInfo.ambientLightIntensity;
vec3 color = ambient + Lo;
outFragColor = vec4(color, 1.0f);
if (length(normal) < 0.001) {
outFragColor = vec4(albedo,1.0f);
return;
}
// outFragColor = vec4(normal, 1.0f);
}

View file

@ -0,0 +1,256 @@
#version 330 core
const int MAX_LIGHTS = 32;
const float PI = 3.14159265359;
const float SPECULAR_POWER = 10;
in vec4 outPos;
in vec3 outNormal;
in vec3 outTangent;
in vec3 outBitangent;
in vec2 outTextCoords;
out vec4 fragColor;
struct Attenuation
{
float constant;
float linear;
float exponent;
};
struct Light {
vec3 position;
int lightType;
float intensity;
vec3 color;
vec3 conedir;
float cutoff;
Attenuation attenuation;
};
struct Material {
vec4 diffuse;
int hasTexture;
int hasNormalMap;
int hasRoughMap;
float roughnessFactor;
float metallicFactor;
};
uniform sampler2D textureSampler;
uniform sampler2D normalSampler;
uniform sampler2D roughnessSampler;
uniform Light lights[MAX_LIGHTS];
struct SceneInfo {
vec3 camPos;
float ambientLightIntensity;
vec3 ambientLightColor;
int LightCount;
};
uniform Material material;
uniform SceneInfo sceneInfo;
vec4 calcAmbient(Light ambientLight, vec4 ambient) {
return vec4(ambientLight.intensity * ambientLight.color, 1) * ambient;
}
vec4 calcLightColor(vec4 diffuse, vec4 specular, vec3 lightColor, float light_intensity, vec3 position, vec3 to_light_dir, vec3 normal, float Metallic) {
vec4 diffuseColor = vec4(0, 0, 0, 1);
vec4 specColor = vec4(0, 0, 0, 1);
float diffuseFactor = max(dot(normal, to_light_dir), 0.0);
diffuseColor = diffuse * vec4(lightColor, 1.0) * light_intensity * diffuseFactor;
vec3 camera_direction = normalize(-position);
vec3 from_light_dir = -to_light_dir;
vec3 reflected_light = normalize(reflect(from_light_dir, normal));
float specularFactor = max(dot(camera_direction, reflected_light), 0.0);
specularFactor = pow(specularFactor, SPECULAR_POWER);
specColor = specular * light_intensity * specularFactor * Metallic * vec4(lightColor, 1.0);
return (diffuseColor + specColor);
}
vec4 calcPointLight(vec4 diffuse, vec4 specular, Light light, vec3 position, vec3 normal, float Metallic) {
vec3 light_direction = light.position - position;
vec3 to_light_dir = normalize(light_direction);
vec4 light_color = calcLightColor(diffuse, specular, light.color, light.intensity, position, to_light_dir, normal,Metallic);
float distance = length(light_direction);
float attenuationInv = light.attenuation.constant + light.attenuation.linear * distance +
light.attenuation.exponent * distance * distance;
return light_color / attenuationInv;
}
vec4 calcSpotLight(vec4 diffuse, vec4 specular, Light light, vec3 position, vec3 normal,float Metallic) {
vec3 light_direction = light.position - position;
vec3 to_light_dir = normalize(light_direction);
vec3 from_light_dir = -to_light_dir;
float spot_alfa = dot(from_light_dir, normalize(light.conedir));
vec4 color = vec4(0, 0, 0, 0);
if (spot_alfa > light.cutoff)
{
color = calcPointLight(diffuse, specular, light, position, normal,Metallic);
color *= (1.0 - (1.0 - spot_alfa)/(1.0 - light.cutoff));
}
return color;
}
vec4 calcDirLight(vec4 diffuse, vec4 specular, Light light, vec3 position, vec3 normal,float Metallic) {
return calcLightColor(diffuse, specular, light.color, light.intensity, position, normalize(light.position), normal,Metallic);
}
vec3 calcNormal(Material material, vec3 normal, vec2 textCoords, mat3 TBN)
{
vec3 newNormal = normal;
if (material.hasNormalMap > 0)
{
newNormal = texture(normalSampler, textCoords).rgb;
newNormal = normalize(newNormal * 2.0 - 1.0);
newNormal = normalize(TBN * newNormal);
}
return newNormal;
}
float distributionGGX(vec3 N, vec3 H, float roughness) {
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH * NdotH;
float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / denom;
}
float geometrySchlickGGX(float NdotV, float roughness) {
float r = (roughness + 1.0);
float k = (r * r) / 8.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
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);
float ggx2 = geometrySchlickGGX(NdotV, roughness);
float ggx1 = geometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
vec3 calculatePointLight(Light light, vec3 worldPos, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness) {
vec3 tmpSub = light.position - worldPos;
vec3 L = normalize(tmpSub);
vec3 H = normalize(V + L);
// Calculate distance and attenuation
float distance = length(tmpSub);
float attenuation = 1.0 / (distance * distance);
float intensity = 10.0f;
vec3 radiance = light.color * light.intensity * attenuation;
// Cook-Torrance BRDF
float NDF = distributionGGX(N, H, roughness);
float G = geometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
vec3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
vec3 specular = numerator / denominator;
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;
float NdotL = max(dot(N, L), 0.0);
return (kD * albedo / PI + specular) * radiance * NdotL;
}
vec3 calculateDirectionalLight(Light light, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness) {
vec3 L = normalize(-light.position);
vec3 H = normalize(V + L);
vec3 radiance = light.color * light.intensity;
// Cook-Torrance BRDF
float NDF = distributionGGX(N, H, roughness);
float G = geometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
vec3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
vec3 specular = numerator / denominator;
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;
float NdotL = max(dot(N, L), 0.0);
return (kD * albedo / PI + specular) * radiance * NdotL;
}
void main()
{
vec4 text_color = texture(textureSampler, outTextCoords);
if(text_color.a < 0.5) discard;
vec4 diffuse = text_color;
mat3 TBN = mat3(outTangent, outBitangent, outNormal);
vec3 newNormal = calcNormal(material, outNormal, outTextCoords, TBN);
float ao = 0.5;
float roughnessFactor = 0.0;
float metallicFactor = 0.0;
if (material.hasRoughMap > 0) {
vec4 metRoughValue = texture(roughnessSampler, outTextCoords);
roughnessFactor = metRoughValue.g;
metallicFactor = metRoughValue.b;
} else {
roughnessFactor = material.roughnessFactor;
metallicFactor = material.metallicFactor;
}
vec4 specular = text_color + metallicFactor - roughnessFactor;
vec4 pbr = vec4(ao, roughnessFactor, metallicFactor, text_color.a);
float roughness = pbr.g;
float metallic = pbr.b;
vec3 N = normalize(newNormal);
vec3 V = normalize(sceneInfo.camPos - outPos.rgb);
vec3 F0 = vec3(0.04);
F0 = mix(F0, text_color.rgb, metallic);
vec3 Lo = vec3(0.0);
for (int i = 0; i < sceneInfo.LightCount; i++) {
Light light = lights[i];
vec3 Pos = vec3(outPos.rgb);
if (light.lightType == 1) {
//Lo += calculateDirectionalLight(light, V, N, F0, text_color.rgb, metallic, roughness);
Lo += calcDirLight(diffuse, specular, light, Pos, outNormal,metallic).rgb;
} else {
// Lo += calculatePointLight(light, outPos.rgb, V, N, F0, text_color.rgb, metallic, roughness);
Lo += calcPointLight(diffuse, specular, light, Pos, outNormal,metallic).rgb;
}
}
vec3 ambient = sceneInfo.ambientLightColor * text_color.rgb * sceneInfo.ambientLightIntensity;
vec3 color = ambient + Lo;
fragColor = vec4(color, 1.0f);
}

View file

@ -0,0 +1,77 @@
#version 450
const int MAX_TEXTURES = 256;
out vec4 outPos;
out vec3 outNormal;
out vec3 outTangent;
out vec3 outBitangent;
out vec2 outTextCoords;
out vec4 outAlbedo ;
out vec4 outPosition;
out vec4 outNormals;
out vec4 outPBR;
struct Material {
vec4 diffuse;
int hasTexture;
int hasNormalMap;
int hasRoughMap;
float roughnessFactor;
float metallicFactor;
};
uniform sampler2D textureSampler;
uniform sampler2D normalSampler;
uniform sampler2D roughnessSampler;
uniform Material material;
vec3 calcNormal(Material material, vec3 normal, vec2 textCoords, mat3 TBN)
{
vec3 newNormal = normal;
if (material.hasNormalMap > 0)
{
newNormal = texture(normalSampler, textCoords).rgb;
newNormal = normalize(newNormal * 2.0 - 1.0);
newNormal = normalize(TBN * newNormal);
}
return newNormal;
}
layout(push_constant) uniform pc {
layout(offset = 64) uint materialIdx;
} push_constants;
void main()
{
outPosition = outPos;
if (material.hasTexture == 1) {
outAlbedo = texture(textureSampler, outTextCoords);
} else {
outAlbedo = material.diffuse;
}
if(outAlbedo.a < 0.5) discard;
mat3 TBN = mat3( outTangent, outBitangent, outNormal);
vec3 newNormal = calcNormal(material, outNormal, outTextCoords, TBN);
outNormals = vec4(newNormal, 1.0f);
float ao = 0.5f;
float roughnessFactor = 0.0f;
float metallicFactor = 0.0f;
if (material.hasRoughMap > 0) {
vec4 metRoughValue = texture(roughnessSampler, outTextCoords);
roughnessFactor = metRoughValue.g;
metallicFactor = metRoughValue.b;
} else {
roughnessFactor = material.roughnessFactor;
metallicFactor = material.metallicFactor;
}
outPBR = vec4(ao, roughnessFactor, metallicFactor, 1.0f);
}

View file

@ -0,0 +1,37 @@
#version 330 core
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inNormal;
layout (location = 2) in vec3 inTangent;
layout (location = 3) in vec3 inBitangent;
layout (location = 4) in vec2 inTextCoords;
out vec4 outPos;
out vec3 outNormal;
out vec3 outTangent;
out vec3 outBitangent;
out vec2 outTextCoords;
uniform mat4 projectionMatrix;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
void main()
{
// vec4 worldPos = modelMatrix * vec4(inPos,1);
// gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(inPos, 1.0);
// mat3 mNormal = transpose(inverse(mat3(modelMatrix)));
// outPos = worldPos;
// outNormal = mNormal * normalize(inNormal);
// outTextCoords = inTextCoords;
mat4 modelViewMatrix = viewMatrix * modelMatrix;
vec4 mvPosition = modelViewMatrix * vec4(inPos, 1.0);
gl_Position = projectionMatrix * mvPosition;
outPos = mvPosition;
outNormal = normalize(modelViewMatrix * vec4(inNormal, 0.0)).xyz;
outTangent = inNormal * normalize(inTangent);
outBitangent = inNormal * normalize(inBitangent);
outTextCoords = inTextCoords;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

View file

@ -0,0 +1,2 @@
Sky texture:
kaori669 on deviant art

View file

@ -0,0 +1,28 @@
#version 450
const int MAX_TEXTURES = 512;
const float GAMMA_CONST = 0.4545;
layout(location = 0) in vec2 inUV;
layout(location = 0) out vec4 outColor;
layout(push_constant) uniform pc {
layout(offset = 28) uint textureIndex;
} push_constants;
layout(set = 1, binding = 0) uniform sampler2D spriteTextures[MAX_TEXTURES];
vec4 gamma(vec4 color){
return color = vec4(pow(color.rgb,vec3(GAMMA_CONST)),color.a);
}
void main() {
if (push_constants.textureIndex >= MAX_TEXTURES){
outColor = vec4(0.0,0.0,1.0,1.0);
return;
}
vec4 tex = texture(spriteTextures[push_constants.textureIndex], inUV);
outColor = gamma(tex);
if (outColor.a <= 0.09) {
discard;
}
}

View file

@ -0,0 +1,19 @@
#version 450
const int MAX_TEXTURES = 128;
layout(location = 0) in vec2 inUV;
layout(location = 0) out vec4 outColor;
layout(push_constant) uniform pc {
layout(offset = 28) uint textureIndex;
} push_constants;
layout(set = 1, binding = 0) uniform sampler2D spriteTextures[MAX_TEXTURES];
void main() {
vec4 tex = texture(spriteTextures[push_constants.textureIndex], inUV);
outColor = tex;
if(outColor.a >= 0.9 || outColor.a <= 0.001){discard;}
}

View file

@ -0,0 +1,36 @@
#version 450
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inUV;
layout(location = 0) out vec2 outUV;
layout(push_constant) uniform pc {
vec2 modelSize;
vec2 position;
vec2 screenSize;
float zAmount;
} push_constants;
layout(set = 0, binding = 0) uniform ViewUniform{
vec2 camPos;
vec2 camScale;
} viewUniform;
void main() {
vec2 ScaledPos = inPos * push_constants.modelSize;
vec2 worldPos = push_constants.position + ScaledPos;
worldPos += (viewUniform.camPos * push_constants.zAmount);
vec2 ndc = vec2(
(worldPos.x / push_constants.screenSize.x) * 2.0 - 1.0,
(worldPos.y / push_constants.screenSize.y) * 2.0 - 1.0
);
ndc.y = -ndc.y;
gl_Position = vec4(ndc * viewUniform.camScale, 0.0, 1.0);
outUV = vec2(inUV.x, 1 - inUV.y);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -0,0 +1,236 @@
#version 460
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
const int CHUNK_SIZE = 16;
const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
const int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
const uint FLOATS_PER_VERTEX = 14u;
const uint INTEGERS_PER_VERTEX = 1u;
const uint VERTICES_PER_FACE = 4u;
const uint INDICES_PER_FACE = 6u;
const uint MAX_VISIBLE_FACES_PER_CHUNK = uint(CHUNK_SIZE * CHUNK_SIZE * 12);
const uint MAX_VERTICES = MAX_VISIBLE_FACES_PER_CHUNK * VERTICES_PER_FACE;
const uint MAX_INDICES = MAX_VISIBLE_FACES_PER_CHUNK * INDICES_PER_FACE;
layout(std430, binding = 0) readonly buffer VoxelData {
uint voxels[];
};
layout(std430, binding = 1) buffer VertexBuffer {
float vertices[];
};
layout(std430, binding = 2) buffer IndexBuffer {
uint indices[];
};
layout(std430, binding = 3) buffer DrawCommand {
uint indexCount;
uint instanceCount;
uint firstIndex;
int vertexOffset;
uint firstInstance;
} drawCmd;
layout(std430, binding = 4) buffer Counters {
uint vertexCount;
uint indexCount;
} counters;
layout(push_constant) uniform ChunkInfo {
ivec3 chunkPos;
int padding0;
};
uint flatten(ivec3 pos) {
return uint((pos.x * CHUNK_AREA) + (pos.y * CHUNK_SIZE) + pos.z);
}
uint getVoxel(ivec3 pos) {
if (pos.x < 0 || pos.x >= CHUNK_SIZE) return 0;
if (pos.y < 0 || pos.y >= CHUNK_SIZE) return 0;
if (pos.z < 0 || pos.z >= CHUNK_SIZE) return 0;
return voxels[flatten(pos)];
}
void writeVertex(uint vertexIndex,vec3 position,vec3 normal,
vec3 tangent,vec3 bitangent,vec2 uv) {
uint base = vertexIndex * FLOATS_PER_VERTEX;
vertices[base + 0u] = position.x;
vertices[base + 1u] = position.y;
vertices[base + 2u] = position.z;
vertices[base + 3u] = normal.x;
vertices[base + 4u] = normal.y;
vertices[base + 5u] = normal.z;
vertices[base + 6u] = tangent.x;
vertices[base + 7u] = tangent.y;
vertices[base + 8u] = tangent.z;
vertices[base + 9u] = bitangent.x;
vertices[base + 10u] = bitangent.y;
vertices[base + 11u] = bitangent.z;
vertices[base + 12u] = uv.x;
vertices[base + 13u] = uv.y;
}
void emitFace(ivec3 voxelPos, int faceIndex) {
uint baseVertex = atomicAdd(counters.vertexCount, VERTICES_PER_FACE);
uint baseIndex = atomicAdd(counters.indexCount, INDICES_PER_FACE);
if (baseVertex + VERTICES_PER_FACE > MAX_VERTICES ||
baseIndex + INDICES_PER_FACE > MAX_INDICES) {
return;
}
vec3 p = vec3(voxelPos);
vec3 normal;
vec3 tangent;
vec3 bitangent;
vec3 v0;
vec3 v1;
vec3 v2;
vec3 v3;
vec2 uv0;
vec2 uv1;
vec2 uv2;
vec2 uv3;
if (faceIndex == 0) {
// Top +Y
normal = vec3(0.0, 1.0, 0.0);
tangent = vec3(1.0, 0.0, 0.0);
bitangent = vec3(0.0, 0.0, 1.0);
v0 = p + vec3(0.0, 1.0, 0.0);
v1 = p + vec3(0.0, 1.0, 1.0);
v2 = p + vec3(1.0, 1.0, 1.0);
v3 = p + vec3(1.0, 1.0, 0.0);
uv0 = vec2(0.0, 0.5);
uv1 = vec2(0.0, 1.0);
uv2 = vec2(0.5, 1.0);
uv3 = vec2(0.5, 0.5);
} else if (faceIndex == 1) {
// Bottom -Y
normal = vec3(0.0, -1.0, 0.0);
tangent = vec3(1.0, 0.0, 0.0);
bitangent = vec3(0.0, 0.0, -1.0);
v0 = p + vec3(0.0, 0.0, 0.0);
v1 = p + vec3(1.0, 0.0, 0.0);
v2 = p + vec3(1.0, 0.0, 1.0);
v3 = p + vec3(0.0, 0.0, 1.0);
uv0 = vec2(0.5, 0.0);
uv1 = vec2(0.5, 0.5);
uv2 = vec2(1.0, 0.5);
uv3 = vec2(1.0, 0.0);
} else if (faceIndex == 2) {
// Right +X
normal = vec3(1.0, 0.0, 0.0);
tangent = vec3(0.0, 0.0, -1.0);
bitangent = vec3(0.0, 1.0, 0.0);
v0 = p + vec3(1.0, 0.0, 0.0);
v1 = p + vec3(1.0, 1.0, 0.0);
v2 = p + vec3(1.0, 1.0, 1.0);
v3 = p + vec3(1.0, 0.0, 1.0);
uv0 = vec2(0.0, 0.0);
uv3 = vec2(0.0, 0.5);
uv2 = vec2(0.5, 0.5);
uv1 = vec2(0.5, 0.0);
} else if (faceIndex == 3) {
// Left -X
normal = vec3(-1.0, 0.0, 0.0);
tangent = vec3(0.0, 0.0, 1.0);
bitangent = vec3(0.0, 1.0, 0.0);
v0 = p + vec3(0.0, 0.0, 0.0);
v1 = p + vec3(0.0, 0.0, 1.0);
v2 = p + vec3(0.0, 1.0, 1.0);
v3 = p + vec3(0.0, 1.0, 0.0);
uv0 = vec2(0.0, 0.0);
uv1 = vec2(0.0, 0.5);
uv2 = vec2(0.5, 0.5);
uv3 = vec2(0.5, 0.0);
} else if (faceIndex == 4) {
// Front +Z
normal = vec3(0.0, 0.0, 1.0);
tangent = vec3(1.0, 0.0, 0.0);
bitangent = vec3(0.0, 1.0, 0.0);
v0 = p + vec3(0.0, 0.0, 1.0);
v1 = p + vec3(1.0, 0.0, 1.0);
v2 = p + vec3(1.0, 1.0, 1.0);
v3 = p + vec3(0.0, 1.0, 1.0);
uv0 = vec2(0.0, 0.0);
uv1 = vec2(0.0, 0.5);
uv2 = vec2(0.5, 0.5);
uv3 = vec2(0.5, 0.0);
} else {
// Back -Z
normal = vec3(0.0, 0.0, -1.0);
tangent = vec3(-1.0, 0.0, 0.0);
bitangent = vec3(0.0, 1.0, 0.0);
v0 = p + vec3(0.0, 0.0, 0.0);
v1 = p + vec3(0.0, 1.0, 0.0);
v2 = p + vec3(1.0, 1.0, 0.0);
v3 = p + vec3(1.0, 0.0, 0.0);
uv0 = vec2(0.0, 0.0);
uv1 = vec2(0.0, 0.5);
uv2 = vec2(0.5, 0.5);
uv3 = vec2(0.5, 0.0);
}
writeVertex(baseVertex + 0u, v0, normal, tangent, bitangent, uv0);
writeVertex(baseVertex + 1u, v1, normal, tangent, bitangent, uv1);
writeVertex(baseVertex + 2u, v2, normal, tangent, bitangent, uv2);
writeVertex(baseVertex + 3u, v3, normal, tangent, bitangent, uv3);
indices[baseIndex + 0u] = baseVertex + 0u;
indices[baseIndex + 1u] = baseVertex + 1u;
indices[baseIndex + 2u] = baseVertex + 2u;
indices[baseIndex + 3u] = baseVertex + 0u;
indices[baseIndex + 4u] = baseVertex + 2u;
indices[baseIndex + 5u] = baseVertex + 3u;
atomicAdd(drawCmd.indexCount, INDICES_PER_FACE);
}
void main() {
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
if (pos.x >= CHUNK_SIZE || pos.y >= CHUNK_SIZE || pos.z >= CHUNK_SIZE) {
return;
}
uint current = getVoxel(pos);
if (current == 0u) {
return;
}
if (getVoxel(pos + ivec3( 0, 1, 0)) == 0u) emitFace(pos, 0);
if (getVoxel(pos + ivec3( 0, -1, 0)) == 0u) emitFace(pos, 1);
if (getVoxel(pos + ivec3( 1, 0, 0)) == 0u) emitFace(pos, 2);
if (getVoxel(pos + ivec3(-1, 0, 0)) == 0u) emitFace(pos, 3);
if (getVoxel(pos + ivec3( 0, 0, 1)) == 0u) emitFace(pos, 4);
if (getVoxel(pos + ivec3( 0, 0, -1)) == 0u) emitFace(pos, 5);
}

View file

@ -0,0 +1,201 @@
#version 460
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
const int CHUNK_SIZE = 16;
const int SCRATCH_SIZE = CHUNK_SIZE + 2;
const int SCRATCH_AREA = SCRATCH_SIZE * SCRATCH_SIZE;
const int SCRATCH_VOXEL_COUNT = SCRATCH_SIZE * SCRATCH_SIZE * SCRATCH_SIZE;
const uint MAX_VISIBLE_FACES_PER_CHUNK = uint(CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE * 6);
layout(std430, binding = 0) readonly buffer VoxelData {
uint voxels[];
};
layout(std430, binding = 1) buffer FaceBuffer {
uint faces[];
};
layout(std430, binding = 2) buffer Counters {
uint faceCount[];
} counters;
struct Voxel {
uint MaterialIndex;
uint BlockType;
uvec2[2] UpIndex;
uvec2[2] DownIndex;
uvec2[2] NorthIndex;
uvec2[2] SouthIndex;
uvec2[2] EastIndex;
uvec2[2] WestIndex;
};
layout(std430, set = 1, binding = 0) readonly buffer VoxelUniform {
Voxel materials[];
} voxelReg;
layout(push_constant) uniform ChunkInfo {
ivec3 chunkPos;
int slot;
uint faceOffset;
uint voxelTypeCount;
uint biomeCount;
uint structureCount;
uint worldSeed;
};
uint flatten(ivec3 pos) {
pos += ivec3(1);
return uint(slot * SCRATCH_VOXEL_COUNT + pos.x * SCRATCH_AREA + pos.y * SCRATCH_SIZE + pos.z);
}
bool isSeeThrough(Voxel voxel, uint type) {
if (type == 0u || voxel.BlockType == 3u || type > voxelTypeCount) return true;
return voxelReg.materials[type - 1u].BlockType >= 1u;
}
uint getVoxel(ivec3 pos) {
if (pos.x < -1 || pos.x > CHUNK_SIZE) return 0u;
if (pos.y < -1 || pos.y > CHUNK_SIZE) return 0u;
if (pos.z < -1 || pos.z > CHUNK_SIZE) return 0u;
return voxels[flatten(pos)];
}
uint hash21(uvec2 p) {
p = p * 1664525u + 1013904223u;
p.x += p.y * 1664525u;
p.y += p.x * 1664525u;
return p.x ^ (p.x >> 16);
}
uint pcg_hash(uint seed) {
uint state = seed * 747796405u + 289133645u;
uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
return (word >> 22u) ^ word;
}
uint randomRangeUint(uint seed, uint minVal, uint maxVal) {
uint range = maxVal - minVal + 1u;
return minVal + (pcg_hash(seed) % range);
}
uint random_1_to_3(vec2 uv, uint customSeed) {
uvec2 p = uvec2(floatBitsToUint(uv.x), floatBitsToUint(uv.y));
p.x ^= customSeed;
uint randInt = hash21(p);
return (randInt % 3u) + 1u;
}
uint packFace(uvec3 voxelPos, uint faceIndex, Voxel voxel) {
uint randomSeed = uint(voxelPos.x) * 73856093u ^ uint(voxelPos.z) * 19349663u;
uvec2 UpIndex = uvec2(randomRangeUint(randomSeed,voxel.UpIndex[0].x,voxel.UpIndex[1].x),randomRangeUint(randomSeed,voxel.UpIndex[0].y,voxel.UpIndex[1].y));
uvec2 DownIndex = uvec2(randomRangeUint(randomSeed,voxel.DownIndex[0].x,voxel.DownIndex[1].x),randomRangeUint(randomSeed,voxel.DownIndex[0].y,voxel.DownIndex[1].y));
uvec2 NorthIndex = uvec2(randomRangeUint(randomSeed,voxel.NorthIndex[0].x,voxel.NorthIndex[1].x),randomRangeUint(randomSeed,voxel.NorthIndex[0].y,voxel.NorthIndex[1].y));
uvec2 SouthIndex = uvec2(randomRangeUint(randomSeed,voxel.SouthIndex[0].x,voxel.SouthIndex[1].x),randomRangeUint(randomSeed,voxel.SouthIndex[0].y,voxel.SouthIndex[1].y));
uvec2 EastIndex = uvec2(randomRangeUint(randomSeed,voxel.EastIndex[0].x,voxel.EastIndex[1].x),randomRangeUint(randomSeed,voxel.EastIndex[0].y,voxel.EastIndex[1].y));
uvec2 WestIndex = uvec2(randomRangeUint(randomSeed,voxel.WestIndex[0].x,voxel.WestIndex[1].x),randomRangeUint(randomSeed,voxel.WestIndex[0].y,voxel.WestIndex[1].y));
uvec2 textureIndices[8] = uvec2[8](UpIndex, DownIndex, NorthIndex,
SouthIndex, EastIndex, WestIndex, NorthIndex,SouthIndex);
uvec2 tex = textureIndices[faceIndex];
uint textureIndexX = tex.x;
uint textureIndexY = tex.y;
uint materialId = voxel.MaterialIndex;
return (voxelPos.x & 0xFu) |
((voxelPos.y & 0xFu) << 4u) |
((voxelPos.z & 0xFu) << 8u) |
((faceIndex & 0x7u) << 12u) |
((materialId & 0x7FFu) << 15u) |
((textureIndexX & 0x7u) << 26u) |
((textureIndexY & 0x7u) << 29u);
}
uint packFace(uvec3 voxelPos, uint faceIndex, uint materialId) {
uint randomFaceValue = random_1_to_3(vec2(voxelPos.x, voxelPos.z),faceOffset);
uint textureIndexX = 0u;
uint textureIndexY = 0u;
if(materialId == 1u){
if(faceIndex == 0u){
textureIndexX = 0u;
textureIndexY = randomFaceValue;
} else if(faceIndex == 1u){
textureIndexX = 1u;
textureIndexY = 0u;
}
else{
textureIndexX = 0u;
textureIndexY = 0u;
}
} else if(materialId == 2u){
textureIndexX = 1u;
textureIndexY = 0u;
}else if(materialId == 3u){
textureIndexX = 1u;
textureIndexY = 0u;
}else if(materialId == 4u){
textureIndexX = 1u;
textureIndexY = randomFaceValue;
}else if(materialId == 5u){
textureIndexX = 2u;
textureIndexY = 3u;
}else if(materialId == 5u){
if (faceIndex == 0u || faceIndex == 1u){
textureIndexX = 2u;
textureIndexY = 1u;
} else{
textureIndexX = 2u;
textureIndexY = 2u;
}
}else if(materialId == 6u){
textureIndexX = 2u;
textureIndexY = 0u;
}
return (voxelPos.x & 0xFu) |
((voxelPos.y & 0xFu) << 4u) |
((voxelPos.z & 0xFu) << 8u) |
((faceIndex & 0x7u) << 12u) |
((materialId & 0x7FFu) << 15u) |
((textureIndexX & 0x7u) << 26u) |
((textureIndexY & 0x7u) << 29u);
}
void emitFace(ivec3 voxelPos, uint faceIndex, uint voxelType) {
if (voxelType == 0u || voxelType > voxelTypeCount) {
return;
}
uint localFace = atomicAdd(counters.faceCount[slot], 1u);
if (localFace >= MAX_VISIBLE_FACES_PER_CHUNK) {
return;
}
Voxel voxel = voxelReg.materials[voxelType - 1u];
faces[faceOffset + localFace] = packFace(uvec3(voxelPos), faceIndex, voxel);
}
void main() {
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
if (pos.x >= CHUNK_SIZE || pos.y >= CHUNK_SIZE || pos.z >= CHUNK_SIZE) {
return;
}
uint current = getVoxel(pos);
if (current == 0u || current > voxelTypeCount) {
return;
}
Voxel voxel = voxelReg.materials[current - 1u];
if (voxel.BlockType == 1u) {
emitFace(pos, 6u, current);
emitFace(pos, 7u, current);
return;
}
if (isSeeThrough(voxel,getVoxel(pos + ivec3( 0, 1, 0)))) emitFace(pos, 0u, current);
if (isSeeThrough(voxel,getVoxel(pos + ivec3( 0, -1, 0)))) emitFace(pos, 1u, current);
if (isSeeThrough(voxel,getVoxel(pos + ivec3( 1, 0, 0)))) emitFace(pos, 2u, current);
if (isSeeThrough(voxel,getVoxel(pos + ivec3(-1, 0, 0)))) emitFace(pos, 3u, current);
if (isSeeThrough(voxel,getVoxel(pos + ivec3( 0, 0, 1)))) emitFace(pos, 4u, current);
if (isSeeThrough(voxel,getVoxel(pos + ivec3( 0, 0, -1)))) emitFace(pos, 5u, current);
}

View file

@ -0,0 +1,27 @@
#version 460
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(std430, binding = 0) buffer DrawCommand {
uint indexCount;
uint instanceCount;
uint firstIndex;
int vertexOffset;
uint firstInstance;
} drawCmd;
layout(std430, binding = 1) buffer Counters {
uint vertexCount;
uint indexCount;
} counters;
void main() {
drawCmd.indexCount = 0u;
drawCmd.instanceCount = 1u;
drawCmd.firstIndex = 0u;
drawCmd.vertexOffset = 0;
drawCmd.firstInstance = 0u;
counters.vertexCount = 0u;
counters.indexCount = 0u;
}

View file

@ -0,0 +1,21 @@
#version 460
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(std430, binding = 0) buffer Counters {
uint faceCount[];
} counters;
layout(push_constant) uniform ChunkInfo {
ivec3 chunkPos;
int slot;
uint faceOffset;
uint voxelTypeCount;
uint biomeCount;
uint structureCount;
uint worldSeed;
};
void main() {
counters.faceCount[slot] = 0u;
}

View file

@ -0,0 +1,201 @@
#version 460
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
const int CHUNK_SIZE = 16;
const int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
// A 1D storage buffer representing a flat 3D array of voxel IDs
layout(std430, binding = 0) buffer VoxelData {
uint voxels[];
};
layout(push_constant) uniform ChunkOffset {
ivec3 chunkPos;
int padding0;
};
// Description : Array and textureless GLSL 2D/3D/4D simplex
// noise functions.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : stegu
// Lastmod : 20110822 (ijm)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com
vec4 permute(vec4 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }
vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }
float simplex_noise(vec3 v) {
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
// First corner
vec3 i = floor(v + dot(v, C.yyy));
vec3 x0 = v - i + dot(i, C.xxx);
// Other corners
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min(g.xyz, l.zxy);
vec3 i2 = max(g.xyz, l.zxy);
// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
// Permutations
i = mod(i, 289.0);
vec4 p = permute(permute(permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
float n_ = 0.142857142857; // 1.0/7.0
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z); // mod(p,7*7)
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_); // mod(j,N)
vec4 x = x_ * ns.x + ns.yyyy;
vec4 y = y_ * ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4(x.xy, y.xy);
vec4 b1 = vec4(x.zw, y.zw);
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
vec4 s0 = floor(b0) * 2.0 + 1.0;
vec4 s1 = floor(b1) * 2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
vec3 p0 = vec3(a0.xy, h.x);
vec3 p1 = vec3(a0.zw, h.y);
vec3 p2 = vec3(a1.xy, h.z);
vec3 p3 = vec3(a1.zw, h.w);
// Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
// Mix final noise value
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
// Returns a value scaled exactly between -1.0 and 1.0
return 42.0 * dot(m * m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));
}
float noise2D(vec2 p) {
return simplex_noise(vec3(p.x, p.y, 0.0));
}
float fbm(vec2 p, int octaves, float lacunarity, float gain) {
float value = 0.0;
float amplitude = 0.5;
float frequency = 1.0;
float amplitudeSum = 0.0;
for (int i = 0; i < octaves; i++) {
value += noise2D(p * frequency) * amplitude;
amplitudeSum += amplitude;
frequency *= lacunarity;
amplitude *= gain;
}
return value / amplitudeSum;
}
float ridgedFbm(vec2 p, int octaves, float lacunarity, float gain) {
float value = 0.0;
float amplitude = 0.5;
float frequency = 1.0;
float amplitudeSum = 0.0;
for (int i = 0; i < octaves; i++) {
float n = noise2D(p * frequency);
n = 1.0 - abs(n);
n = n * n;
value += n * amplitude;
amplitudeSum += amplitude;
frequency *= lacunarity;
amplitude *= gain;
}
return value / amplitudeSum;
}
vec2 domainWarp(vec2 p) {
float wx = fbm(p + vec2(17.31, 91.73), 3, 2.0, 0.5);
float wz = fbm(p + vec2(43.17, 12.89), 3, 2.0, 0.5);
return p + vec2(wx, wz) * 35.0;
}
float terrainHeight(vec2 worldXZ) {
vec2 p = worldXZ;
vec2 warped = domainWarp(p * 0.006);
float continent = fbm(warped * 0.45, 5, 2.0, 0.5);
continent = continent * 0.5 + 0.5;
float hills = fbm(p * 0.025, 5, 2.0, 0.48);
float detail = fbm(p * 0.09, 3, 2.1, 0.45);
float mountainMask = smoothstep(0.52, 0.82, continent);
float mountains = ridgedFbm(warped * 1.15, 5, 2.0, 0.52);
float height = 18.0;
height += continent * 28.0;
height += hills * 14.0;
height += detail * 3.0;
height += mountainMask * mountains * 55.0;
return height;
}
void main() {
ivec3 localPos = ivec3(gl_GlobalInvocationID.xyz);
if (localPos.x >= CHUNK_SIZE || localPos.y >= CHUNK_SIZE || localPos.z >= CHUNK_SIZE) {
return;
}
ivec3 worldPos = chunkPos * CHUNK_SIZE + localPos;
float height = terrainHeight(vec2(worldPos.x,worldPos.z) * 0.02) * 0.0015 + 10 ;
uint voxelType = 0u;
if (float(worldPos.y) <= height) {
float depthBelowSurface = height - float(worldPos.y);
if (depthBelowSurface < 1.5) {
voxelType = 1u; // Grass/topsoil
} else if (depthBelowSurface < 5.0) {
voxelType = 2u; // Dirt
} else {
voxelType = 3u; // Stone
}
}
uint index = uint((localPos.x * CHUNK_AREA) + (localPos.y * CHUNK_SIZE) + localPos.z);
voxels[index] = voxelType;
}

View file

@ -0,0 +1,596 @@
#version 460
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
const int CHUNK_SIZE = 16;
const int SCRATCH_SIZE = CHUNK_SIZE + 2;
const int SCRATCH_AREA = SCRATCH_SIZE * SCRATCH_SIZE;
const int SCRATCH_VOXEL_COUNT = SCRATCH_SIZE * SCRATCH_SIZE * SCRATCH_SIZE;
const int STRUCTURE_CELL_SIZE = 16;
const int REPLACE_AIR_ONLY = 1;
const int REPLACE_FOLIAGE = 2;
const int REQUIRE_FLAT_GROUND = 4;
const int HAS_FOUNDATION = 8;
layout(push_constant) uniform ChunkInfo {
ivec3 chunkPos;
int slot;
uint faceOffset;
uint voxelTypeCount;
uint biomeCount;
uint structureCount;
uint worldSeed;
};
struct Biome {
uint surfaceBlock;
uint dirtBlock;
uint stoneBlock;
uint grassFoliage;
uint[4] flowers;
uint[4] tallBlocks;
uint[4] otherFoliage;
};
struct Structure {
uint sizeX;
uint sizeY;
uint sizeZ;
uint blockOffset;
uint spawnSpacing;
uint spawnChance;
uint allowedBiome;
uint groundBlock;
uint flags;
};
struct StructureVoxelResult {
uint block;
uint flags;
};
layout(std430, binding = 0) buffer VoxelData {
uint voxels[];
};
layout(std430, set = 1, binding = 0) readonly buffer BiomeUniform {
Biome biomes[];
} BiomeReg;
layout(std430, set = 2, binding = 0) readonly buffer StructureRegistry {
Structure structures[];
} structureReg;
layout(std430, set = 2, binding = 1) readonly buffer StructureBlocks {
uint blocks[];
} structureBlocks;
uint hash21(uvec2 p) {
p = p * 1664525u + 1013904223u;
p.x += p.y * 1664525u;
p.y += p.x * 1664525u;
return p.x ^ (p.x >> 16);
}
float random3to1(vec3 st) {
return fract(sin(dot(st, vec3(127.1, 311.7, 74.7))) * 43758.5453123);
}
float interpolate(float a, float b, float c, float d, float x) {
float p = (d - c) - (a - b);
return x * (x * (x * p + ((a - b) - p)) + (c - a)) + b;
}
float sampleX(vec3 at) {
float floored = floor(at.x);
return interpolate(
random3to1(vec3(floored - 1.0, at.yz)),
random3to1(vec3(floored, at.yz)),
random3to1(vec3(floored + 1.0, at.yz)),
random3to1(vec3(floored + 2.0, at.yz)),
at.x - floored) * 0.5 + 0.25;
}
float sampleY(vec3 at) {
float floored = floor(at.y);
return interpolate(
sampleX(vec3(at.x, floored - 1.0, at.z)),
sampleX(vec3(at.x, floored, at.z)),
sampleX(vec3(at.x, floored + 1.0, at.z)),
sampleX(vec3(at.x, floored + 2.0, at.z)),
at.y - floored);
}
float cubicNoise(vec3 at) {
float floored = floor(at.z);
return interpolate(
sampleY(vec3(at.xy, floored - 1.0)),
sampleY(vec3(at.xy, floored)),
sampleY(vec3(at.xy, floored + 1.0)),
sampleY(vec3(at.xy, floored + 2.0)),
at.z - floored);
}
float rand(vec2 co) {
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}
float valueNoise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
float a = rand(i);
float b = rand(i + vec2(1.0, 0.0));
float c = rand(i + vec2(0.0, 1.0));
float d = rand(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(a, b, u.x) +
(c - a) * u.y * (1.0 - u.x) +
(d - b) * u.x * u.y;
}
uint pcg_hash(uint seed) {
uint state = seed * 747796405u + 289133645u;
uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
return (word >> 22u) ^ word;
}
uint randomRangeUint(uint seed, uint minVal, uint maxVal) {
uint range = maxVal - minVal + 1u;
return minVal + (pcg_hash(seed) % range);
}
uint GetBiome(vec3 worldPos, uint MaxBiomes) {
if (MaxBiomes == 0u) return 0u;
vec3 X = vec3(worldPos);
X = mat3(
0.788675134594813, -0.211324865405187, -0.577350269189626,
-0.211324865405187, 0.788675134594813, -0.577350269189626,
0.577350269189626, 0.577350269189626, 0.577350269189626) * X;
float n = clamp(cubicNoise(X), 0.0, 0.9999);
uint Biome = uint(floor(n * float(MaxBiomes)));
return min(Biome, MaxBiomes - 1u);
}
bool isCave(vec3 worldPos) {
vec3 X = vec3(worldPos);
X = mat3(
0.788675134594813, -0.211324865405187, -0.577350269189626,
-0.211324865405187, 0.788675134594813, -0.577350269189626,
0.577350269189626, 0.577350269189626, 0.577350269189626) * X;
float n = cubicNoise(X);
return n > 0.5;
}
bool shouldSpawn(uint seed, Structure s) {
return pcg_hash(seed) % 1000u < s.spawnChance;
}
bool hasFlag(uint flags, uint flag) {
return (flags & flag) != 0u;
}
int floorDiv(int value, int divisor) {
int q = value / divisor;
int r = value - q * divisor;
if (r != 0 && ((r < 0) != (divisor < 0))) {
q -= 1;
}
return q;
}
ivec2 getStructureCell(ivec2 worldXZ, int spacing) {
return ivec2(
floorDiv(worldXZ.x, spacing),
floorDiv(worldXZ.y, spacing)
);
}
float getPrimarySurfaceHeight(int worldX, int worldY, int worldZ) {
float YZone = floor(float(worldY) / 150.0) * 150.0;
return valueNoise(vec2(float(worldX) + YZone * 2.0, float(worldZ) + YZone * 2.0) * 0.005) * 100.0 +
valueNoise(vec2(float(worldX) + YZone * 2.0, float(worldZ) + YZone * 2.0) * 0.01) * 10.0 +
valueNoise(vec2(float(worldX) + YZone * 2.0, float(worldZ) + YZone * 2.0) * 0.1) * 5.0 +
valueNoise(vec2(float(worldX) + YZone * 2.0, float(worldZ) + YZone * 2.0)) * 0.5 +
YZone;
}
float getSecondarySurfaceHeight(int worldX, int worldY, int worldZ) {
float YZone2 = floor(float(worldY) / 75.0) * 75.0;
return valueNoise(vec2(float(worldX) + YZone2 * 2.0, float(worldZ) + YZone2 * 2.0) * 0.005) * 50.0 +
valueNoise(vec2(float(worldX) + YZone2 * 2.0, float(worldZ) + YZone2 * 2.0) * 0.01) * 10.0 +
valueNoise(vec2(float(worldX) + YZone2 * 2.0, float(worldZ) + YZone2 * 2.0) * 0.1) * 5.0 +
valueNoise(vec2(float(worldX) + YZone2 * 2.0, float(worldZ) + YZone2 * 2.0)) * 0.5 +
YZone2;
}
float getSurfaceHeight(int worldX, int worldZ, int referenceY) {
float primary = getPrimarySurfaceHeight(worldX, referenceY, worldZ);
float secondary = getSecondarySurfaceHeight(worldX, referenceY, worldZ);
float primaryDist = abs(primary - float(referenceY));
float secondaryDist = abs(secondary - float(referenceY));
return primaryDist <= secondaryDist ? primary : secondary;
}
bool cellSpawnsStructure(uint seed, Structure s) {
if (s.spawnChance == 0u) {
return false;
}
return pcg_hash(seed) % 1000u < s.spawnChance;
}
uint chooseStructure(uint seed, uint biome) {
if (structureCount == 0u) {
return 0u;
}
uint start = pcg_hash(seed ^ 0xA53A9D31u) % structureCount;
for (uint i = 0u; i < structureCount; i++) {
uint id = (start + i) % structureCount;
Structure s = structureReg.structures[id];
if (s.allowedBiome == 0u || s.allowedBiome == biome + 1u) {
return id;
}
}
return start;
}
ivec2 getStructureAnchorXZ(ivec2 cell, uint seed, uint spacing) {
int structureSpacing = int(max(spacing, 1u));
uint jitterX = randomRangeUint(seed ^ 0xB5297A4Du, 0u, uint(structureSpacing - 1));
uint jitterZ = randomRangeUint(seed ^ 0x68E31DA4u, 0u, uint(structureSpacing - 1));
return cell * structureSpacing + ivec2(int(jitterX), int(jitterZ));
}
uint getStructureBlock(uint structureId, ivec3 localPos) {
Structure s = structureReg.structures[structureId];
if (localPos.x < 0 || localPos.x >= int(s.sizeX)) return 0u;
if (localPos.y < 0 || localPos.y >= int(s.sizeY)) return 0u;
if (localPos.z < 0 || localPos.z >= int(s.sizeZ)) return 0u;
uint index =
uint(localPos.x) * s.sizeY * s.sizeZ +
uint(localPos.y) * s.sizeZ +
uint(localPos.z);
return structureBlocks.blocks[s.blockOffset + index];
}
bool isGroundFlatEnough(ivec2 anchorXZ, uint structureId, int referenceY) {
Structure s = structureReg.structures[structureId];
float h0 = getSurfaceHeight(anchorXZ.x, anchorXZ.y, referenceY);
float h1 = getSurfaceHeight(anchorXZ.x + int(s.sizeX) - 1, anchorXZ.y, referenceY);
float h2 = getSurfaceHeight(anchorXZ.x, anchorXZ.y + int(s.sizeZ) - 1, referenceY);
float h3 = getSurfaceHeight(anchorXZ.x + int(s.sizeX) - 1, anchorXZ.y + int(s.sizeZ) - 1, referenceY);
float minH = min(min(h0, h1), min(h2, h3));
float maxH = max(max(h0, h1), max(h2, h3));
return maxH - minH <= 2.0;
}
ivec3 getStructureCell3D(ivec3 worldPos, int spacing) {
return ivec3(
floorDiv(worldPos.x, spacing),
floorDiv(worldPos.y, 75),
floorDiv(worldPos.z, spacing)
);
}
uint hash31(ivec3 p) {
uvec3 v = uvec3(p) * uvec3(1664525u, 22695477u, 1103515245u) + uvec3(1013904223u);
v.x += v.y * v.z;
v.y += v.z * v.x;
v.z += v.x * v.y;
return v.x ^ v.y ^ v.z;
}
uint getBaseTerrainVoxelAt(ivec3 worldPos, uint biome) {
Biome currentBiome = BiomeReg.biomes[biome];
float YZone = floor(float(worldPos.y) / 150.0) * 150.0;
float SurfaceHeight =
valueNoise(vec2(float(worldPos.x) + YZone * 2.0, float(worldPos.z) + YZone * 2.0) * 0.005) * 100.0 +
valueNoise(vec2(float(worldPos.x) + YZone * 2.0, float(worldPos.z) + YZone * 2.0) * 0.01) * 10.0 +
valueNoise(vec2(float(worldPos.x) + YZone * 2.0, float(worldPos.z) + YZone * 2.0) * 0.1) * 5.0 +
valueNoise(vec2(float(worldPos.x) + YZone * 2.0, float(worldPos.z) + YZone * 2.0)) * 0.5 +
YZone;
float IslandUnderneathHeight =
valueNoise(vec2(float(worldPos.x) + YZone * 2.0, float(worldPos.z) + YZone * 2.0) * 0.005) * 100.0 +
valueNoise(vec2(float(worldPos.x) + YZone * 2.0, float(worldPos.z) + YZone * 2.0) * 0.1) * 20.0 +
valueNoise(vec2(float(worldPos.x) + YZone * 2.0, float(worldPos.z) + YZone * 2.0) * 0.1) * 5.0 +
valueNoise(vec2(float(worldPos.x) + YZone * 2.0, float(worldPos.z) + YZone * 2.0)) * 0.5 -
15.0 +
YZone;
float grassNoise = valueNoise(vec2(float(worldPos.z) * 0.5 - YZone * 2.0, float(worldPos.x) * 0.5 - YZone * 2.0));
uint randomBlockVal = randomRangeUint(uint(worldPos.x) * 73856093u ^ uint(worldPos.z) * 19349663u, 0u, 3u);
uint voxelType = 0u;
if (float(worldPos.y) <= SurfaceHeight && float(worldPos.y) >= IslandUnderneathHeight) {
float depthBelowSurface = SurfaceHeight - float(worldPos.y);
if (depthBelowSurface < 0.5) {
if (grassNoise < 0.65) voxelType = currentBiome.grassFoliage;
else if (grassNoise < 0.75) voxelType = currentBiome.flowers[randomBlockVal];
else if (grassNoise < 0.85) voxelType = currentBiome.otherFoliage[randomBlockVal];
else voxelType = 0u;
} else if (depthBelowSurface < 2.5) {
voxelType = currentBiome.surfaceBlock;
} else if (depthBelowSurface < 6.0) {
voxelType = currentBiome.dirtBlock;
} else {
voxelType = currentBiome.stoneBlock;
}
} else {
float YZone2 = floor(float(worldPos.y) / 75.0) * 75.0;
float IslandUnderneathHeight2 =
valueNoise(vec2(float(worldPos.x) - YZone2 * 2.0, float(worldPos.z) - YZone2 * 2.0) * 0.005) * 60.0 +
valueNoise(vec2(float(worldPos.x) + YZone2 * 2.0, float(worldPos.z) + YZone2 * 2.0) * 0.1) * 20.0 +
valueNoise(vec2(float(worldPos.x) + YZone2 * 2.0, float(worldPos.z) + YZone2 * 2.0) * 0.1) * 10.0 +
valueNoise(vec2(float(worldPos.x) + YZone2 * 2.0, float(worldPos.z) + YZone2 * 2.0)) * 0.5 -
5.0 +
YZone2;
float height2 =
valueNoise(vec2(float(worldPos.x) + YZone2 * 2.0, float(worldPos.z) + YZone2 * 2.0) * 0.005) * 50.0 +
valueNoise(vec2(float(worldPos.x) + YZone2 * 2.0, float(worldPos.z) + YZone2 * 2.0) * 0.01) * 10.0 +
valueNoise(vec2(float(worldPos.x) + YZone2 * 2.0, float(worldPos.z) + YZone2 * 2.0) * 0.1) * 5.0 +
valueNoise(vec2(float(worldPos.x) + YZone2 * 2.0, float(worldPos.z) + YZone2 * 2.0)) * 0.5 +
YZone2;
if (float(worldPos.y) <= height2 && float(worldPos.y) >= IslandUnderneathHeight2) {
float depthBelowSurface = height2 - float(worldPos.y);
if (depthBelowSurface < 0.5) {
if (grassNoise < 0.65) voxelType = currentBiome.grassFoliage;
else if (grassNoise < 0.75) voxelType = currentBiome.flowers[randomBlockVal];
else if (grassNoise < 0.85) voxelType = currentBiome.otherFoliage[randomBlockVal];
else voxelType = 0u;
} else if (depthBelowSurface < 1.5) {
voxelType = currentBiome.surfaceBlock;
} else if (depthBelowSurface < 6.0) {
voxelType = currentBiome.dirtBlock;
} else {
voxelType = currentBiome.stoneBlock;
}
}
}
if (voxelType != 0u && isCave(vec3(worldPos) * 0.05)) {
voxelType = 0u;
}
return voxelType;
}
bool isValidStructureAnchor(ivec3 origin, uint structureId, uint biome) {
Structure s = structureReg.structures[structureId];
ivec3 groundPos = origin + ivec3(0, -1, 0);
ivec3 basePos = origin;
uint groundVoxel = getBaseTerrainVoxelAt(groundPos, biome);
uint baseVoxel = getBaseTerrainVoxelAt(basePos, biome);
if (groundVoxel == 0u) {
return false;
}
if (s.groundBlock != 0u && groundVoxel != s.groundBlock) {
return false;
}
if (baseVoxel != 0u) {
return false;
}
if (isCave(vec3(groundPos) * 0.05)) {
return false;
}
return true;
}
int getStructureReferenceY(int worldY) {
return floorDiv(worldY, 75) * 75;
}
bool isStructureFootprintSupported(ivec3 origin, uint structureId, uint biome) {
Structure s = structureReg.structures[structureId];
int supportedCorners = 0;
ivec3 p0 = origin + ivec3(0, -1, 0);
ivec3 p1 = origin + ivec3(int(s.sizeX) - 1, -1, 0);
ivec3 p2 = origin + ivec3(0, -1, int(s.sizeZ) - 1);
ivec3 p3 = origin + ivec3(int(s.sizeX) - 1, -1, int(s.sizeZ) - 1);
if (getBaseTerrainVoxelAt(p0, biome) != 0u) supportedCorners++;
if (getBaseTerrainVoxelAt(p1, biome) != 0u) supportedCorners++;
if (getBaseTerrainVoxelAt(p2, biome) != 0u) supportedCorners++;
if (getBaseTerrainVoxelAt(p3, biome) != 0u) supportedCorners++;
return supportedCorners == 4;
}
StructureVoxelResult getStructureVoxelAt(ivec3 worldPos, uint biome) {
StructureVoxelResult result;
result.block = 0u;
result.flags = 0u;
if (structureCount == 0u) {
return result;
}
for (uint structureId = 0u; structureId < structureCount; structureId++) {
Structure s = structureReg.structures[structureId];
if (s.allowedBiome != 0u && s.allowedBiome != biome + 1u) {
continue;
}
int spacing = int(max(s.spawnSpacing, 1u));
ivec3 baseCell = getStructureCell3D(worldPos, spacing);
for (int ox = -1; ox <= 1; ox++) {
for (int oy = -1; oy <= 1; oy++) {
for (int oz = -1; oz <= 1; oz++) {
ivec3 cell = baseCell + ivec3(ox, oy, oz);
uint seed = hash31(cell + ivec3(0, int(structureId) * 97, 0)) ^ worldSeed;
if (!cellSpawnsStructure(seed, s)) {
continue;
}
ivec2 anchorXZ = getStructureAnchorXZ(cell.xz, seed, s.spawnSpacing);
// Match getStructureBlock's uncentered footprint before sampling terrain.
ivec2 localXZ = worldPos.xz - anchorXZ;
if (localXZ.x < 0 || localXZ.x >= int(s.sizeX) ||
localXZ.y < 0 || localXZ.y >= int(s.sizeZ)) {
continue;
}
int referenceY = cell.y * 75;
float anchorHeight = getSurfaceHeight(int(anchorXZ.x - s.sizeX/2), int(anchorXZ.y - s.sizeZ/2), referenceY);
int anchorY = int(floor(anchorHeight)) + 1;
ivec3 origin = ivec3(anchorXZ.x, anchorY, anchorXZ.y);
if (!isValidStructureAnchor(origin, structureId, biome)) {
continue;
}
ivec3 local = worldPos - origin;
uint block = getStructureBlock(structureId, local);
if (block != 0u) {
result.block = block;
result.flags = s.flags;
return result;
}
}
}
}
}
return result;
}
void main() {
if (any(greaterThanEqual(gl_GlobalInvocationID.xyz, uvec3(SCRATCH_SIZE)))) {
return;
}
ivec3 localPos = ivec3(gl_GlobalInvocationID.xyz) - ivec3(1);
ivec3 worldPos = chunkPos * CHUNK_SIZE + localPos;
uint biome = GetBiome(vec3(worldPos.z, worldPos.y, worldPos.x) * 0.005, biomeCount);
Biome currentBiome = BiomeReg.biomes[biome];
float YZone = floor(worldPos.y/150.0)*150.0;
float SurfaceHeight = valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.005) * 100 +
valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.01) * 10 +
valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.1) * 5 +
valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2)) * 0.5 + YZone;
uint RandomBlockVal = randomRangeUint(uint(worldPos.x) * 73856093u ^ uint(worldPos.z) * 19349663u,0u ,3u);
float IslandUnderneathHeight = valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.005) * 100 +
valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.1) * 20 +
valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2) * 0.1) * 5 +
valueNoise(vec2(worldPos.x + YZone * 2, worldPos.z + YZone * 2)) * 0.5 - 15 + YZone;
float grassNoise = valueNoise(vec2(worldPos.z * 0.5 - YZone * 2, worldPos.x * 0.5 - YZone * 2));
uint voxelType = 0u;
if (float(worldPos.y) <= SurfaceHeight && float(worldPos.y) >= IslandUnderneathHeight) {
float depthBelowSurface = SurfaceHeight - float(worldPos.y);
if (depthBelowSurface < 0.5) {
if(grassNoise < 0.65) voxelType = currentBiome.grassFoliage; // Grass foliage
else if (grassNoise < 0.75) voxelType = currentBiome.flowers[RandomBlockVal];
else if (grassNoise < 0.85) voxelType = currentBiome.otherFoliage[RandomBlockVal];
else voxelType = 0u;
}else if (depthBelowSurface < 2.5) {
voxelType = currentBiome.surfaceBlock; // Grass
} else if (depthBelowSurface < 6.0) {
voxelType = currentBiome.dirtBlock; // Dirt(also stone rn)
} else {
voxelType = currentBiome.stoneBlock; // Stone
}
}
else{
float YZone2 = floor(worldPos.y/75.0)*75.0;
float IslandUnderneathHeight2 = valueNoise(vec2(worldPos.x - YZone2 * 2, worldPos.z -YZone2 * 2) * 0.005) * 60 +
valueNoise(vec2(worldPos.x + YZone2 * 2, worldPos.z + YZone2 * 2) * 0.1) * 20 +
valueNoise(vec2(worldPos.x + YZone2 * 2, worldPos.z + YZone2 * 2) * 0.1) * 10+
valueNoise(vec2(worldPos.x + YZone2 * 2, worldPos.z + YZone2 * 2)) * 0.5 - 5 + YZone2;
float height2 = valueNoise(vec2(worldPos.x + YZone2 * 2, worldPos.z + YZone2 * 2) * 0.005) * 50 +
valueNoise(vec2(worldPos.x + YZone2 * 2, worldPos.z + YZone2 * 2) * 0.01) * 10 +
valueNoise(vec2(worldPos.x + YZone2 * 2, worldPos.z + YZone2 * 2) * 0.1) * 5+
valueNoise(vec2(worldPos.x + YZone2 * 2, worldPos.z + YZone2 * 2)) * 0.5 + YZone2;
if (float(worldPos.y) <= height2 && float(worldPos.y) >= IslandUnderneathHeight2) {
float depthBelowSurface = height2 - float(worldPos.y);
if (depthBelowSurface < 0.5) {
if (grassNoise < 0.65) voxelType = currentBiome.grassFoliage; // Grass foliage
else if (grassNoise < 0.75) voxelType = currentBiome.flowers[RandomBlockVal];
else if (grassNoise < 0.85) voxelType = currentBiome.otherFoliage[RandomBlockVal];
else voxelType = 0u;
} else if (depthBelowSurface < 1.5) {
voxelType = currentBiome.surfaceBlock; // Grass
} else if (depthBelowSurface < 6.0) {
voxelType = currentBiome.dirtBlock; // Dirt(also stone rn)
} else {
voxelType = currentBiome.stoneBlock; // Stone
}
}
}
if (voxelType != 0u) {
if (isCave(vec3(worldPos*0.05))) {
voxelType = 0u;
}
}
StructureVoxelResult structureVoxel = getStructureVoxelAt(worldPos, biome);
if (structureVoxel.block != 0u) {
if (hasFlag(structureVoxel.flags, uint(REPLACE_AIR_ONLY))) {
if (voxelType == 0u) {
voxelType = structureVoxel.block;
}
} else {
voxelType = structureVoxel.block;
}
}
uint index = uint(slot * SCRATCH_VOXEL_COUNT + (localPos.x + 1) * SCRATCH_AREA +
(localPos.y + 1) * SCRATCH_SIZE + localPos.z + 1);
voxels[index] = voxelType;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 MiB

After

Width:  |  Height:  |  Size: 12 MiB

Before After
Before After

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,29 @@
#version 450
layout(location = 0) in vec3 fragPosition;
layout(location = 1) in vec4 fragWeights;
layout(location = 2) in vec2 fragUV;
layout(binding = 1) uniform sampler2DArray terrainTexArray;
layout(location = 0) out vec4 outColor;
void main() {
vec4 colorGrass = texture(terrainTexArray, vec3(fragUV, 0.0)); // Index 0
vec4 colorRock = texture(terrainTexArray, vec3(fragUV, 1.0)); // Index 1
vec4 colorSand = texture(terrainTexArray, vec3(fragUV, 2.0)); // Index 2
vec4 colorMud = texture(terrainTexArray, vec3(fragUV, 3.0)); // Index 3
vec4 dynamicTerrainColor =
(colorGrass * fragWeights.r) +
(colorRock * fragWeights.g) +
(colorSand * fragWeights.b) +
(colorMud * fragWeights.a);
float totalWeight = fragWeights.r + fragWeights.g + fragWeights.b + fragWeights.a;
if (totalWeight > 0.0) {
dynamicTerrainColor /= totalWeight;
}
outColor = dynamicTerrainColor;
}

View file

@ -0,0 +1,21 @@
#version 450
layout(binding = 0) uniform UniformBufferObject {
mat4 model;
mat4 view;
mat4 proj;
} ubo;
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec4 inMaterialWeights;
layout(location = 0) out vec3 fragPosition;
layout(location = 1) out vec4 fragWeights;
layout(location = 2) out vec2 fragUV;
void main() {
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
fragPosition = inPosition;
fragWeights = inMaterialWeights;
fragUV = inPosition.xz * 0.1;
}

View file

@ -4,5 +4,5 @@ layout(location = 0) out vec2 outTextCoord;
void main() {
outTextCoord = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(outTextCoord.x * 2.0f - 1.0f, outTextCoord.y * -2.0f + 1.0f,0.0f,1.0f);
gl_Position = vec4(outTextCoord.x * 2.0f - 1.0f, outTextCoord.y * - 2.0f + 1.0f, 0.0f, 1.0f);
}

View file

@ -0,0 +1,29 @@
#version 450
layout(location = 0) in vec2 inTextCoord;
layout(location = 0) out vec4 outBloomColour;
layout(set = 0, binding = 0) uniform sampler2D inputTexture;
layout(push_constant) uniform PassConfig {
int horizontal;
float GAMMA_CONST;
float Exposure;
float blur_radius;
vec2 bloomSize;
} config;
vec3 extractBloom(vec2 uv) {
vec3 color = max(texture(inputTexture, uv).rgb, vec3(0.0));
float brightness = dot(color, vec3(0.2126, 0.7152, 0.0722));
float contribution = max(brightness - 1.0, 0.0);
return color * (contribution / (contribution + 0.5));
}
void main() {
vec2 offset = 0.25 / config.bloomSize;
vec3 bloom = extractBloom(inTextCoord + vec2(-offset.x, -offset.y))
+ extractBloom(inTextCoord + vec2( offset.x, -offset.y))
+ extractBloom(inTextCoord + vec2(-offset.x, offset.y))
+ extractBloom(inTextCoord + vec2( offset.x, offset.y));
outBloomColour = vec4(bloom * 0.25, 1.0);
}

View file

@ -0,0 +1,30 @@
#version 450
layout(location = 0) out vec4 FragColor;
layout(location = 0) in vec2 TexCoords;
layout(set = 0, binding = 0) uniform sampler2D bloomImage;
layout(push_constant) uniform PassConfig {
int horizontal;
float GAMMA_CONST;
float Exposure;
float blur_radius;
vec2 bloomSize;
} config;
const float weight[5] = float[](0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
vec3 safeBloomSample(vec2 uv) {
return max(texture(bloomImage, uv).rgb, vec3(0.0));
}
void main() {
vec2 tex_offset = config.blur_radius / vec2(textureSize(bloomImage, 0));
vec2 direction = config.horizontal != 0 ? vec2(tex_offset.x, 0.0) : vec2(0.0, tex_offset.y);
vec3 result = safeBloomSample(TexCoords) * weight[0];
for (int i = 1; i < 5; i++) {
result += safeBloomSample(TexCoords + direction * i) * weight[i];
result += safeBloomSample(TexCoords - direction * i) * weight[i];
}
FragColor = vec4(result, 1.0);
}

View file

@ -0,0 +1,11 @@
#version 450
layout(location = 0) in vec3 outTexCoords;
layout(location = 0) out vec4 outColor;
layout(set = 2, binding = 0) uniform samplerCube skyboxSampler;
void main() {
outColor = vec4(texture(skyboxSampler, outTexCoords).rgb, 1.0);
}

View file

@ -0,0 +1,172 @@
#version 450
#extension GL_EXT_scalar_block_layout: require
// CREDITS: functions obtained from this link: https://github.com/SaschaWillems/Vulkan
// developed by Sascha Willems, https://twitter.com/JoeyDeVriez, licensed under MIT License (MIT)
// also Vulkan Book https://github.com/lwjglgamedev/vulkanbook/blob/master/bookcontents/chapter-15/chapter-15.md
const int MAX_LIGHTS = 1000;
const float PI = 3.14159265359;
struct Light {
vec3 position;
uint directional;
float intensity;
vec3 color;
};
layout(location = 0) in vec2 inTextCoord;
layout(location = 0) out vec4 outFragColor;
layout(set = 0, binding = 0) uniform sampler2D posSampler;
layout(set = 0, binding = 1) uniform sampler2D albedoSampler;
layout(set = 0, binding = 2) uniform sampler2D normalsSampler;
layout(set = 0, binding = 3) uniform sampler2D pbrSampler;
layout(set = 0, binding = 4) uniform sampler2D emissiveSampler;
layout(set = 0, binding = 5) uniform sampler2D TranslucencySampler;
layout(set = 0, binding = 6) uniform sampler2D OpacitySampler;
layout(set = 0, binding = 7) uniform sampler2D ViewPos;
layout(set = 0, binding = 8) uniform sampler2D ssaoBlur;
layout(scalar, set = 1, binding = 0) readonly buffer Lights {
Light lights[];
} lights;
layout(scalar, set = 2, binding = 0) uniform SceneInfo {
vec3 camPos;
float ambientLightIntensity;
vec3 ambientLightColor;
uint numLights;
mat4 viewMatrix;
} sceneInfo;
float distributionGGX(vec3 N, vec3 H, float roughness) {
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH * NdotH;
float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / denom;
}
float geometrySchlickGGX(float NdotV, float roughness) {
float r = (roughness + 1.0);
float k = (r * r) / 8.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
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);
float ggx2 = geometrySchlickGGX(NdotV, roughness);
float ggx1 = geometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
vec3 calculatePointLight(Light light, vec3 worldPos, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness) {
vec3 tmpSub = light.position - worldPos;
vec3 L = normalize(tmpSub);
vec3 H = normalize(V + L);
// Calculate distance and attenuation
float distance = length(tmpSub);
float attenuation = 1.0 / (distance * distance);
float intensity = 10.0f;
vec3 radiance = light.color * light.intensity * attenuation;
// Cook-Torrance BRDF
float NDF = distributionGGX(N, H, roughness);
float G = geometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
vec3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
vec3 specular = numerator / denominator;
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;
float NdotL = max(dot(N, L), 0.0);
return (kD * albedo / PI + specular) * radiance * NdotL;
}
vec3 calculateDirectionalLight(Light light, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness) {
vec3 L = normalize(-light.position);
vec3 H = normalize(V + L);
vec3 radiance = light.color * light.intensity;
// Cook-Torrance BRDF
float NDF = distributionGGX(N, H, roughness);
float G = geometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
vec3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
vec3 specular = numerator / denominator;
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;
float NdotL = max(dot(N, L), 0.0);
return (kD * albedo / PI + specular) * radiance * NdotL;
}
void main() {
vec3 albedo = texture(albedoSampler, inTextCoord).rgb;
vec4 normalW = texture(normalsSampler, inTextCoord);
vec3 normal = normalW.rgb;
vec3 viewPos = texture(ViewPos, inTextCoord).rgb;
vec3 worldPos = texture(posSampler, inTextCoord).rgb;
vec4 pbr = texture(pbrSampler, inTextCoord);
vec3 emissive = texture(emissiveSampler, inTextCoord).rgb;
vec3 translucency = texture(TranslucencySampler, inTextCoord).rgb;
float emissiveness = emissive.r;
float ssao = texture(ssaoBlur, inTextCoord).r;
float roughness = pbr.g;
float metallic = pbr.b;
vec3 N = normalize(normal);
vec3 V = normalize(sceneInfo.camPos - worldPos);
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic);
vec3 Lo = vec3(0.0);
for (uint i = 0; i < sceneInfo.numLights; i++) {
Light light = lights.lights[i];
if (light.directional == 1) {
Lo += calculateDirectionalLight(light, V, N, F0, albedo, metallic, roughness);
} else {
Lo += calculatePointLight(light, worldPos, V, N, F0, albedo, metallic, roughness);
}
}
vec3 ambient = sceneInfo.ambientLightColor * albedo * sceneInfo.ambientLightIntensity * vec3(ssao,ssao,ssao);;
if(emissive.x > 0 || emissive.y > 0 || emissive.z > 0) ambient = emissive;
outFragColor = vec4(Lo + ambient, 1.0f);
outFragColor = vec4(outFragColor.xyz/2 + (outFragColor.xyz/2) * vec3(ssao,ssao,ssao),1);
// outFragColor = vec4(color, 1.0f);
if (length(normal) < 0.001) {
outFragColor = vec4(albedo,1.0f);
return;
}
// outFragColor = vec4(normal, 1.0f);
}

View file

@ -0,0 +1,291 @@
#version 450
#extension GL_EXT_scalar_block_layout: require
// CREDITS: Most of the functions here have been obtained from this link: https://github.com/SaschaWillems/Vulkan
// developed by Sascha Willems, https://twitter.com/JoeyDeVriez, and licensed under the terms of the MIT License (MIT)
layout (constant_id = 0) const int SHADOW_MAP_CASCADE_COUNT = 6;
layout (constant_id = 1) const int DEBUG_SHADOWS = 0;
const float PI = 3.14159265359;
struct Light {
vec3 position;
uint directional;
float intensity;
vec3 color;
};
struct CascadeShadow {
mat4 projViewMatrix;
vec4 splitDistance;
};
layout(location = 0) in vec2 inTextCoord;
layout(location = 0) out vec4 outFragColor;
layout(set = 0, binding = 0) uniform sampler2D posSampler;
layout(set = 0, binding = 1) uniform sampler2D albedoSampler;
layout(set = 0, binding = 2) uniform sampler2D normalsSampler;
layout(set = 0, binding = 3) uniform sampler2D pbrSampler;
layout(set = 0, binding = 4) uniform sampler2D emissiveSampler;
layout(set = 0, binding = 5) uniform sampler2D TranslucencySampler;
layout(set = 0, binding = 6) uniform sampler2D OpacitySampler;
layout(set = 0, binding = 7) uniform sampler2D viewPos;
layout(set = 0, binding = 8) uniform sampler2D ssaoBlur;
layout(set = 0, binding = 9) uniform sampler2DArray shadowSampler;
layout(scalar, set = 1, binding = 0) readonly buffer Lights {
Light lights[];
} lights;
layout(set = 2, binding = 0) readonly buffer Shadows {
CascadeShadow cascadeshadows[];
} shadows;
layout(scalar, set = 3, binding = 0) uniform SceneInfo {
vec3 camPos;
float ambientLightIntensity;
vec3 ambientLightColor;
uint numLights;
mat4 viewMatrix;
} sceneInfo;
float chebyshevUpperBound(vec2 moments, float t) {
// Surface is fully lit if the current fragment is before the light occluder
if (t <= moments.x)
return 1.0;
// Compute variance
float variance = moments.y - (moments.x * moments.x);
variance = max(variance, 0.00002); // Small epsilon to avoid divide by zero
// Compute probabilistic upper bound
float d = t - moments.x;
float p_max = variance / (variance + d * d);
// Reduce light bleeding
p_max = smoothstep(0.5, 1.0, p_max);
return p_max;
}
float calcVisibility(vec4 worldPosition, uint cascadeIndex, vec2 texelSize) {
vec4 shadowMapPosition = shadows.cascadeshadows[cascadeIndex].projViewMatrix * worldPosition;
if (!(shadowMapPosition.w > 0.0) || any(isnan(shadowMapPosition)) || any(isinf(shadowMapPosition))) {
return 1.0;
}
shadowMapPosition.xyz /= shadowMapPosition.w;
vec2 uv = vec2(
shadowMapPosition.x * 0.5 + 0.5,
shadowMapPosition.y * -0.5 + 0.5
);
float depth = shadowMapPosition.z;
if (uv.x < 0.0 || uv.x > 1.0 ||
uv.y < 0.0 || uv.y > 1.0 ||
depth < 0.0 || depth > 1.0) {
return 1.0;
}
float shadow = 0.0;
// vec2 moments = texture(shadowSampler, vec3((uv), cascadeIndex)).rg;
// float visibility = chebyshevUpperBound(moments, depth);
// shadow += visibility;
for(int x = -1; x <= 1; ++x)
{
for(int y = -1; y <= 1; ++y)
{
vec2 sampleUV = uv + vec2(x, y) * texelSize;
if (any(lessThan(sampleUV, vec2(0.0))) || any(greaterThan(sampleUV, vec2(1.0)))) {
shadow += 1.0;
continue;
}
sampleUV = clamp(sampleUV, texelSize * 0.5, vec2(1.0) - texelSize * 0.5);
vec2 moments = texture(shadowSampler, vec3(sampleUV, cascadeIndex)).rg;
float visibility = chebyshevUpperBound(moments, depth);
shadow += visibility;
}
}
shadow /= 9.0;
return shadow;
}
float distributionGGX(vec3 N, vec3 H, float roughness) {
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH * NdotH;
float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / denom;
}
float geometrySchlickGGX(float NdotV, float roughness) {
float r = (roughness + 1.0);
float k = (r * r) / 8.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
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);
float ggx2 = geometrySchlickGGX(NdotV, roughness);
float ggx1 = geometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
vec3 calculatePointLight(Light light, vec3 worldPos, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness) {
vec3 tmpSub = light.position - worldPos;
vec3 L = normalize(tmpSub);
vec3 H = normalize(V + L);
// Calculate distance and attenuation
float distance = length(tmpSub);
float attenuation = 1.0 / (distance * distance);
float intensity = 10.0f;
vec3 radiance = light.color * light.intensity * attenuation;
// Cook-Torrance BRDF
float NDF = distributionGGX(N, H, roughness);
float G = geometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
vec3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
vec3 specular = numerator / denominator;
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;
float NdotL = max(dot(N, L), 0.0);
return (kD * albedo / PI + specular) * radiance * NdotL;
}
vec3 calculateDirectionalLight(Light light, vec3 V, vec3 N, vec3 F0, vec3 albedo, float metallic, float roughness, float translucency) {
vec3 L = normalize(-light.position);
vec3 H = normalize(V + L);
vec3 radiance = light.color * light.intensity;
// Cook-Torrance BRDF
float NDF = distributionGGX(N, H, roughness);
float G = geometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
vec3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
vec3 specular = numerator / denominator;
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;
float NdotL = max(dot(N, L), 0.0);
vec3 shadowValue = (kD * albedo / PI + specular) * radiance * NdotL;
vec3 lightValue = (kD * albedo / PI + specular) * radiance;
return (shadowValue * (1 - translucency)) + (lightValue * translucency);
}
void main() {
vec3 albedo = texture(albedoSampler, inTextCoord).rgb;
vec4 normalW = texture(normalsSampler, inTextCoord);
vec3 normal = normalW.rgb;
vec4 worldPosW = texture(posSampler, inTextCoord);
vec3 worldPos = worldPosW.xyz;
vec4 pbrW = texture(pbrSampler, inTextCoord);
vec3 pbr = pbrW.rgb;
vec3 emissive = texture(emissiveSampler, inTextCoord).rgb;
vec3 Opacity = texture(OpacitySampler, inTextCoord).rgb;
vec3 translucency = texture(TranslucencySampler, inTextCoord).rgb;
float Reflectivity = pbrW.a;
float Refractivity = normalW.a;
float emissiveness = emissive.r;
float translucencyf = translucency.r;
float ssao = texture(ssaoBlur, inTextCoord).r;
// outFragColor = vec4(emissive,1);
// return;
float opacityf = Opacity.x + Opacity.y + Opacity.z;
opacityf = opacityf/3.0;
float roughness = pbr.g;
float metallic = pbr.b;
vec3 N = normalize(normal);
vec3 V = normalize(sceneInfo.camPos - worldPos);
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic);
uint cascadeIndex = SHADOW_MAP_CASCADE_COUNT;
vec4 viewPos = sceneInfo.viewMatrix * vec4(worldPos, 1.0);
float lastSplit = shadows.cascadeshadows[SHADOW_MAP_CASCADE_COUNT - 1].splitDistance.x;
float shadow = 1.0;
if (lastSplit < 0.0 && viewPos.z < 0.0 && viewPos.z >= lastSplit) {
cascadeIndex = 0;
for (uint i = 0; i < SHADOW_MAP_CASCADE_COUNT - 1; ++i) {
if (viewPos.z < shadows.cascadeshadows[i].splitDistance.x) {
cascadeIndex = i + 1;
}
}
vec2 texelSizeShadow = 1.0 / textureSize(shadowSampler, 0).rg;
shadow = calcVisibility(vec4(worldPos, 1), cascadeIndex, texelSizeShadow);
}
vec3 Lo = vec3(0.0);
for (uint i = 0; i < sceneInfo.numLights; i++) {
Light light = lights.lights[i];
if (light.directional == 1) {
Lo += calculateDirectionalLight(light, V, N, F0, albedo, metallic, roughness,translucencyf) * shadow;
} else {
Lo += calculatePointLight(light, worldPos, V, N, F0, albedo, metallic, roughness);
}
}
vec3 ambient = sceneInfo.ambientLightColor * albedo * sceneInfo.ambientLightIntensity * vec3(ssao,ssao,ssao);
if(emissive.x > 0 || emissive.y > 0 || emissive.z > 0) ambient = emissive;
outFragColor = vec4(Lo + ambient, 1.0f);
outFragColor = vec4(outFragColor.xyz/2 + (outFragColor.xyz/2) * vec3(ssao,ssao,ssao),1);
if (DEBUG_SHADOWS == 1 && cascadeIndex < SHADOW_MAP_CASCADE_COUNT) {
switch (cascadeIndex) {
case 0:
outFragColor.rgb *= vec3(1.0f, 0.25f, 0.25f);
break;
case 1:
outFragColor.rgb *= vec3(0.25f, 1.0f, 0.25f);
break;
case 2:
outFragColor.rgb *= vec3(0.25f, 0.25f, 1.0f);
break;
default:
outFragColor.rgb *= vec3(1.0f, 1.0f, 0.25f);
break;
}
}
if (length(normal) < 0.001) {
outFragColor = vec4(albedo,1.0f);
return;
}
}

View file

@ -0,0 +1,34 @@
#version 450
layout(location = 0) in vec2 inTextCoord;
layout(location = 0) out vec4 outBloomColour;
layout(set = 0, binding = 0) uniform sampler2DMS inputTexture;
layout(push_constant) uniform PassConfig {
int horizontal;
float GAMMA_CONST;
float Exposure;
float blur_radius;
vec2 bloomSize;
} config;
vec3 extractBloom(vec2 uv) {
ivec2 size = textureSize(inputTexture);
ivec2 pixel = clamp(ivec2(uv * vec2(size)), ivec2(0), size - 1);
int samples = textureSamples(inputTexture);
vec3 color = vec3(0.0);
for (int i = 0; i < samples; i++) color += texelFetch(inputTexture, pixel, i).rgb;
color = max(color / float(samples), vec3(0.0));
float brightness = dot(color, vec3(0.2126, 0.7152, 0.0722));
float contribution = max(brightness - 1.0, 0.0);
return color * (contribution / (contribution + 0.5));
}
void main() {
vec2 offset = 0.25 / config.bloomSize;
vec3 bloom = extractBloom(inTextCoord + vec2(-offset.x, -offset.y))
+ extractBloom(inTextCoord + vec2( offset.x, -offset.y))
+ extractBloom(inTextCoord + vec2(-offset.x, offset.y))
+ extractBloom(inTextCoord + vec2( offset.x, offset.y));
outBloomColour = vec4(bloom * 0.25, 1.0);
}

View file

@ -1,53 +1,42 @@
#version 450
layout(constant_id = 0) const int USE_AA = 0;
const float GAMMA_CONST = 0.4545;
const float SPAN_MAX = 8.0;
const float REDUCE_MIN = 1.0/128.0;
const float REDUCE_MUL = 1.0/32.0;
layout(location = 0) in vec2 inTextCoord;
layout(location = 0) out vec4 outFragColor;
layout(set = 0, binding = 0) uniform sampler2DMS inputTexture;
layout(set = 0, binding = 1) uniform sampler2D bloomImage;
layout(set = 1, binding = 0) uniform ScreenSize{
vec2 size;
} screenSize;
layout(push_constant) uniform PassConfig {
int horizontal;
float GAMMA_CONST;
float Exposure;
float blur_radius;
vec2 bloomSize;
} config;
vec4 gamma(vec4 color){
return color = vec4(pow(color.rgb,vec3(GAMMA_CONST)),color.a);
}
vec4 msaa(int sampleCount, sampler2DMS textureIn,vec2 TextCoord){
ivec2 pixelCoords = ivec2(TextCoord * textureSize(textureIn));
vec4 msaa(int sampleCount, sampler2DMS textureIn, vec2 TextCoord) {
ivec2 size = textureSize(textureIn);
ivec2 pixelCoords = clamp(ivec2(TextCoord * vec2(size)), ivec2(0), size - 1);
vec4 colorSum = vec4(0.0);
for(int i = 0; i < sampleCount; ++i) {
vec4 sampleColor = texelFetch(textureIn, pixelCoords, i);
colorSum += sampleColor;
}
for (int i = 0; i < sampleCount; i++) colorSum += texelFetch(textureIn, pixelCoords, i);
return colorSum / float(sampleCount);
}
void main(){
ivec2 pixelCoords = ivec2(inTextCoord * textureSize(inputTexture));
vec3 bloomAt(ivec2 pixel, ivec2 size) {
return texelFetch(bloomImage, clamp(pixel, ivec2(0), size - 1), 0).rgb;
}
if(USE_AA == 0){
outFragColor = texelFetch(inputTexture,pixelCoords,0);
}
if(USE_AA == 1){
outFragColor = texelFetch(inputTexture,pixelCoords,0);
}
if(USE_AA == 2){
outFragColor = msaa(2,inputTexture,inTextCoord);
}
if(USE_AA == 3){
outFragColor = msaa(4,inputTexture,inTextCoord);
}
if(USE_AA == 4){
outFragColor = msaa(8,inputTexture,inTextCoord);
}
outFragColor = gamma(outFragColor);
}
vec3 upsampleBloom(vec2 uv) {
ivec2 size = textureSize(bloomImage, 0);
vec2 pixel = uv * vec2(size) - 0.5;
ivec2 base = ivec2(floor(pixel));
vec2 blend = fract(pixel);
return mix(mix(bloomAt(base, size), bloomAt(base + ivec2(1, 0), size), blend.x),
mix(bloomAt(base + ivec2(0, 1), size), bloomAt(base + ivec2(1, 1), size), blend.x), blend.y);
}
void main() {
vec4 sceneColor = msaa(textureSamples(inputTexture), inputTexture, inTextCoord);
vec3 hdrColour = max(sceneColor.rgb + upsampleBloom(inTextCoord), vec3(0.0));
vec3 result = vec3(1.0) - exp(-hdrColour * config.Exposure);
outFragColor = vec4(pow(result, vec3(1.0 / config.GAMMA_CONST)), sceneColor.a);
}

View file

@ -0,0 +1,88 @@
#version 450
#extension GL_EXT_nonuniform_qualifier : require
const int MAX_TEXTURES = 128;
layout(location = 0) in vec4 inPos;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec3 inTangent;
layout(location = 3) in vec3 inBitangent;
layout(location = 4) in vec2 inTextCoords;
layout(location = 5) in mat4 viewMatrix;
layout(location = 9) in flat uint textureIndex;
layout(location = 0) out vec4 outAlbedo;
layout(location = 1) out vec4 outViewPos;
struct Material {
vec4 diffuseColor; //16
uint hasTexture; //20
uint textureIdx; //24
uint hasNormalMap; //28
uint normalMapIdx; //32
uint hasRoughMap; //36
uint roughMapIdx; //40
float roughnessFactor; //44
float metallicFactor; //48
vec4 emissiveColour; //64
uint hasEmissiveMap; //68
uint emissiveMapIdx; //72
uint hasTranslucencyMap; //76
uint translucencyMapIdx; //80
float translucencyFactor; //84
uint hasOpacityMap; //88
uint OpacityMapIdx; //92
float OpacityFactor; //96
float reflectiveness; //100
float refractiveness; //104
float Padding1; //108
float Padding2; //112
};
layout(set = 2, binding = 0) readonly buffer MaterialUniform{
Material materials[];
} matUniform;
layout(set = 3, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES];
layout(push_constant) uniform pc{
layout(offset = 64) uint materialIdx;
} push_constants;
void main()
{
vec4 viewPos = vec4(viewMatrix * inPos);
outViewPos = viewPos;
Material material = matUniform.materials[textureIndex];
uint albedoTextureIndex = material.textureIdx;
if (albedoTextureIndex >= MAX_TEXTURES){
outAlbedo = vec4(0.0,0.0,1.0,1.0);
return;
}
if(material.hasTexture == 1){
vec4 texColor = texture(textSampler[nonuniformEXT(albedoTextureIndex)], inTextCoords);
outAlbedo = texColor;
} else{
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
}
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
Opacity = texture(textSampler[nonuniformEXT(material.OpacityMapIdx)], inTextCoords);
}
float opacityf = Opacity.x + Opacity.y + Opacity.z;
opacityf = opacityf / 3;
if(opacityf < 0.4){ discard; }
outAlbedo = vec4(outAlbedo.rgb, opacityf);
}

View file

@ -0,0 +1,149 @@
#version 450
#extension GL_EXT_nonuniform_qualifier : require
const int MAX_TEXTURES = 128;
layout(location = 0) in vec4 inPos;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec3 inTangent;
layout(location = 3) in vec3 inBitangent;
layout(location = 4) in vec2 inTextCoords;
layout(location = 5) in mat4 viewMatrix;
layout(location = 9) in flat uint MaterialID;
layout(location = 1) out vec4 outAlbedo ;
layout(location = 0) out vec4 outPos;
layout(location = 2) out vec4 outNormal;
layout(location = 3) out vec4 outPBR;
layout(location = 4) out vec4 outEmissive;
layout(location = 5) out vec4 outTranslucency;
layout(location = 6) out vec4 outOpacity;
layout(location = 7) out vec4 outViewPos;
struct Material {
vec4 diffuseColor; //16
uint hasTexture; //20
uint textureIdx; //24
uint hasNormalMap; //28
uint normalMapIdx; //32
uint hasRoughMap; //36
uint roughMapIdx; //40
float roughnessFactor; //44
float metallicFactor; //48
vec4 emissiveColour; //64
uint hasEmissiveMap; //68
uint emissiveMapIdx; //72
uint hasTranslucencyMap; //76
uint translucencyMapIdx; //80
float translucencyFactor; //84
uint hasOpacityMap; //88
uint OpacityMapIdx; //92
float OpacityFactor; //96
float reflectiveness; //100
float refractiveness; //104
float Padding1; //108
float Padding2; //112
};
layout(set = 2, binding = 0) readonly buffer MaterialUniform {
Material materials[];
} matUniform;
layout(set = 3, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES];
vec3 calcNormal(Material material, vec3 normal, vec2 textCoords, mat3 TBN)
{
vec3 newNormal = normal;
if (material.hasNormalMap > 0 && material.normalMapIdx < MAX_TEXTURES)
{
newNormal = texture(textSampler[nonuniformEXT(material.normalMapIdx)], textCoords).rgb;
newNormal = normalize(newNormal * 2.0 - 1.0);
newNormal = normalize(TBN * newNormal);
}
return newNormal;
}
layout(push_constant) uniform pc {
layout(offset = 64) uint materialIdx;
} push_constants;
void main()
{
outPos = inPos;
vec4 viewPos = vec4(viewMatrix * vec4(inPos.xyz, 1.0));
outViewPos = viewPos;
Material material = matUniform.materials[MaterialID];
uint albedoTextureIndex = material.textureIdx;
if (albedoTextureIndex >= MAX_TEXTURES) {
outAlbedo = vec4(0.0,0.0,1.0,1.0);
outOpacity = vec4(0.0,0.0,1.0,1.0);
outNormal = vec4(0.0,0.0,1.0,1.0);
outEmissive = vec4(0.0,0.0,1.0,1.0);
outTranslucency = vec4(0.0,0.0,1.0,1.0);
outPBR = vec4(0.0,0.0,1.0,1.0);
return;
}
if (material.hasTexture == 1) {
outAlbedo = texture(textSampler[nonuniformEXT(albedoTextureIndex)], inTextCoords);
} else {
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
}
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
outOpacity = texture(textSampler[nonuniformEXT(material.OpacityMapIdx)], inTextCoords);
} else {
outOpacity = Opacity;
}
Opacity = outOpacity;
float opacityf = Opacity.x + Opacity.y + Opacity.z;
opacityf = opacityf / 3;
outAlbedo = vec4(outAlbedo.rgb, opacityf);
if(outAlbedo.a < 0.5) discard;
mat3 TBN = mat3(inTangent, inBitangent, inNormal);
vec3 newNormal = calcNormal(material, inNormal, inTextCoords, TBN);
float ao = 0.5f;
float roughnessFactor = 0.0f;
float metallicFactor = 0.0f;
if (material.hasRoughMap > 0 && material.roughMapIdx < MAX_TEXTURES) {
vec4 metRoughValue = texture(textSampler[nonuniformEXT(material.roughMapIdx)], inTextCoords);
roughnessFactor = metRoughValue.g;
metallicFactor = metRoughValue.b;
} else {
roughnessFactor = material.roughnessFactor;
metallicFactor = material.metallicFactor;
}
vec4 emissive = material.emissiveColour;
if (material.hasEmissiveMap > 0 && material.emissiveMapIdx < MAX_TEXTURES) {
emissive = texture(textSampler[nonuniformEXT(material.emissiveMapIdx)], inTextCoords);
}
outEmissive = emissive;
vec4 Translucency = vec4(material.translucencyFactor, material.translucencyFactor, material.translucencyFactor, 1);
if(material.hasTranslucencyMap > 0 && material.translucencyMapIdx < MAX_TEXTURES){
Translucency = texture(textSampler[nonuniformEXT(material.translucencyMapIdx)], inTextCoords);
}
outTranslucency = Translucency;
float Refractiveness = material.refractiveness;
float Reflectiveness = material.reflectiveness;
outNormal = vec4(newNormal, Refractiveness);
outPBR = vec4(ao, roughnessFactor, metallicFactor, Reflectiveness);
}

View file

@ -0,0 +1,96 @@
#version 450
layout(location = 0) in uint inPackedVertex;
layout(location = 0) out vec4 outPos;
layout(location = 1) out vec3 outNormal;
layout(location = 2) out vec3 outTangent;
layout(location = 3) out vec3 outBitangent;
layout(location = 4) out vec2 outTextCoords;
layout(location = 5) out mat4 viewMatrix;
const vec3 NORMALS[6] = vec3[6](
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, -1.0, 0.0),
vec3( 1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0),
vec3( 0.0, 0.0, 1.0),
vec3( 0.0, 0.0, -1.0)
);
const vec3 TANGENTS[6] = vec3[6](
vec3( 1.0, 0.0, 0.0),
vec3( 1.0, 0.0, 0.0),
vec3( 0.0, 0.0, -1.0),
vec3( 0.0, 0.0, 1.0),
vec3( 1.0, 0.0, 0.0),
vec3(-1.0, 0.0, 0.0)
);
const vec3 BITANGENTS[6] = vec3[6](
vec3( 0.0, 0.0, 1.0),
vec3( 0.0, 0.0, -1.0),
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, 1.0, 0.0),
vec3( 0.0, 1.0, 0.0)
);
const vec2 CORNER_UVS[16] = vec2[16](
vec2(0.5, 0.0),
vec2(0.5, 0.5),
vec2(1.0, 0.5),
vec2(1.0, 0.0),
vec2(0.0, 0.5),
vec2(0.0, 1.0),
vec2(0.5, 1.0),
vec2(0.5, 0.5),
vec2(0.5, 0.0),
vec2(0.5, 0.5),
vec2(1.0, 0.5),
vec2(1.0, 0.0),
vec2(0.5, 0.0),
vec2(0.5, 0.5),
vec2(1.0, 0.5),
vec2(1.0, 0.0)
);
layout(set = 0, binding = 0) uniform ProjUniform { mat4 matrix; } projUniform;
layout(set = 1, binding = 0) uniform ViewUniform { mat4 matrix; } viewUniform;
layout(push_constant) uniform pc {
vec4 ModelOffset;
vec4 Padding0;
vec4 Padding1;
vec4 Padding2;
} push_constants;
void main() {
viewMatrix = viewUniform.matrix;
uint posX = inPackedVertex & 0x1Fu;
uint posY = (inPackedVertex >> 5u) & 0x1Fu;
uint posZ = (inPackedVertex >> 10u) & 0x1Fu;
uint faceIdx = (inPackedVertex >> 15u) & 0x7u;
uint cornerIdx = (inPackedVertex >> 18u) & 0x3u;
uint matId = (inPackedVertex >> 20u) & 0xFFu;
vec3 inPos = vec3(posX, posY, posZ) + push_constants.ModelOffset.xyz * 16.0;
vec3 inNormal = NORMALS[faceIdx];
vec3 inTangent = TANGENTS[faceIdx];
vec3 inBitangent = BITANGENTS[faceIdx];
vec2 inTextCoords = CORNER_UVS[cornerIdx + 4 * matId];
vec4 worldPos = vec4(inPos, 1.0);
gl_Position = projUniform.matrix * viewUniform.matrix * worldPos;
outPos = worldPos;
outNormal = inNormal;
outTangent = inTangent;
outBitangent = inBitangent;
outTextCoords = inTextCoords;
}

View file

@ -0,0 +1,134 @@
#version 450
layout(location = 0) out vec4 outPos;
layout(location = 1) out vec3 outNormal;
layout(location = 2) out vec3 outTangent;
layout(location = 3) out vec3 outBitangent;
layout(location = 4) out vec2 outTextCoords;
layout(location = 5) out mat4 viewMatrix;
layout(location = 9) out flat uint outMaterialID;
layout(set = 0, binding = 0) uniform ProjUniform { mat4 matrix; } projUniform;
layout(set = 1, binding = 0) uniform ViewUniform { mat4 matrix; } viewUniform;
layout(set = 4, binding = 0) readonly buffer FaceBuffer {
uint faces[];
};
layout(push_constant) uniform pc {
vec4 ModelOffset;
vec4 Padding0;
vec4 Padding1;
vec4 Padding2;
} push_constants;
const uint TRI_TO_CORNER[6] = uint[6](0u, 1u, 2u, 0u, 2u, 3u);
const vec3 NORMALS[8] = vec3[8](
vec3( 0.0, 1.0, 0.0), // Face 0 (+Y)
vec3( 0.0, -1.0, 0.0), // Face 1 (-Y)
vec3( 1.0, 0.0, 0.0), // Face 2 (+X)
vec3(-1.0, 0.0, 0.0), // Face 3 (-X)
vec3( 0.0, 0.0, 1.0), // Face 4 (+Z)
vec3( 0.0, 0.0, -1.0), // Face 5 (-Z)
vec3(-0.7071, 0.0, 0.7071), // Face 6
vec3( 0.7071, 0.0, 0.7071) // Face 7
);
const vec3 TANGENTS[8] = vec3[8](
vec3( 1.0, 0.0, 0.0), // Face 0
vec3( 1.0, 0.0, 0.0), // Face 1
vec3( 0.0, 0.0, -1.0), // Face 2
vec3( 0.0, 0.0, 1.0), // Face 3
vec3( 1.0, 0.0, 0.0), // Face 4
vec3(-1.0, 0.0, 0.0), // Face 5
vec3( 0.7071, 0.0, 0.7071), // Face 6
vec3( 0.7071, 0.0,-0.7071) // Face 7
);
const vec3 BITANGENTS[8] = vec3[8](
vec3( 0.0, 0.0, 1.0), // Face 0
vec3( 0.0, 0.0, -1.0), // Face 1
vec3( 0.0, 1.0, 0.0), // Face 2
vec3( 0.0, 1.0, 0.0), // Face 3
vec3( 0.0, 1.0, 0.0), // Face 4
vec3( 0.0, 1.0, 0.0), // Face 5
vec3( 0.0, 1.0, 0.0), // Face 6
vec3( 0.0, 1.0, 0.0) // Face 7
);
const vec2 CORNER_UVS[5][4] = vec2[5][4](
vec2[4](vec2(0.5, 0.0), vec2(0.5, 0.5), vec2(1.0, 0.5), vec2(1.0, 0.0)),
vec2[4](vec2(0.0, 0.5), vec2(0.0, 1.0), vec2(0.5, 1.0), vec2(0.5, 0.5)),
vec2[4](vec2(0.5, 0.0), vec2(0.5, 0.5), vec2(1.0, 0.5), vec2(1.0, 0.0)),
vec2[4](vec2(0.5, 0.0), vec2(0.5, 0.5), vec2(1.0, 0.5), vec2(1.0, 0.0)),
vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.5), vec2(0.5, 0.5), vec2(0.5, 1.0))
);
const vec2 CORNER_UVS_GRASS_BLOCK[8][4] = vec2[8][4](
vec2[4](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)),
vec2[4](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)),
vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0), vec2(0.0, 1.0)),
vec2[4]( vec2(0.0, 1.0),vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0)),
vec2[4]( vec2(0.0, 1.0),vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0)),
vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0), vec2(0.0, 1.0)),
vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(0.0, 1.0)),
vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(0.0, 1.0))
);
const vec3 FACE_CORNERS[8][4] = vec3[8][4](
vec3[4](vec3(0.0, 1.0, 0.0), vec3(0.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 0.0)), // Face 0 (+Y)
vec3[4](vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 1.0), vec3(0.0, 0.0, 1.0)), // Face 1 (-Y)
vec3[4](vec3(1.0, 0.0, 0.0), vec3(1.0, 1.0, 0.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 0.0, 1.0)), // Face 2 (+X)
vec3[4](vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 1.0, 1.0), vec3(0.0, 1.0, 0.0)), // Face 3 (-X)
vec3[4](vec3(0.0, 0.0, 1.0), vec3(1.0, 0.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(0.0, 1.0, 1.0)), // Face 4 (+Z)
vec3[4](vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(1.0, 1.0, 0.0), vec3(1.0, 0.0, 0.0)), // Face 5 (-Z)
vec3[4](vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 0.0, 1.0)), // Face 6 (cross model pane 1)
vec3[4](vec3(0.0, 0.0, 1.0), vec3(0.0, 1.0, 1.0), vec3(1.0, 1.0, 0.0), vec3(1.0, 0.0, 0.0)) // Face 7 (cross model pane 2)
);
void main() {
viewMatrix = viewUniform.matrix;
uint faceRecordIndex = uint(gl_VertexIndex) / 6u;
uint triangleVertex = (uint(gl_VertexIndex))% 6u;
uint cornerIndex = TRI_TO_CORNER[triangleVertex];
uint packedFace = faces[faceRecordIndex];
uint voxelX = packedFace & 0xFu;
uint voxelY = (packedFace >> 4u) & 0xFu;
uint voxelZ = (packedFace >> 8u) & 0xFu;
uint faceId = (packedFace >> 12u) & 0x7u;
uint matId = (packedFace >> 15u) & 0x7FFu;
uint texIdxX = (packedFace >> 26u) & 0x7u;
uint texIdxY = (packedFace >> 29u) & 0x7u;
vec2 texID = vec2((texIdxX)/4.0,(texIdxY)/4.0);
vec2 scalar = vec2(1.0/4.0,1.0/4.0);
faceId = min(faceId, 7u);
vec3 localPos = vec3(voxelX, voxelY, voxelZ) + FACE_CORNERS[faceId][cornerIndex];
vec3 Offset = vec3(0,0,0);
if (gl_InstanceIndex != 0) {
uint encoded = uint(gl_InstanceIndex);
Offset = vec3(int(encoded & 1023u) - 512, int((encoded >> 10u) & 1023u) - 512,
int((encoded >> 20u) & 1023u) - 512) * 16.0;
}
vec3 worldPos = localPos + Offset + push_constants.ModelOffset.xyz * 16.0;
vec4 worldPosVec4 = vec4(worldPos, 1.0);
gl_Position = projUniform.matrix * viewUniform.matrix * worldPosVec4;
outPos = worldPosVec4;
outNormal = NORMALS[faceId];
outTangent = TANGENTS[faceId];
outBitangent = BITANGENTS[faceId];
vec2 atlasSize = vec2(64, 64);
vec2 texel = 0.5 / atlasSize;
vec2 tileMin = vec2(texIdxX, texIdxY) * scalar + texel;
vec2 tileMax = vec2(texIdxX + 1u, texIdxY + 1u) * scalar - texel;
outTextCoords = mix(tileMin, tileMax, CORNER_UVS_GRASS_BLOCK[faceId][cornerIndex]);
outMaterialID = matId;
}

View file

@ -2,7 +2,6 @@
layout(constant_id = 0) const int USE_AA = 0;
const float GAMMA_CONST = 0.4545;
const float SPAN_MAX = 8.0;
const float REDUCE_MIN = 1.0/128.0;
const float REDUCE_MUL = 1.0/32.0;
@ -11,18 +10,19 @@ layout(location = 0) in vec2 inTextCoord;
layout(location = 0) out vec4 outFragColor;
layout(set = 0, binding = 0) uniform sampler2D inputTexture;
layout(set = 0, binding = 1) uniform sampler2D bloomImage;
layout(set = 1, binding = 0) uniform ScreenSize{
vec2 size;
} screenSize;
vec4 gamma(vec4 color){
return color = vec4(pow(color.rgb,vec3(GAMMA_CONST)),color.a);
}
layout(push_constant) uniform PassConfig {
int horizontal;
float GAMMA_CONST;
float Exposure;
float blur_radius;
vec2 bloomSize;
} config;
// Sourced from: https://mini.gmshaders.com/p/gm-shaders-mini-fxaa
vec4 fxaa(sampler2D tex, vec2 uv) {
vec2 u_texel = 1.0 / screenSize.size;
vec2 u_texel = 1.0 / vec2(textureSize(inputTexture, 0));
//Sample center and 4 corners
vec3 rgbCC = texture(tex, uv).rgb;
@ -70,21 +70,22 @@ vec4 fxaa(sampler2D tex, vec2 uv) {
return ((lumaB < lumaMin) || (lumaB > lumaMax)) ? A : B;
}
vec3 bloomAt(ivec2 pixel, ivec2 size) {
return texelFetch(bloomImage, clamp(pixel, ivec2(0), size - 1), 0).rgb;
}
vec3 upsampleBloom(vec2 uv) {
ivec2 size = textureSize(bloomImage, 0);
vec2 pixel = uv * vec2(size) - 0.5;
ivec2 base = ivec2(floor(pixel));
vec2 blend = fract(pixel);
return mix(mix(bloomAt(base, size), bloomAt(base + ivec2(1, 0), size), blend.x),
mix(bloomAt(base + ivec2(0, 1), size), bloomAt(base + ivec2(1, 1), size), blend.x), blend.y);
}
void main(){
if(USE_AA == 1){
outFragColor = fxaa(inputTexture, inTextCoord);
outFragColor = gamma(outFragColor);
return;
}
if(USE_AA == 2){
}
if(USE_AA == 3){
}
if(USE_AA == 4){
}
outFragColor = gamma(texture(inputTexture,inTextCoord));
vec4 sceneColor = USE_AA == 1 ? fxaa(inputTexture, inTextCoord) : texture(inputTexture, inTextCoord);
vec3 hdrColour = max(sceneColor.rgb + upsampleBloom(inTextCoord), vec3(0.0));
vec3 result = vec3(1.0) - exp(-hdrColour * config.Exposure);
outFragColor = vec4(pow(result, vec3(1.0 / config.GAMMA_CONST)), sceneColor.a);
}

View file

@ -1,9 +0,0 @@
#version 450
layout(location = 0 ) out vec2 outTextCoord;
void main()
{
outTextCoord = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(outTextCoord.x * 2.0f - 1.0f, outTextCoord.y * -2.0f + 1.0f,0.0f,1.0f);
}

View file

@ -1,15 +1,40 @@
#version 450
const int MAX_TEXTURES = 500;
const int MAX_TEXTURES = 128;
layout(location = 0) in vec2 inTextCoords;
layout(location = 0) out vec4 outFragColor;
layout(location = 0) in vec4 inPos;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec3 inTangent;
layout(location = 3) in vec3 inBitangent;
layout(location = 4) in vec2 inTextCoords;
layout(location = 5) in mat4 viewMatrix;
struct Material{
vec4 diffuseColor;
uint hasTexture;
uint textureIdx;
uint padding[2];
layout(location = 0) out vec4 outAlbedo;
layout(location = 1) out vec4 outViewPos;
struct Material {
vec4 diffuseColor; //16
uint hasTexture; //20
uint textureIdx; //24
uint hasNormalMap; //28
uint normalMapIdx; //32
uint hasRoughMap; //36
uint roughMapIdx; //40
float roughnessFactor; //44
float metallicFactor; //48
vec4 emissiveColour; //64
uint hasEmissiveMap; //68
uint emissiveMapIdx; //72
uint hasTranslucencyMap; //76
uint translucencyMapIdx; //80
float translucencyFactor; //84
uint hasOpacityMap; //88
uint OpacityMapIdx; //92
float OpacityFactor; //96
float reflectiveness; //100
float refractiveness; //104
float Padding1; //108
float Padding2; //112
};
layout(set = 2, binding = 0) readonly buffer MaterialUniform{
@ -18,18 +43,42 @@ layout(set = 2, binding = 0) readonly buffer MaterialUniform{
layout(set = 3, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES];
layout(push_constant) uniform pc{
layout(offset = 64) uint materialIdx;
} push_constants;
void main()
{
vec4 viewPos = vec4(viewMatrix * inPos);
outViewPos = viewPos;
Material material = matUniform.materials[push_constants.materialIdx];
int textureIndex = int(material.textureIdx);
if (textureIndex >= MAX_TEXTURES){
outAlbedo = vec4(0.0,0.0,1.0,1.0);
return;
}
if(material.hasTexture == 1){
vec4 texColor = texture(textSampler[material.textureIdx],inTextCoords);
if(texColor.a < 0.1){discard;}
outFragColor = texColor;
outAlbedo = texColor;
} else{
outFragColor = material.diffuseColor;
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
}
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}
float opacityf = Opacity.x + Opacity.y + Opacity.z;
opacityf = opacityf/3;
if(opacityf < 0.4){discard;}
outAlbedo = vec4(outAlbedo.rgb, opacityf);
}

View file

@ -0,0 +1,143 @@
#version 450
const int MAX_TEXTURES = 128;
layout(location = 0) in vec4 inPos;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec3 inTangent;
layout(location = 3) in vec3 inBitangent;
layout(location = 4) in vec2 inTextCoords;
layout(location = 5) in mat4 viewMatrix;
layout(location = 1) out vec4 outAlbedo ;
layout(location = 0) out vec4 outPos;
layout(location = 2) out vec4 outNormal;
layout(location = 3) out vec4 outPBR;
layout(location = 4) out vec4 outEmissive;
layout(location = 5) out vec4 outTranslucency;
layout(location = 6) out vec4 outOpacity;
layout(location = 7) out vec4 outViewPos;
struct Material {
vec4 diffuseColor; //16
uint hasTexture; //20
uint textureIdx; //24
uint hasNormalMap; //28
uint normalMapIdx; //32
uint hasRoughMap; //36
uint roughMapIdx; //40
float roughnessFactor; //44
float metallicFactor; //48
vec4 emissiveColour; //64
uint hasEmissiveMap; //68
uint emissiveMapIdx; //72
uint hasTranslucencyMap; //76
uint translucencyMapIdx; //80
float translucencyFactor; //84
uint hasOpacityMap; //88
uint OpacityMapIdx; //92
float OpacityFactor; //96
float reflectiveness; //100
float refractiveness; //104
float Padding1; //108
float Padding2; //112
};
layout(set = 2, binding = 0) readonly buffer MaterialUniform {
Material materials[];
} matUniform;
layout(set = 3, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES];
vec3 calcNormal(Material material, vec3 normal, vec2 textCoords, mat3 TBN)
{
vec3 newNormal = normal;
if (material.hasNormalMap > 0)
{
newNormal = texture(textSampler[material.normalMapIdx], textCoords).rgb;
newNormal = normalize(newNormal * 2.0 - 1.0);
newNormal = normalize(TBN * newNormal);
}
return newNormal;
}
layout(push_constant) uniform pc {
layout(offset = 64) uint materialIdx;
} push_constants;
void main()
{
outPos = inPos;
vec4 viewPos = vec4(viewMatrix * vec4(inPos.xyz, 1.0));
outViewPos = viewPos;
Material material = matUniform.materials[push_constants.materialIdx];
int textureIndex = int(material.textureIdx);
if (textureIndex >= MAX_TEXTURES){
outAlbedo = vec4(0.0,0.0,1.0,1.0);
outOpacity = vec4(0.0,0.0,1.0,1.0);
outNormal = vec4(0.0,0.0,1.0,1.0);
outEmissive = vec4(0.0,0.0,1.0,1.0);
outTranslucency = vec4(0.0,0.0,1.0,1.0);
outPBR = vec4(0.0,0.0,1.0,1.0);
return;
}
if (material.hasTexture == 1) {
outAlbedo = texture(textSampler[material.textureIdx], inTextCoords);
} else {
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
}
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}
outOpacity = Opacity;
float opacityf = Opacity.x + Opacity.y + Opacity.z;
opacityf = opacityf/3;
outAlbedo = vec4(outAlbedo.rgb, opacityf);
if(outAlbedo.a < 0.5) discard;
mat3 TBN = mat3(inTangent, inBitangent, inNormal);
vec3 newNormal = calcNormal(material, inNormal, inTextCoords, TBN);
float ao = 0.5f;
float roughnessFactor = 0.0f;
float metallicFactor = 0.0f;
if (material.hasRoughMap > 0) {
vec4 metRoughValue = texture(textSampler[material.roughMapIdx], inTextCoords);
roughnessFactor = metRoughValue.g;
metallicFactor = metRoughValue.b;
} else {
roughnessFactor = material.roughnessFactor;
metallicFactor = material.metallicFactor;
}
vec4 emissive = material.emissiveColour;
if (material.hasEmissiveMap > 0 && material.emissiveMapIdx < MAX_TEXTURES) {
emissive = texture(textSampler[material.emissiveMapIdx], inTextCoords);
}
outEmissive = emissive;
vec4 Translucency = vec4(material.translucencyFactor,material.translucencyFactor,material.translucencyFactor,1);
if(material.hasTranslucencyMap > 0 && material.translucencyMapIdx < MAX_TEXTURES){
Translucency = texture(textSampler[material.translucencyMapIdx], inTextCoords);
}
outTranslucency = Translucency;
float Refractiveness = material.refractiveness;
float Reflectiveness = material.reflectiveness;
outNormal = vec4(newNormal, Refractiveness);
outPBR = vec4(ao, roughnessFactor, metallicFactor, Reflectiveness);
}

View file

@ -1,15 +1,41 @@
#version 450
const int MAX_TEXTURES = 500;
const int MAX_TEXTURES = 128;
layout(location = 0) in vec2 inTextCoords;
layout(location = 0) out vec4 outFragColor;
struct Material{
vec4 diffuseColor;
uint hasTexture;
uint textureIdx;
uint padding[2];
layout(location = 0) in vec4 inPos;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec3 inTangent;
layout(location = 3) in vec3 inBitangent;
layout(location = 4) in vec2 inTextCoords;
layout(location = 5) in mat4 viewMatrix;
layout(location = 0) out vec4 outAlbedo;
layout(location = 1) out vec4 outViewPos;
struct Material {
vec4 diffuseColor; //16
uint hasTexture; //20
uint textureIdx; //24
uint hasNormalMap; //28
uint normalMapIdx; //32
uint hasRoughMap; //36
uint roughMapIdx; //40
float roughnessFactor; //44
float metallicFactor; //48
vec4 emissiveColour; //64
uint hasEmissiveMap; //68
uint emissiveMapIdx; //72
uint hasTranslucencyMap; //76
uint translucencyMapIdx; //80
float translucencyFactor; //84
uint hasOpacityMap; //88
uint OpacityMapIdx; //92
float OpacityFactor; //96
float reflectiveness; //100
float refractiveness; //104
float Padding1; //108
float Padding2; //112
};
layout(set = 2, binding = 0) readonly buffer MaterialUniform{
@ -24,12 +50,34 @@ layout(push_constant) uniform pc{
void main()
{
vec4 viewPos = vec4(viewMatrix * inPos);
outViewPos = viewPos;
Material material = matUniform.materials[push_constants.materialIdx];
int textureIndex = int(material.textureIdx);
if (textureIndex >= MAX_TEXTURES){
outAlbedo = vec4(0.0,0.0,1.0,1.0);
return;
}
if(material.hasTexture == 1){
vec4 texColor = texture(textSampler[material.textureIdx],inTextCoords);
if(texColor.a < 0.9){discard;}
outFragColor = texColor;
outAlbedo = texColor;
} else{
outFragColor = material.diffuseColor;
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
}
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}
float opacityf = Opacity.x + Opacity.y + Opacity.z;
opacityf = opacityf/3;
if(opacityf < 0.9){discard;}
outAlbedo = vec4(outAlbedo.rgb, opacityf);
}

View file

@ -0,0 +1,148 @@
#version 450
const int MAX_TEXTURES = 128;
layout(location = 0) in vec4 inPos;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec3 inTangent;
layout(location = 3) in vec3 inBitangent;
layout(location = 4) in vec2 inTextCoords;
layout(location = 5) in mat4 viewMatrix;
layout(location = 1) out vec4 outAlbedo ;
layout(location = 0) out vec4 outPos;
layout(location = 2) out vec4 outNormal;
layout(location = 3) out vec4 outPBR;
layout(location = 4) out vec4 outEmissive;
layout(location = 5) out vec4 outTranslucency;
layout(location = 6) out vec4 outOpacity;
layout(location = 7) out vec4 outViewPos;
const float bayerMatrix[16] = float[](
0.0 / 16.0, 8.0 / 16.0, 2.0 / 16.0, 10.0 / 16.0,
12.0 / 16.0, 4.0 / 16.0, 14.0 / 16.0, 6.0 / 16.0,
3.0 / 16.0, 11.0 / 16.0, 1.0 / 16.0, 9.0 / 16.0,
15.0 / 16.0, 7.0 / 16.0, 13.0 / 16.0, 5.0 / 16.0
);
struct Material {
vec4 diffuseColor; //16
uint hasTexture; //20
uint textureIdx; //24
uint hasNormalMap; //28
uint normalMapIdx; //32
uint hasRoughMap; //36
uint roughMapIdx; //40
float roughnessFactor; //44
float metallicFactor; //48
vec4 emissiveColour; //64
uint hasEmissiveMap; //68
uint emissiveMapIdx; //72
uint hasTranslucencyMap; //76
uint translucencyMapIdx; //80
float translucencyFactor; //84
uint hasOpacityMap; //88
uint OpacityMapIdx; //92
float OpacityFactor; //96
float reflectiveness; //100
float refractiveness; //104
float Padding1; //108
float Padding2; //112
};
layout(set = 2, binding = 0) readonly buffer MaterialUniform {
Material materials[];
} matUniform;
layout(set = 3, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES];
vec3 calcNormal(Material material, vec3 normal, vec2 textCoords, mat3 TBN)
{
vec3 newNormal = normal;
if (material.hasNormalMap > 0)
{
newNormal = texture(textSampler[material.normalMapIdx], textCoords).rgb;
newNormal = normalize(newNormal * 2.0 - 1.0);
newNormal = normalize(TBN * newNormal);
}
return newNormal;
}
layout(push_constant) uniform pc {
layout(offset = 64) uint materialIdx;
} push_constants;
void main()
{
outPos = inPos;
vec4 viewPos = vec4(viewMatrix * vec4(inPos.xyz, 1.0));
outViewPos = viewPos;
Material material = matUniform.materials[push_constants.materialIdx];
int textureIndex = int(material.textureIdx);
if (textureIndex >= MAX_TEXTURES){
outAlbedo = vec4(0.0,0.0,1.0,1.0);
outOpacity = vec4(0.0,0.0,1.0,1.0);
outNormal = vec4(0.0,0.0,1.0,1.0);
outEmissive = vec4(0.0,0.0,1.0,1.0);
outTranslucency = vec4(0.0,0.0,1.0,1.0);
outPBR = vec4(0.0,0.0,1.0,1.0);
return;
}
if (material.hasTexture == 1) {
outAlbedo = texture(textSampler[material.textureIdx], inTextCoords);
} else {
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
}
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}
outOpacity = Opacity;
float opacityf = Opacity.x + Opacity.y + Opacity.z;
opacityf = opacityf/3;
outAlbedo = vec4(outAlbedo.rgb, opacityf);
if(outAlbedo.a < 0.9) discard;
mat3 TBN = mat3(inTangent, inBitangent, inNormal);
vec3 newNormal = calcNormal(material, inNormal, inTextCoords, TBN);
float ao = 0.5f;
float roughnessFactor = 0.0f;
float metallicFactor = 0.0f;
if (material.hasRoughMap > 0) {
vec4 metRoughValue = texture(textSampler[material.roughMapIdx], inTextCoords);
roughnessFactor = metRoughValue.g;
metallicFactor = metRoughValue.b;
} else {
roughnessFactor = material.roughnessFactor;
metallicFactor = material.metallicFactor;
}
vec4 emissive = material.emissiveColour;
if (material.hasEmissiveMap > 0 && material.emissiveMapIdx < MAX_TEXTURES) {
emissive = texture(textSampler[material.emissiveMapIdx], inTextCoords);
}
outEmissive = emissive;
vec4 Translucency = vec4(material.translucencyFactor,material.translucencyFactor,material.translucencyFactor,1);
if(material.hasTranslucencyMap > 0 && material.translucencyMapIdx < MAX_TEXTURES){
Translucency = texture(textSampler[material.translucencyMapIdx], inTextCoords);
}
outTranslucency = Translucency;
float Refractiveness = material.refractiveness;
float Reflectiveness = material.reflectiveness;
outNormal = vec4(newNormal, Refractiveness);
outPBR = vec4(ao, roughnessFactor, metallicFactor, Reflectiveness);
}

View file

@ -1,17 +1,41 @@
#version 450
const int MAX_TEXTURES = 500;
const int MAX_TEXTURES = 128;
layout(location = 0) in vec2 inTextCoords;
layout(location = 0) out vec4 outFragColor;
layout(location = 0) in vec4 inPos;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec3 inTangent;
layout(location = 3) in vec3 inBitangent;
layout(location = 4) in vec2 inTextCoords;
layout(location = 5) in mat4 viewMatrix;
struct Material{
vec4 diffuseColor;
uint hasTexture;
uint textureIdx;
uint padding[2];
layout(location = 0) out vec4 outAlbedo;
layout(location = 1) out vec4 outViewPos;
struct Material {
vec4 diffuseColor; //16
uint hasTexture; //20
uint textureIdx; //24
uint hasNormalMap; //28
uint normalMapIdx; //32
uint hasRoughMap; //36
uint roughMapIdx; //40
float roughnessFactor; //44
float metallicFactor; //48
vec4 emissiveColour; //64
uint hasEmissiveMap; //68
uint emissiveMapIdx; //72
uint hasTranslucencyMap; //76
uint translucencyMapIdx; //80
float translucencyFactor; //84
uint hasOpacityMap; //88
uint OpacityMapIdx; //92
float OpacityFactor; //96
float reflectiveness; //100
float refractiveness; //104
float Padding1; //108
float Padding2; //112
};
layout(set = 2, binding = 0) readonly buffer MaterialUniform{
Material materials[];
} matUniform;
@ -24,12 +48,36 @@ layout(push_constant) uniform pc{
void main()
{
vec4 viewPos = vec4(viewMatrix * inPos);
outViewPos = viewPos;
Material material = matUniform.materials[push_constants.materialIdx];
int textureIndex = int(material.textureIdx);
if (textureIndex >= MAX_TEXTURES){
outAlbedo = vec4(0.0,0.0,1.0,1.0);
return;
}
if(material.hasTexture == 1){
vec4 texColor = texture(textSampler[material.textureIdx],inTextCoords);
if(texColor.a < 0.05 || texColor.a >= 0.9){discard;}
outFragColor = texColor;
outAlbedo = texColor;
} else{
outFragColor = material.diffuseColor;
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
}
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}
float opacityf = Opacity.x + Opacity.y + Opacity.z;
opacityf = opacityf/3;
if(opacityf >= 0.9){discard;}
outAlbedo = vec4(outAlbedo.rgb, opacityf);
}

View file

@ -0,0 +1,150 @@
#version 450
const int MAX_TEXTURES = 128;
layout(location = 0) in vec4 inPos;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec3 inTangent;
layout(location = 3) in vec3 inBitangent;
layout(location = 4) in vec2 inTextCoords;
layout(location = 5) in mat4 viewMatrix;
layout(location = 1) out vec4 outAlbedo ;
layout(location = 0) out vec4 outPos;
layout(location = 2) out vec4 outNormal;
layout(location = 3) out vec4 outPBR;
layout(location = 4) out vec4 outEmissive;
layout(location = 5) out vec4 outTranslucency;
layout(location = 6) out vec4 outOpacity;
layout(location = 7) out vec4 outViewPos;
const float bayerMatrix[16] = float[](
0.0 / 16.0, 8.0 / 16.0, 2.0 / 16.0, 10.0 / 16.0,
12.0 / 16.0, 4.0 / 16.0, 14.0 / 16.0, 6.0 / 16.0,
3.0 / 16.0, 11.0 / 16.0, 1.0 / 16.0, 9.0 / 16.0,
15.0 / 16.0, 7.0 / 16.0, 13.0 / 16.0, 5.0 / 16.0
);
struct Material {
vec4 diffuseColor; //16
uint hasTexture; //20
uint textureIdx; //24
uint hasNormalMap; //28
uint normalMapIdx; //32
uint hasRoughMap; //36
uint roughMapIdx; //40
float roughnessFactor; //44
float metallicFactor; //48
vec4 emissiveColour; //64
uint hasEmissiveMap; //68
uint emissiveMapIdx; //72
uint hasTranslucencyMap; //76
uint translucencyMapIdx; //80
float translucencyFactor; //84
uint hasOpacityMap; //88
uint OpacityMapIdx; //92
float OpacityFactor; //96
float reflectiveness; //100
float refractiveness; //104
float Padding1; //108
float Padding2; //112
};
layout(set = 2, binding = 0) readonly buffer MaterialUniform {
Material materials[];
} matUniform;
layout(set = 3, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES];
vec3 calcNormal(Material material, vec3 normal, vec2 textCoords, mat3 TBN)
{
vec3 newNormal = normal;
if (material.hasNormalMap > 0)
{
newNormal = texture(textSampler[material.normalMapIdx], textCoords).rgb;
newNormal = normalize(newNormal * 2.0 - 1.0);
newNormal = normalize(TBN * newNormal);
}
return newNormal;
}
layout(push_constant) uniform pc {
layout(offset = 64) uint materialIdx;
} push_constants;
void main()
{
outPos = inPos;
vec4 viewPos = vec4(viewMatrix * vec4(inPos.xyz, 1.0));
outViewPos = viewPos;
Material material = matUniform.materials[push_constants.materialIdx];
int textureIndex = int(material.textureIdx);
if (textureIndex >= MAX_TEXTURES){
outAlbedo = vec4(0.0,0.0,1.0,1.0);
outOpacity = vec4(0.0,0.0,1.0,1.0);
outNormal = vec4(0.0,0.0,1.0,1.0);
outEmissive = vec4(0.0,0.0,1.0,1.0);
outTranslucency = vec4(0.0,0.0,1.0,1.0);
outPBR = vec4(0.0,0.0,1.0,1.0);
return;
}
if (material.hasTexture == 1) {
outAlbedo = texture(textSampler[material.textureIdx], inTextCoords);
} else {
outAlbedo = material.diffuseColor;
}
vec4 Opacity = vec4(outAlbedo.a, outAlbedo.a, outAlbedo.a, 1.0);
if (material.OpacityFactor > 0.0 && material.OpacityFactor < 1.0) {
Opacity = vec4(material.OpacityFactor, material.OpacityFactor, material.OpacityFactor, 1.0);
}
if (material.hasOpacityMap > 0 && material.OpacityMapIdx < MAX_TEXTURES) {
Opacity = texture(textSampler[material.OpacityMapIdx], inTextCoords);
}
outOpacity = Opacity;
float opacityf = Opacity.x + Opacity.y + Opacity.z;
opacityf = opacityf/3;
outAlbedo = vec4(outAlbedo.rgb, opacityf);
if(outAlbedo.a >= 0.9 || outAlbedo.a <= 0.1) discard;
mat3 TBN = mat3(inTangent, inBitangent, inNormal);
vec3 newNormal = calcNormal(material, inNormal, inTextCoords, TBN);
float ao = 0.5f;
float roughnessFactor = 0.0f;
float metallicFactor = 0.0f;
if (material.hasRoughMap > 0) {
vec4 metRoughValue = texture(textSampler[material.roughMapIdx], inTextCoords);
roughnessFactor = metRoughValue.g;
metallicFactor = metRoughValue.b;
} else {
roughnessFactor = material.roughnessFactor;
metallicFactor = material.metallicFactor;
}
vec4 emissive = material.emissiveColour;
if (material.hasEmissiveMap > 0 && material.emissiveMapIdx < MAX_TEXTURES) {
emissive = texture(textSampler[material.emissiveMapIdx], inTextCoords);
}
outEmissive = emissive;
vec4 Translucency = vec4(material.translucencyFactor,material.translucencyFactor,material.translucencyFactor,1);
if(material.hasTranslucencyMap > 0 && material.translucencyMapIdx < MAX_TEXTURES){
Translucency = texture(textSampler[material.translucencyMapIdx], inTextCoords);
}
outTranslucency = Translucency;
float Refractiveness = material.refractiveness;
float Reflectiveness = material.reflectiveness;
outNormal = vec4(newNormal, Refractiveness);
outPBR = vec4(ao, roughnessFactor, metallicFactor, Reflectiveness);
}

View file

@ -1,10 +1,17 @@
#version 450
layout(location = 0) in vec3 inPos;
layout(location = 1) in vec2 inTextCoords;
layout(location = 0) out vec2 outTextCoords;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec3 inTangent;
layout(location = 3) in vec3 inBitangent;
layout(location = 4) in vec2 inTextCoords;
layout(location = 0) out vec4 outPos;
layout(location = 1) out vec3 outNormal;
layout(location = 2) out vec3 outTangent;
layout(location = 3) out vec3 outBitangent;
layout(location = 4) out vec2 outTextCoords;
layout(location = 5) out mat4 viewMatrix;
layout(set = 0, binding = 0) uniform ProjUniform{
mat4 matrix;
@ -20,6 +27,13 @@ layout(push_constant) uniform pc{
void main()
{
viewMatrix = viewUniform.matrix;
vec4 worldPos = push_constants.modelMatrix * vec4(inPos,1);
gl_Position = projUniform.matrix * viewUniform.matrix * push_constants.modelMatrix * vec4(inPos,1);
mat3 mNormal = transpose(inverse(mat3(push_constants.modelMatrix)));
outPos = worldPos;
outNormal = mNormal * normalize(inNormal);
outTangent = mNormal * normalize(inTangent);
outBitangent = mNormal * normalize(inBitangent);
outTextCoords = inTextCoords;
}

View file

@ -0,0 +1,104 @@
#version 450
layout(location = 0) in vec2 inTextCoord;
layout(location = 0) out float outAO;
layout(set = 0, binding = 0) uniform sampler2D posSampler;
layout(set = 0, binding = 1) uniform sampler2D normalSampler;
layout(set = 0, binding = 2) uniform sampler2D noiseSampler;
layout(set = 1, binding = 0) readonly buffer SSAOKernel {
vec4 samples[];
} kernel;
layout(set = 2, binding = 0) uniform SSAOInfo {
mat4 projection; //64
mat4 view; //128
vec2 screenSize; // 136
float radius; //140
float bias; //144
int kernelSize; //160
} ssao;
void main() {
vec2 uv = inTextCoord;
vec3 worldPos = texture(posSampler, uv).xyz;
vec3 worldNormal = normalize(texture(normalSampler, uv).xyz);
if (length(worldNormal) < 0.001) {
outAO = 1.0;
return;
}
vec3 fragPos = vec3(ssao.view * vec4(worldPos, 1.0));
vec3 normal = normalize(mat3(ssao.view) * worldNormal);
vec2 noiseScale = ssao.screenSize / 4.0;
vec3 randomVec = normalize(texture(noiseSampler, inTextCoord * noiseScale).xyz);
vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);
float occlusion = 0.0;
float validSamples = 0.0;;
for (int i = 0; i < ssao.kernelSize; i++) {
vec3 samplePos = TBN * kernel.samples[i].xyz;
samplePos = fragPos + samplePos * ssao.radius;
vec4 offset = vec4(samplePos, 1.0);
offset = ssao.projection * offset;
offset.xyz /= offset.w;
offset.xyz = offset.xyz * 0.5 + 0.5;
vec2 sampleUV = offset.xy;
sampleUV.y = 1.0 - sampleUV.y;
if (sampleUV.x < 0.0 || sampleUV.x > 1.0 ||
sampleUV.y < 0.0 || sampleUV.y > 1.0) {
continue;
}
vec3 sampleWorldPos = texture(posSampler, sampleUV).xyz;
vec3 sampleWorldNormal = texture(normalSampler, sampleUV).xyz;
if (length(sampleWorldNormal) < 0.001) {
continue;
}
vec3 sampleViewPos = vec3(ssao.view * vec4(sampleWorldPos, 1.0));
float depthDelta = abs(fragPos.z - sampleViewPos.z);
occlusion += abs(fragPos.z)/200.0f;
validSamples += 1.0;
continue;
if (depthDelta > ssao.radius) {
continue;
}
float rangeCheck = 1.0 - depthDelta / ssao.radius;
rangeCheck = rangeCheck * rangeCheck * (3.0 - 2.0 * rangeCheck);
if (sampleViewPos.z >= samplePos.z + ssao.bias) {
occlusion += rangeCheck;
}
validSamples += 1.0;
}
if (validSamples <= 0.0) {
outAO = 1.0;
return;
}
occlusion = 1.0 - occlusion / validSamples;
outAO = clamp(occlusion, 0.0, 1.0);
}

View file

@ -0,0 +1,122 @@
#version 450
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor;
layout(set = 0, binding = 0) uniform sampler2D albedoSampler;
layout(set = 0, binding = 1) uniform sampler2D worldPosSampler;
layout(set = 0, binding = 2) uniform sampler2D normalSampler;
layout(set = 0, binding = 3) uniform sampler2D pbrSampler;
layout(set = 1, binding = 0) uniform CameraProperties {
mat4 projection;
mat4 view;
float ssrStepSize;
float ssrMaxDistance;
int maxSteps;
int padding;
vec4 cameraWorldPos;
} ubo;
const float THICKNESS = 0.35;
const float MIN_REFLECTION = 0.01;
float edgeFade(vec2 uv) {
vec2 fade = smoothstep(vec2(0.0), vec2(0.08), uv) *
smoothstep(vec2(0.0), vec2(0.08), vec2(1.0) - uv);
return fade.x * fade.y;
}
void main() {
outColor = vec4(0.0);
vec4 posSample = texture(worldPosSampler, fragTexCoord);
vec4 normalSample = texture(normalSampler, fragTexCoord);
vec4 pbrSample = texture(pbrSampler, fragTexCoord);
if (posSample.a == 0.0 || length(posSample.xyz) == 0.0 || length(normalSample.xyz) < 0.001) {
return;
}
vec3 worldPos = posSample.xyz;
vec3 worldNormal = normalize(normalSample.xyz);
float roughness = clamp(pbrSample.g, 0.0, 1.0);
float metallic = clamp(pbrSample.b, 0.0, 1.0);
float reflectiveness = clamp(pbrSample.a, 0.0, 1.0);
float refractiveness = clamp(normalSample.a, 0.0, 2.0);
vec3 viewDirToCamera = normalize(ubo.cameraWorldPos.xyz - worldPos);
float NoV = clamp(dot(worldNormal, viewDirToCamera), 0.0, 1.0);
float fresnel = pow(1.0 - NoV, 5.0);
float materialReflection = reflectiveness + (refractiveness - 1.05);
materialReflection *= mix(0.75, 1.0, metallic);
materialReflection *= 1.0 - smoothstep(0.05, 0.7, roughness);
materialReflection *= mix(0.45, 1.0, fresnel);
if (materialReflection <= MIN_REFLECTION) {
return;
}
vec3 viewDir = normalize(worldPos - ubo.cameraWorldPos.xyz);
vec3 reflectDir = normalize(reflect(viewDir, worldNormal));
if (dot(reflectDir, worldNormal) <= 0.0) {
return;
}
int steps = clamp(ubo.maxSteps, 1, 128);
float stepSize = max(ubo.ssrStepSize, 0.01);
float maxDistance = max(ubo.ssrMaxDistance, stepSize);
vec3 rayPos = worldPos;
vec2 hitUV = vec2(0.0);
bool hitFound = false;
for (int i = 0; i < steps; i++) {
rayPos += reflectDir * stepSize;
if (distance(rayPos, worldPos) > maxDistance) {
break;
}
vec4 clip = ubo.projection * ubo.view * vec4(rayPos, 1.0);
if (clip.w <= 0.0) {
break;
}
vec2 uv = clip.xy / clip.w;
uv = uv * 0.5 + 0.5;
uv.y = 1.0 - uv.y;
if (uv.x <= 0.0 || uv.x >= 1.0 || uv.y <= 0.0 || uv.y >= 1.0) {
break;
}
vec4 surfaceWorld = texture(worldPosSampler, uv);
if (surfaceWorld.a == 0.0 || length(surfaceWorld.xyz) == 0.0) {
continue;
}
float rayViewZ = abs((ubo.view * vec4(rayPos, 1.0)).z);
float surfaceViewZ = abs((ubo.view * vec4(surfaceWorld.xyz, 1.0)).z);
float depthDelta = rayViewZ - surfaceViewZ;
if (depthDelta >= 0.0 && depthDelta < THICKNESS) {
hitUV = uv;
hitFound = true;
break;
}
}
if (!hitFound) {
return;
}
vec3 reflectedColor = texture(albedoSampler, hitUV).rgb;
float fade = edgeFade(hitUV);
float weight = clamp(materialReflection * fade, 0.0, 0.85);
outColor = vec4(reflectedColor * weight, weight);
}

View file

@ -0,0 +1,81 @@
#version 450
// Keep in sync manually with Java code
const int MAX_TEXTURES = 128;
layout (location = 0) in vec2 inTextCoords;
layout (location = 1) in flat uint inMaterialIdx;
layout(location = 0) out vec2 outFragColor;
struct Material {
vec4 diffuseColor; //16
uint hasTexture; //20
uint textureIdx; //24
uint hasNormalMap; //28
uint normalMapIdx; //32
uint hasRoughMap; //36
uint roughMapIdx; //40
float roughnessFactor; //44
float metallicFactor; //48
vec4 emissiveColour; //64
uint hasEmissiveMap; //68
uint emissiveMapIdx; //72
uint hasTranslucencyMap; //76
uint translucencyMapIdx; //80
float translucencyFactor; //84
uint hasOpacityMap; //88
uint OpacityMapIdx; //92
float OpacityFactor; //96
float reflectiveness; //100
float refractiveness; //104
float Padding1; //108
float Padding2; //112
};
layout(set = 1, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES];
layout(set = 2, binding = 0) readonly buffer MaterialUniform {
Material materials[];
} matUniform;
void main()
{
Material material = matUniform.materials[inMaterialIdx];
float Refractiveness = material.refractiveness;
float Reflectiveness = material.reflectiveness;
float Translucency = material.translucencyFactor;
float Opacity = material.OpacityFactor;
if(material.hasTranslucencyMap > 0){
vec4 translucencyMap = texture(textSampler[material.translucencyMapIdx], inTextCoords);
Translucency = (translucencyMap.x + translucencyMap.y + translucencyMap.z)/3.0;
}
if(material.hasOpacityMap > 0){
vec4 opacityMap = texture(textSampler[material.OpacityMapIdx], inTextCoords);
Opacity = (opacityMap.x + opacityMap.y + opacityMap.z)/3.0;
}
int textureIndex = int(material.textureIdx);
if (textureIndex >= MAX_TEXTURES){
outFragColor = vec2(0.0,0.0);
return;
}
vec4 albedo;
if (material.hasTexture == 1) {
albedo = texture(textSampler[material.textureIdx], inTextCoords);
} else {
albedo = material.diffuseColor;
}
if (albedo.a < 0.5 || Translucency > 0.95 || Opacity < 0.5) {
discard;
}
float depth = gl_FragCoord.z;
float moment1 = depth;
float moment2 = depth * depth;
float dx = dFdx(depth);
float dy = dFdy(depth);
moment2 += 0.25 * (dx * dx + dy * dy);
outFragColor = vec2(moment1, moment2) * (1 - Translucency);
}

View file

@ -0,0 +1,29 @@
#version 450
#define SHADOW_MAP_CASCADE_COUNT 6
layout (triangles, invocations = SHADOW_MAP_CASCADE_COUNT) in;
layout (triangle_strip, max_vertices = 3) out;
layout (location = 0) in vec2 inTextCoords[];
layout (location = 1) in flat uint inMaterialIdx[];
layout (location = 0) out vec2 outTextCoords;
layout (location = 1) out flat uint outMaterialIdx;
layout(set = 0, binding = 0) uniform ProjUniforms {
mat4 projViewMatrices[SHADOW_MAP_CASCADE_COUNT];
} projUniforms;
void main()
{
for (int i = 0; i < 3; i++)
{
outTextCoords = inTextCoords[i];
outMaterialIdx = inMaterialIdx[i];
gl_Layer = gl_InvocationID;
gl_Position = projUniforms.projViewMatrices[gl_InvocationID] * gl_in[i].gl_Position;
EmitVertex();
}
EndPrimitive();
}

View file

@ -0,0 +1,23 @@
#version 450
layout(location = 0) in vec3 entityPos;
layout(location = 1) in vec3 entityNormal;
layout(location = 2) in vec3 entityTangent;
layout(location = 3) in vec3 entityBitangent;
layout(location = 4) in vec2 entityTextCoords;
layout(push_constant) uniform matrices {
mat4 modelMatrix;
uint materialIdx;
} push_constants;
layout (location = 0) out vec2 outTextCoord;
layout (location = 1) out flat uint outMaterialIdx;
void main()
{
outTextCoord = entityTextCoords;
outMaterialIdx = push_constants.materialIdx;
gl_Position = push_constants.modelMatrix * vec4(entityPos, 1.0f);
}

View file

@ -0,0 +1,115 @@
#version 450
layout(set = 3, binding = 0) readonly buffer FaceBuffer {
uint faces[];
};
layout(push_constant) uniform matrices {
vec4 ModelOffset;
vec4 Padding0;
vec4 Padding1;
vec4 Padding2;
uint materialIdx;
} push_constants;
layout(location = 0) out vec2 outTextCoord;
layout(location = 1) out flat uint outMaterialIdx;
const uint TRI_TO_CORNER[6] = uint[6](0u, 1u, 2u, 0u, 2u, 3u);
const vec3 NORMALS[8] = vec3[8](
vec3( 0.0, 1.0, 0.0), // Face 0 (+Y)
vec3( 0.0, -1.0, 0.0), // Face 1 (-Y)
vec3( 1.0, 0.0, 0.0), // Face 2 (+X)
vec3(-1.0, 0.0, 0.0), // Face 3 (-X)
vec3( 0.0, 0.0, 1.0), // Face 4 (+Z)
vec3( 0.0, 0.0, -1.0), // Face 5 (-Z)
vec3(-0.7071, 0.0, 0.7071), // Face 6
vec3( 0.7071, 0.0, 0.7071) // Face 7
);
const vec3 TANGENTS[8] = vec3[8](
vec3( 1.0, 0.0, 0.0), // Face 0
vec3( 1.0, 0.0, 0.0), // Face 1
vec3( 0.0, 0.0, -1.0), // Face 2
vec3( 0.0, 0.0, 1.0), // Face 3
vec3( 1.0, 0.0, 0.0), // Face 4
vec3(-1.0, 0.0, 0.0), // Face 5
vec3( 0.7071, 0.0, 0.7071), // Face 6
vec3( 0.7071, 0.0,-0.7071) // Face 7
);
const vec3 BITANGENTS[8] = vec3[8](
vec3( 0.0, 0.0, 1.0), // Face 0
vec3( 0.0, 0.0, -1.0), // Face 1
vec3( 0.0, 1.0, 0.0), // Face 2
vec3( 0.0, 1.0, 0.0), // Face 3
vec3( 0.0, 1.0, 0.0), // Face 4
vec3( 0.0, 1.0, 0.0), // Face 5
vec3( 0.0, 1.0, 0.0), // Face 6
vec3( 0.0, 1.0, 0.0) // Face 7
);
const vec2 CORNER_UVS[5][4] = vec2[5][4](
vec2[4](vec2(0.5, 0.0), vec2(0.5, 0.5), vec2(1.0, 0.5), vec2(1.0, 0.0)),
vec2[4](vec2(0.0, 0.5), vec2(0.0, 1.0), vec2(0.5, 1.0), vec2(0.5, 0.5)),
vec2[4](vec2(0.5, 0.0), vec2(0.5, 0.5), vec2(1.0, 0.5), vec2(1.0, 0.0)),
vec2[4](vec2(0.5, 0.0), vec2(0.5, 0.5), vec2(1.0, 0.5), vec2(1.0, 0.0)),
vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.5), vec2(0.5, 0.5), vec2(0.5, 1.0))
);
const vec2 CORNER_UVS_GRASS_BLOCK[8][4] = vec2[8][4](
vec2[4](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)),
vec2[4](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)),
vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0), vec2(0.0, 1.0)),
vec2[4]( vec2(0.0, 1.0),vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0)),
vec2[4]( vec2(0.0, 1.0),vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0)),
vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0),vec2(0.0, 0.0), vec2(0.0, 1.0)),
vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(0.0, 1.0)),
vec2[4](vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(0.0, 1.0))
);
const vec3 FACE_CORNERS[8][4] = vec3[8][4](
vec3[4](vec3(0.0, 1.0, 0.0), vec3(0.0, 1.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 1.0, 0.0)), // Face 0 (+Y)
vec3[4](vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 1.0), vec3(0.0, 0.0, 1.0)), // Face 1 (-Y)
vec3[4](vec3(1.0, 0.0, 0.0), vec3(1.0, 1.0, 0.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 0.0, 1.0)), // Face 2 (+X)
vec3[4](vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 1.0, 1.0), vec3(0.0, 1.0, 0.0)), // Face 3 (-X)
vec3[4](vec3(0.0, 0.0, 1.0), vec3(1.0, 0.0, 1.0), vec3(1.0, 1.0, 1.0), vec3(0.0, 1.0, 1.0)), // Face 4 (+Z)
vec3[4](vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(1.0, 1.0, 0.0), vec3(1.0, 0.0, 0.0)), // Face 5 (-Z)
vec3[4](vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(1.0, 1.0, 1.0), vec3(1.0, 0.0, 1.0)), // Face 6 (cross model pane 1)
vec3[4](vec3(0.0, 0.0, 1.0), vec3(0.0, 1.0, 1.0), vec3(1.0, 1.0, 0.0), vec3(1.0, 0.0, 0.0)) // Face 7 (cross model pane 2)
);
void main() {
uint faceRecordIndex = uint(gl_VertexIndex) / 6u;
uint triangleVertex = (uint(gl_VertexIndex))% 6u;
uint cornerIndex = TRI_TO_CORNER[triangleVertex];
uint packedFace = faces[faceRecordIndex];
uint voxelX = packedFace & 0xFu;
uint voxelY = (packedFace >> 4u) & 0xFu;
uint voxelZ = (packedFace >> 8u) & 0xFu;
uint faceId = (packedFace >> 12u) & 0x7u;
uint matId = (packedFace >> 15u) & 0x7FFu;
uint texIdxX = (packedFace >> 26u) & 0x7u;
uint texIdxY = (packedFace >> 29u) & 0x7u;
vec2 texID = vec2((texIdxX)/4.0,(texIdxY)/4.0);
vec2 scalar = vec2(1.0/4.0,1.0/4.0);
faceId = min(faceId, 7u);
vec3 localPos = vec3(voxelX, voxelY, voxelZ) + FACE_CORNERS[faceId][cornerIndex];
vec3 worldPos = localPos + push_constants.ModelOffset.xyz * 16.0;
if (gl_InstanceIndex != 0) {
uint encoded = uint(gl_InstanceIndex);
worldPos += vec3(int(encoded & 1023u) - 512, int((encoded >> 10u) & 1023u) - 512,
int((encoded >> 20u) & 1023u) - 512) * 16.0;
}
outTextCoord = CORNER_UVS_GRASS_BLOCK[faceId][cornerIndex] * scalar + texID;
outMaterialIdx = matId;
gl_Position = vec4(worldPos, 1.0);
}

View file

@ -0,0 +1,11 @@
#version 450
layout(location = 0) in vec3 outTexCoords;
layout(location = 1) out vec4 outColor;
layout(set = 2, binding = 0) uniform samplerCube skyboxSampler;
void main() {
outColor = texture(skyboxSampler, outTexCoords); //* vec4(0.0,0.05,0.1,1);
}

View file

@ -0,0 +1,18 @@
#version 450
layout(location = 0) in vec3 inPosition;
layout(location = 0) out vec3 outTexCoords;
layout(set = 0, binding = 0) uniform ProjectionBuffer {
mat4 proj;
} uboProj;
layout(set = 1, binding = 0) uniform ViewBuffer {
mat4 view;
} uboView;
void main() {
outTexCoords = inPosition;
mat4 skyView = mat4(mat3(uboView.view));
vec4 pos = uboProj.proj * skyView * vec4(inPosition, 1.0);
gl_Position = vec4(pos.xy, 0.0, pos.w);
}

View file

@ -0,0 +1,45 @@
#version 450
layout(location = 0) in vec2 inTextCoord;
layout(location = 0) out float outAO;
layout(set = 0, binding = 0) uniform sampler2D ssaoSampler;
layout(set = 0, binding = 1) uniform sampler2D viewPosSampler;
void main() {
vec2 texelSize = 1.0 / vec2(textureSize(ssaoSampler, 0));
float centerAO = texture(ssaoSampler, inTextCoord).r;
float centerDepth = texture(viewPosSampler, inTextCoord).z;
float totalAO = centerAO;
float totalWeight = 1.0;
float weights[4] = float[](0.1216216, 0.1945946, 0.1945946, 0.1216216);
int offsets[4] = int[](-2, -1, 1, 2);
const float Sharpness = 20.0;
for (int i = 0; i < 4; i++) {
vec2 offsetH = vec2(float(offsets[i]), 0.0) * texelSize;
vec2 uvH = inTextCoord + offsetH;
float neighborAOH = texture(ssaoSampler, uvH).r;
float neighborDepthH = texture(viewPosSampler, uvH).z;
float weightH = weights[i] * max(0.0, 1.0 - Sharpness * abs(centerDepth - neighborDepthH));
totalAO += neighborAOH * weightH;
totalWeight += weightH;
vec2 offsetV = vec2(0.0, float(offsets[i])) * texelSize;
vec2 uvV = inTextCoord + offsetV;
float neighborAOV = texture(ssaoSampler, uvV).r;
float neighborDepthV = texture(viewPosSampler, uvV).z;
float weightV = weights[i] * max(0.0, 1.0 - Sharpness * abs(centerDepth - neighborDepthV));
totalAO += neighborAOV * weightV;
totalWeight += weightV;
}
outAO = totalAO / totalWeight;
}

View file

@ -0,0 +1,78 @@
#version 450
layout(location = 0) in vec2 inTextCoord;
layout(location = 0) out float outAO;
layout(set = 0, binding = 0) uniform sampler2D posSampler;
layout(set = 0, binding = 1) uniform sampler2D normalSampler;
layout(set = 0, binding = 2) uniform sampler2D noiseSampler;
layout(set = 1, binding = 0) uniform SSAOKernel {
vec4 samples[64];
} kernel;
layout(set = 2, binding = 0) uniform SSAOInfo {
mat4 projection; //64
mat4 view; //128
vec2 screenSize; // 136
float radius; //140
float bias; //144
int kernelSize; //148
} ssao;
void main() {
int KERNEL_SIZE = clamp(ssao.kernelSize, 1, 64);
vec3 fragPos = texture(posSampler, inTextCoord).xyz;
vec3 worldNorm = texture(normalSampler, inTextCoord).xyz;
if (dot(worldNorm, worldNorm) < 0.001 || fragPos.z >= 0.0) {
outAO = 1.0;
return;
}
vec3 normal = normalize(mat3(ssao.view) * worldNorm);
vec3 randomVec = texelFetch(noiseSampler, ivec2(gl_FragCoord.xy) % 4, 0).xyz;
vec3 tangent = randomVec - normal * dot(randomVec, normal);
if (dot(tangent, tangent) < 0.0001) {
tangent = cross(normal, abs(normal.z) < 0.9 ? vec3(0, 0, 1) : vec3(0, 1, 0));
}
tangent = normalize(tangent);
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);
float fragDepth = -fragPos.z;
float occlusion = 0.0;
float Passes = 0.0f;
for (int i = 0; i < KERNEL_SIZE; i++) {
// Cover the complete radius distribution, even with a smaller sample budget.
int sampleIndex = i * 64 / KERNEL_SIZE;
vec3 samplePos = fragPos + (TBN * kernel.samples[sampleIndex].xyz) * ssao.radius;
vec4 offset = ssao.projection * vec4(samplePos, 1.0);
if (offset.w <= 0.0) continue;
offset.xyz /= offset.w;
offset.xyz = offset.xyz * 0.5 + 0.5;
vec2 sampleUV = vec2(offset.x, 1.0 - offset.y);
if (any(lessThan(sampleUV, vec2(0))) || any(greaterThan(sampleUV, vec2(1)))) continue;
vec3 sampleViewPos = texture(posSampler, sampleUV).xyz;
if (sampleViewPos.z >= 0.0) continue;
float sampleDepth = -sampleViewPos.z;
float depthDelta = abs(fragDepth - sampleDepth);
if (depthDelta > ssao.radius * 2.0) {
continue;
}
float rangeCheck = smoothstep(0.0, 1.0, ssao.radius / max(depthDelta, 0.0001));
float isOccluded = step(samplePos.z + ssao.bias, sampleViewPos.z);
occlusion += isOccluded * rangeCheck;
Passes += 1.0;
}
float Subtraction = 0.0;
if(Passes > 0){
Subtraction = (occlusion / Passes);
}
occlusion = 1.0 - Subtraction;
outAO = clamp(pow(occlusion, 3), 0.0, 1.0);
}

View file

@ -0,0 +1,34 @@
#version 450
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor;
layout(set = 0, binding = 0) uniform sampler2D sceneSampler;
layout(set = 0, binding = 1) uniform sampler2D reflectionSampler;
layout(set = 0, binding = 2) uniform sampler2D pbrSampler;
layout(set = 0, binding = 3) uniform sampler2D normalSampler;
vec4 reflectionAt(ivec2 pixel, ivec2 size) {
return texelFetch(reflectionSampler, clamp(pixel, ivec2(0), size - 1), 0);
}
void main() {
vec4 sceneColor = texture(sceneSampler, fragTexCoord);
vec4 pbr = texture(pbrSampler, fragTexCoord);
vec4 normal = texture(normalSampler, fragTexCoord);
float materialReflection = (pbr.a + normal.a - 1.05) * (1.0 - smoothstep(0.05, 0.7, pbr.g));
if (dot(normal.xyz, normal.xyz) < 0.001 || materialReflection <= 0.01) {
outColor = sceneColor;
return;
}
// The shared sampler is nearest-filtered. Upsample only premultiplied reflections.
ivec2 size = textureSize(reflectionSampler, 0);
vec2 pixel = fragTexCoord * vec2(size) - 0.5;
ivec2 base = ivec2(floor(pixel));
vec2 blend = fract(pixel);
vec4 reflection = mix(
mix(reflectionAt(base, size), reflectionAt(base + ivec2(1, 0), size), blend.x),
mix(reflectionAt(base + ivec2(0, 1), size), reflectionAt(base + ivec2(1, 1), size), blend.x), blend.y);
outColor = vec4(sceneColor.rgb * (1.0 - reflection.a) + reflection.rgb, sceneColor.a);
}

View file

@ -0,0 +1 @@
[]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -1,15 +0,0 @@
{
"ID": "Welsh040Alice",
"Meshes": [
{
"ID": "cube_0",
"MaterialID": "Welsh040Alice-mat-1",
"OffsetVertex": 0,
"VertexSize": 42720,
"OffsetIndex": 0,
"IndexSize": 14976
}
],
"VertexPath": "resources/models/Alice/Welsh040Alice.vtx",
"IndexPath": "resources/models/Alice/Welsh040Alice.idx"
}

View file

@ -1,4 +0,0 @@
# Made in Blockbench 5.1.4
newmtl m_43544ac2-29ce-cec1-9562-1ae6e86abc5a
map_Kd Alice040.png
newmtl none

File diff suppressed because it is too large Load diff

View file

@ -1,32 +0,0 @@
[
{
"ID": "Welsh040Alice-mat-0",
"TexturePath": "",
"DiffuseColour": {
"X": 0.6,
"Y": 0.6,
"Z": 0.6,
"W": 1.0
}
},
{
"ID": "Welsh040Alice-mat-1",
"TexturePath": "resources\\models\\Alice\\Alice040.png",
"DiffuseColour": {
"X": 0.6,
"Y": 0.6,
"Z": 0.6,
"W": 1.0
}
},
{
"ID": "Welsh040Alice-mat-2",
"TexturePath": "",
"DiffuseColour": {
"X": 0.6,
"Y": 0.6,
"Z": 0.6,
"W": 1.0
}
}
]

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show more