From 796a6fb860b16b5b682f6f46330bcb8d7744cc2c Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Thu, 9 May 2024 08:37:18 -0500 Subject: [PATCH] feat: add variable point & directional lights to metal/glsl shaders --- apps/app.c | 112 +++++----- extensions/pl_ref_renderer_ext.c | 79 ++++--- scripts/gen_build.py | 1 + shaders/glsl/defines.glsl | 43 ++++ shaders/glsl/gbuffer_common.glsl | 369 ------------------------------- shaders/glsl/lighting.frag | 186 ++++++---------- shaders/glsl/lighting.vert | 2 +- shaders/glsl/lights.glsl | 37 ++++ shaders/glsl/material.glsl | 106 +++++++++ shaders/glsl/math.glsl | 12 + shaders/glsl/primitive.frag | 217 +++++++++++++++++- shaders/glsl/primitive.vert | 64 +++++- shaders/glsl/transparent.frag | 282 ++++++++++++++++++++--- shaders/glsl/transparent.vert | 141 ++++++++++++ shaders/metal/lighting.metal | 199 +++++++++++------ shaders/metal/transparent.metal | 224 ++++++++++++------- 16 files changed, 1301 insertions(+), 773 deletions(-) create mode 100644 shaders/glsl/defines.glsl delete mode 100644 shaders/glsl/gbuffer_common.glsl create mode 100644 shaders/glsl/lights.glsl create mode 100644 shaders/glsl/material.glsl create mode 100644 shaders/glsl/math.glsl create mode 100644 shaders/glsl/transparent.vert diff --git a/apps/app.c b/apps/app.c index 6a1337c7..b4ace879 100644 --- a/apps/app.c +++ b/apps/app.c @@ -41,6 +41,8 @@ Index of this file: // misc #include "helper_windows.h" +#define LIGHT_COUNT 100 + //----------------------------------------------------------------------------- // [SECTION] structs //----------------------------------------------------------------------------- @@ -74,14 +76,12 @@ typedef struct plAppData_t bool bFreezeCullCamera; plEntity tCullCamera; plEntity tMainCamera; - plEntity tMainCamera2; + plEntity tSunlight; + plEntity atPointLight[LIGHT_COUNT]; // views uint32_t uSceneHandle0; - uint32_t uSceneHandle1; uint32_t uViewHandle0; - uint32_t uViewHandle1; - uint32_t uViewHandle2; // drawing plDrawLayer* ptDrawLayer; @@ -227,26 +227,39 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData) ptAppData->atSempahore[i] = gptDevice->create_semaphore(&gptRenderer->get_graphics()->tDevice, false); ptAppData->uSceneHandle0 = gptRenderer->create_scene(); - ptAppData->uSceneHandle1 = gptRenderer->create_scene(); - pl_begin_profile_sample("load environments"); - const plMat4 tTransform0 = pl_mat4_translate_xyz(2.0f, 1.0f, 0.0f); - gptRenderer->load_skybox_from_panorama(ptAppData->uSceneHandle0, "../data/glTF-Sample-Environments-main/field.jpg", 1024); - gptRenderer->load_skybox_from_panorama(ptAppData->uSceneHandle1, "../data/glTF-Sample-Environments-main/field.jpg", 1024); - pl_end_profile_sample(); + // pl_begin_profile_sample("load environments"); + // gptRenderer->load_skybox_from_panorama(ptAppData->uSceneHandle0, "../data/glTF-Sample-Environments-main/field.jpg", 1024); + // pl_end_profile_sample(); pl_begin_profile_sample("create scene views"); ptAppData->uViewHandle0 = gptRenderer->create_view(ptAppData->uSceneHandle0, (plVec2){ptIO->afMainViewportSize[0] , ptIO->afMainViewportSize[1]}); - ptAppData->uViewHandle1 = gptRenderer->create_view(ptAppData->uSceneHandle0, (plVec2){500.0f, 500.0f}); - ptAppData->uViewHandle2 = gptRenderer->create_view(ptAppData->uSceneHandle1, (plVec2){500.0f, 500.0f}); pl_end_profile_sample(); // temporary draw layer for submitting fullscreen quad of offscreen render ptAppData->ptDrawLayer = pl_request_layer(pl_get_draw_list(NULL), "draw layer"); - // create main camera plComponentLibrary* ptMainComponentLibrary = gptRenderer->get_component_library(ptAppData->uSceneHandle0); - ptAppData->tMainCamera = gptEcs->create_perspective_camera(ptMainComponentLibrary, "main camera", (plVec3){0, 0, 5.0f}, PL_PI_3, ptIO->afMainViewportSize[0] / ptIO->afMainViewportSize[1], 0.01f, 400.0f); + + // create lights + // ptAppData->tSunlight = gptEcs->create_directional_light(ptMainComponentLibrary, "sunlight", (plVec3){-1.0f, -1.0f, -1.0f}); + for(uint32_t i = 0; i < LIGHT_COUNT; i++) + { + + ptAppData->atPointLight[i] = gptEcs->create_point_light(ptMainComponentLibrary, "point", (plVec3){0}); + + plLightComponent* ptLight = gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_LIGHT, ptAppData->atPointLight[i]); + int iR = rand() % 256; + int iG = rand() % 256; + int iB = rand() % 256; + ptLight->tColor.r = (float)iR / 256.0f; + ptLight->tColor.g = (float)iG / 256.0f; + ptLight->tColor.b = (float)iB / 256.0f; + ptLight->fRange = 8.0f; + } + + // create main camera + ptAppData->tMainCamera = gptEcs->create_perspective_camera(ptMainComponentLibrary, "main camera", (plVec3){0, 2.0f, 5.0f}, PL_PI_3, ptIO->afMainViewportSize[0] / ptIO->afMainViewportSize[1], 0.01f, 400.0f); gptCamera->set_pitch_yaw(gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tMainCamera), 0.0f, PL_PI); gptCamera->update(gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tMainCamera)); @@ -255,29 +268,24 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData) gptCamera->set_pitch_yaw(gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tCullCamera), 0.0f, PL_PI); gptCamera->update(gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tCullCamera)); - plComponentLibrary* ptSecondaryComponentLibrary = gptRenderer->get_component_library(ptAppData->uSceneHandle1); - ptAppData->tMainCamera2 = gptEcs->create_perspective_camera(ptSecondaryComponentLibrary, "secondary camera", (plVec3){-3.265f, 2.967f, 0.311f}, PL_PI_3, 1.0f, 0.01f, 400.0f); - gptCamera->set_pitch_yaw(gptEcs->get_component(ptSecondaryComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tMainCamera2), -0.535f, 1.737f); - gptCamera->update(gptEcs->get_component(ptSecondaryComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tMainCamera2)); - // load models plModelLoaderData tLoaderData0 = {0}; pl_begin_profile_sample("load models 0"); - // gptModelLoader->load_gltf(ptMainComponentLibrary, "../data/glTF-Sample-Assets-main/Models/FlightHelmet/glTF/FlightHelmet.gltf", NULL, &tLoaderData0); - gptModelLoader->load_gltf(ptMainComponentLibrary, "../data/glTF-Sample-Assets-main/Models/CesiumMan/glTF/CesiumMan.gltf", NULL, &tLoaderData0); - // gptModelLoader->load_gltf(ptMainComponentLibrary, "../data/glTF-Sample-Assets-main/Models/DamagedHelmet/glTF/DamagedHelmet.gltf", NULL, &tLoaderData0); + // const plMat4 tTransform0 = pl_mat4_translate_xyz(2.0f, 1.0f, 0.0f); + // const plMat4 tTransform0 = pl_mat4_scale_xyz(2.0f, 2.0f, 2.0f); + + // const plMat4 atTransforms[] = { + // pl_mat4_translate_xyz(0.0f, 0.0f, 0.0f), + // }; + // gptModelLoader->load_gltf(ptMainComponentLibrary, "../data/terrain_gridlines.gltf", NULL, &tLoaderData0); + // gptModelLoader->load_gltf(ptMainComponentLibrary, "../data/town.gltf", &tTransform0, &tLoaderData0); gptModelLoader->load_gltf(ptMainComponentLibrary, "../data/glTF-Sample-Assets-main/Models/Sponza/glTF/Sponza.gltf", NULL, &tLoaderData0); - gptModelLoader->load_stl(ptMainComponentLibrary, "../data/pilotlight-assets-master/meshes/monkey.stl", (plVec4){1.0f, 1.0f, 0.0f, 0.80f}, &tTransform0, &tLoaderData0); - gptRenderer->add_drawable_objects_to_scene(ptAppData->uSceneHandle0, tLoaderData0.uOpaqueCount, tLoaderData0.atOpaqueObjects, tLoaderData0.uTransparentCount, tLoaderData0.atTransparentObjects); - gptModelLoader->free_data(&tLoaderData0); - pl_end_profile_sample(); - pl_begin_profile_sample("load models 1"); - gptModelLoader->load_gltf(ptSecondaryComponentLibrary, "../data/glTF-Sample-Assets-main/Models/CesiumMan/glTF/CesiumMan.gltf", NULL, &tLoaderData0); - gptModelLoader->load_stl(ptSecondaryComponentLibrary, "../data/pilotlight-assets-master/meshes/monkey.stl", (plVec4){1.0f, 0.0f, 0.0f, 0.80f}, &tTransform0, &tLoaderData0); - gptRenderer->add_drawable_objects_to_scene(ptAppData->uSceneHandle1, tLoaderData0.uOpaqueCount, tLoaderData0.atOpaqueObjects, tLoaderData0.uTransparentCount, tLoaderData0.atTransparentObjects); + // for(uint32_t i = 0; i < 1; i++) + // gptModelLoader->load_gltf(ptMainComponentLibrary, "../data/oaktree.gltf", &atTransforms[i], &tLoaderData0); + gptRenderer->add_drawable_objects_to_scene(ptAppData->uSceneHandle0, tLoaderData0.uOpaqueCount, tLoaderData0.atOpaqueObjects, tLoaderData0.uTransparentCount, tLoaderData0.atTransparentObjects); gptModelLoader->free_data(&tLoaderData0); pl_end_profile_sample(); @@ -285,10 +293,6 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData) gptRenderer->finalize_scene(ptAppData->uSceneHandle0); pl_end_profile_sample(); - pl_begin_profile_sample("finalize scene 1"); - gptRenderer->finalize_scene(ptAppData->uSceneHandle1); - pl_end_profile_sample(); - pl_end_profile_frame(); // temporary for profiling loading procedures @@ -392,10 +396,29 @@ pl_app_update(plAppData* ptAppData) // handle input plComponentLibrary* ptMainComponentLibrary = gptRenderer->get_component_library(ptAppData->uSceneHandle0); - plComponentLibrary* ptSecondaryComponentLibrary = gptRenderer->get_component_library(ptAppData->uSceneHandle1); + + // float fXSeed = sinf((float)ptIO->dTime); + // float fYSeed = cosf((float)ptIO->dTime); + // float fZSeed = sinf((float)ptIO->dTime + PL_PI_4); + for(uint32_t i = 0; i < LIGHT_COUNT; i++) + { + plLightComponent* ptLight = gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_LIGHT, ptAppData->atPointLight[i]); + + // srand(i); + int iX = rand() % 101; + + // ptLight->tPosition.x += (float)iX * 0.01f; + // ptLight->tPosition.y += (float)iY * 0.01f; + // ptLight->tPosition.z += (float)iZ * 0.01f; + + // ptLight->tPosition = pl_clamp_vec3((plVec3){-10.0f, 0.0f, -5.0f}, ptLight->tPosition, (plVec3){10.0f, 20.0f, 5.0f}); + + ptLight->tPosition.x = (float)i * 0.025f * sinf((float)ptIO->dTime + i * 0.25f); + ptLight->tPosition.y = (float)(i % 5) + 0.25f + sinf((float)ptIO->dTime+ i * 0.25f); + ptLight->tPosition.z = (float)i * 0.025f * cosf((float)ptIO->dTime + i * 0.25f); + } plCameraComponent* ptCamera = gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tMainCamera); - plCameraComponent* ptCamera2 = gptEcs->get_component(ptSecondaryComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tMainCamera2); plCameraComponent* ptCullCamera = gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tCullCamera); static const float fCameraTravelSpeed = 4.0f; @@ -424,12 +447,10 @@ pl_app_update(plAppData* ptAppData) } gptCamera->update(ptCamera); - gptCamera->update(ptCamera2); gptCamera->update(ptCullCamera); // run ecs system gptRenderer->run_ecs(ptAppData->uSceneHandle0); - gptRenderer->run_ecs(ptAppData->uSceneHandle1); // new ui frame pl_new_frame(); @@ -453,7 +474,6 @@ pl_app_update(plAppData* ptAppData) plCommandBuffer tCommandBuffer = gptGfx->begin_command_recording(ptGraphics, &tBeginInfo0); gptRenderer->update_skin_textures(tCommandBuffer, ptAppData->uSceneHandle0); - gptRenderer->update_skin_textures(tCommandBuffer, ptAppData->uSceneHandle1); gptGfx->end_command_recording(ptGraphics, &tCommandBuffer); const plSubmitInfo tSubmitInfo0 = { @@ -471,7 +491,6 @@ pl_app_update(plAppData* ptAppData) tCommandBuffer = gptGfx->begin_command_recording(ptGraphics, &tBeginInfo00); gptRenderer->perform_skinning(tCommandBuffer, ptAppData->uSceneHandle0); - gptRenderer->perform_skinning(tCommandBuffer, ptAppData->uSceneHandle1); gptGfx->end_command_recording(ptGraphics, &tCommandBuffer); const plSubmitInfo tSubmitInfo00 = { @@ -490,15 +509,6 @@ pl_app_update(plAppData* ptAppData) .ptCullCamera = ptAppData->bFrustumCulling ? ptCamera : NULL }; - plViewOptions tViewOptions2 = { - .bShowAllBoundingBoxes = ptAppData->bDrawAllBoundingBoxes, - .bShowVisibleBoundingBoxes = ptAppData->bDrawVisibleBoundingBoxes, - .bShowOrigin = false, - .bCullStats = false, - .ptViewCamera = ptCamera2, - .ptCullCamera = ptCamera2 - }; - if(ptAppData->bFrustumCulling && ptAppData->bFreezeCullCamera) tViewOptions.ptCullCamera = ptCullCamera; @@ -512,8 +522,6 @@ pl_app_update(plAppData* ptAppData) }; tCommandBuffer = gptGfx->begin_command_recording(ptGraphics, &tBeginInfo1); gptRenderer->render_scene(tCommandBuffer, ptAppData->uSceneHandle0, ptAppData->uViewHandle0, tViewOptions); - gptRenderer->render_scene(tCommandBuffer, ptAppData->uSceneHandle0, ptAppData->uViewHandle1, tViewOptions2); - gptRenderer->render_scene(tCommandBuffer, ptAppData->uSceneHandle1, ptAppData->uViewHandle2, tViewOptions2); gptGfx->end_command_recording(ptGraphics, &tCommandBuffer); @@ -623,8 +631,6 @@ pl_app_update(plAppData* ptAppData) // add full screen quad for offscreen render pl_add_image(ptAppData->ptDrawLayer, gptRenderer->get_view_texture_id(ptAppData->uSceneHandle0, ptAppData->uViewHandle0), (plVec2){0}, (plVec2){ptIO->afMainViewportSize[0], ptIO->afMainViewportSize[1]}); - pl_add_image(ptAppData->ptDrawLayer, gptRenderer->get_view_texture_id(ptAppData->uSceneHandle0, ptAppData->uViewHandle1), (plVec2){0}, (plVec2){500.0f, 500.0f}); - pl_add_image(ptAppData->ptDrawLayer, gptRenderer->get_view_texture_id(ptAppData->uSceneHandle1, ptAppData->uViewHandle2), (plVec2){0.0f, 500.0f}, (plVec2){500.0f, 1000.0f}); pl_submit_layer(ptAppData->ptDrawLayer); plRenderEncoder tEncoder = gptGfx->begin_render_pass(ptGraphics, &tCommandBuffer, ptGraphics->tMainRenderPass); diff --git a/extensions/pl_ref_renderer_ext.c b/extensions/pl_ref_renderer_ext.c index 4d0ebed9..ba4eaa3f 100644 --- a/extensions/pl_ref_renderer_ext.c +++ b/extensions/pl_ref_renderer_ext.c @@ -486,7 +486,7 @@ pl_refr_initialize(plWindow* ptWindow) // create template shaders - int aiConstantData[5] = {0}; + int aiConstantData[6] = {0, 0, 0, 0, 0, 1}; plShaderDescription tOpaqueShaderDescription = { @@ -591,7 +591,7 @@ pl_refr_initialize(plWindow* ptWindow) .pcVertexShader = "../shaders/metal/transparent.metal", .pcPixelShader = "../shaders/metal/transparent.metal", #else - .pcVertexShader = "primitive.vert.spv", + .pcVertexShader = "transparent.vert.spv", .pcPixelShader = "transparent.frag.spv", #endif .tGraphicsState = { @@ -610,7 +610,7 @@ pl_refr_initialize(plWindow* ptWindow) .uByteStride = sizeof(float) * 3, .atAttributes = { {.uByteOffset = 0, .tFormat = PL_FORMAT_R32G32B32_FLOAT}} }, - .uConstantCount = 5, + .uConstantCount = 6, .pTempConstantData = aiConstantData, .atBlendStates = { pl__get_blend_state(PL_BLEND_MODE_ALPHA) @@ -618,7 +618,7 @@ pl_refr_initialize(plWindow* ptWindow) .uBlendStateCount = 1, .tRenderPassLayout = gptData->tRenderPassLayout, .uSubpassIndex = 2, - .uBindGroupLayoutCount = 2, + .uBindGroupLayoutCount = 3, .atBindGroupLayouts = { { .uBufferBindingCount = 3, @@ -651,6 +651,16 @@ pl_refr_initialize(plWindow* ptWindow) {.uSlot = 7, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL, .tType = PL_TEXTURE_BINDING_TYPE_SAMPLED, .uDescriptorCount = 1} } }, + { + .uBufferBindingCount = 1, + .aBufferBindings = { + { + .tType = PL_BUFFER_BINDING_TYPE_UNIFORM, + .uSlot = 0, + .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL + } + }, + }, { .uTextureBindingCount = 12, .atTextureBindings = { @@ -2201,6 +2211,8 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) &ptScene->tOpaqueHashmap, &ptScene->tTransparentHashmap }; + + const plLightComponent* sbtLights = ptScene->tComponentLibrary.tLightComponentManager.pComponents; for(uint32_t uDrawableBatchIndex = 0; uDrawableBatchIndex < 2; uDrawableBatchIndex++) { @@ -2243,16 +2255,20 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) } // choose shader variant - int aiConstantData0[5] = { + int aiConstantData0[] = { (int)ptMesh->ulVertexStreamMask, iDataStride, iTextureMappingFlags, PL_INFO_MATERIAL_METALLICROUGHNESS, - iSceneWideRenderingFlags + iSceneWideRenderingFlags, + pl_sb_size(sbtLights) }; plGraphicsState tVariantTemp = atTemplateVariants[uDrawableBatchIndex]; + if(ptMaterial->tFlags & PL_MATERIAL_FLAG_DOUBLE_SIDED) + tVariantTemp.ulCullMode = PL_CULL_MODE_NONE; + const plShaderVariant tVariant = { .pTempConstantData = aiConstantData0, .tGraphicsState = tVariantTemp @@ -2347,7 +2363,6 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) } // create lighting shader - const plLightComponent* sbtLights = ptScene->tComponentLibrary.tLightComponentManager.pComponents; int aiLightingConstantData[] = {iSceneWideRenderingFlags, pl_sb_size(sbtLights)}; plShaderDescription tLightingShaderDesc = { #ifdef PL_METAL_BACKEND @@ -2437,7 +2452,7 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL } }, - }, + } } }; for(uint32_t i = 0; i < tLightingShaderDesc.uConstantCount; i++) @@ -2988,6 +3003,29 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint plMat4 tModel; } plOutlineDynamicData; + + plBindGroupLayout tOutlineBindGroupLayout0 = { + .uBufferBindingCount = 2, + .aBufferBindings = { + { .uSlot = 0, .tType = PL_BUFFER_BINDING_TYPE_UNIFORM, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL}, + { .uSlot = 1, .tType = PL_BUFFER_BINDING_TYPE_STORAGE, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL} + }, + }; + plBindGroupHandle tOutlineGlobalBG = gptDevice->get_temporary_bind_group(ptDevice, &tOutlineBindGroupLayout0, "temporary outline global bind group"); + + const plBindGroupUpdateBufferData atOutlineBufferData[] = + { + { .uSlot = 0, .tBuffer = ptView->atGlobalBuffers[ptGraphics->uCurrentFrameIndex], .szBufferRange = sizeof(BindGroup_0)}, + { .uSlot = 1, .tBuffer = ptScene->tStorageBuffer, .szBufferRange = sizeof(plVec4) * pl_sb_size(ptScene->sbtVertexDataBuffer)}, + + }; + + plBindGroupUpdateData tOutlineBGData0 = { + .uBufferCount = 2, + .atBuffers = atOutlineBufferData, + }; + gptDevice->update_bind_group(&ptGraphics->tDevice, tOutlineGlobalBG, &tOutlineBGData0); + const plVec4 tOutlineColor = (plVec4){(float)sin(pl_get_io()->dTime * 3.0) * 0.25f + 0.75f, 0.0f, 0.0f, 1.0f}; const plVec4 tOutlineColor2 = (plVec4){0.0f, tOutlineColor.r, 0.0f, 1.0f}; for(uint32_t i = 0; i < uOutlineDrawableCount; i++) @@ -3016,6 +3054,7 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint .uIndexBuffer = tDrawable.uIndexCount == 0 ? UINT32_MAX : ptScene->tIndexBuffer.uIndex, .uIndexOffset = tDrawable.uIndexOffset, .uTriangleCount = tDrawable.uIndexCount == 0 ? tDrawable.uVertexCount / 3 : tDrawable.uIndexCount / 3, + .uBindGroup0 = tOutlineGlobalBG.uIndex, .uBindGroup1 = UINT32_MAX, .uBindGroup2 = UINT32_MAX, .uDynamicBufferOffset = tDynamicBinding.uByteOffset, @@ -3023,30 +3062,6 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint .uInstanceCount = 1 }); } - - plBindGroupLayout tOutlineBindGroupLayout0 = { - .uBufferBindingCount = 2, - .aBufferBindings = { - { .uSlot = 0, .tType = PL_BUFFER_BINDING_TYPE_UNIFORM, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL}, - { .uSlot = 1, .tType = PL_BUFFER_BINDING_TYPE_STORAGE, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL} - }, - }; - plBindGroupHandle tOutlineGlobalBG = gptDevice->get_temporary_bind_group(ptDevice, &tOutlineBindGroupLayout0, "temporary outline global bind group"); - - const plBindGroupUpdateBufferData atOutlineBufferData[] = - { - { .uSlot = 0, .tBuffer = ptView->atGlobalBuffers[ptGraphics->uCurrentFrameIndex], .szBufferRange = sizeof(BindGroup_0)}, - { .uSlot = 1, .tBuffer = ptScene->tStorageBuffer, .szBufferRange = sizeof(plVec4) * pl_sb_size(ptScene->sbtVertexDataBuffer)}, - - }; - - plBindGroupUpdateData tOutlineBGData0 = { - .uBufferCount = 2, - .atBuffers = atOutlineBufferData, - }; - gptDevice->update_bind_group(&ptGraphics->tDevice, tOutlineGlobalBG, &tOutlineBGData0); - - tArea.uBindGroup0 = tOutlineGlobalBG.uIndex; gptGfx->draw_stream(&tEncoder, 1, &tArea); } diff --git a/scripts/gen_build.py b/scripts/gen_build.py index 6135afe4..eb39126a 100644 --- a/scripts/gen_build.py +++ b/scripts/gen_build.py @@ -149,6 +149,7 @@ def add_plugin_to_metal_app(name, reloadable, objc = False, binary_name = None): "skybox.vert", "primitive.frag", "primitive.vert", + "transparent.vert", "transparent.frag", "lighting.vert", "lighting.frag", diff --git a/shaders/glsl/defines.glsl b/shaders/glsl/defines.glsl new file mode 100644 index 00000000..d8c0e3ff --- /dev/null +++ b/shaders/glsl/defines.glsl @@ -0,0 +1,43 @@ + +// math +const float M_PI = 3.141592653589793; +const float GAMMA = 2.2; +const float INV_GAMMA = 1.0 / GAMMA; + +// iMeshVariantFlags +const int PL_MESH_FORMAT_FLAG_NONE = 0; +const int PL_MESH_FORMAT_FLAG_HAS_POSITION = 1 << 0; +const int PL_MESH_FORMAT_FLAG_HAS_NORMAL = 1 << 1; +const int PL_MESH_FORMAT_FLAG_HAS_TANGENT = 1 << 2; +const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0 = 1 << 3; +const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1 = 1 << 4; +const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2 = 1 << 5; +const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3 = 1 << 6; +const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4 = 1 << 7; +const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5 = 1 << 8; +const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6 = 1 << 9; +const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7 = 1 << 10; +const int PL_MESH_FORMAT_FLAG_HAS_COLOR_0 = 1 << 11; +const int PL_MESH_FORMAT_FLAG_HAS_COLOR_1 = 1 << 12; +const int PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 = 1 << 13; +const int PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 = 1 << 14; +const int PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 = 1 << 15; +const int PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 = 1 << 16; + +// iTextureMappingFlags +const int PL_HAS_BASE_COLOR_MAP = 1 << 0; +const int PL_HAS_NORMAL_MAP = 1 << 1; +const int PL_HAS_EMISSIVE_MAP = 1 << 2; +const int PL_HAS_OCCLUSION_MAP = 1 << 3; +const int PL_HAS_METALLIC_ROUGHNESS_MAP = 1 << 4; + +// iMaterialFlags +const int PL_MATERIAL_METALLICROUGHNESS = 1 << 0; + +// iRenderingFlags +const int PL_RENDERING_FLAG_USE_PUNCTUAL = 1 << 0; +const int PL_RENDERING_FLAG_USE_IBL = 1 << 1; + +// lights +const int PL_LIGHT_TYPE_DIRECTIONAL = 0; +const int PL_LIGHT_TYPE_POINT = 1; \ No newline at end of file diff --git a/shaders/glsl/gbuffer_common.glsl b/shaders/glsl/gbuffer_common.glsl deleted file mode 100644 index e053d801..00000000 --- a/shaders/glsl/gbuffer_common.glsl +++ /dev/null @@ -1,369 +0,0 @@ - -//----------------------------------------------------------------------------- -// [SECTION] structs -//----------------------------------------------------------------------------- - -struct tMaterial -{ - // Metallic Roughness - int u_MipCount; - float u_MetallicFactor; - float u_RoughnessFactor; - //-------------------------- ( 16 bytes ) - - vec4 u_BaseColorFactor; - //-------------------------- ( 16 bytes ) - - // Clearcoat - float u_ClearcoatFactor; - float u_ClearcoatRoughnessFactor; - vec2 _unused1; - //-------------------------- ( 16 bytes ) - - // Specular - vec3 u_KHR_materials_specular_specularColorFactor; - float u_KHR_materials_specular_specularFactor; - //-------------------------- ( 16 bytes ) - - // Iridescence - float u_IridescenceFactor; - float u_IridescenceIor; - float u_IridescenceThicknessMinimum; - float u_IridescenceThicknessMaximum; - //-------------------------- ( 16 bytes ) - - // Emissive Strength - vec3 u_EmissiveFactor; - float u_EmissiveStrength; - //-------------------------- ( 16 bytes ) - - - // // IOR - float u_Ior; - - // Alpha mode - float u_AlphaCutoff; - float u_OcclusionStrength; - float u_Unuses; - //-------------------------- ( 16 bytes ) - - int BaseColorUVSet; - int NormalUVSet; - int EmissiveUVSet; - int OcclusionUVSet; - //-------------------------- ( 16 bytes ) - - int MetallicRoughnessUVSet; - int ClearcoatUVSet; - int ClearcoatRoughnessUVSet; - int ClearcoatNormalUVSet; - //-------------------------- ( 16 bytes ) - - int SpecularUVSet; - int SpecularColorUVSet; - int IridescenceUVSet; - int IridescenceThicknessUVSet; - //-------------------------- ( 16 bytes ) -}; - -//----------------------------------------------------------------------------- -// [SECTION] bind group 0 -//----------------------------------------------------------------------------- - -layout(set = 0, binding = 0) uniform _plGlobalInfo -{ - vec4 tCameraPos; - mat4 tCameraView; - mat4 tCameraProjection; - mat4 tCameraViewProjection; -} tGlobalInfo; - -layout(std140, set = 0, binding = 1) readonly buffer _tVertexBuffer -{ - vec4 atVertexData[]; -} tVertexBuffer; - -layout(set = 0, binding = 2) readonly buffer plMaterialInfo -{ - tMaterial atMaterials[]; -} tMaterialInfo; - -layout(set = 0, binding = 3) uniform sampler tDefaultSampler; -layout(set = 0, binding = 4) uniform sampler tEnvSampler; -layout (set = 0, binding = 5) uniform textureCube u_LambertianEnvSampler; -layout (set = 0, binding = 6) uniform textureCube u_GGXEnvSampler; -layout (set = 0, binding = 7) uniform texture2D u_GGXLUT; - -//----------------------------------------------------------------------------- -// [SECTION] bind group 1 -//----------------------------------------------------------------------------- - -layout(set = 1, binding = 0) uniform texture2D tBaseColorTexture; -layout(set = 1, binding = 1) uniform texture2D tNormalTexture; -layout(set = 1, binding = 2) uniform texture2D tEmissiveTexture; -layout(set = 1, binding = 3) uniform texture2D tMetallicRoughnessTexture; -layout(set = 1, binding = 4) uniform texture2D tOcclusionTexture; -layout(set = 1, binding = 5) uniform texture2D tClearcoatTexture; -layout(set = 1, binding = 6) uniform texture2D tClearcoatRoughnessTexture; -layout(set = 1, binding = 7) uniform texture2D tClearcoatNormalTexture; -layout(set = 1, binding = 8) uniform texture2D tIridescenceTexture; -layout(set = 1, binding = 9) uniform texture2D tIridescenceThicknessTexture; -layout(set = 1, binding = 10) uniform texture2D tSpecularTexture; -layout(set = 1, binding = 11) uniform texture2D tSpecularColorTexture; - -//----------------------------------------------------------------------------- -// [SECTION] dynamic bind group -//----------------------------------------------------------------------------- - -layout(set = 2, binding = 0) uniform _plObjectInfo -{ - int iDataOffset; - int iVertexOffset; - int iMaterialIndex; - mat4 tModel; -} tObjectInfo; - -//----------------------------------------------------------------------------- -// [SECTION] specialication constants -//----------------------------------------------------------------------------- - -layout(constant_id = 0) const int iMeshVariantFlags = 0; -layout(constant_id = 1) const int iDataStride = 0; -layout(constant_id = 2) const int iTextureMappingFlags = 0; -layout(constant_id = 3) const int iMaterialFlags = 0; -layout(constant_id = 4) const int iRenderingFlags = 0; - -//----------------------------------------------------------------------------- -// [SECTION] defines -//----------------------------------------------------------------------------- - -// iMeshVariantFlags -const int PL_MESH_FORMAT_FLAG_NONE = 0; -const int PL_MESH_FORMAT_FLAG_HAS_POSITION = 1 << 0; -const int PL_MESH_FORMAT_FLAG_HAS_NORMAL = 1 << 1; -const int PL_MESH_FORMAT_FLAG_HAS_TANGENT = 1 << 2; -const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0 = 1 << 3; -const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1 = 1 << 4; -const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2 = 1 << 5; -const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3 = 1 << 6; -const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4 = 1 << 7; -const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5 = 1 << 8; -const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6 = 1 << 9; -const int PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7 = 1 << 10; -const int PL_MESH_FORMAT_FLAG_HAS_COLOR_0 = 1 << 11; -const int PL_MESH_FORMAT_FLAG_HAS_COLOR_1 = 1 << 12; -const int PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 = 1 << 13; -const int PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 = 1 << 14; -const int PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 = 1 << 15; -const int PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 = 1 << 16; - -// iTextureMappingFlags -const int PL_HAS_BASE_COLOR_MAP = 1 << 0; -const int PL_HAS_NORMAL_MAP = 1 << 1; -const int PL_HAS_EMISSIVE_MAP = 1 << 2; -const int PL_HAS_OCCLUSION_MAP = 1 << 3; -const int PL_HAS_METALLIC_ROUGHNESS_MAP = 1 << 4; - -// iMaterialFlags -const int PL_MATERIAL_METALLICROUGHNESS = 1 << 0; - -// iRenderingFlags -const int PL_RENDERING_FLAG_USE_PUNCTUAL = 1 << 0; -const int PL_RENDERING_FLAG_USE_IBL = 1 << 1; - -//----------------------------------------------------------------------------- -// [SECTION] helpers -//----------------------------------------------------------------------------- - -#ifdef PL_FRAGMENT_SHADER -struct NormalInfo { - vec3 ng; // Geometry normal - vec3 t; // Geometry tangent - vec3 b; // Geometry bitangent - vec3 n; // Shading normal - vec3 ntex; // Normal from texture, scaling is accounted for. -}; - -NormalInfo pl_get_normal_info(int iUVSet) -{ - vec2 UV = tShaderIn.tUV[iUVSet]; - vec2 uv_dx = dFdx(UV); - vec2 uv_dy = dFdy(UV); - - if (length(uv_dx) <= 1e-2) { - uv_dx = vec2(1.0, 0.0); - } - - if (length(uv_dy) <= 1e-2) { - uv_dy = vec2(0.0, 1.0); - } - - vec3 t_ = (uv_dy.t * dFdx(tShaderIn.tPosition) - uv_dx.t * dFdy(tShaderIn.tPosition)) / - (uv_dx.s * uv_dy.t - uv_dy.s * uv_dx.t); - - vec3 n, t, b, ng; - - // Compute geometrical TBN: - if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_NORMAL)) - { - - if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TANGENT)) - { - // Trivial TBN computation, present as vertex attribute. - // Normalize eigenvectors as matrix is linearly interpolated. - t = normalize(tShaderIn.tTBN[0]); - b = normalize(tShaderIn.tTBN[1]); - ng = normalize(tShaderIn.tTBN[2]); - } - else - { - // Normals are either present as vertex attributes or approximated. - ng = normalize(tShaderIn.tWorldNormal); - t = normalize(t_ - ng * dot(ng, t_)); - b = cross(ng, t); - } - } - else - { - ng = normalize(cross(dFdx(tShaderIn.tPosition), dFdy(tShaderIn.tPosition))); - t = normalize(t_ - ng * dot(ng, t_)); - b = cross(ng, t); - } - - - // For a back-facing surface, the tangential basis vectors are negated. - if (gl_FrontFacing == false) - { - t *= -1.0; - b *= -1.0; - ng *= -1.0; - } - - // Compute normals: - NormalInfo info; - info.ng = ng; - if(bool(iTextureMappingFlags & PL_HAS_NORMAL_MAP)) - { - info.ntex = texture(sampler2D(tNormalTexture, tDefaultSampler), UV).rgb * 2.0 - vec3(1.0); - // info.ntex *= vec3(0.2, 0.2, 1.0); - // info.ntex *= vec3(u_NormalScale, u_NormalScale, 1.0); - info.ntex = normalize(info.ntex); - info.n = normalize(mat3(t, b, ng) * info.ntex); - } - else - { - info.n = ng; - } - info.t = t; - info.b = b; - return info; -} -#endif - -//----------------------------------------------------------------------------- -// [SECTION] normal info -//----------------------------------------------------------------------------- - -const float M_PI = 3.141592653589793; - -vec4 getBaseColor(vec4 u_ColorFactor, int iUVSet) -{ - vec4 baseColor = vec4(1); - - // if(bool(MATERIAL_SPECULARGLOSSINESS)) - // { - // baseColor = u_DiffuseFactor; - // } - // else if(bool(MATERIAL_METALLICROUGHNESS)) - if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS)) - { - // baseColor = u_BaseColorFactor; - baseColor = u_ColorFactor; - } - - // if(bool(MATERIAL_SPECULARGLOSSINESS) && bool(HAS_DIFFUSE_MAP)) - // { - // // baseColor *= texture(u_DiffuseSampler, getDiffuseUV()); - // baseColor *= texture(u_DiffuseSampler, tShaderIn.tUV); - // } - // else if(bool(MATERIAL_METALLICROUGHNESS) && bool(HAS_BASE_COLOR_MAP)) - if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS) && bool(iTextureMappingFlags & PL_HAS_BASE_COLOR_MAP)) - { - baseColor *= texture(sampler2D(tBaseColorTexture, tDefaultSampler), tShaderIn.tUV[iUVSet]); - } - return baseColor * tShaderIn.tColor; -} - -//----------------------------------------------------------------------------- -// [SECTION] material info -//----------------------------------------------------------------------------- - -struct MaterialInfo -{ - float ior; - float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) - vec3 f0; // full reflectance color (n incidence angle) - - float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) - vec3 c_diff; - - vec3 f90; // reflectance color at grazing angle - float metallic; - - vec3 baseColor; - - float sheenRoughnessFactor; - vec3 sheenColorFactor; - - vec3 clearcoatF0; - vec3 clearcoatF90; - float clearcoatFactor; - vec3 clearcoatNormal; - float clearcoatRoughness; - - // KHR_materials_specular - float specularWeight; // product of specularFactor and specularTexture.a - - float transmissionFactor; - - float thickness; - vec3 attenuationColor; - float attenuationDistance; - - // KHR_materials_iridescence - float iridescenceFactor; - float iridescenceIor; - float iridescenceThickness; - - // KHR_materials_anisotropy - vec3 anisotropicT; - vec3 anisotropicB; - float anisotropyStrength; -}; - -MaterialInfo getMetallicRoughnessInfo(MaterialInfo info, float u_MetallicFactor, float u_RoughnessFactor, int UVSet) -{ - info.metallic = u_MetallicFactor; - info.perceptualRoughness = u_RoughnessFactor; - - if(bool(iTextureMappingFlags & PL_HAS_METALLIC_ROUGHNESS_MAP)) - { - // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. - // This layout intentionally reserves the 'r' channel for (optional) occlusion map data - vec4 mrSample = texture(sampler2D(tMetallicRoughnessTexture, tDefaultSampler), tShaderIn.tUV[UVSet]); - info.perceptualRoughness *= mrSample.g; - info.metallic *= mrSample.b; - } - - // Achromatic f0 based on IOR. - info.c_diff = mix(info.baseColor.rgb, vec3(0), info.metallic); - info.f0 = mix(info.f0, info.baseColor.rgb, info.metallic); - return info; -} - -MaterialInfo getIorInfo(MaterialInfo info, float u_Ior) -{ - info.f0 = vec3(pow(( u_Ior - 1.0) / (u_Ior + 1.0), 2.0)); - info.ior = u_Ior; - return info; -} diff --git a/shaders/glsl/lighting.frag b/shaders/glsl/lighting.frag index 2bee466f..194147c5 100644 --- a/shaders/glsl/lighting.frag +++ b/shaders/glsl/lighting.frag @@ -1,85 +1,21 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable -const float M_PI = 3.141592653589793; +#include "defines.glsl" +#include "material.glsl" +#include "lights.glsl" +#include "math.glsl" -struct tMaterial -{ - // Metallic Roughness - int u_MipCount; - float u_MetallicFactor; - float u_RoughnessFactor; - //-------------------------- ( 16 bytes ) - - vec4 u_BaseColorFactor; - //-------------------------- ( 16 bytes ) - - // // Specular Glossiness - // vec3 u_SpecularFactor; - // vec4 u_DiffuseFactor; - // float u_GlossinessFactor; - - // // Sheen - // float u_SheenRoughnessFactor; - // vec3 u_SheenColorFactor; - - // Clearcoat - float u_ClearcoatFactor; - float u_ClearcoatRoughnessFactor; - vec2 _unused1; - //-------------------------- ( 16 bytes ) - - // Specular - vec3 u_KHR_materials_specular_specularColorFactor; - float u_KHR_materials_specular_specularFactor; - //-------------------------- ( 16 bytes ) - - // // Transmission - // float u_TransmissionFactor; - - // // Volume - // float u_ThicknessFactor; - // vec3 u_AttenuationColor; - // float u_AttenuationDistance; - - // Iridescence - float u_IridescenceFactor; - float u_IridescenceIor; - float u_IridescenceThicknessMinimum; - float u_IridescenceThicknessMaximum; - //-------------------------- ( 16 bytes ) - - // Emissive Strength - vec3 u_EmissiveFactor; - float u_EmissiveStrength; - //-------------------------- ( 16 bytes ) - - - // // IOR - float u_Ior; - - // // Anisotropy - // vec3 u_Anisotropy; - - // Alpha mode - float u_AlphaCutoff; - float u_OcclusionStrength; - float u_Unuses; - //-------------------------- ( 16 bytes ) - - int BaseColorUVSet; - int NormalUVSet; - int EmissiveUVSet; - int OcclusionUVSet; - int MetallicRoughnessUVSet; - int ClearcoatUVSet; - int ClearcoatRoughnessUVSet; - int ClearcoatNormalUVSet; - int SpecularUVSet; - int SpecularColorUVSet; - int IridescenceUVSet; - int IridescenceThicknessUVSet; -}; +//----------------------------------------------------------------------------- +// [SECTION] specialication constants +//----------------------------------------------------------------------------- + +layout(constant_id = 0) const int iRenderingFlags = 0; +layout(constant_id = 1) const int iLightCount = 1; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 0 +//----------------------------------------------------------------------------- layout(set = 0, binding = 0) uniform _plGlobalInfo { @@ -104,6 +40,10 @@ layout (set = 0, binding = 5) uniform textureCube u_LambertianEnvSampler; layout (set = 0, binding = 6) uniform textureCube u_GGXEnvSampler; layout (set = 0, binding = 7) uniform texture2D u_GGXLUT; +//----------------------------------------------------------------------------- +// [SECTION] bind group 1 +//----------------------------------------------------------------------------- + layout(input_attachment_index = 1, set = 1, binding = 0) uniform subpassInput tAlbedoSampler; layout(input_attachment_index = 2, set = 1, binding = 1) uniform subpassInput tNormalTexture; layout(input_attachment_index = 3, set = 1, binding = 2) uniform subpassInput tPositionSampler; @@ -111,26 +51,28 @@ layout(input_attachment_index = 4, set = 1, binding = 3) uniform subpassInput t layout(input_attachment_index = 5, set = 1, binding = 4) uniform subpassInput tAOMetalRoughnessTexture; layout(input_attachment_index = 0, set = 1, binding = 5) uniform subpassInput tDepthSampler; -layout(set = 2, binding = 0) uniform _plObjectInfo +//----------------------------------------------------------------------------- +// [SECTION] bind group 2 +//----------------------------------------------------------------------------- + +layout(set = 2, binding = 0) uniform _plLightInfo +{ + plLightData atData[iLightCount]; +} tLightInfo; + +//----------------------------------------------------------------------------- +// [SECTION] dynamic bind group +//----------------------------------------------------------------------------- + +layout(set = 3, binding = 0) uniform _plObjectInfo { int iDataOffset; int iVertexOffset; } tObjectInfo; -// iRenderingFlags -const int PL_RENDERING_FLAG_USE_PUNCTUAL = 1 << 0; -const int PL_RENDERING_FLAG_USE_IBL = 1 << 1; -layout(constant_id = 0) const int iRenderingFlags = 0; - -const float GAMMA = 2.2; -const float INV_GAMMA = 1.0 / GAMMA; - -// linear to sRGB approximation -// see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html -vec3 linearTosRGB(vec3 color) -{ - return pow(color, vec3(INV_GAMMA)); -} +//----------------------------------------------------------------------------- +// [SECTION] input & output +//----------------------------------------------------------------------------- layout(location = 0) out vec4 outColor; @@ -139,11 +81,6 @@ layout(location = 0) in struct plShaderIn { vec2 tUV; } tShaderIn; -float clampedDot(vec3 x, vec3 y) -{ - return clamp(dot(x, y), 0.0, 1.0); -} - //----------------------------------------------------------------------------- // [SECTION] BRDF //----------------------------------------------------------------------------- @@ -312,7 +249,6 @@ vec3 getIBLRadianceGGX(vec3 n, vec3 v, float roughness, vec3 F0, float specularW return specularWeight * specularLight * FssEss; } - // specularWeight is introduced with KHR_materials_specular vec3 getIBLRadianceLambertian(vec3 n, vec3 v, float roughness, vec3 diffuseColor, vec3 F0, float specularWeight) { @@ -341,15 +277,11 @@ vec3 getIBLRadianceLambertian(vec3 n, vec3 v, float roughness, vec3 diffuseColor void main() { - vec3 tSunlightColor = vec3(1.0, 1.0, 1.0); - float lightIntensity = 1.0; - vec4 tBaseColor = subpassLoad(tAlbedoSampler); vec4 tPosition = subpassLoad(tPositionSampler); float specularWeight = tPosition.a; vec3 n = subpassLoad(tNormalTexture).xyz; - vec3 tSunLightDirection = vec3(-1.0, -1.0, -1.0); vec4 AORoughnessMetalnessData = subpassLoad(tAOMetalRoughnessTexture); const float fPerceptualRoughness = AORoughnessMetalnessData.b; @@ -392,25 +324,37 @@ void main() if(bool(iRenderingFlags & PL_RENDERING_FLAG_USE_PUNCTUAL)) { - vec3 pointToLight = -tSunLightDirection; - - // BSTF - vec3 l = normalize(pointToLight); // Direction from surface point to light - vec3 h = normalize(l + v); // Direction of the vector between l and v, called halfway vector - float NdotL = clampedDot(n, l); - float NdotV = clampedDot(n, v); - float NdotH = clampedDot(n, h); - float LdotH = clampedDot(l, h); - float VdotH = clampedDot(v, h); - if (NdotL > 0.0 || NdotV > 0.0) + + for(int i = 0; i < iLightCount; i++) { - // Calculation of analytical light - // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB - // vec3 intensity = getLighIntensity(light, pointToLight); - - vec3 intensity = tSunlightColor * lightIntensity; - f_diffuse += intensity * NdotL * BRDF_lambertian(f0, f90, c_diff, specularWeight, VdotH); - f_specular += intensity * NdotL * BRDF_specularGGX(f0, f90, fAlphaRoughness, specularWeight, VdotH, NdotL, NdotV, NdotH); + plLightData tLightData = tLightInfo.atData[i]; + + vec3 pointToLight; + + if(tLightData.iType != PL_LIGHT_TYPE_DIRECTIONAL) + { + pointToLight = tLightData.tPosition - tPosition.xyz; + } + else + { + pointToLight = -tLightData.tDirection; + } + + // BSTF + vec3 l = normalize(pointToLight); // Direction from surface point to light + vec3 h = normalize(l + v); // Direction of the vector between l and v, called halfway vector + float NdotL = clampedDot(n, l); + float NdotV = clampedDot(n, v); + float NdotH = clampedDot(n, h); + float LdotH = clampedDot(l, h); + float VdotH = clampedDot(v, h); + if (NdotL > 0.0 || NdotV > 0.0) + { + vec3 intensity = getLighIntensity(tLightData, pointToLight); + f_diffuse += intensity * NdotL * BRDF_lambertian(f0, f90, c_diff, specularWeight, VdotH); + f_specular += intensity * NdotL * BRDF_specularGGX(f0, f90, fAlphaRoughness, specularWeight, VdotH, NdotL, NdotV, NdotH); + } + } } diff --git a/shaders/glsl/lighting.vert b/shaders/glsl/lighting.vert index 8deaf455..5e4b7c85 100644 --- a/shaders/glsl/lighting.vert +++ b/shaders/glsl/lighting.vert @@ -103,7 +103,7 @@ layout (set = 0, binding = 5) uniform textureCube u_LambertianEnvSampler; layout (set = 0, binding = 6) uniform textureCube u_GGXEnvSampler; layout (set = 0, binding = 7) uniform texture2D u_GGXLUT; -layout(set = 2, binding = 0) uniform _plObjectInfo +layout(set = 3, binding = 0) uniform _plObjectInfo { int iDataOffset; int iVertexOffset; diff --git a/shaders/glsl/lights.glsl b/shaders/glsl/lights.glsl new file mode 100644 index 00000000..f409129b --- /dev/null +++ b/shaders/glsl/lights.glsl @@ -0,0 +1,37 @@ + +struct plLightData +{ + vec3 tPosition; + float fIntensity; + + vec3 tDirection; + int iType; + + vec3 tColor; + float fRange; +}; + +float +getRangeAttenuation(float range, float dist) +{ + if (range <= 0.0) + { + // negative range means unlimited + return 1.0 / pow(dist, 2.0); + } + return max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / pow(dist, 2.0); +} + +vec3 +getLighIntensity(plLightData light, vec3 pointToLight) +{ + float rangeAttenuation = 1.0; + + if (light.iType != PL_LIGHT_TYPE_DIRECTIONAL) + { + rangeAttenuation = getRangeAttenuation(light.fRange, length(pointToLight)); + } + + + return rangeAttenuation * light.fIntensity * light.tColor; +} \ No newline at end of file diff --git a/shaders/glsl/material.glsl b/shaders/glsl/material.glsl new file mode 100644 index 00000000..236fef6c --- /dev/null +++ b/shaders/glsl/material.glsl @@ -0,0 +1,106 @@ + +struct tMaterial +{ + // Metallic Roughness + int u_MipCount; + float u_MetallicFactor; + float u_RoughnessFactor; + //-------------------------- ( 16 bytes ) + + vec4 u_BaseColorFactor; + //-------------------------- ( 16 bytes ) + + // Clearcoat + float u_ClearcoatFactor; + float u_ClearcoatRoughnessFactor; + vec2 _unused1; + //-------------------------- ( 16 bytes ) + + // Specular + vec3 u_KHR_materials_specular_specularColorFactor; + float u_KHR_materials_specular_specularFactor; + //-------------------------- ( 16 bytes ) + + // Iridescence + float u_IridescenceFactor; + float u_IridescenceIor; + float u_IridescenceThicknessMinimum; + float u_IridescenceThicknessMaximum; + //-------------------------- ( 16 bytes ) + + // Emissive Strength + vec3 u_EmissiveFactor; + float u_EmissiveStrength; + //-------------------------- ( 16 bytes ) + + + // // IOR + float u_Ior; + + // Alpha mode + float u_AlphaCutoff; + float u_OcclusionStrength; + float u_Unuses; + //-------------------------- ( 16 bytes ) + + int BaseColorUVSet; + int NormalUVSet; + int EmissiveUVSet; + int OcclusionUVSet; + //-------------------------- ( 16 bytes ) + + int MetallicRoughnessUVSet; + int ClearcoatUVSet; + int ClearcoatRoughnessUVSet; + int ClearcoatNormalUVSet; + //-------------------------- ( 16 bytes ) + + int SpecularUVSet; + int SpecularColorUVSet; + int IridescenceUVSet; + int IridescenceThicknessUVSet; + //-------------------------- ( 16 bytes ) +}; + +struct MaterialInfo +{ + float ior; + float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) + vec3 f0; // full reflectance color (n incidence angle) + + float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) + vec3 c_diff; + + vec3 f90; // reflectance color at grazing angle + float metallic; + + vec3 baseColor; + + float sheenRoughnessFactor; + vec3 sheenColorFactor; + + vec3 clearcoatF0; + vec3 clearcoatF90; + float clearcoatFactor; + vec3 clearcoatNormal; + float clearcoatRoughness; + + // KHR_materials_specular + float specularWeight; // product of specularFactor and specularTexture.a + + float transmissionFactor; + + float thickness; + vec3 attenuationColor; + float attenuationDistance; + + // KHR_materials_iridescence + float iridescenceFactor; + float iridescenceIor; + float iridescenceThickness; + + // KHR_materials_anisotropy + vec3 anisotropicT; + vec3 anisotropicB; + float anisotropyStrength; +}; \ No newline at end of file diff --git a/shaders/glsl/math.glsl b/shaders/glsl/math.glsl new file mode 100644 index 00000000..a2f98f87 --- /dev/null +++ b/shaders/glsl/math.glsl @@ -0,0 +1,12 @@ + +float +clampedDot(vec3 x, vec3 y) +{ + return clamp(dot(x, y), 0.0, 1.0); +} + +vec3 +linearTosRGB(vec3 color) +{ + return pow(color, vec3(INV_GAMMA)); +} \ No newline at end of file diff --git a/shaders/glsl/primitive.frag b/shaders/glsl/primitive.frag index b0306980..b3bfc90b 100644 --- a/shaders/glsl/primitive.frag +++ b/shaders/glsl/primitive.frag @@ -1,6 +1,80 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable +#include "defines.glsl" +#include "material.glsl" + +//----------------------------------------------------------------------------- +// [SECTION] specialication constants +//----------------------------------------------------------------------------- + +layout(constant_id = 0) const int iMeshVariantFlags = 0; +layout(constant_id = 1) const int iDataStride = 0; +layout(constant_id = 2) const int iTextureMappingFlags = 0; +layout(constant_id = 3) const int iMaterialFlags = 0; +layout(constant_id = 4) const int iRenderingFlags = 0; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 0 +//----------------------------------------------------------------------------- + +layout(set = 0, binding = 0) uniform _plGlobalInfo +{ + vec4 tCameraPos; + mat4 tCameraView; + mat4 tCameraProjection; + mat4 tCameraViewProjection; +} tGlobalInfo; + +layout(std140, set = 0, binding = 1) readonly buffer _tVertexBuffer +{ + vec4 atVertexData[]; +} tVertexBuffer; + +layout(set = 0, binding = 2) readonly buffer plMaterialInfo +{ + tMaterial atMaterials[]; +} tMaterialInfo; + +layout(set = 0, binding = 3) uniform sampler tDefaultSampler; +layout(set = 0, binding = 4) uniform sampler tEnvSampler; +layout (set = 0, binding = 5) uniform textureCube u_LambertianEnvSampler; +layout (set = 0, binding = 6) uniform textureCube u_GGXEnvSampler; +layout (set = 0, binding = 7) uniform texture2D u_GGXLUT; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 1 +//----------------------------------------------------------------------------- + +layout(set = 1, binding = 0) uniform texture2D tBaseColorTexture; +layout(set = 1, binding = 1) uniform texture2D tNormalTexture; +layout(set = 1, binding = 2) uniform texture2D tEmissiveTexture; +layout(set = 1, binding = 3) uniform texture2D tMetallicRoughnessTexture; +layout(set = 1, binding = 4) uniform texture2D tOcclusionTexture; +layout(set = 1, binding = 5) uniform texture2D tClearcoatTexture; +layout(set = 1, binding = 6) uniform texture2D tClearcoatRoughnessTexture; +layout(set = 1, binding = 7) uniform texture2D tClearcoatNormalTexture; +layout(set = 1, binding = 8) uniform texture2D tIridescenceTexture; +layout(set = 1, binding = 9) uniform texture2D tIridescenceThicknessTexture; +layout(set = 1, binding = 10) uniform texture2D tSpecularTexture; +layout(set = 1, binding = 11) uniform texture2D tSpecularColorTexture; + +//----------------------------------------------------------------------------- +// [SECTION] dynamic bind group +//----------------------------------------------------------------------------- + +layout(set = 2, binding = 0) uniform _plObjectInfo +{ + int iDataOffset; + int iVertexOffset; + int iMaterialIndex; + mat4 tModel; +} tObjectInfo; + +//----------------------------------------------------------------------------- +// [SECTION] input & output +//----------------------------------------------------------------------------- + layout(location = 0) out vec4 outAlbedo; layout(location = 1) out vec4 outNormal; layout(location = 2) out vec4 outPosition; @@ -17,11 +91,146 @@ layout(location = 0) in struct plShaderIn { mat3 tTBN; } tShaderIn; -#define PL_FRAGMENT_SHADER -#include "gbuffer_common.glsl" +//----------------------------------------------------------------------------- +// [SECTION] helpers +//----------------------------------------------------------------------------- + +struct NormalInfo { + vec3 ng; // Geometry normal + vec3 t; // Geometry tangent + vec3 b; // Geometry bitangent + vec3 n; // Shading normal + vec3 ntex; // Normal from texture, scaling is accounted for. +}; + +NormalInfo pl_get_normal_info(int iUVSet) +{ + vec2 UV = tShaderIn.tUV[iUVSet]; + vec2 uv_dx = dFdx(UV); + vec2 uv_dy = dFdy(UV); + + if (length(uv_dx) <= 1e-2) { + uv_dx = vec2(1.0, 0.0); + } + + if (length(uv_dy) <= 1e-2) { + uv_dy = vec2(0.0, 1.0); + } + + vec3 t_ = (uv_dy.t * dFdx(tShaderIn.tPosition) - uv_dx.t * dFdy(tShaderIn.tPosition)) / + (uv_dx.s * uv_dy.t - uv_dy.s * uv_dx.t); + + vec3 n, t, b, ng; + + // Compute geometrical TBN: + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_NORMAL)) + { + + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TANGENT)) + { + // Trivial TBN computation, present as vertex attribute. + // Normalize eigenvectors as matrix is linearly interpolated. + t = normalize(tShaderIn.tTBN[0]); + b = normalize(tShaderIn.tTBN[1]); + ng = normalize(tShaderIn.tTBN[2]); + } + else + { + // Normals are either present as vertex attributes or approximated. + ng = normalize(tShaderIn.tWorldNormal); + t = normalize(t_ - ng * dot(ng, t_)); + b = cross(ng, t); + } + } + else + { + ng = normalize(cross(dFdx(tShaderIn.tPosition), dFdy(tShaderIn.tPosition))); + t = normalize(t_ - ng * dot(ng, t_)); + b = cross(ng, t); + } + + + // For a back-facing surface, the tangential basis vectors are negated. + if (gl_FrontFacing == false) + { + t *= -1.0; + b *= -1.0; + ng *= -1.0; + } + + // Compute normals: + NormalInfo info; + info.ng = ng; + if(bool(iTextureMappingFlags & PL_HAS_NORMAL_MAP)) + { + info.ntex = texture(sampler2D(tNormalTexture, tDefaultSampler), UV).rgb * 2.0 - vec3(1.0); + // info.ntex *= vec3(0.2, 0.2, 1.0); + // info.ntex *= vec3(u_NormalScale, u_NormalScale, 1.0); + info.ntex = normalize(info.ntex); + info.n = normalize(mat3(t, b, ng) * info.ntex); + } + else + { + info.n = ng; + } + info.t = t; + info.b = b; + return info; +} + +vec4 getBaseColor(vec4 u_ColorFactor, int iUVSet) +{ + vec4 baseColor = vec4(1); + + // if(bool(MATERIAL_SPECULARGLOSSINESS)) + // { + // baseColor = u_DiffuseFactor; + // } + // else if(bool(MATERIAL_METALLICROUGHNESS)) + if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS)) + { + // baseColor = u_BaseColorFactor; + baseColor = u_ColorFactor; + } + + // if(bool(MATERIAL_SPECULARGLOSSINESS) && bool(HAS_DIFFUSE_MAP)) + // { + // // baseColor *= texture(u_DiffuseSampler, getDiffuseUV()); + // baseColor *= texture(u_DiffuseSampler, tShaderIn.tUV); + // } + // else if(bool(MATERIAL_METALLICROUGHNESS) && bool(HAS_BASE_COLOR_MAP)) + if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS) && bool(iTextureMappingFlags & PL_HAS_BASE_COLOR_MAP)) + { + baseColor *= texture(sampler2D(tBaseColorTexture, tDefaultSampler), tShaderIn.tUV[iUVSet]); + } + return baseColor * tShaderIn.tColor; +} + +MaterialInfo getMetallicRoughnessInfo(MaterialInfo info, float u_MetallicFactor, float u_RoughnessFactor, int UVSet) +{ + info.metallic = u_MetallicFactor; + info.perceptualRoughness = u_RoughnessFactor; + + if(bool(iTextureMappingFlags & PL_HAS_METALLIC_ROUGHNESS_MAP)) + { + // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. + // This layout intentionally reserves the 'r' channel for (optional) occlusion map data + vec4 mrSample = texture(sampler2D(tMetallicRoughnessTexture, tDefaultSampler), tShaderIn.tUV[UVSet]); + info.perceptualRoughness *= mrSample.g; + info.metallic *= mrSample.b; + } + + // Achromatic f0 based on IOR. + info.c_diff = mix(info.baseColor.rgb, vec3(0), info.metallic); + info.f0 = mix(info.f0, info.baseColor.rgb, info.metallic); + return info; +} + +//----------------------------------------------------------------------------- +// [SECTION] entry +//----------------------------------------------------------------------------- -void -main() +void main() { tMaterial material = tMaterialInfo.atMaterials[tObjectInfo.iMaterialIndex]; vec4 tBaseColor = getBaseColor(material.u_BaseColorFactor, material.BaseColorUVSet); diff --git a/shaders/glsl/primitive.vert b/shaders/glsl/primitive.vert index 8c42cb34..5e32711e 100644 --- a/shaders/glsl/primitive.vert +++ b/shaders/glsl/primitive.vert @@ -1,6 +1,63 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable +#include "defines.glsl" +#include "material.glsl" + +//----------------------------------------------------------------------------- +// [SECTION] specialication constants +//----------------------------------------------------------------------------- + +layout(constant_id = 0) const int iMeshVariantFlags = 0; +layout(constant_id = 1) const int iDataStride = 0; +layout(constant_id = 2) const int iTextureMappingFlags = 0; +layout(constant_id = 3) const int iMaterialFlags = 0; +layout(constant_id = 4) const int iRenderingFlags = 0; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 0 +//----------------------------------------------------------------------------- + +layout(set = 0, binding = 0) uniform _plGlobalInfo +{ + vec4 tCameraPos; + mat4 tCameraView; + mat4 tCameraProjection; + mat4 tCameraViewProjection; +} tGlobalInfo; + +layout(std140, set = 0, binding = 1) readonly buffer _tVertexBuffer +{ + vec4 atVertexData[]; +} tVertexBuffer; + +layout(set = 0, binding = 2) readonly buffer plMaterialInfo +{ + tMaterial atMaterials[]; +} tMaterialInfo; + +layout(set = 0, binding = 3) uniform sampler tDefaultSampler; +layout(set = 0, binding = 4) uniform sampler tEnvSampler; +layout (set = 0, binding = 5) uniform textureCube u_LambertianEnvSampler; +layout (set = 0, binding = 6) uniform textureCube u_GGXEnvSampler; +layout (set = 0, binding = 7) uniform texture2D u_GGXLUT; + +//----------------------------------------------------------------------------- +// [SECTION] dynamic bind group +//----------------------------------------------------------------------------- + +layout(set = 2, binding = 0) uniform _plObjectInfo +{ + int iDataOffset; + int iVertexOffset; + int iMaterialIndex; + mat4 tModel; +} tObjectInfo; + +//----------------------------------------------------------------------------- +// [SECTION] input & output +//----------------------------------------------------------------------------- + // input layout(location = 0) in vec3 inPos; @@ -14,10 +71,11 @@ layout(location = 0) out struct plShaderOut { mat3 tTBN; } tShaderIn; -#include "gbuffer_common.glsl" +//----------------------------------------------------------------------------- +// [SECTION] entry +//----------------------------------------------------------------------------- -void -main() +void main() { vec4 inPosition = vec4(inPos, 1.0); diff --git a/shaders/glsl/transparent.frag b/shaders/glsl/transparent.frag index 7e92bdef..d189d1fd 100644 --- a/shaders/glsl/transparent.frag +++ b/shaders/glsl/transparent.frag @@ -1,17 +1,91 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable +#include "defines.glsl" +#include "material.glsl" +#include "lights.glsl" +#include "math.glsl" +//----------------------------------------------------------------------------- +// [SECTION] specialication constants +//----------------------------------------------------------------------------- + +layout(constant_id = 0) const int iMeshVariantFlags = 0; +layout(constant_id = 1) const int iDataStride = 0; +layout(constant_id = 2) const int iTextureMappingFlags = 0; +layout(constant_id = 3) const int iMaterialFlags = 0; +layout(constant_id = 4) const int iRenderingFlags = 0; +layout(constant_id = 5) const int iLightCount = 1; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 0 +//----------------------------------------------------------------------------- -const float GAMMA = 2.2; -const float INV_GAMMA = 1.0 / GAMMA; +layout(set = 0, binding = 0) uniform _plGlobalInfo +{ + vec4 tCameraPos; + mat4 tCameraView; + mat4 tCameraProjection; + mat4 tCameraViewProjection; +} tGlobalInfo; -// linear to sRGB approximation -// see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html -vec3 linearTosRGB(vec3 color) +layout(std140, set = 0, binding = 1) readonly buffer _tVertexBuffer { - return pow(color, vec3(INV_GAMMA)); -} + vec4 atVertexData[]; +} tVertexBuffer; + +layout(set = 0, binding = 2) readonly buffer plMaterialInfo +{ + tMaterial atMaterials[]; +} tMaterialInfo; + +layout(set = 0, binding = 3) uniform sampler tDefaultSampler; +layout(set = 0, binding = 4) uniform sampler tEnvSampler; +layout (set = 0, binding = 5) uniform textureCube u_LambertianEnvSampler; +layout (set = 0, binding = 6) uniform textureCube u_GGXEnvSampler; +layout (set = 0, binding = 7) uniform texture2D u_GGXLUT; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 1 +//----------------------------------------------------------------------------- + +layout(set = 1, binding = 0) uniform _plLightInfo +{ + plLightData atData[iLightCount]; +} tLightInfo; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 2 +//----------------------------------------------------------------------------- + +layout(set = 2, binding = 0) uniform texture2D tBaseColorTexture; +layout(set = 2, binding = 1) uniform texture2D tNormalTexture; +layout(set = 2, binding = 2) uniform texture2D tEmissiveTexture; +layout(set = 2, binding = 3) uniform texture2D tMetallicRoughnessTexture; +layout(set = 2, binding = 4) uniform texture2D tOcclusionTexture; +layout(set = 2, binding = 5) uniform texture2D tClearcoatTexture; +layout(set = 2, binding = 6) uniform texture2D tClearcoatRoughnessTexture; +layout(set = 2, binding = 7) uniform texture2D tClearcoatNormalTexture; +layout(set = 2, binding = 8) uniform texture2D tIridescenceTexture; +layout(set = 2, binding = 9) uniform texture2D tIridescenceThicknessTexture; +layout(set = 2, binding = 10) uniform texture2D tSpecularTexture; +layout(set = 2, binding = 11) uniform texture2D tSpecularColorTexture; + +//----------------------------------------------------------------------------- +// [SECTION] dynamic bind group +//----------------------------------------------------------------------------- + +layout(set = 3, binding = 0) uniform _plObjectInfo +{ + int iDataOffset; + int iVertexOffset; + int iMaterialIndex; + mat4 tModel; +} tObjectInfo; + +//----------------------------------------------------------------------------- +// [SECTION] input & output +//----------------------------------------------------------------------------- layout(location = 0) out vec4 outColor; @@ -25,12 +99,139 @@ layout(location = 0) in struct plShaderIn { mat3 tTBN; } tShaderIn; -#define PL_FRAGMENT_SHADER -#include "gbuffer_common.glsl" +//----------------------------------------------------------------------------- +// [SECTION] helpers +//----------------------------------------------------------------------------- + +struct NormalInfo { + vec3 ng; // Geometry normal + vec3 t; // Geometry tangent + vec3 b; // Geometry bitangent + vec3 n; // Shading normal + vec3 ntex; // Normal from texture, scaling is accounted for. +}; + +NormalInfo pl_get_normal_info(int iUVSet) +{ + vec2 UV = tShaderIn.tUV[iUVSet]; + vec2 uv_dx = dFdx(UV); + vec2 uv_dy = dFdy(UV); + + if (length(uv_dx) <= 1e-2) { + uv_dx = vec2(1.0, 0.0); + } + + if (length(uv_dy) <= 1e-2) { + uv_dy = vec2(0.0, 1.0); + } + + vec3 t_ = (uv_dy.t * dFdx(tShaderIn.tPosition) - uv_dx.t * dFdy(tShaderIn.tPosition)) / + (uv_dx.s * uv_dy.t - uv_dy.s * uv_dx.t); + + vec3 n, t, b, ng; + + // Compute geometrical TBN: + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_NORMAL)) + { + + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TANGENT)) + { + // Trivial TBN computation, present as vertex attribute. + // Normalize eigenvectors as matrix is linearly interpolated. + t = normalize(tShaderIn.tTBN[0]); + b = normalize(tShaderIn.tTBN[1]); + ng = normalize(tShaderIn.tTBN[2]); + } + else + { + // Normals are either present as vertex attributes or approximated. + ng = normalize(tShaderIn.tWorldNormal); + t = normalize(t_ - ng * dot(ng, t_)); + b = cross(ng, t); + } + } + else + { + ng = normalize(cross(dFdx(tShaderIn.tPosition), dFdy(tShaderIn.tPosition))); + t = normalize(t_ - ng * dot(ng, t_)); + b = cross(ng, t); + } + + + // For a back-facing surface, the tangential basis vectors are negated. + if (gl_FrontFacing == false) + { + t *= -1.0; + b *= -1.0; + ng *= -1.0; + } + + // Compute normals: + NormalInfo info; + info.ng = ng; + if(bool(iTextureMappingFlags & PL_HAS_NORMAL_MAP)) + { + info.ntex = texture(sampler2D(tNormalTexture, tDefaultSampler), UV).rgb * 2.0 - vec3(1.0); + // info.ntex *= vec3(0.2, 0.2, 1.0); + // info.ntex *= vec3(u_NormalScale, u_NormalScale, 1.0); + info.ntex = normalize(info.ntex); + info.n = normalize(mat3(t, b, ng) * info.ntex); + } + else + { + info.n = ng; + } + info.t = t; + info.b = b; + return info; +} + +vec4 getBaseColor(vec4 u_ColorFactor, int iUVSet) +{ + vec4 baseColor = vec4(1); + + // if(bool(MATERIAL_SPECULARGLOSSINESS)) + // { + // baseColor = u_DiffuseFactor; + // } + // else if(bool(MATERIAL_METALLICROUGHNESS)) + if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS)) + { + // baseColor = u_BaseColorFactor; + baseColor = u_ColorFactor; + } + + // if(bool(MATERIAL_SPECULARGLOSSINESS) && bool(HAS_DIFFUSE_MAP)) + // { + // // baseColor *= texture(u_DiffuseSampler, getDiffuseUV()); + // baseColor *= texture(u_DiffuseSampler, tShaderIn.tUV); + // } + // else if(bool(MATERIAL_METALLICROUGHNESS) && bool(HAS_BASE_COLOR_MAP)) + if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS) && bool(iTextureMappingFlags & PL_HAS_BASE_COLOR_MAP)) + { + baseColor *= texture(sampler2D(tBaseColorTexture, tDefaultSampler), tShaderIn.tUV[iUVSet]); + } + return baseColor * tShaderIn.tColor; +} -float clampedDot(vec3 x, vec3 y) +MaterialInfo getMetallicRoughnessInfo(MaterialInfo info, float u_MetallicFactor, float u_RoughnessFactor, int UVSet) { - return clamp(dot(x, y), 0.0, 1.0); + info.metallic = u_MetallicFactor; + info.perceptualRoughness = u_RoughnessFactor; + + if(bool(iTextureMappingFlags & PL_HAS_METALLIC_ROUGHNESS_MAP)) + { + // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. + // This layout intentionally reserves the 'r' channel for (optional) occlusion map data + vec4 mrSample = texture(sampler2D(tMetallicRoughnessTexture, tDefaultSampler), tShaderIn.tUV[UVSet]); + info.perceptualRoughness *= mrSample.g; + info.metallic *= mrSample.b; + } + + // Achromatic f0 based on IOR. + info.c_diff = mix(info.baseColor.rgb, vec3(0), info.metallic); + info.f0 = mix(info.f0, info.baseColor.rgb, info.metallic); + return info; } //----------------------------------------------------------------------------- @@ -227,14 +428,12 @@ vec3 getIBLRadianceLambertian(vec3 n, vec3 v, float roughness, vec3 diffuseColor return (FmsEms + k_D) * irradiance; } -void -main() -{ +//----------------------------------------------------------------------------- +// [SECTION] entry +//----------------------------------------------------------------------------- - // settings - vec3 tSunlightColor = vec3(1.0, 1.0, 1.0); - float lightIntensity = 1.0; - vec3 tSunLightDirection = vec3(-1.0, -1.0, -1.0); +void main() +{ tMaterial material = tMaterialInfo.atMaterials[tObjectInfo.iMaterialIndex]; vec4 tBaseColor = getBaseColor(material.u_BaseColorFactor, material.BaseColorUVSet); @@ -325,25 +524,36 @@ main() if(bool(iRenderingFlags & PL_RENDERING_FLAG_USE_PUNCTUAL)) { - vec3 pointToLight = -tSunLightDirection; - - // BSTF - vec3 l = normalize(pointToLight); // Direction from surface point to light - vec3 h = normalize(l + v); // Direction of the vector between l and v, called halfway vector - float NdotL = clampedDot(n, l); - float NdotV = clampedDot(n, v); - float NdotH = clampedDot(n, h); - float LdotH = clampedDot(l, h); - float VdotH = clampedDot(v, h); - if (NdotL > 0.0 || NdotV > 0.0) + for(int i = 0; i < iLightCount; i++) { - // Calculation of analytical light - // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB - // vec3 intensity = getLighIntensity(light, pointToLight); - - vec3 intensity = tSunlightColor * lightIntensity; - f_diffuse += intensity * NdotL * BRDF_lambertian(materialInfo.f0, materialInfo.f90, materialInfo.c_diff, materialInfo.specularWeight, VdotH); - f_specular += intensity * NdotL * BRDF_specularGGX(materialInfo.f0, materialInfo.f90, materialInfo.alphaRoughness, materialInfo.specularWeight, VdotH, NdotL, NdotV, NdotH); + plLightData tLightData = tLightInfo.atData[i]; + + vec3 pointToLight; + + if(tLightData.iType != PL_LIGHT_TYPE_DIRECTIONAL) + { + pointToLight = tLightData.tPosition - tShaderIn.tPosition.xyz; + } + else + { + pointToLight = -tLightData.tDirection; + } + + // BSTF + vec3 l = normalize(pointToLight); // Direction from surface point to light + vec3 h = normalize(l + v); // Direction of the vector between l and v, called halfway vector + float NdotL = clampedDot(n, l); + float NdotV = clampedDot(n, v); + float NdotH = clampedDot(n, h); + float LdotH = clampedDot(l, h); + float VdotH = clampedDot(v, h); + if (NdotL > 0.0 || NdotV > 0.0) + { + vec3 intensity = getLighIntensity(tLightData, pointToLight); + f_diffuse += intensity * NdotL * BRDF_lambertian(materialInfo.f0, materialInfo.f90, materialInfo.c_diff, materialInfo.specularWeight, VdotH); + f_specular += intensity * NdotL * BRDF_specularGGX(materialInfo.f0, materialInfo.f90, materialInfo.alphaRoughness, materialInfo.specularWeight, VdotH, NdotL, NdotV, NdotH); + } + } } diff --git a/shaders/glsl/transparent.vert b/shaders/glsl/transparent.vert new file mode 100644 index 00000000..58ad3bdf --- /dev/null +++ b/shaders/glsl/transparent.vert @@ -0,0 +1,141 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +#include "defines.glsl" +#include "material.glsl" + +//----------------------------------------------------------------------------- +// [SECTION] specialication constants +//----------------------------------------------------------------------------- + +layout(constant_id = 0) const int iMeshVariantFlags = 0; +layout(constant_id = 1) const int iDataStride = 0; +layout(constant_id = 2) const int iTextureMappingFlags = 0; +layout(constant_id = 3) const int iMaterialFlags = 0; +layout(constant_id = 4) const int iRenderingFlags = 0; +layout(constant_id = 5) const int iLightCount = 1; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 0 +//----------------------------------------------------------------------------- + +layout(set = 0, binding = 0) uniform _plGlobalInfo +{ + vec4 tCameraPos; + mat4 tCameraView; + mat4 tCameraProjection; + mat4 tCameraViewProjection; +} tGlobalInfo; + +layout(std140, set = 0, binding = 1) readonly buffer _tVertexBuffer +{ + vec4 atVertexData[]; +} tVertexBuffer; + +layout(set = 0, binding = 2) readonly buffer plMaterialInfo +{ + tMaterial atMaterials[]; +} tMaterialInfo; + +layout(set = 0, binding = 3) uniform sampler tDefaultSampler; +layout(set = 0, binding = 4) uniform sampler tEnvSampler; +layout (set = 0, binding = 5) uniform textureCube u_LambertianEnvSampler; +layout (set = 0, binding = 6) uniform textureCube u_GGXEnvSampler; +layout (set = 0, binding = 7) uniform texture2D u_GGXLUT; + +//----------------------------------------------------------------------------- +// [SECTION] dynamic bind group +//----------------------------------------------------------------------------- + +layout(set = 3, binding = 0) uniform _plObjectInfo +{ + int iDataOffset; + int iVertexOffset; + int iMaterialIndex; + mat4 tModel; +} tObjectInfo; + +//----------------------------------------------------------------------------- +// [SECTION] input & output +//----------------------------------------------------------------------------- + +// input +layout(location = 0) in vec3 inPos; + +// output +layout(location = 0) out struct plShaderOut { + vec3 tPosition; + vec4 tWorldPosition; + vec2 tUV[8]; + vec4 tColor; + vec3 tWorldNormal; + mat3 tTBN; +} tShaderIn; + +//----------------------------------------------------------------------------- +// [SECTION] entry +//----------------------------------------------------------------------------- + +void main() +{ + + vec4 inPosition = vec4(inPos, 1.0); + vec3 inNormal = vec3(0.0, 0.0, 0.0); + vec4 inTangent = vec4(0.0, 0.0, 0.0, 0.0); + vec2 inTexCoord0 = vec2(0.0, 0.0); + vec2 inTexCoord1 = vec2(0.0, 0.0); + vec2 inTexCoord2 = vec2(0.0, 0.0); + vec2 inTexCoord3 = vec2(0.0, 0.0); + vec2 inTexCoord4 = vec2(0.0, 0.0); + vec2 inTexCoord5 = vec2(0.0, 0.0); + vec2 inTexCoord6 = vec2(0.0, 0.0); + vec2 inTexCoord7 = vec2(0.0, 0.0); + vec4 inColor0 = vec4(1.0, 1.0, 1.0, 1.0); + vec4 inColor1 = vec4(0.0, 0.0, 0.0, 0.0); + int iCurrentAttribute = 0; + + // offset = offset into current mesh + offset into global buffer + const uint iVertexDataOffset = iDataStride * (gl_VertexIndex - tObjectInfo.iVertexOffset) + tObjectInfo.iDataOffset; + + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_POSITION)) { inPosition.xyz = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute].xyz; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_NORMAL)) { inNormal = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute].xyz; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TANGENT)) { inTangent = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute]; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0)){ inTexCoord0 = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1)){ inTexCoord1 = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2)){ inTexCoord2 = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3)){ inTexCoord3 = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4)){ inTexCoord4 = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5)){ inTexCoord5 = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6)){ inTexCoord6 = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7)){ inTexCoord7 = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_COLOR_0)) { inColor0 = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute]; iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_COLOR_1)) { inColor1 = tVertexBuffer.atVertexData[iVertexDataOffset + iCurrentAttribute]; iCurrentAttribute++;} + + tShaderIn.tWorldNormal = mat3(tObjectInfo.tModel) * normalize(inNormal); + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_NORMAL)) + { + + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TANGENT)) + { + vec3 tangent = normalize(inTangent.xyz); + vec3 WorldTangent = mat3(tObjectInfo.tModel) * tangent; + vec3 WorldBitangent = cross(normalize(inNormal), tangent) * inTangent.w; + WorldBitangent = mat3(tObjectInfo.tModel) * WorldBitangent; + tShaderIn.tTBN = mat3(WorldTangent, WorldBitangent, tShaderIn.tWorldNormal); + } + } + + vec4 pos = tObjectInfo.tModel * inPosition; + tShaderIn.tPosition = pos.xyz / pos.w; + gl_Position = tGlobalInfo.tCameraViewProjection * pos; + tShaderIn.tUV[0] = inTexCoord0; + tShaderIn.tUV[1] = inTexCoord1; + tShaderIn.tUV[2] = inTexCoord2; + tShaderIn.tUV[3] = inTexCoord3; + tShaderIn.tUV[4] = inTexCoord4; + tShaderIn.tUV[5] = inTexCoord5; + tShaderIn.tUV[6] = inTexCoord6; + tShaderIn.tUV[7] = inTexCoord7; + tShaderIn.tWorldPosition = gl_Position / gl_Position.w; + tShaderIn.tColor = inColor0; +} \ No newline at end of file diff --git a/shaders/metal/lighting.metal b/shaders/metal/lighting.metal index 805b982c..50b5440f 100644 --- a/shaders/metal/lighting.metal +++ b/shaders/metal/lighting.metal @@ -8,6 +8,7 @@ using namespace metal; //----------------------------------------------------------------------------- constant int iRenderingFlags [[ function_constant(0) ]]; +constant int iLightCount [[ function_constant(1) ]]; //----------------------------------------------------------------------------- // [SECTION] defines & structs @@ -21,6 +22,9 @@ constant const float INV_GAMMA = 1.0 / GAMMA; #define PL_RENDERING_FLAG_USE_PUNCTUAL 1 << 0 #define PL_RENDERING_FLAG_USE_IBL 1 << 1 +#define PL_LIGHT_TYPE_DIRECTIONAL 0 +#define PL_LIGHT_TYPE_POINT 1 + struct tMaterial { // Metallic Roughness @@ -122,6 +126,27 @@ struct BindGroup_1 texture2d tDepthTexture; }; +//----------------------------------------------------------------------------- +// [SECTION] bind group 2 +//----------------------------------------------------------------------------- + +struct plLightData +{ + packed_float3 tPosition; + float fIntensity; + + packed_float3 tDirection; + int iType; + + packed_float3 tColor; + float fRange; +}; + +struct BindGroup_2 +{ + device plLightData* atData; +}; + //----------------------------------------------------------------------------- // [SECTION] dynamic bind group //----------------------------------------------------------------------------- @@ -148,7 +173,7 @@ struct VertexIn { float3 linearTosRGB(float3 color) { - return pow(color, float3(INV_GAMMA)); + return fast::pow(color, float3(INV_GAMMA)); } static inline __attribute__((always_inline)) @@ -157,14 +182,14 @@ float clampedDot(thread const float3& x, thread const float3& y) return fast::clamp(dot(x, y), 0.0, 1.0); } -float3 -F_Schlick(float3 f0, float3 f90, float VdotH) +static inline __attribute__((always_inline)) +float3 F_Schlick(thread const float3& f0, thread const float3& f90, float VdotH) { - return f0 + (f90 - f0) * pow(fast::clamp(1.0 - VdotH, 0.0, 1.0), 5.0); + return f0 + (f90 - f0) * fast::pow(fast::clamp(1.0 - VdotH, 0.0, 1.0), 5.0); } -float -F_Schlick(float f0, float f90, float VdotH) +static inline __attribute__((always_inline)) +float F_Schlick(float f0, float f90, float VdotH) { float x = fast::clamp(1.0 - VdotH, 0.0, 1.0); float x2 = x * x; @@ -172,15 +197,15 @@ F_Schlick(float f0, float f90, float VdotH) return f0 + (f90 - f0) * x5; } -float -F_Schlick(float f0, float VdotH) +static inline __attribute__((always_inline)) +float F_Schlick(float f0, float VdotH) { float f90 = 1.0; //fast::clamp(50.0 * f0, 0.0, 1.0); return F_Schlick(f0, f90, VdotH); } -float3 -F_Schlick(float3 f0, float f90, float VdotH) +static inline __attribute__((always_inline)) +float3 F_Schlick(thread const float3& f0, float f90, float VdotH) { float x = fast::clamp(1.0 - VdotH, 0.0, 1.0); float x2 = x * x; @@ -188,15 +213,15 @@ F_Schlick(float3 f0, float f90, float VdotH) return f0 + (f90 - f0) * x5; } -float3 -F_Schlick(float3 f0, float VdotH) +static inline __attribute__((always_inline)) +float3 F_Schlick(thread const float3& f0, float VdotH) { float f90 = 1.0; //fast::clamp(dot(f0, float3(50.0 * 0.33)), 0.0, 1.0); return F_Schlick(f0, f90, VdotH); } -float3 -Schlick_to_F0(float3 f, float3 f90, float VdotH) +static inline __attribute__((always_inline)) +float3 Schlick_to_F0(thread const float3& f, thread const float3& f90, float VdotH) { float x = fast::clamp(1.0 - VdotH, 0.0, 1.0); float x2 = x * x; @@ -205,8 +230,8 @@ Schlick_to_F0(float3 f, float3 f90, float VdotH) return (f - f90 * x5) / (1.0 - x5); } -float -Schlick_to_F0(float f, float f90, float VdotH) +static inline __attribute__((always_inline)) +float Schlick_to_F0(float f, float f90, float VdotH) { float x = fast::clamp(1.0 - VdotH, 0.0, 1.0); float x2 = x * x; @@ -215,25 +240,25 @@ Schlick_to_F0(float f, float f90, float VdotH) return (f - f90 * x5) / (1.0 - x5); } -float3 -Schlick_to_F0(float3 f, float VdotH) +static inline __attribute__((always_inline)) +float3 Schlick_to_F0(thread const float3& f, float VdotH) { return Schlick_to_F0(f, float3(1.0), VdotH); } -float -Schlick_to_F0(float f, float VdotH) +static inline __attribute__((always_inline)) +float Schlick_to_F0(float f, float VdotH) { return Schlick_to_F0(f, 1.0, VdotH); } -float -V_GGX(float NdotL, float NdotV, float alphaRoughness) +static inline __attribute__((always_inline)) +float V_GGX(float NdotL, float NdotV, float alphaRoughness) { float alphaRoughnessSq = alphaRoughness * alphaRoughness; - float GGXV = NdotL * sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq); - float GGXL = NdotV * sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq); + float GGXV = NdotL * fast::sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq); + float GGXL = NdotV * fast::sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq); float GGX = GGXV + GGXL; if (GGX > 0.0) @@ -243,22 +268,22 @@ V_GGX(float NdotL, float NdotV, float alphaRoughness) return 0.0; } -float -D_GGX(float NdotH, float alphaRoughness) +static inline __attribute__((always_inline)) +float D_GGX(float NdotH, float alphaRoughness) { float alphaRoughnessSq = alphaRoughness * alphaRoughness; float f = (NdotH * NdotH) * (alphaRoughnessSq - 1.0) + 1.0; return alphaRoughnessSq / (M_PI * f * f); } -float3 -BRDF_lambertian(float3 f0, float3 f90, float3 diffuseColor, float specularWeight, float VdotH) +static inline __attribute__((always_inline)) +float3 BRDF_lambertian(thread const float3& f0, thread const float3& f90, thread const float3& diffuseColor, float specularWeight, float VdotH) { return (1.0 - specularWeight * F_Schlick(f0, f90, VdotH)) * (diffuseColor / M_PI); } -float3 -BRDF_specularGGX(float3 f0, float3 f90, float alphaRoughness, float specularWeight, float VdotH, float NdotL, float NdotV, float NdotH) +static inline __attribute__((always_inline)) +float3 BRDF_specularGGX(thread const float3& f0, thread const float3& f90, float alphaRoughness, float specularWeight, float VdotH, float NdotL, float NdotV, float NdotH) { float3 F = F_Schlick(f0, f90, VdotH); float Vis = V_GGX(NdotL, NdotV, alphaRoughness); @@ -266,22 +291,22 @@ BRDF_specularGGX(float3 f0, float3 f90, float alphaRoughness, float specularWeig return specularWeight * F * Vis * D; } -float3 -getDiffuseLight(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float3 n) +static inline __attribute__((always_inline)) +float3 getDiffuseLight(device const BindGroup_0& bg0, float3 n) { n.z = -n.z; return bg0.u_LambertianEnvSampler.sample(bg0.tEnvSampler, n).rgb; } -float4 -getSpecularSample(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float3 reflection, float lod) +static inline __attribute__((always_inline)) +float4 getSpecularSample(device const BindGroup_0& bg0, float3 reflection, float lod) { reflection.z = -reflection.z; return bg0.u_GGXEnvSampler.sample(bg0.tEnvSampler, reflection, level(lod)); } -float3 -getIBLRadianceGGX(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float3 n, float3 v, float roughness, float3 F0, float specularWeight, int u_MipCount) +static float3 +getIBLRadianceGGX(device const BindGroup_0& bg0, thread const float3& n, thread const float3& v, float roughness, thread const float3& F0, float specularWeight, int u_MipCount) { float NdotV = clampedDot(n, v); float lod = roughness * float(u_MipCount - 1); @@ -289,28 +314,28 @@ getIBLRadianceGGX(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float2 brdfSamplePoint = fast::clamp(float2(NdotV, roughness), float2(0.0, 0.0), float2(1.0, 1.0)); float2 f_ab = bg0.u_GGXLUT.sample(bg0.tEnvSampler, brdfSamplePoint).rg; - float4 specularSample = getSpecularSample(bg0, bg1, reflection, lod); + float4 specularSample = getSpecularSample(bg0, reflection, lod); float3 specularLight = specularSample.rgb; float3 Fr = fast::max(float3(1.0 - roughness), F0) - F0; - float3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0); + float3 k_S = F0 + Fr * fast::pow(1.0 - NdotV, 5.0); float3 FssEss = (k_S * f_ab.x) + float3(f_ab.y); return (specularWeight * specularLight) * FssEss; } -float3 -getIBLRadianceLambertian(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float3 n, float3 v, float roughness, float3 diffuseColor, float3 F0, float specularWeight) +static float3 +getIBLRadianceLambertian(device const BindGroup_0& bg0, thread const float3& n, thread const float3& v, float roughness, thread const float3& diffuseColor, thread const float3& F0, float specularWeight) { float NdotV = clampedDot(n, v); float2 brdfSamplePoint = fast::clamp(float2(NdotV, roughness), float2(0.0, 0.0), float2(1.0, 1.0)); float2 f_ab = bg0.u_GGXLUT.sample(bg0.tEnvSampler, brdfSamplePoint).rg; - float3 irradiance = getDiffuseLight(bg0, bg1, n); + float3 irradiance = getDiffuseLight(bg0, n); - float3 Fr = max(float3(1.0 - roughness), F0) - F0; - float3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0); + float3 Fr = fast::max(float3(1.0 - roughness), F0) - F0; + float3 k_S = F0 + Fr * fast::pow(1.0 - NdotV, 5.0); float3 FssEss = specularWeight * k_S * f_ab.x + f_ab.y; float Ems = (1.0 - (f_ab.x + f_ab.y)); @@ -321,6 +346,31 @@ getIBLRadianceLambertian(device const BindGroup_0& bg0, device const BindGroup_1 return (FmsEms + k_D) * irradiance; } +static inline __attribute__((always_inline)) +float getRangeAttenuation(float range, float distance) +{ + if (range <= 0.0) + { + // negative range means unlimited + return 1.0 / fast::pow(distance, 2.0); + } + return fast::max(fast::min(1.0 - fast::pow(distance / range, 4.0), 1.0), 0.0) / fast::pow(distance, 2.0); +} + + +static float3 getLighIntensity(device const plLightData& light, thread const float3& pointToLight) +{ + float rangeAttenuation = 1.0; + + if (light.iType != PL_LIGHT_TYPE_DIRECTIONAL) + { + rangeAttenuation = getRangeAttenuation(light.fRange, fast::length(pointToLight)); + } + + + return rangeAttenuation * light.fIntensity * light.tColor; +} + //----------------------------------------------------------------------------- // [SECTION] output //----------------------------------------------------------------------------- @@ -339,7 +389,8 @@ vertex VertexOut vertex_main( VertexIn in [[stage_in]], device const BindGroup_0& bg0 [[ buffer(1) ]], device const BindGroup_1& bg1 [[ buffer(2) ]], - device const DynamicData& tObjectInfo [[ buffer(3) ]] + device const BindGroup_2& bg2 [[ buffer(3) ]], + device const DynamicData& tObjectInfo [[ buffer(4) ]] ) { @@ -360,22 +411,18 @@ fragment float4 fragment_main( VertexOut in [[stage_in]], device const BindGroup_0& bg0 [[ buffer(1) ]], device const BindGroup_1& bg1 [[ buffer(2) ]], - device const DynamicData& tObjectInfo [[ buffer(3) ]], + device const BindGroup_2& bg2 [[ buffer(3) ]], + device const DynamicData& tObjectInfo [[ buffer(4) ]], bool front_facing [[front_facing]] ) { float4 outColor = float4(0); - // settings - float3 tSunlightColor = float3(1.0, 1.0, 1.0); - float lightIntensity = 1.0; - float4 tBaseColor = bg1.tAlbedoTexture.sample(bg0.tEnvSampler, in.tUV); float4 tPosition = bg1.tPositionTexture.sample(bg0.tEnvSampler, in.tUV); float specularWeight = tPosition.a; float3 n = bg1.tNormalTexture.sample(bg0.tEnvSampler, in.tUV).xyz; - float3 tSunLightDirection = float3(-1.0, -1.0, -1.0); float4 AORoughnessMetalnessData = bg1.tAOMetalRoughnessTexture.sample(bg0.tEnvSampler, in.tUV); const float fPerceptualRoughness = AORoughnessMetalnessData.b; @@ -388,7 +435,6 @@ fragment float4 fragment_main( float3 f0 = mix(float3(0.04), tBaseColor.rgb, fMetalness); float3 v = normalize(bg0.data->tCameraPos.xyz - tPosition.xyz); - float NdotV = clampedDot(n, v); // LIGHTING float3 f_specular = float3(0.0); @@ -397,13 +443,12 @@ fragment float4 fragment_main( int iMips = int(f_emissive.a); float3 f_clearcoat = float3(0.0); float3 f_sheen = float3(0.0); - float3 f_transmission = float3(0.0); // IBL STUFF if(bool(iRenderingFlags & PL_RENDERING_FLAG_USE_IBL)) { - f_specular += getIBLRadianceGGX(bg0, bg1, n, v, fPerceptualRoughness, f0, specularWeight, iMips); - f_diffuse += getIBLRadianceLambertian(bg0, bg1, n, v, fPerceptualRoughness, c_diff, f0, specularWeight); + f_specular += getIBLRadianceGGX(bg0, n, v, fPerceptualRoughness, f0, specularWeight, iMips); + f_diffuse += getIBLRadianceLambertian(bg0, n, v, fPerceptualRoughness, c_diff, f0, specularWeight); } // punctual stuff @@ -418,27 +463,35 @@ fragment float4 fragment_main( if(bool(iRenderingFlags & PL_RENDERING_FLAG_USE_PUNCTUAL)) { - float3 pointToLight = -tSunLightDirection; - - // BSTF - float3 l = normalize(pointToLight); // Direction from surface point to light - float3 h = normalize(l + v); // Direction of the vector between l and v, called halfway vector - float NdotL = clampedDot(n, l); - float NdotV = clampedDot(n, v); - float NdotH = clampedDot(n, h); - float LdotH = clampedDot(l, h); - float VdotH = clampedDot(v, h); - if (NdotL > 0.0 || NdotV > 0.0) + for(int i = 0; i < iLightCount; i++) { - // Calculation of analytical light - // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB - // float3 intensity = getLighIntensity(light, pointToLight); - - float3 intensity = tSunlightColor * lightIntensity; - f_diffuse += intensity * NdotL * BRDF_lambertian(f0, f90, c_diff, specularWeight, VdotH); - f_specular += intensity * NdotL * BRDF_specularGGX(f0, f90, fAlphaRoughness, specularWeight, VdotH, NdotL, NdotV, NdotH); - } + device const plLightData& tLightData = bg2.atData[i]; + float3 pointToLight; + + if(tLightData.iType != PL_LIGHT_TYPE_DIRECTIONAL) + { + pointToLight = tLightData.tPosition - tPosition.xyz; + } + else + { + pointToLight = -tLightData.tDirection; + } + + // BSTF + float3 l = fast::normalize(pointToLight); // Direction from surface point to light + float3 h = fast::normalize(l + v); // Direction of the vector between l and v, called halfway vector + float NdotL = clampedDot(n, l); + float NdotV = clampedDot(n, v); + float NdotH = clampedDot(n, h); + float VdotH = clampedDot(v, h); + if (NdotL > 0.0 || NdotV > 0.0) + { + float3 intensity = getLighIntensity(tLightData, pointToLight); + f_diffuse += intensity * NdotL * BRDF_lambertian(f0, f90, c_diff, specularWeight, VdotH); + f_specular += intensity * NdotL * BRDF_specularGGX(f0, f90, fAlphaRoughness, specularWeight, VdotH, NdotL, NdotV, NdotH); + } + } } // Layer blending diff --git a/shaders/metal/transparent.metal b/shaders/metal/transparent.metal index a812c0e8..3c846f09 100644 --- a/shaders/metal/transparent.metal +++ b/shaders/metal/transparent.metal @@ -12,6 +12,7 @@ constant int iDataStride [[ function_constant(1) ]]; constant int iTextureMappingFlags [[ function_constant(2) ]]; constant int iMaterialFlags [[ function_constant(3) ]]; constant int iRenderingFlags [[ function_constant(4) ]]; +constant int iLightCount [[ function_constant(5) ]]; //----------------------------------------------------------------------------- // [SECTION] defines & structs @@ -56,6 +57,9 @@ constant const float INV_GAMMA = 1.0 / GAMMA; #define PL_RENDERING_FLAG_USE_PUNCTUAL 1 << 0 #define PL_RENDERING_FLAG_USE_IBL 1 << 1 +#define PL_LIGHT_TYPE_DIRECTIONAL 0 +#define PL_LIGHT_TYPE_POINT 1 + struct tMaterial { // Metallic Roughness @@ -162,6 +166,10 @@ struct MaterialInfo float anisotropyStrength; }; +//----------------------------------------------------------------------------- +// [SECTION] bind group 0 +//----------------------------------------------------------------------------- + struct BindGroupData_0 { float4 tCameraPos; @@ -182,7 +190,32 @@ struct BindGroup_0 texture2d u_GGXLUT; }; +//----------------------------------------------------------------------------- +// [SECTION] bind group 1 +//----------------------------------------------------------------------------- + +struct plLightData +{ + packed_float3 tPosition; + float fIntensity; + + packed_float3 tDirection; + int iType; + + packed_float3 tColor; + float fRange; +}; + struct BindGroup_1 +{ + device plLightData* atData; +}; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 2 +//----------------------------------------------------------------------------- + +struct BindGroup_2 { texture2d tBaseColorTexture; texture2d tNormalTexture; @@ -235,7 +268,8 @@ vertex VertexOut vertex_main( VertexIn in [[stage_in]], device const BindGroup_0& bg0 [[ buffer(1) ]], device const BindGroup_1& bg1 [[ buffer(2) ]], - device const DynamicData& tObjectInfo [[ buffer(3) ]] + device const BindGroup_2& bg2 [[ buffer(3) ]], + device const DynamicData& tObjectInfo [[ buffer(4) ]] ) { @@ -316,7 +350,7 @@ struct NormalInfo { }; NormalInfo -pl_get_normal_info(device const BindGroup_0& bg0, device const BindGroup_1& bg1, VertexOut tShaderIn, bool front_facing, float2 UV) +pl_get_normal_info(device const BindGroup_0& bg0, device const BindGroup_2& bg2, VertexOut tShaderIn, bool front_facing, float2 UV) { float2 uv_dx = dfdx(UV); float2 uv_dy = dfdy(UV); @@ -375,7 +409,7 @@ pl_get_normal_info(device const BindGroup_0& bg0, device const BindGroup_1& bg1, info.ng = ng; if(bool(iTextureMappingFlags & PL_HAS_NORMAL_MAP)) { - info.ntex = bg1.tNormalTexture.sample(bg0.tDefaultSampler, UV).rgb * 2.0 - float3(1.0); + info.ntex = bg2.tNormalTexture.sample(bg0.tDefaultSampler, UV).rgb * 2.0 - float3(1.0); // info.ntex *= vec3(0.2, 0.2, 1.0); // info.ntex *= vec3(u_NormalScale, u_NormalScale, 1.0); info.ntex = fast::normalize(info.ntex); @@ -391,7 +425,7 @@ pl_get_normal_info(device const BindGroup_0& bg0, device const BindGroup_1& bg1, } float4 -getBaseColor(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float4 u_ColorFactor, VertexOut tShaderIn, float2 UV) +getBaseColor(device const BindGroup_0& bg0, device const BindGroup_2& bg2, float4 u_ColorFactor, VertexOut tShaderIn, float2 UV) { float4 baseColor = float4(1); @@ -415,7 +449,7 @@ getBaseColor(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS) && bool(iTextureMappingFlags & PL_HAS_BASE_COLOR_MAP)) { // baseColor *= texture(u_BaseColorSampler, getBaseColorUV()); - baseColor *= bg1.tBaseColorTexture.sample(bg0.tDefaultSampler, UV); + baseColor *= bg2.tBaseColorTexture.sample(bg0.tDefaultSampler, UV); } return baseColor * tShaderIn.tColor; } @@ -427,7 +461,7 @@ linearTosRGB(float3 color) } MaterialInfo -getMetallicRoughnessInfo(VertexOut in, device const BindGroup_0& bg0, device const BindGroup_1& bg1, MaterialInfo info, float u_MetallicFactor, float u_RoughnessFactor, float2 UV) +getMetallicRoughnessInfo(VertexOut in, device const BindGroup_0& bg0, device const BindGroup_2& bg2, MaterialInfo info, float u_MetallicFactor, float u_RoughnessFactor, float2 UV) { info.metallic = u_MetallicFactor; info.perceptualRoughness = u_RoughnessFactor; @@ -436,7 +470,7 @@ getMetallicRoughnessInfo(VertexOut in, device const BindGroup_0& bg0, device con { // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. // This layout intentionally reserves the 'r' channel for (optional) occlusion map data - float4 mrSample = float4(bg1.tMetallicRoughnessTexture.sample(bg0.tDefaultSampler, UV).rgb, 1.0); + float4 mrSample = float4(bg2.tMetallicRoughnessTexture.sample(bg0.tDefaultSampler, UV).rgb, 1.0); info.perceptualRoughness *= mrSample.g; info.metallic *= mrSample.b; } @@ -453,14 +487,14 @@ float clampedDot(thread const float3& x, thread const float3& y) return fast::clamp(dot(x, y), 0.0, 1.0); } -float3 -F_Schlick(float3 f0, float3 f90, float VdotH) +static inline __attribute__((always_inline)) +float3 F_Schlick(thread const float3& f0, thread const float3& f90, float VdotH) { - return f0 + (f90 - f0) * pow(fast::clamp(1.0 - VdotH, 0.0, 1.0), 5.0); + return f0 + (f90 - f0) * fast::pow(fast::clamp(1.0 - VdotH, 0.0, 1.0), 5.0); } -float -F_Schlick(float f0, float f90, float VdotH) +static inline __attribute__((always_inline)) +float F_Schlick(float f0, float f90, float VdotH) { float x = fast::clamp(1.0 - VdotH, 0.0, 1.0); float x2 = x * x; @@ -468,15 +502,15 @@ F_Schlick(float f0, float f90, float VdotH) return f0 + (f90 - f0) * x5; } -float -F_Schlick(float f0, float VdotH) +static inline __attribute__((always_inline)) +float F_Schlick(float f0, float VdotH) { float f90 = 1.0; //fast::clamp(50.0 * f0, 0.0, 1.0); return F_Schlick(f0, f90, VdotH); } -float3 -F_Schlick(float3 f0, float f90, float VdotH) +static inline __attribute__((always_inline)) +float3 F_Schlick(thread const float3& f0, float f90, float VdotH) { float x = fast::clamp(1.0 - VdotH, 0.0, 1.0); float x2 = x * x; @@ -484,15 +518,15 @@ F_Schlick(float3 f0, float f90, float VdotH) return f0 + (f90 - f0) * x5; } -float3 -F_Schlick(float3 f0, float VdotH) +static inline __attribute__((always_inline)) +float3 F_Schlick(thread const float3& f0, float VdotH) { float f90 = 1.0; //fast::clamp(dot(f0, float3(50.0 * 0.33)), 0.0, 1.0); return F_Schlick(f0, f90, VdotH); } -float3 -Schlick_to_F0(float3 f, float3 f90, float VdotH) +static inline __attribute__((always_inline)) +float3 Schlick_to_F0(thread const float3& f, thread const float3& f90, float VdotH) { float x = fast::clamp(1.0 - VdotH, 0.0, 1.0); float x2 = x * x; @@ -501,8 +535,8 @@ Schlick_to_F0(float3 f, float3 f90, float VdotH) return (f - f90 * x5) / (1.0 - x5); } -float -Schlick_to_F0(float f, float f90, float VdotH) +static inline __attribute__((always_inline)) +float Schlick_to_F0(float f, float f90, float VdotH) { float x = fast::clamp(1.0 - VdotH, 0.0, 1.0); float x2 = x * x; @@ -511,25 +545,25 @@ Schlick_to_F0(float f, float f90, float VdotH) return (f - f90 * x5) / (1.0 - x5); } -float3 -Schlick_to_F0(float3 f, float VdotH) +static inline __attribute__((always_inline)) +float3 Schlick_to_F0(thread const float3& f, float VdotH) { return Schlick_to_F0(f, float3(1.0), VdotH); } -float -Schlick_to_F0(float f, float VdotH) +static inline __attribute__((always_inline)) +float Schlick_to_F0(float f, float VdotH) { return Schlick_to_F0(f, 1.0, VdotH); } -float -V_GGX(float NdotL, float NdotV, float alphaRoughness) +static inline __attribute__((always_inline)) +float V_GGX(float NdotL, float NdotV, float alphaRoughness) { float alphaRoughnessSq = alphaRoughness * alphaRoughness; - float GGXV = NdotL * sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq); - float GGXL = NdotV * sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq); + float GGXV = NdotL * fast::sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq); + float GGXL = NdotV * fast::sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq); float GGX = GGXV + GGXL; if (GGX > 0.0) @@ -539,22 +573,22 @@ V_GGX(float NdotL, float NdotV, float alphaRoughness) return 0.0; } -float -D_GGX(float NdotH, float alphaRoughness) +static inline __attribute__((always_inline)) +float D_GGX(float NdotH, float alphaRoughness) { float alphaRoughnessSq = alphaRoughness * alphaRoughness; float f = (NdotH * NdotH) * (alphaRoughnessSq - 1.0) + 1.0; return alphaRoughnessSq / (M_PI * f * f); } -float3 -BRDF_lambertian(float3 f0, float3 f90, float3 diffuseColor, float specularWeight, float VdotH) +static inline __attribute__((always_inline)) +float3 BRDF_lambertian(thread const float3& f0, thread const float3& f90, thread const float3& diffuseColor, float specularWeight, float VdotH) { return (1.0 - specularWeight * F_Schlick(f0, f90, VdotH)) * (diffuseColor / M_PI); } -float3 -BRDF_specularGGX(float3 f0, float3 f90, float alphaRoughness, float specularWeight, float VdotH, float NdotL, float NdotV, float NdotH) +static inline __attribute__((always_inline)) +float3 BRDF_specularGGX(thread const float3& f0, thread const float3& f90, float alphaRoughness, float specularWeight, float VdotH, float NdotL, float NdotV, float NdotH) { float3 F = F_Schlick(f0, f90, VdotH); float Vis = V_GGX(NdotL, NdotV, alphaRoughness); @@ -562,22 +596,22 @@ BRDF_specularGGX(float3 f0, float3 f90, float alphaRoughness, float specularWeig return specularWeight * F * Vis * D; } -float3 -getDiffuseLight(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float3 n) +static inline __attribute__((always_inline)) +float3 getDiffuseLight(device const BindGroup_0& bg0, float3 n) { n.z = -n.z; return bg0.u_LambertianEnvSampler.sample(bg0.tEnvSampler, n).rgb; } -float4 -getSpecularSample(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float3 reflection, float lod) +static inline __attribute__((always_inline)) +float4 getSpecularSample(device const BindGroup_0& bg0, float3 reflection, float lod) { reflection.z = -reflection.z; return bg0.u_GGXEnvSampler.sample(bg0.tEnvSampler, reflection, level(lod)); } -float3 -getIBLRadianceGGX(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float3 n, float3 v, float roughness, float3 F0, float specularWeight, int u_MipCount) +static float3 +getIBLRadianceGGX(device const BindGroup_0& bg0, thread const float3& n, thread const float3& v, float roughness, thread const float3& F0, float specularWeight, int u_MipCount) { float NdotV = clampedDot(n, v); float lod = roughness * float(u_MipCount - 1); @@ -585,28 +619,28 @@ getIBLRadianceGGX(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float2 brdfSamplePoint = fast::clamp(float2(NdotV, roughness), float2(0.0, 0.0), float2(1.0, 1.0)); float2 f_ab = bg0.u_GGXLUT.sample(bg0.tEnvSampler, brdfSamplePoint).rg; - float4 specularSample = getSpecularSample(bg0, bg1, reflection, lod); + float4 specularSample = getSpecularSample(bg0, reflection, lod); float3 specularLight = specularSample.rgb; float3 Fr = fast::max(float3(1.0 - roughness), F0) - F0; - float3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0); + float3 k_S = F0 + Fr * fast::pow(1.0 - NdotV, 5.0); float3 FssEss = (k_S * f_ab.x) + float3(f_ab.y); return (specularWeight * specularLight) * FssEss; } -float3 -getIBLRadianceLambertian(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float3 n, float3 v, float roughness, float3 diffuseColor, float3 F0, float specularWeight) +static float3 +getIBLRadianceLambertian(device const BindGroup_0& bg0, thread const float3& n, thread const float3& v, float roughness, thread const float3& diffuseColor, thread const float3& F0, float specularWeight) { float NdotV = clampedDot(n, v); float2 brdfSamplePoint = fast::clamp(float2(NdotV, roughness), float2(0.0, 0.0), float2(1.0, 1.0)); float2 f_ab = bg0.u_GGXLUT.sample(bg0.tEnvSampler, brdfSamplePoint).rg; - float3 irradiance = getDiffuseLight(bg0, bg1, n); + float3 irradiance = getDiffuseLight(bg0, n); - float3 Fr = max(float3(1.0 - roughness), F0) - F0; - float3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0); + float3 Fr = fast::max(float3(1.0 - roughness), F0) - F0; + float3 k_S = F0 + Fr * fast::pow(1.0 - NdotV, 5.0); float3 FssEss = specularWeight * k_S * f_ab.x + f_ab.y; float Ems = (1.0 - (f_ab.x + f_ab.y)); @@ -617,6 +651,31 @@ getIBLRadianceLambertian(device const BindGroup_0& bg0, device const BindGroup_1 return (FmsEms + k_D) * irradiance; } +static inline __attribute__((always_inline)) +float getRangeAttenuation(float range, float distance) +{ + if (range <= 0.0) + { + // negative range means unlimited + return 1.0 / fast::pow(distance, 2.0); + } + return fast::max(fast::min(1.0 - fast::pow(distance / range, 4.0), 1.0), 0.0) / fast::pow(distance, 2.0); +} + + +static float3 getLighIntensity(device const plLightData& light, thread const float3& pointToLight) +{ + float rangeAttenuation = 1.0; + + if (light.iType != PL_LIGHT_TYPE_DIRECTIONAL) + { + rangeAttenuation = getRangeAttenuation(light.fRange, fast::length(pointToLight)); + } + + + return rangeAttenuation * light.fIntensity * light.tColor; +} + struct plRenderTargets { float4 outColor [[ color(0) ]]; @@ -626,7 +685,8 @@ fragment plRenderTargets fragment_main( VertexOut in [[stage_in]], device const BindGroup_0& bg0 [[ buffer(1) ]], device const BindGroup_1& bg1 [[ buffer(2) ]], - device const DynamicData& tObjectInfo [[ buffer(3) ]], + device const BindGroup_2& bg2 [[ buffer(3) ]], + device const DynamicData& tObjectInfo [[ buffer(4) ]], bool front_facing [[front_facing]] ) { @@ -642,20 +702,15 @@ fragment plRenderTargets fragment_main( in.tUV7 }; - // settings - float3 tSunlightColor = float3(1.0, 1.0, 1.0); - float lightIntensity = 1.0; - float3 tSunLightDirection = float3(-1.0, -1.0, -1.0); - tMaterial material = bg0.atMaterials[tObjectInfo.iMaterialIndex]; - float4 tBaseColor = getBaseColor(bg0, bg1, material.u_BaseColorFactor, in, tUV[material.BaseColorUVSet]); + float4 tBaseColor = getBaseColor(bg0, bg2, material.u_BaseColorFactor, in, tUV[material.BaseColorUVSet]); if(tBaseColor.a < 0.1) { discard_fragment(); } - NormalInfo tNormalInfo = pl_get_normal_info(bg0, bg1, in, front_facing, tUV[material.NormalUVSet]); + NormalInfo tNormalInfo = pl_get_normal_info(bg0, bg2, in, front_facing, tUV[material.NormalUVSet]); float3 n = tNormalInfo.n; @@ -669,7 +724,7 @@ fragment plRenderTargets fragment_main( if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS)) { - materialInfo = getMetallicRoughnessInfo(in, bg0, bg1, materialInfo, material.u_MetallicFactor, material.u_RoughnessFactor, tUV[material.MetallicRoughnessUVSet]); + materialInfo = getMetallicRoughnessInfo(in, bg0, bg2, materialInfo, material.u_MetallicFactor, material.u_RoughnessFactor, tUV[material.MetallicRoughnessUVSet]); } materialInfo.perceptualRoughness = fast::clamp(materialInfo.perceptualRoughness, 0.0, 1.0); @@ -689,14 +744,14 @@ fragment plRenderTargets fragment_main( float3 f_emissive = material.u_EmissiveFactor; if(bool(iTextureMappingFlags & PL_HAS_EMISSIVE_MAP)) { - f_emissive *= bg1.tEmissiveTexture.sample(bg0.tDefaultSampler, tUV[material.EmissiveUVSet]).rgb; + f_emissive *= bg2.tEmissiveTexture.sample(bg0.tDefaultSampler, tUV[material.EmissiveUVSet]).rgb; } // ambient occlusion float ao = 1.0; if(bool(iTextureMappingFlags & PL_HAS_OCCLUSION_MAP)) { - ao = bg1.tOcclusionTexture.sample(bg0.tDefaultSampler, tUV[material.OcclusionUVSet]).r; + ao = bg2.tOcclusionTexture.sample(bg0.tDefaultSampler, tUV[material.OcclusionUVSet]).r; } float3 v = normalize(bg0.data->tCameraPos.xyz - in.tPosition.xyz); @@ -706,13 +761,12 @@ fragment plRenderTargets fragment_main( float3 f_diffuse = float3(0.0); float3 f_clearcoat = float3(0.0); float3 f_sheen = float3(0.0); - float3 f_transmission = float3(0.0); // IBL STUFF if(bool(iRenderingFlags & PL_RENDERING_FLAG_USE_IBL)) { - f_specular += getIBLRadianceGGX(bg0, bg1, n, v, materialInfo.perceptualRoughness, materialInfo.f0, materialInfo.specularWeight, material.u_MipCount); - f_diffuse += getIBLRadianceLambertian(bg0, bg1, n, v, materialInfo.perceptualRoughness, materialInfo.c_diff, materialInfo.f0, materialInfo.specularWeight); + f_specular += getIBLRadianceGGX(bg0, n, v, materialInfo.perceptualRoughness, materialInfo.f0, materialInfo.specularWeight, material.u_MipCount); + f_diffuse += getIBLRadianceLambertian(bg0, n, v, materialInfo.perceptualRoughness, materialInfo.c_diff, materialInfo.f0, materialInfo.specularWeight); } // punctual stuff @@ -727,26 +781,34 @@ fragment plRenderTargets fragment_main( if(bool(iRenderingFlags & PL_RENDERING_FLAG_USE_PUNCTUAL)) { - float3 pointToLight = -tSunLightDirection; - - // BSTF - float3 l = normalize(pointToLight); // Direction from surface point to light - float3 h = normalize(l + v); // Direction of the vector between l and v, called halfway vector - float NdotL = clampedDot(n, l); - float NdotV = clampedDot(n, v); - float NdotH = clampedDot(n, h); - float VdotH = clampedDot(v, h); - if (NdotL > 0.0 || NdotV > 0.0) + for(int i = 0; i < iLightCount; i++) { - // Calculation of analytical light - // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB - // float3 intensity = getLighIntensity(light, pointToLight); - - float3 intensity = tSunlightColor * lightIntensity; - f_diffuse += intensity * NdotL * BRDF_lambertian(materialInfo.f0, materialInfo.f90, materialInfo.c_diff, materialInfo.specularWeight, VdotH); - f_specular += intensity * NdotL * BRDF_specularGGX(materialInfo.f0, materialInfo.f90, materialInfo.alphaRoughness, materialInfo.specularWeight, VdotH, NdotL, NdotV, NdotH); + device const plLightData& tLightData = bg1.atData[i]; + float3 pointToLight; + + if(tLightData.iType != PL_LIGHT_TYPE_DIRECTIONAL) + { + pointToLight = tLightData.tPosition - in.tPosition.xyz; + } + else + { + pointToLight = -tLightData.tDirection; + } + + // BSTF + float3 l = fast::normalize(pointToLight); // Direction from surface point to light + float3 h = fast::normalize(l + v); // Direction of the vector between l and v, called halfway vector + float NdotL = clampedDot(n, l); + float NdotV = clampedDot(n, v); + float NdotH = clampedDot(n, h); + float VdotH = clampedDot(v, h); + if (NdotL > 0.0 || NdotV > 0.0) + { + float3 intensity = getLighIntensity(tLightData, pointToLight); + f_diffuse += intensity * NdotL * BRDF_lambertian(materialInfo.f0, materialInfo.f90, materialInfo.c_diff, materialInfo.specularWeight, VdotH); + f_specular += intensity * NdotL * BRDF_specularGGX(materialInfo.f0, materialInfo.f90, materialInfo.alphaRoughness, materialInfo.specularWeight, VdotH, NdotL, NdotV, NdotH); + } } - } // Layer blending