From 4c7f78b24a9c92caff004189b74f864c3d1ad65b Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Fri, 3 May 2024 10:12:57 -0500 Subject: [PATCH 01/23] feat: add initial entity selection --- apps/app.c | 70 ++---- apps/helper_windows.h | 13 +- extensions/pl_ref_renderer_ext.c | 408 ++++++++++++++++++++++++++++++- extensions/pl_ref_renderer_ext.h | 1 + 4 files changed, 435 insertions(+), 57 deletions(-) diff --git a/apps/app.c b/apps/app.c index 151546fd..159f97c5 100644 --- a/apps/app.c +++ b/apps/app.c @@ -62,20 +62,21 @@ typedef struct plAppData_t bool bFrustumCulling; bool bAlwaysResize; + // selected entityes + + bool bUpdateEntitySelection; + plEntity tSelectedEntity; + // scene bool bDrawAllBoundingBoxes; bool bDrawVisibleBoundingBoxes; bool bFreezeCullCamera; plEntity tCullCamera; plEntity tMainCamera; - plEntity tMainCamera2; // views uint32_t uSceneHandle0; - uint32_t uSceneHandle1; uint32_t uViewHandle0; - uint32_t uViewHandle1; - uint32_t uViewHandle2; // drawing plDrawLayer* ptDrawLayer; @@ -221,18 +222,13 @@ 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("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 @@ -249,40 +245,25 @@ 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"); + plMat4 tTransform0 = pl_mat4_translate_xyz(2, 2, 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); 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); + gptModelLoader->load_stl(ptMainComponentLibrary, "../data/pilotlight-assets-master/meshes/monkey.stl", (plVec4){1.0f, 1.0f, 0.0f, 0.8f}, &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); - gptModelLoader->free_data(&tLoaderData0); - pl_end_profile_sample(); - pl_begin_profile_sample("finalize scene 0"); 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 @@ -356,6 +337,8 @@ pl_app_update(plAppData* ptAppData) ptAppData->bResize = false; } + + if(!gptGfx->begin_frame(ptGraphics)) { gptGfx->resize(ptGraphics); @@ -364,6 +347,15 @@ pl_app_update(plAppData* ptAppData) return; } + if(ptAppData->bUpdateEntitySelection) + { + if(ptAppData->tSelectedEntity.uIndex == UINT32_MAX) + gptRenderer->select_entities(ptAppData->uSceneHandle0, 0, NULL); + else + gptRenderer->select_entities(ptAppData->uSceneHandle0, 1, &ptAppData->tSelectedEntity); + ptAppData->bUpdateEntitySelection = false; + } + // update statistics gptStats->new_frame(); static double* pdFrameTimeCounter = NULL; @@ -377,10 +369,8 @@ pl_app_update(plAppData* ptAppData) // handle input plComponentLibrary* ptMainComponentLibrary = gptRenderer->get_component_library(ptAppData->uSceneHandle0); - plComponentLibrary* ptSecondaryComponentLibrary = gptRenderer->get_component_library(ptAppData->uSceneHandle1); 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; @@ -409,12 +399,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(); @@ -438,7 +426,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 = { @@ -456,7 +443,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 = { @@ -475,15 +461,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; @@ -497,8 +474,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); @@ -586,7 +561,12 @@ pl_app_update(plAppData* ptAppData) gptDebug->show_debug_windows(&ptAppData->tDebugInfo); if(ptAppData->bShowEntityWindow) - pl_show_ecs_window(gptEcs, gptRenderer->get_component_library(ptAppData->uSceneHandle0), &ptAppData->bShowEntityWindow); + { + plEntity tNextSelectedEntity = pl_show_ecs_window(gptEcs, gptRenderer->get_component_library(ptAppData->uSceneHandle0), &ptAppData->bShowEntityWindow); + if(tNextSelectedEntity.ulData != ptAppData->tSelectedEntity.ulData) + ptAppData->bUpdateEntitySelection = true; + ptAppData->tSelectedEntity = tNextSelectedEntity; + } if(ptAppData->bShowUiDemo) { @@ -603,8 +583,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/apps/helper_windows.h b/apps/helper_windows.h index f192d6bc..5963390a 100644 --- a/apps/helper_windows.h +++ b/apps/helper_windows.h @@ -8,9 +8,11 @@ #include "pl_ds.h" #include "pl_string.h" -static void +static plEntity pl_show_ecs_window(const plEcsI* ptECS, plComponentLibrary* ptLibrary, bool* pbShowWindow) { + static int iSelectedEntity = -1; + static plEntity tSelectedEntity = {UINT32_MAX, UINT32_MAX}; if(pl_begin_window("Entities", pbShowWindow, false)) { const plVec2 tWindowSize = pl_get_window_size(); @@ -21,8 +23,7 @@ pl_show_ecs_window(const plEcsI* ptECS, plComponentLibrary* ptLibrary, bool* pbS pl_layout_dynamic(0.0f, 1); pl_separator(); pl_layout_row(PL_UI_LAYOUT_ROW_TYPE_DYNAMIC, tWindowSize.y - 75.0f, 2, pfRatios); - static int iSelectedEntity = -1; - static plEntity tSelectedEntity = {0}; + if(pl_begin_child("Entities")) { @@ -48,7 +49,11 @@ pl_show_ecs_window(const plEcsI* ptECS, plComponentLibrary* ptLibrary, bool* pbS tSelectedEntity = ptLibrary->tTagComponentManager.sbtEntities[i]; } else + { iSelectedEntity = -1; + tSelectedEntity.uIndex = UINT32_MAX; + tSelectedEntity.uGeneration = UINT32_MAX; + } } } } @@ -273,4 +278,6 @@ pl_show_ecs_window(const plEcsI* ptECS, plComponentLibrary* ptLibrary, bool* pbS pl_end_window(); } + + return tSelectedEntity; } \ No newline at end of file diff --git a/extensions/pl_ref_renderer_ext.c b/extensions/pl_ref_renderer_ext.c index 05187b9e..f45de513 100644 --- a/extensions/pl_ref_renderer_ext.c +++ b/extensions/pl_ref_renderer_ext.c @@ -79,7 +79,7 @@ typedef struct _plDrawable uint32_t uIndexOffset; uint32_t uIndexCount; uint32_t uMaterialIndex; - uint32_t uShader; + plShaderHandle tShader; uint32_t uSkinIndex; bool bCulled; } plDrawable; @@ -181,6 +181,7 @@ typedef struct _plRefView // drawing api plDrawList3D t3DDrawList; + plDrawList3D t3DSelectionDrawList; } plRefView; typedef struct _plRefScene @@ -227,6 +228,12 @@ typedef struct _plRefScene // drawables (per scene, will be culled by views) plDrawable* sbtOpaqueDrawables; plDrawable* sbtTransparentDrawables; + plDrawable* sbtOutlineDrawables; + plShaderHandle* sbtOutlineDrawablesOldShaders; + + // hashmaps + plHashMap tOpaqueHashmap; + plHashMap tTransparentHashmap; } plRefScene; @@ -242,6 +249,7 @@ typedef struct _plRefRendererData plShaderHandle tOpaqueShader; plShaderHandle tTransparentShader; plShaderHandle tSkyboxShader; + plShaderHandle tOutlineShader; // graphics shader variant system uint32_t uVariantCount; @@ -652,6 +660,58 @@ pl_refr_initialize(plWindow* ptWindow) tTransparentShaderDescription.atConstants[i].tType = PL_DATA_TYPE_INT; } gptData->tTransparentShader = gptDevice->create_shader(&gptData->tGraphics.tDevice, &tTransparentShaderDescription); + + plShaderDescription tOutlineShaderDescription = { + + #ifdef PL_METAL_BACKEND + .pcVertexShader = "../shaders/metal/outline.metal", + .pcPixelShader = "../shaders/metal/outline.metal", + #else + .pcVertexShader = "outline.vert.spv", + .pcPixelShader = "outline.frag.spv", + #endif + .tGraphicsState = { + .ulDepthWriteEnabled = 0, + .ulDepthMode = PL_COMPARE_MODE_ALWAYS, + .ulCullMode = PL_CULL_MODE_CULL_FRONT, + .ulWireframe = 0, + .ulStencilMode = PL_COMPARE_MODE_LESS_OR_EQUAL, + .ulStencilRef = 128, + .ulStencilMask = 0xff, + .ulStencilOpFail = PL_STENCIL_OP_KEEP, + .ulStencilOpDepthFail = PL_STENCIL_OP_KEEP, + .ulStencilOpPass = PL_STENCIL_OP_KEEP + }, + .tVertexBufferBinding = { + .uByteStride = sizeof(float) * 3, + .atAttributes = { {.uByteOffset = 0, .tFormat = PL_FORMAT_R32G32B32_FLOAT}} + }, + .uConstantCount = 2, + .pTempConstantData = aiConstantData, + .atBlendStates = { + pl__get_blend_state(PL_BLEND_MODE_ALPHA) + }, + .uBlendStateCount = 1, + .tRenderPassLayout = gptData->tRenderPassLayout, + .uSubpassIndex = 2, + .uBindGroupLayoutCount = 1, + .atBindGroupLayouts = { + { + .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} + }, + } + } + }; + for(uint32_t i = 0; i < tOutlineShaderDescription.uConstantCount; i++) + { + tOutlineShaderDescription.atConstants[i].uID = i; + tOutlineShaderDescription.atConstants[i].uOffset = i * sizeof(int); + tOutlineShaderDescription.atConstants[i].tType = PL_DATA_TYPE_INT; + } + gptData->tOutlineShader = gptDevice->create_shader(&gptData->tGraphics.tDevice, &tOutlineShaderDescription); } static uint32_t @@ -880,6 +940,7 @@ pl_refr_create_view(uint32_t uSceneHandle, plVec2 tDimensions) // register debug 3D drawlist gptGfx->register_3d_drawlist(ptGraphics, &ptView->t3DDrawList); + gptGfx->register_3d_drawlist(ptGraphics, &ptView->t3DSelectionDrawList); // create lighting composition quad const uint32_t uVertexStartIndex = pl_sb_size(ptScene->sbtVertexPosBuffer); @@ -1068,8 +1129,17 @@ pl_refr_cleanup(void) pl_sb_free(ptScene->sbtOpaqueDrawables); pl_sb_free(ptScene->sbtTransparentDrawables); pl_sb_free(ptScene->sbtSkinData); + pl_sb_free(ptScene->sbtSkinVertexDataBuffer); + pl_sb_free(ptScene->sbtOutlineDrawables); + pl_sb_free(ptScene->sbtOutlineDrawablesOldShaders); + pl_hm_free(&ptScene->tOpaqueHashmap); + pl_hm_free(&ptScene->tTransparentHashmap); gptECS->cleanup_component_library(&ptScene->tComponentLibrary); } + for(uint32_t i = 0; i < pl_sb_size(gptData->_sbtVariantHandles); i++) + { + gptDevice->queue_shader_for_deletion(&gptData->tGraphics.tDevice, gptData->_sbtVariantHandles[i]); + } pl_sb_free(gptData->_sbtVariantHandles); pl_hm_free(&gptData->tVariantHashmap); gptDevice->flush_device(&gptData->tGraphics.tDevice); @@ -1757,6 +1827,238 @@ pl__create_texture_helper(plMaterialComponent* ptMaterial, plTextureSlot tSlot, return tTexture; } +static void +pl_refr_select_entities(uint32_t uSceneHandle, uint32_t uCount, plEntity* atEntities) +{ + // for convience + plRefScene* ptScene = &gptData->sbtScenes[uSceneHandle]; + plGraphics* ptGraphics = &gptData->tGraphics; + plDevice* ptDevice = &ptGraphics->tDevice; + + int iSceneWideRenderingFlags = PL_RENDERING_FLAG_USE_PUNCTUAL; + if(ptScene->tGGXEnvTexture.uIndex != UINT32_MAX) + iSceneWideRenderingFlags |= PL_RENDERING_FLAG_USE_IBL; + + // reset old entities + const uint32_t uOldSelectedEntityCount = pl_sb_size(ptScene->sbtOutlineDrawables); + for(uint32_t i = 0; i < uOldSelectedEntityCount; i++) + { + plEntity tEntity = ptScene->sbtOutlineDrawables[i].tEntity; + plShader* ptOutlineShader = gptDevice->get_shader(ptDevice, ptScene->sbtOutlineDrawables[i].tShader); + + plObjectComponent* ptObject = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_OBJECT, tEntity); + plMeshComponent* ptMesh = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_MESH, ptObject->tMesh); + plMaterialComponent* ptMaterial = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_MATERIAL, ptMesh->tMaterial); + + int iDataStride = 0; + int iFlagCopy0 = (int)ptMesh->ulVertexStreamMask; + while(iFlagCopy0) + { + iDataStride += iFlagCopy0 & 1; + iFlagCopy0 >>= 1; + } + + int iTextureMappingFlags = 0; + for(uint32_t j = 0; j < PL_TEXTURE_SLOT_COUNT; j++) + { + if((ptMaterial->atTextureMaps[j].acName[0] != 0)) + iTextureMappingFlags |= 1 << j; + } + + // choose shader variant + int aiConstantData0[5] = { + (int)ptMesh->ulVertexStreamMask, + iDataStride, + iTextureMappingFlags, + PL_INFO_MATERIAL_METALLICROUGHNESS, + iSceneWideRenderingFlags + }; + + // use stencil buffer + const plGraphicsState tOutlineVariantTemp = { + .ulDepthWriteEnabled = 0, + .ulDepthMode = PL_COMPARE_MODE_ALWAYS, + .ulCullMode = PL_CULL_MODE_CULL_FRONT, + .ulWireframe = 0, + .ulStencilTestEnabled = 1, + .ulStencilMode = PL_COMPARE_MODE_GREATER, + .ulStencilRef = 128, + .ulStencilMask = 0xff, + .ulStencilOpFail = PL_STENCIL_OP_KEEP, + .ulStencilOpDepthFail = PL_STENCIL_OP_KEEP, + .ulStencilOpPass = PL_STENCIL_OP_KEEP + }; + + const plShaderVariant tOutlineVariant = { + .pTempConstantData = aiConstantData0, + .tGraphicsState = tOutlineVariantTemp + }; + + size_t szSpecializationSize = 0; + for(uint32_t j = 0; j < ptOutlineShader->tDescription.uConstantCount; j++) + { + const plSpecializationConstant* ptConstant = &ptOutlineShader->tDescription.atConstants[j]; + szSpecializationSize += pl__get_data_type_size(ptConstant->tType); + } + + const uint64_t ulVariantHash = pl_hm_hash(tOutlineVariant.pTempConstantData, szSpecializationSize, tOutlineVariant.tGraphicsState.ulValue); + pl_hm_remove(&gptData->tVariantHashmap, ulVariantHash); + + if(pl_hm_has_key(&ptScene->tOpaqueHashmap, tEntity.ulData)) + { + uint64_t ulIndex = pl_hm_lookup(&ptScene->tOpaqueHashmap, tEntity.ulData); + plDrawable* ptDrawable = &ptScene->sbtOpaqueDrawables[ulIndex]; + ptDrawable->tShader = ptScene->sbtOutlineDrawablesOldShaders[i]; + } + else if(pl_hm_has_key(&ptScene->tTransparentHashmap, tEntity.ulData)) + { + uint64_t ulIndex = pl_hm_lookup(&ptScene->tTransparentHashmap, tEntity.ulData); + plDrawable* ptDrawable = &ptScene->sbtTransparentDrawables[ulIndex]; + ptDrawable->tShader = ptScene->sbtOutlineDrawablesOldShaders[i]; + } + + gptDevice->queue_shader_for_deletion(ptDevice, ptScene->sbtOutlineDrawables[i].tShader); + } + pl_sb_reset(ptScene->sbtOutlineDrawables) + pl_sb_reset(ptScene->sbtOutlineDrawablesOldShaders) + + + + for(uint32_t i = 0; i < uCount; i++) + { + plEntity tEntity = atEntities[i]; + + plObjectComponent* ptObject = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_OBJECT, tEntity); + if(ptObject == NULL) + continue; + plMeshComponent* ptMesh = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_MESH, ptObject->tMesh); + plMaterialComponent* ptMaterial = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_MATERIAL, ptMesh->tMaterial); + + ptMaterial->tFlags |= PL_MATERIAL_FLAG_OUTLINE; + + int iDataStride = 0; + int iFlagCopy0 = (int)ptMesh->ulVertexStreamMask; + while(iFlagCopy0) + { + iDataStride += iFlagCopy0 & 1; + iFlagCopy0 >>= 1; + } + + int iTextureMappingFlags = 0; + for(uint32_t j = 0; j < PL_TEXTURE_SLOT_COUNT; j++) + { + if((ptMaterial->atTextureMaps[j].acName[0] != 0)) + iTextureMappingFlags |= 1 << j; + } + + // choose shader variant + int aiConstantData0[5] = { + (int)ptMesh->ulVertexStreamMask, + iDataStride, + iTextureMappingFlags, + PL_INFO_MATERIAL_METALLICROUGHNESS, + iSceneWideRenderingFlags + }; + + if(pl_hm_has_key(&ptScene->tOpaqueHashmap, tEntity.ulData)) + { + uint64_t ulIndex = pl_hm_lookup(&ptScene->tOpaqueHashmap, tEntity.ulData); + plDrawable* ptDrawable = &ptScene->sbtOpaqueDrawables[ulIndex]; + plShader* ptOldShader = gptDevice->get_shader(ptDevice, ptDrawable->tShader); + plGraphicsState tVariantTemp = ptOldShader->tDescription.tGraphicsState; + + // write into stencil buffer + tVariantTemp.ulStencilTestEnabled = 1; + tVariantTemp.ulStencilMode = PL_COMPARE_MODE_ALWAYS; + tVariantTemp.ulStencilRef = 0xff; + tVariantTemp.ulStencilMask = 0xff; + tVariantTemp.ulStencilOpFail = PL_STENCIL_OP_REPLACE; + tVariantTemp.ulStencilOpDepthFail = PL_STENCIL_OP_REPLACE; + tVariantTemp.ulStencilOpPass = PL_STENCIL_OP_REPLACE; + + // use stencil buffer + const plGraphicsState tOutlineVariantTemp = { + .ulDepthWriteEnabled = 0, + .ulDepthMode = PL_COMPARE_MODE_ALWAYS, + .ulCullMode = PL_CULL_MODE_CULL_FRONT, + .ulWireframe = 0, + .ulStencilTestEnabled = 1, + .ulStencilMode = PL_COMPARE_MODE_GREATER, + .ulStencilRef = 128, + .ulStencilMask = 0xff, + .ulStencilOpFail = PL_STENCIL_OP_KEEP, + .ulStencilOpDepthFail = PL_STENCIL_OP_KEEP, + .ulStencilOpPass = PL_STENCIL_OP_KEEP + }; + + const plShaderVariant tOutlineVariant = { + .pTempConstantData = aiConstantData0, + .tGraphicsState = tOutlineVariantTemp + }; + + plShaderHandle tOutlineShader = pl__get_shader_variant(uSceneHandle, gptData->tOutlineShader, &tOutlineVariant); + pl_sb_push(ptScene->sbtOutlineDrawables, *ptDrawable); + ptScene->sbtOutlineDrawables[pl_sb_size(ptScene->sbtOutlineDrawables) - 1].tShader = tOutlineShader; + + const plShaderVariant tVariant = { + .pTempConstantData = aiConstantData0, + .tGraphicsState = tVariantTemp + }; + + pl_sb_push(ptScene->sbtOutlineDrawablesOldShaders, ptDrawable->tShader); + ptDrawable->tShader = pl__get_shader_variant(uSceneHandle, gptData->tOpaqueShader, &tVariant); + } + else if(pl_hm_has_key(&ptScene->tTransparentHashmap, tEntity.ulData)) + { + uint64_t ulIndex = pl_hm_lookup(&ptScene->tTransparentHashmap, tEntity.ulData); + plDrawable* ptDrawable = &ptScene->sbtTransparentDrawables[ulIndex]; + plShader* ptOldShader = gptDevice->get_shader(ptDevice, ptDrawable->tShader); + plGraphicsState tVariantTemp = ptOldShader->tDescription.tGraphicsState; + + // write into stencil buffer + tVariantTemp.ulStencilTestEnabled = 1; + tVariantTemp.ulStencilMode = PL_COMPARE_MODE_ALWAYS; + tVariantTemp.ulStencilRef = 0xff; + tVariantTemp.ulStencilMask = 0xff; + tVariantTemp.ulStencilOpFail = PL_STENCIL_OP_REPLACE; + tVariantTemp.ulStencilOpDepthFail = PL_STENCIL_OP_REPLACE; + tVariantTemp.ulStencilOpPass = PL_STENCIL_OP_REPLACE; + + // use stencil buffer + const plGraphicsState tOutlineVariantTemp = { + .ulDepthWriteEnabled = 0, + .ulDepthMode = PL_COMPARE_MODE_ALWAYS, + .ulCullMode = PL_CULL_MODE_CULL_FRONT, + .ulWireframe = 0, + .ulStencilTestEnabled = 1, + .ulStencilMode = PL_COMPARE_MODE_GREATER, + .ulStencilRef = 128, + .ulStencilMask = 0xff, + .ulStencilOpFail = PL_STENCIL_OP_KEEP, + .ulStencilOpDepthFail = PL_STENCIL_OP_KEEP, + .ulStencilOpPass = PL_STENCIL_OP_KEEP + }; + + const plShaderVariant tOutlineVariant = { + .pTempConstantData = aiConstantData0, + .tGraphicsState = tOutlineVariantTemp + }; + + plShaderHandle tOutlineShader = pl__get_shader_variant(uSceneHandle, gptData->tOutlineShader, &tOutlineVariant); + pl_sb_push(ptScene->sbtOutlineDrawables, *ptDrawable); + ptScene->sbtOutlineDrawables[pl_sb_size(ptScene->sbtOutlineDrawables) - 1].tShader = tOutlineShader; + + const plShaderVariant tVariant = { + .pTempConstantData = aiConstantData0, + .tGraphicsState = tVariantTemp + }; + + pl_sb_push(ptScene->sbtOutlineDrawablesOldShaders, ptDrawable->tShader); + ptDrawable->tShader = pl__get_shader_variant(uSceneHandle, gptData->tTransparentShader, &tVariant); + } + } +} + static void pl_refr_finalize_scene(uint32_t uSceneHandle) { @@ -1877,14 +2179,22 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) } }; + plHashMap* atHashmaps[] = { + &ptScene->tOpaqueHashmap, + &ptScene->tTransparentHashmap + }; + for(uint32_t uDrawableBatchIndex = 0; uDrawableBatchIndex < 2; uDrawableBatchIndex++) { + plHashMap* ptHashmap = atHashmaps[uDrawableBatchIndex]; const uint32_t uDrawableCount = pl_sb_size(sbtDrawables[uDrawableBatchIndex]); + pl_hm_resize(ptHashmap, uDrawableCount); for(uint32_t i = 0; i < uDrawableCount; i++) { (sbtDrawables[uDrawableBatchIndex])[i].uSkinIndex = UINT32_MAX; plEntity tEntity = (sbtDrawables[uDrawableBatchIndex])[i].tEntity; + pl_hm_insert(ptHashmap, tEntity.ulData, i); // get actual components plObjectComponent* ptObject = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_OBJECT, tEntity); @@ -1922,13 +2232,15 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) PL_INFO_MATERIAL_METALLICROUGHNESS, iSceneWideRenderingFlags }; - + + plGraphicsState tVariantTemp = atTemplateVariants[uDrawableBatchIndex]; + const plShaderVariant tVariant = { .pTempConstantData = aiConstantData0, - .tGraphicsState = atTemplateVariants[uDrawableBatchIndex] + .tGraphicsState = tVariantTemp }; - (sbtDrawables[uDrawableBatchIndex])[i].uShader = pl__get_shader_variant(uSceneHandle, atTemplateShaders[uDrawableBatchIndex], &tVariant).uIndex; + (sbtDrawables[uDrawableBatchIndex])[i].tShader = pl__get_shader_variant(uSceneHandle, atTemplateShaders[uDrawableBatchIndex], &tVariant); } } @@ -2457,7 +2769,7 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint gptGfx->add_to_stream(ptStream, (plStreamDraw) { - .uShaderVariant = tDrawable.uShader, + .uShaderVariant = tDrawable.tShader.uIndex, .uDynamicBuffer = tDynamicBinding.uBufferHandle, .uVertexBuffer = ptScene->tVertexBuffer.uIndex, .uIndexBuffer = tDrawable.uIndexCount == 0 ? UINT32_MAX : ptScene->tIndexBuffer.uIndex, @@ -2550,7 +2862,7 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint gptGfx->add_to_stream(ptStream, (plStreamDraw) { - .uShaderVariant = tDrawable.uShader, + .uShaderVariant = tDrawable.tShader.uIndex, .uDynamicBuffer = tDynamicBinding.uBufferHandle, .uVertexBuffer = ptScene->tVertexBuffer.uIndex, .uIndexBuffer = tDrawable.uIndexCount == 0 ? UINT32_MAX : ptScene->tIndexBuffer.uIndex, @@ -2565,6 +2877,84 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint } gptGfx->draw_stream(&tEncoder, 1, &tArea); + const uint32_t uOutlineDrawableCount = pl_sb_size(ptScene->sbtOutlineDrawables); + if(uOutlineDrawableCount > 0) + { + + gptGfx->reset_draw_stream(ptStream); + + typedef struct _plOutlineDynamicData + { + plVec4 tColor; + float fThickness; + int iDataOffset; + int iVertexOffset; + int iPadding[1]; + plMat4 tModel; + } plOutlineDynamicData; + + 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++) + { + const plDrawable tDrawable = ptScene->sbtOutlineDrawables[i]; + plObjectComponent* ptObject = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_OBJECT, tDrawable.tEntity); + plTransformComponent* ptTransform = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_TRANSFORM, ptObject->tTransform); + + plMeshComponent* ptMesh = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_MESH, ptObject->tMesh); + gptGfx->add_3d_aabb(&ptView->t3DSelectionDrawList, ptMesh->tAABBFinal.tMin, ptMesh->tAABBFinal.tMax, tOutlineColor2, 0.02f); + + plDynamicBinding tDynamicBinding = gptDevice->allocate_dynamic_data(ptDevice, sizeof(plOutlineDynamicData)); + + plOutlineDynamicData* ptDynamicData = (plOutlineDynamicData*)tDynamicBinding.pcData; + ptDynamicData->iDataOffset = tDrawable.uDataOffset; + ptDynamicData->iVertexOffset = tDrawable.uVertexOffset; + ptDynamicData->tModel = ptTransform->tWorld; + ptDynamicData->fThickness = 0.02f; + ptDynamicData->tColor = tOutlineColor; + + gptGfx->add_to_stream(ptStream, (plStreamDraw) + { + .uShaderVariant = tDrawable.tShader.uIndex, + .uDynamicBuffer = tDynamicBinding.uBufferHandle, + .uVertexBuffer = ptScene->tVertexBuffer.uIndex, + .uIndexBuffer = tDrawable.uIndexCount == 0 ? UINT32_MAX : ptScene->tIndexBuffer.uIndex, + .uIndexOffset = tDrawable.uIndexOffset, + .uTriangleCount = tDrawable.uIndexCount == 0 ? tDrawable.uVertexCount / 3 : tDrawable.uIndexCount / 3, + .uBindGroup1 = UINT32_MAX, + .uBindGroup2 = UINT32_MAX, + .uDynamicBufferOffset = tDynamicBinding.uByteOffset, + .uInstanceStart = 0, + .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); + } + if(tOptions.bShowAllBoundingBoxes) { for(uint32_t i = 0; i < uOpaqueDrawableCount; i++) @@ -2599,17 +2989,18 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint if(tOptions.bShowOrigin) { const plMat4 tTransform = pl_identity_mat4(); - gptGfx->add_3d_transform(&ptView->t3DDrawList, &tTransform, 10.0f, 0.02f); + gptGfx->add_3d_transform(&ptView->t3DSelectionDrawList, &tTransform, 10.0f, 0.02f); } if(tOptions.ptCullCamera && tOptions.ptCullCamera != tOptions.ptViewCamera) { - gptGfx->add_3d_frustum(&ptView->t3DDrawList, &tOptions.ptCullCamera->tTransformMat, tOptions.ptCullCamera->fFieldOfView, tOptions.ptCullCamera->fAspectRatio, tOptions.ptCullCamera->fNearZ, tOptions.ptCullCamera->fFarZ, (plVec4){1.0f, 1.0f, 0.0f, 1.0f}, 0.02f); + gptGfx->add_3d_frustum(&ptView->t3DSelectionDrawList, &tOptions.ptCullCamera->tTransformMat, tOptions.ptCullCamera->fFieldOfView, tOptions.ptCullCamera->fAspectRatio, tOptions.ptCullCamera->fNearZ, tOptions.ptCullCamera->fFarZ, (plVec4){1.0f, 1.0f, 0.0f, 1.0f}, 0.02f); } const plMat4 tMVP = pl_mul_mat4(&ptCamera->tProjMat, &ptCamera->tViewMat); gptGfx->submit_3d_drawlist(&ptView->t3DDrawList, tEncoder, tDimensions.x, tDimensions.y, &tMVP, PL_PIPELINE_FLAG_DEPTH_TEST | PL_PIPELINE_FLAG_DEPTH_WRITE, 1); + gptGfx->submit_3d_drawlist(&ptView->t3DSelectionDrawList, tEncoder, tDimensions.x, tDimensions.y, &tMVP, 0, 1); gptGfx->end_render_pass(&tEncoder); pl_end_profile_sample(); } @@ -3644,6 +4035,7 @@ pl_load_ref_renderer_api(void) .get_graphics = pl_refr_get_graphics, .load_skybox_from_panorama = pl_refr_load_skybox_from_panorama, .finalize_scene = pl_refr_finalize_scene, + .select_entities = pl_refr_select_entities, .update_skin_textures = pl_refr_update_skin_textures, .perform_skinning = pl_refr_perform_skinning, .render_scene = pl_refr_render_scene, diff --git a/extensions/pl_ref_renderer_ext.h b/extensions/pl_ref_renderer_ext.h index 4358c756..a32910c3 100644 --- a/extensions/pl_ref_renderer_ext.h +++ b/extensions/pl_ref_renderer_ext.h @@ -86,6 +86,7 @@ typedef struct _plRefRendererI void (*render_scene)(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint32_t uViewHandle, plViewOptions tOptions); // misc + void (*select_entities)(uint32_t uSceneHandle, uint32_t uCount, plEntity*); plComponentLibrary* (*get_component_library)(uint32_t uSceneHandle); plGraphics* (*get_graphics)(void); From fb039339e1de7a0aff8616fc6d03fb8493b02da3 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 7 May 2024 15:45:43 -0500 Subject: [PATCH 02/23] refac: change global allocator critical section to mutex --- src/pilotlight_lib.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/pilotlight_lib.c b/src/pilotlight_lib.c index 8ff01bbb..6f62956d 100644 --- a/src/pilotlight_lib.c +++ b/src/pilotlight_lib.c @@ -35,13 +35,13 @@ #include "pl_os.h" static plMemoryContext* gptMemoryContext = NULL; -static plCriticalSection* gptCriticalSection = NULL; +static plMutex* gptMutex = NULL; void pl_set_memory_context(plMemoryContext* ptMemoryContext) { gptMemoryContext = ptMemoryContext; - ptMemoryContext->plThreadsI->create_critical_section(&gptCriticalSection); + ptMemoryContext->plThreadsI->create_mutex(&gptMutex); } plMemoryContext* @@ -53,12 +53,13 @@ pl_get_memory_context(void) void* pl_realloc(void* pBuffer, size_t szSize, const char* pcFile, int iLine) { - + gptMemoryContext->plThreadsI->lock_mutex(gptMutex); + void* pNewBuffer = NULL; if(szSize > 0) { - gptMemoryContext->plThreadsI->enter_critical_section(gptCriticalSection); + gptMemoryContext->szActiveAllocations++; gptMemoryContext->szMemoryUsage += szSize; pNewBuffer = malloc(szSize); @@ -80,14 +81,13 @@ pl_realloc(void* pBuffer, size_t szSize, const char* pcFile, int iLine) gptMemoryContext->sbtAllocations[ulFreeIndex].pAddress = pNewBuffer; gptMemoryContext->sbtAllocations[ulFreeIndex].szSize = szSize; gptMemoryContext->szAllocationCount++; - gptMemoryContext->plThreadsI->leave_critical_section(gptCriticalSection); + } if(pBuffer) // free { const uint64_t ulHash = pl_hm_hash(&pBuffer, sizeof(void*), 1); - gptMemoryContext->plThreadsI->enter_critical_section(gptCriticalSection); const bool bDataExists = pl_hm_has_key(gptMemoryContext->ptHashMap, ulHash); if(bDataExists) @@ -110,9 +110,10 @@ pl_realloc(void* pBuffer, size_t szSize, const char* pcFile, int iLine) { PL_ASSERT(false); } - gptMemoryContext->plThreadsI->leave_critical_section(gptCriticalSection); free(pBuffer); } + + gptMemoryContext->plThreadsI->unlock_mutex(gptMutex); return pNewBuffer; } From 962834df5736ae941e92956fb323a777249d1907 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 7 May 2024 15:46:22 -0500 Subject: [PATCH 03/23] build: update pl_math to 0.6.4 --- dependencies/pilotlight-libs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/pilotlight-libs b/dependencies/pilotlight-libs index 00e12d0b..597ede27 160000 --- a/dependencies/pilotlight-libs +++ b/dependencies/pilotlight-libs @@ -1 +1 @@ -Subproject commit 00e12d0be39f9ae4994931c7f5bb64fd13fdf497 +Subproject commit 597ede274a645d52756ef3f09a95870205582061 From 50a0f58659cc7bb15d151c144193f042f27cc05c Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 7 May 2024 15:47:38 -0500 Subject: [PATCH 04/23] feat: add support for 8 texture channels to ecs ext --- extensions/pl_ecs_ext.c | 36 +++++++--- extensions/pl_ecs_ext.h | 20 ++++-- extensions/pl_ref_renderer_ext.c | 35 +++++++--- shaders/glsl/gbuffer_common.glsl | 26 ++++--- shaders/glsl/primitive.frag | 12 ++-- shaders/glsl/primitive.vert | 21 +++++- shaders/glsl/skinning.comp | 21 +++--- shaders/glsl/transparent.frag | 14 ++-- shaders/metal/primitive.metal | 79 ++++++++++++++++----- shaders/metal/skinning.metal | 18 +++-- shaders/metal/transparent.metal | 116 +++++++++++++++++++++---------- 11 files changed, 277 insertions(+), 121 deletions(-) diff --git a/extensions/pl_ecs_ext.c b/extensions/pl_ecs_ext.c index e69c03a8..6c9421ff 100644 --- a/extensions/pl_ecs_ext.c +++ b/extensions/pl_ecs_ext.c @@ -277,6 +277,12 @@ pl_ecs_cleanup_component_library(plComponentLibrary* ptLibrary) pl_sb_free(sbtMeshes[i].sbtVertexJoints[1]); pl_sb_free(sbtMeshes[i].sbtVertexTextureCoordinates[0]); pl_sb_free(sbtMeshes[i].sbtVertexTextureCoordinates[1]); + pl_sb_free(sbtMeshes[i].sbtVertexTextureCoordinates[2]); + pl_sb_free(sbtMeshes[i].sbtVertexTextureCoordinates[3]); + pl_sb_free(sbtMeshes[i].sbtVertexTextureCoordinates[4]); + pl_sb_free(sbtMeshes[i].sbtVertexTextureCoordinates[5]); + pl_sb_free(sbtMeshes[i].sbtVertexTextureCoordinates[6]); + pl_sb_free(sbtMeshes[i].sbtVertexTextureCoordinates[7]); pl_sb_free(sbtMeshes[i].sbuIndices); } @@ -540,7 +546,7 @@ pl_ecs_add_component(plComponentLibrary* ptLibrary, plComponentType tType, plEnt if(bAddSlot) pl_sb_add(sbComponents); ptManager->pComponents = sbComponents; - sbComponents[uComponentIndex] = (plObjectComponent){0}; + sbComponents[uComponentIndex] = (plObjectComponent){.tMesh= {UINT32_MAX, UINT32_MAX}, .tTransform ={UINT32_MAX, UINT32_MAX}}; return &sbComponents[uComponentIndex]; } @@ -870,16 +876,28 @@ pl__object_update_job(uint32_t uJobIndex, void* pData) plObjectComponent* ptObject = &sbtComponents[uJobIndex]; plTransformComponent* ptTransform = pl_ecs_get_component(ptLibrary, PL_COMPONENT_TYPE_TRANSFORM, ptObject->tTransform); plMeshComponent* ptMesh = pl_ecs_get_component(ptLibrary, PL_COMPONENT_TYPE_MESH, ptObject->tMesh); + plSkinComponent* ptSkinComponent = pl_ecs_get_component(ptLibrary, PL_COMPONENT_TYPE_SKIN, ptMesh->tSkinComponent); + + plMat4 tTransform = ptTransform->tWorld; + + if(ptSkinComponent) + { + plEntity tJointEntity = ptSkinComponent->sbtJoints[0]; + plTransformComponent* ptJointComponent = pl_ecs_get_component(ptLibrary, PL_COMPONENT_TYPE_TRANSFORM, tJointEntity); + + const plMat4* ptIBM = &ptSkinComponent->sbtInverseBindMatrices[0]; + tTransform = pl_mul_mat4(&ptJointComponent->tWorld, ptIBM); + } const plVec3 tVerticies[] = { - pl_mul_mat4_vec3(&ptTransform->tWorld, (plVec3){ ptMesh->tAABB.tMin.x, ptMesh->tAABB.tMin.y, ptMesh->tAABB.tMin.z }), - pl_mul_mat4_vec3(&ptTransform->tWorld, (plVec3){ ptMesh->tAABB.tMax.x, ptMesh->tAABB.tMin.y, ptMesh->tAABB.tMin.z }), - pl_mul_mat4_vec3(&ptTransform->tWorld, (plVec3){ ptMesh->tAABB.tMax.x, ptMesh->tAABB.tMax.y, ptMesh->tAABB.tMin.z }), - pl_mul_mat4_vec3(&ptTransform->tWorld, (plVec3){ ptMesh->tAABB.tMin.x, ptMesh->tAABB.tMax.y, ptMesh->tAABB.tMin.z }), - pl_mul_mat4_vec3(&ptTransform->tWorld, (plVec3){ ptMesh->tAABB.tMin.x, ptMesh->tAABB.tMin.y, ptMesh->tAABB.tMax.z }), - pl_mul_mat4_vec3(&ptTransform->tWorld, (plVec3){ ptMesh->tAABB.tMax.x, ptMesh->tAABB.tMin.y, ptMesh->tAABB.tMax.z }), - pl_mul_mat4_vec3(&ptTransform->tWorld, (plVec3){ ptMesh->tAABB.tMax.x, ptMesh->tAABB.tMax.y, ptMesh->tAABB.tMax.z }), - pl_mul_mat4_vec3(&ptTransform->tWorld, (plVec3){ ptMesh->tAABB.tMin.x, ptMesh->tAABB.tMax.y, ptMesh->tAABB.tMax.z }), + pl_mul_mat4_vec3(&tTransform, (plVec3){ ptMesh->tAABB.tMin.x, ptMesh->tAABB.tMin.y, ptMesh->tAABB.tMin.z }), + pl_mul_mat4_vec3(&tTransform, (plVec3){ ptMesh->tAABB.tMax.x, ptMesh->tAABB.tMin.y, ptMesh->tAABB.tMin.z }), + pl_mul_mat4_vec3(&tTransform, (plVec3){ ptMesh->tAABB.tMax.x, ptMesh->tAABB.tMax.y, ptMesh->tAABB.tMin.z }), + pl_mul_mat4_vec3(&tTransform, (plVec3){ ptMesh->tAABB.tMin.x, ptMesh->tAABB.tMax.y, ptMesh->tAABB.tMin.z }), + pl_mul_mat4_vec3(&tTransform, (plVec3){ ptMesh->tAABB.tMin.x, ptMesh->tAABB.tMin.y, ptMesh->tAABB.tMax.z }), + pl_mul_mat4_vec3(&tTransform, (plVec3){ ptMesh->tAABB.tMax.x, ptMesh->tAABB.tMin.y, ptMesh->tAABB.tMax.z }), + pl_mul_mat4_vec3(&tTransform, (plVec3){ ptMesh->tAABB.tMax.x, ptMesh->tAABB.tMax.y, ptMesh->tAABB.tMax.z }), + pl_mul_mat4_vec3(&tTransform, (plVec3){ ptMesh->tAABB.tMin.x, ptMesh->tAABB.tMax.y, ptMesh->tAABB.tMax.z }), }; // calculate AABB diff --git a/extensions/pl_ecs_ext.h b/extensions/pl_ecs_ext.h index 3361c2bb..63711c83 100644 --- a/extensions/pl_ecs_ext.h +++ b/extensions/pl_ecs_ext.h @@ -269,12 +269,18 @@ enum _plMeshFormatFlags PL_MESH_FORMAT_FLAG_HAS_TANGENT = 1 << 2, PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0 = 1 << 3, PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1 = 1 << 4, - PL_MESH_FORMAT_FLAG_HAS_COLOR_0 = 1 << 5, - PL_MESH_FORMAT_FLAG_HAS_COLOR_1 = 1 << 6, - PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 = 1 << 7, - PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 = 1 << 8, - PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 = 1 << 9, - PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 = 1 << 10 + PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2 = 1 << 5, + PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3 = 1 << 6, + PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4 = 1 << 7, + PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5 = 1 << 8, + PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6 = 1 << 9, + PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7 = 1 << 10, + PL_MESH_FORMAT_FLAG_HAS_COLOR_0 = 1 << 11, + PL_MESH_FORMAT_FLAG_HAS_COLOR_1 = 1 << 12, + PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 = 1 << 13, + PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 = 1 << 14, + PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 = 1 << 15, + PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 = 1 << 16 }; //----------------------------------------------------------------------------- @@ -421,7 +427,7 @@ typedef struct _plMeshComponent plVec4* sbtVertexColors[2]; plVec4* sbtVertexWeights[2]; plVec4* sbtVertexJoints[2]; - plVec2* sbtVertexTextureCoordinates[2]; + plVec2* sbtVertexTextureCoordinates[8]; uint32_t* sbuIndices; plAABB tAABB; plAABB tAABBFinal; diff --git a/extensions/pl_ref_renderer_ext.c b/extensions/pl_ref_renderer_ext.c index f45de513..9279b964 100644 --- a/extensions/pl_ref_renderer_ext.c +++ b/extensions/pl_ref_renderer_ext.c @@ -3161,6 +3161,12 @@ pl__add_drawable_skin_data_to_global_buffer(plRefScene* ptScene, uint32_t uDrawa if(pl_sb_size(ptMesh->sbtVertexColors[1]) > 0) { uDestStride += 1; } if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[0]) > 0) { uDestStride += 1; } if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[1]) > 0) { uDestStride += 1; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[2]) > 0) { uDestStride += 1; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[3]) > 0) { uDestStride += 1; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[4]) > 0) { uDestStride += 1; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[5]) > 0) { uDestStride += 1; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[6]) > 0) { uDestStride += 1; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[7]) > 0) { uDestStride += 1; } plSkinData tSkinData = { .tEntity = ptMesh->tSkinComponent, @@ -3268,6 +3274,12 @@ pl__add_drawable_data_to_global_buffer(plRefScene* ptScene, uint32_t uDrawableIn if(pl_sb_size(ptMesh->sbtVertexColors[1]) > 0) { uStride += 1; ptMesh->ulVertexStreamMask |= PL_MESH_FORMAT_FLAG_HAS_COLOR_1; } if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[0]) > 0) { uStride += 1; ptMesh->ulVertexStreamMask |= PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0; } if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[1]) > 0) { uStride += 1; ptMesh->ulVertexStreamMask |= PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[2]) > 0) { uStride += 1; ptMesh->ulVertexStreamMask |= PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[3]) > 0) { uStride += 1; ptMesh->ulVertexStreamMask |= PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[4]) > 0) { uStride += 1; ptMesh->ulVertexStreamMask |= PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[5]) > 0) { uStride += 1; ptMesh->ulVertexStreamMask |= PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[6]) > 0) { uStride += 1; ptMesh->ulVertexStreamMask |= PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6; } + if(pl_sb_size(ptMesh->sbtVertexTextureCoordinates[7]) > 0) { uStride += 1; ptMesh->ulVertexStreamMask |= PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7; } pl_sb_add_n(ptScene->sbtVertexDataBuffer, uStride * uVertexCount); @@ -3304,19 +3316,22 @@ pl__add_drawable_data_to_global_buffer(plRefScene* ptScene, uint32_t uDrawableIn uOffset += 1; // texture coordinates 0 - const uint32_t uVertexTexCount = pl_sb_size(ptMesh->sbtVertexTextureCoordinates[0]); - for(uint32_t i = 0; i < uVertexTexCount; i++) + for(uint32_t i = 0; i < 8; i++) { - const plVec2* ptTextureCoordinates = &(ptMesh->sbtVertexTextureCoordinates[0])[i]; - ptScene->sbtVertexDataBuffer[uVertexDataStartIndex + i * uStride + uOffset].x = ptTextureCoordinates->u; - ptScene->sbtVertexDataBuffer[uVertexDataStartIndex + i * uStride + uOffset].y = ptTextureCoordinates->v; - ptScene->sbtVertexDataBuffer[uVertexDataStartIndex + i * uStride + uOffset].z = 0.0f; - ptScene->sbtVertexDataBuffer[uVertexDataStartIndex + i * uStride + uOffset].w = 0.0f; + const uint32_t uVertexTexCount = pl_sb_size(ptMesh->sbtVertexTextureCoordinates[i]); + for(uint32_t j = 0; j < uVertexTexCount; j++) + { + const plVec2* ptTextureCoordinates = &(ptMesh->sbtVertexTextureCoordinates[i])[j]; + ptScene->sbtVertexDataBuffer[uVertexDataStartIndex + j * uStride + uOffset].x = ptTextureCoordinates->u; + ptScene->sbtVertexDataBuffer[uVertexDataStartIndex + j * uStride + uOffset].y = ptTextureCoordinates->v; + ptScene->sbtVertexDataBuffer[uVertexDataStartIndex + j * uStride + uOffset].z = 0.0f; + ptScene->sbtVertexDataBuffer[uVertexDataStartIndex + j * uStride + uOffset].w = 0.0f; - } + } - if(uVertexTexCount > 0) - uOffset += 1; + if(uVertexTexCount > 0) + uOffset += 1; + } // color 0 const uint32_t uVertexColorCount = pl_sb_size(ptMesh->sbtVertexColors[0]); diff --git a/shaders/glsl/gbuffer_common.glsl b/shaders/glsl/gbuffer_common.glsl index 1506dd7e..e053d801 100644 --- a/shaders/glsl/gbuffer_common.glsl +++ b/shaders/glsl/gbuffer_common.glsl @@ -144,12 +144,18 @@ 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_COLOR_0 = 1 << 5; -const int PL_MESH_FORMAT_FLAG_HAS_COLOR_1 = 1 << 6; -const int PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 = 1 << 7; -const int PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 = 1 << 8; -const int PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 = 1 << 9; -const int PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 = 1 << 10; +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; @@ -178,9 +184,9 @@ struct NormalInfo { vec3 ntex; // Normal from texture, scaling is accounted for. }; -NormalInfo pl_get_normal_info() +NormalInfo pl_get_normal_info(int iUVSet) { - vec2 UV = tShaderIn.tUV[0]; + vec2 UV = tShaderIn.tUV[iUVSet]; vec2 uv_dx = dFdx(UV); vec2 uv_dy = dFdy(UV); @@ -260,7 +266,7 @@ NormalInfo pl_get_normal_info() const float M_PI = 3.141592653589793; -vec4 getBaseColor(vec4 u_ColorFactor) +vec4 getBaseColor(vec4 u_ColorFactor, int iUVSet) { vec4 baseColor = vec4(1); @@ -283,7 +289,7 @@ vec4 getBaseColor(vec4 u_ColorFactor) // 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[0]); + baseColor *= texture(sampler2D(tBaseColorTexture, tDefaultSampler), tShaderIn.tUV[iUVSet]); } return baseColor * tShaderIn.tColor; } diff --git a/shaders/glsl/primitive.frag b/shaders/glsl/primitive.frag index 2c94982e..b0306980 100644 --- a/shaders/glsl/primitive.frag +++ b/shaders/glsl/primitive.frag @@ -11,7 +11,7 @@ layout(location = 4) out vec4 outAOMetalnessRoughness; layout(location = 0) in struct plShaderIn { vec3 tPosition; vec4 tWorldPosition; - vec2 tUV[2]; + vec2 tUV[8]; vec4 tColor; vec3 tWorldNormal; mat3 tTBN; @@ -24,9 +24,9 @@ void main() { tMaterial material = tMaterialInfo.atMaterials[tObjectInfo.iMaterialIndex]; - vec4 tBaseColor = getBaseColor(material.u_BaseColorFactor); + vec4 tBaseColor = getBaseColor(material.u_BaseColorFactor, material.BaseColorUVSet); - NormalInfo tNormalInfo = pl_get_normal_info(); + NormalInfo tNormalInfo = pl_get_normal_info(material.NormalUVSet); vec3 n = tNormalInfo.n; vec3 t = tNormalInfo.t; @@ -42,7 +42,7 @@ main() if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS)) { - materialInfo = getMetallicRoughnessInfo(materialInfo, material.u_MetallicFactor, material.u_RoughnessFactor, 0); + materialInfo = getMetallicRoughnessInfo(materialInfo, material.u_MetallicFactor, material.u_RoughnessFactor, material.MetallicRoughnessUVSet); } materialInfo.perceptualRoughness = clamp(materialInfo.perceptualRoughness, 0.0, 1.0); @@ -62,14 +62,14 @@ main() vec3 f_emissive = material.u_EmissiveFactor; if(bool(iTextureMappingFlags & PL_HAS_EMISSIVE_MAP)) { - f_emissive *= texture(sampler2D(tEmissiveTexture, tDefaultSampler), tShaderIn.tUV[0]).rgb; + f_emissive *= texture(sampler2D(tEmissiveTexture, tDefaultSampler), tShaderIn.tUV[material.EmissiveUVSet]).rgb; } // ambient occlusion float ao = 1.0; if(bool(iTextureMappingFlags & PL_HAS_OCCLUSION_MAP)) { - ao = texture(sampler2D(tOcclusionTexture, tDefaultSampler), tShaderIn.tUV[0]).r; + ao = texture(sampler2D(tOcclusionTexture, tDefaultSampler), tShaderIn.tUV[material.OcclusionUVSet]).r; } // fill g-buffer diff --git a/shaders/glsl/primitive.vert b/shaders/glsl/primitive.vert index 08b020eb..8c42cb34 100644 --- a/shaders/glsl/primitive.vert +++ b/shaders/glsl/primitive.vert @@ -8,7 +8,7 @@ layout(location = 0) in vec3 inPos; layout(location = 0) out struct plShaderOut { vec3 tPosition; vec4 tWorldPosition; - vec2 tUV[2]; + vec2 tUV[8]; vec4 tColor; vec3 tWorldNormal; mat3 tTBN; @@ -25,6 +25,12 @@ main() 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; @@ -37,6 +43,12 @@ main() 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++;} @@ -58,6 +70,13 @@ main() 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/glsl/skinning.comp b/shaders/glsl/skinning.comp index 64adc87f..42857d0b 100644 --- a/shaders/glsl/skinning.comp +++ b/shaders/glsl/skinning.comp @@ -61,12 +61,18 @@ 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_COLOR_0 = 1 << 5; -const int PL_MESH_FORMAT_FLAG_HAS_COLOR_1 = 1 << 6; -const int PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 = 1 << 7; -const int PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 = 1 << 8; -const int PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 = 1 << 9; -const int PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 = 1 << 10; +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; mat4 get_matrix_from_texture(int index) @@ -111,9 +117,6 @@ layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; void main() { - // const float fXCoord = gl_WorkGroupID.x * 16 + gl_LocalInvocationID.x; - // const float tYCoord = gl_WorkGroupID.y * 16 + gl_LocalInvocationID.y; - // const int iFace = int(gl_WorkGroupID.z * 3 + gl_LocalInvocationID.z); const uint iVertexIndex = gl_WorkGroupID.x; diff --git a/shaders/glsl/transparent.frag b/shaders/glsl/transparent.frag index 79f8cfa7..7e92bdef 100644 --- a/shaders/glsl/transparent.frag +++ b/shaders/glsl/transparent.frag @@ -19,7 +19,7 @@ layout(location = 0) out vec4 outColor; layout(location = 0) in struct plShaderIn { vec3 tPosition; vec4 tWorldPosition; - vec2 tUV[2]; + vec2 tUV[8]; vec4 tColor; vec3 tWorldNormal; mat3 tTBN; @@ -237,14 +237,14 @@ main() vec3 tSunLightDirection = vec3(-1.0, -1.0, -1.0); tMaterial material = tMaterialInfo.atMaterials[tObjectInfo.iMaterialIndex]; - vec4 tBaseColor = getBaseColor(material.u_BaseColorFactor); + vec4 tBaseColor = getBaseColor(material.u_BaseColorFactor, material.BaseColorUVSet); - if(tBaseColor.a < 0.1) + if(tBaseColor.a < 0.01) { discard; } - NormalInfo tNormalInfo = pl_get_normal_info(); + NormalInfo tNormalInfo = pl_get_normal_info(material.NormalUVSet); vec3 n = tNormalInfo.n; vec3 t = tNormalInfo.t; @@ -260,7 +260,7 @@ main() if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS)) { - materialInfo = getMetallicRoughnessInfo(materialInfo, material.u_MetallicFactor, material.u_RoughnessFactor, 0); + materialInfo = getMetallicRoughnessInfo(materialInfo, material.u_MetallicFactor, material.u_RoughnessFactor, material.MetallicRoughnessUVSet); } materialInfo.perceptualRoughness = clamp(materialInfo.perceptualRoughness, 0.0, 1.0); @@ -280,14 +280,14 @@ main() vec3 f_emissive = material.u_EmissiveFactor; if(bool(iTextureMappingFlags & PL_HAS_EMISSIVE_MAP)) { - f_emissive *= texture(sampler2D(tEmissiveTexture, tDefaultSampler), tShaderIn.tUV[0]).rgb; + f_emissive *= texture(sampler2D(tEmissiveTexture, tDefaultSampler), tShaderIn.tUV[material.EmissiveUVSet]).rgb; } // ambient occlusion float ao = 1.0; if(bool(iTextureMappingFlags & PL_HAS_OCCLUSION_MAP)) { - ao = texture(sampler2D(tOcclusionTexture, tDefaultSampler), tShaderIn.tUV[0]).r; + ao = texture(sampler2D(tOcclusionTexture, tDefaultSampler), tShaderIn.tUV[material.OcclusionUVSet]).r; } // fill g-buffer diff --git a/shaders/metal/primitive.metal b/shaders/metal/primitive.metal index 2126f1cc..b1bce95e 100644 --- a/shaders/metal/primitive.metal +++ b/shaders/metal/primitive.metal @@ -27,12 +27,18 @@ constant const float INV_GAMMA = 1.0 / GAMMA; #define PL_MESH_FORMAT_FLAG_HAS_TANGENT 1 << 2 #define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0 1 << 3 #define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1 1 << 4 -#define PL_MESH_FORMAT_FLAG_HAS_COLOR_0 1 << 5 -#define PL_MESH_FORMAT_FLAG_HAS_COLOR_1 1 << 6 -#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 1 << 7 -#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 1 << 8 -#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 1 << 9 -#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 1 << 10 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2 1 << 5 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3 1 << 6 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4 1 << 7 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5 1 << 8 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6 1 << 9 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7 1 << 10 +#define PL_MESH_FORMAT_FLAG_HAS_COLOR_0 1 << 11 +#define PL_MESH_FORMAT_FLAG_HAS_COLOR_1 1 << 12 +#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 1 << 13 +#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 1 << 14 +#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 1 << 15 +#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 1 << 16 // iTextureMappingFlags #define PL_HAS_BASE_COLOR_MAP 1 << 0 @@ -235,7 +241,14 @@ struct VertexOut { float4 tPositionOut [[position]]; float3 tPosition; float4 tWorldPosition; - float2 tUV; + float2 tUV0; + float2 tUV1; + float2 tUV2; + float2 tUV3; + float2 tUV4; + float2 tUV5; + float2 tUV6; + float2 tUV7; float4 tColor; float3 tWorldNormal; float3 tTBN0; @@ -257,9 +270,8 @@ struct plMultipleRenderTargets //----------------------------------------------------------------------------- NormalInfo -pl_get_normal_info(device const BindGroup_0& bg0, device const BindGroup_1& bg1, VertexOut tShaderIn, bool front_facing) +pl_get_normal_info(device const BindGroup_0& bg0, device const BindGroup_1& bg1, VertexOut tShaderIn, bool front_facing, float2 UV) { - float2 UV = tShaderIn.tUV; float2 uv_dx = dfdx(UV); float2 uv_dy = dfdy(UV); @@ -333,7 +345,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) +getBaseColor(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float4 u_ColorFactor, VertexOut tShaderIn, float2 UV) { float4 baseColor = float4(1); @@ -357,7 +369,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, tShaderIn.tUV); + baseColor *= bg1.tBaseColorTexture.sample(bg0.tDefaultSampler, UV); } return baseColor * tShaderIn.tColor; } @@ -369,7 +381,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, int UVSet) +getMetallicRoughnessInfo(VertexOut in, device const BindGroup_0& bg0, device const BindGroup_1& bg1, MaterialInfo info, float u_MetallicFactor, float u_RoughnessFactor, float2 UV) { info.metallic = u_MetallicFactor; info.perceptualRoughness = u_RoughnessFactor; @@ -378,7 +390,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, in.tUV).rgb, 1.0); + float4 mrSample = float4(bg1.tMetallicRoughnessTexture.sample(bg0.tDefaultSampler, UV).rgb, 1.0); info.perceptualRoughness *= mrSample.g; info.metallic *= mrSample.b; } @@ -408,6 +420,12 @@ vertex VertexOut vertex_main( float4 inTangent = float4(0.0, 0.0, 0.0, 0.0); float2 inTexCoord0 = float2(0.0, 0.0); float2 inTexCoord1 = float2(0.0, 0.0); + float2 inTexCoord2 = float2(0.0, 0.0); + float2 inTexCoord3 = float2(0.0, 0.0); + float2 inTexCoord4 = float2(0.0, 0.0); + float2 inTexCoord5 = float2(0.0, 0.0); + float2 inTexCoord6 = float2(0.0, 0.0); + float2 inTexCoord7 = float2(0.0, 0.0); float4 inColor0 = float4(1.0, 1.0, 1.0, 1.0); float4 inColor1 = float4(0.0, 0.0, 0.0, 0.0); int iCurrentAttribute = 0; @@ -420,6 +438,12 @@ vertex VertexOut vertex_main( if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TANGENT) { inTangent = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute]; iCurrentAttribute++;} if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0){ inTexCoord0 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1){ inTexCoord1 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2){ inTexCoord2 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3){ inTexCoord3 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4){ inTexCoord4 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5){ inTexCoord5 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6){ inTexCoord6 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7){ inTexCoord7 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_COLOR_0) { inColor0 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute]; iCurrentAttribute++;} if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_COLOR_1) { inColor1 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute]; iCurrentAttribute++;} @@ -443,7 +467,14 @@ vertex VertexOut vertex_main( float4 pos = tObjectInfo.tModel * inPosition; tShaderOut.tPosition = pos.xyz / pos.w; tShaderOut.tPositionOut = bg0.data->tCameraViewProjection * pos; - tShaderOut.tUV = inTexCoord0; + tShaderOut.tUV0 = inTexCoord0; + tShaderOut.tUV1 = inTexCoord1; + tShaderOut.tUV2 = inTexCoord2; + tShaderOut.tUV3 = inTexCoord3; + tShaderOut.tUV4 = inTexCoord4; + tShaderOut.tUV5 = inTexCoord5; + tShaderOut.tUV6 = inTexCoord6; + tShaderOut.tUV7 = inTexCoord7; tShaderOut.tWorldPosition = tShaderOut.tPositionOut / tShaderOut.tPositionOut.w; tShaderOut.tColor = inColor0; @@ -459,9 +490,19 @@ fragment plMultipleRenderTargets fragment_main( bool front_facing [[front_facing]] ) { + const float2 tUV[8] = { + in.tUV0, + in.tUV1, + in.tUV2, + in.tUV3, + in.tUV4, + in.tUV5, + in.tUV6, + in.tUV7 + }; tMaterial material = bg0.atMaterials[tObjectInfo.iMaterialIndex]; - float4 tBaseColor = getBaseColor(bg0, bg1, material.u_BaseColorFactor, in); - NormalInfo tNormalInfo = pl_get_normal_info(bg0, bg1, in, front_facing); + float4 tBaseColor = getBaseColor(bg0, bg1, material.u_BaseColorFactor, in, tUV[material.BaseColorUVSet]); + NormalInfo tNormalInfo = pl_get_normal_info(bg0, bg1, in, front_facing, tUV[material.NormalUVSet]); float3 n = tNormalInfo.n; float3 t = tNormalInfo.t; @@ -477,7 +518,7 @@ fragment plMultipleRenderTargets fragment_main( if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS)) { - materialInfo = getMetallicRoughnessInfo(in, bg0, bg1, materialInfo, material.u_MetallicFactor, material.u_RoughnessFactor, 0); + materialInfo = getMetallicRoughnessInfo(in, bg0, bg1, materialInfo, material.u_MetallicFactor, material.u_RoughnessFactor, tUV[material.MetallicRoughnessUVSet]); } materialInfo.perceptualRoughness = fast::clamp(materialInfo.perceptualRoughness, 0.0, 1.0); @@ -497,14 +538,14 @@ fragment plMultipleRenderTargets fragment_main( float3 f_emissive = material.u_EmissiveFactor; if(bool(iTextureMappingFlags & PL_HAS_EMISSIVE_MAP)) { - f_emissive *= bg1.tEmissiveTexture.sample(bg0.tDefaultSampler, in.tUV).rgb; + f_emissive *= bg1.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, in.tUV).r; + ao = bg1.tOcclusionTexture.sample(bg0.tDefaultSampler, tUV[material.OcclusionUVSet]).r; } plMultipleRenderTargets tMRT; diff --git a/shaders/metal/skinning.metal b/shaders/metal/skinning.metal index 152265a0..fe5e5d57 100644 --- a/shaders/metal/skinning.metal +++ b/shaders/metal/skinning.metal @@ -23,12 +23,18 @@ constant int iDestDataStride [[ function_constant(3) ]]; #define PL_MESH_FORMAT_FLAG_HAS_TANGENT 1 << 2 #define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0 1 << 3 #define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1 1 << 4 -#define PL_MESH_FORMAT_FLAG_HAS_COLOR_0 1 << 5 -#define PL_MESH_FORMAT_FLAG_HAS_COLOR_1 1 << 6 -#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 1 << 7 -#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 1 << 8 -#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 1 << 9 -#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 1 << 10 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2 1 << 5 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3 1 << 6 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4 1 << 7 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5 1 << 8 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6 1 << 9 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7 1 << 10 +#define PL_MESH_FORMAT_FLAG_HAS_COLOR_0 1 << 11 +#define PL_MESH_FORMAT_FLAG_HAS_COLOR_1 1 << 12 +#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 1 << 13 +#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 1 << 14 +#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 1 << 15 +#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 1 << 16 //----------------------------------------------------------------------------- // [SECTION] bind group 0 diff --git a/shaders/metal/transparent.metal b/shaders/metal/transparent.metal index 99e10e83..a812c0e8 100644 --- a/shaders/metal/transparent.metal +++ b/shaders/metal/transparent.metal @@ -19,6 +19,9 @@ constant int iRenderingFlags [[ function_constant(4) ]]; constant float M_PI = 3.141592653589793; +constant const float GAMMA = 2.2; +constant const float INV_GAMMA = 1.0 / GAMMA; + // iMeshVariantFlags #define PL_MESH_FORMAT_FLAG_NONE 0 #define PL_MESH_FORMAT_FLAG_HAS_POSITION 1 << 0 @@ -26,12 +29,18 @@ constant float M_PI = 3.141592653589793; #define PL_MESH_FORMAT_FLAG_HAS_TANGENT 1 << 2 #define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0 1 << 3 #define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1 1 << 4 -#define PL_MESH_FORMAT_FLAG_HAS_COLOR_0 1 << 5 -#define PL_MESH_FORMAT_FLAG_HAS_COLOR_1 1 << 6 -#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 1 << 7 -#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 1 << 8 -#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 1 << 9 -#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 1 << 10 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2 1 << 5 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3 1 << 6 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4 1 << 7 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5 1 << 8 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6 1 << 9 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7 1 << 10 +#define PL_MESH_FORMAT_FLAG_HAS_COLOR_0 1 << 11 +#define PL_MESH_FORMAT_FLAG_HAS_COLOR_1 1 << 12 +#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 1 << 13 +#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 1 << 14 +#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 1 << 15 +#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 1 << 16 // iTextureMappingFlags #define PL_HAS_BASE_COLOR_MAP 1 << 0 @@ -197,7 +206,14 @@ struct VertexOut { float4 tPositionOut [[position]]; float3 tPosition; float4 tWorldPosition; - float2 tUV; + float2 tUV0; + float2 tUV1; + float2 tUV2; + float2 tUV3; + float2 tUV4; + float2 tUV5; + float2 tUV6; + float2 tUV7; float4 tColor; float3 tWorldNormal; float3 tTBN0; @@ -229,6 +245,12 @@ vertex VertexOut vertex_main( float4 inTangent = float4(0.0, 0.0, 0.0, 0.0); float2 inTexCoord0 = float2(0.0, 0.0); float2 inTexCoord1 = float2(0.0, 0.0); + float2 inTexCoord2 = float2(0.0, 0.0); + float2 inTexCoord3 = float2(0.0, 0.0); + float2 inTexCoord4 = float2(0.0, 0.0); + float2 inTexCoord5 = float2(0.0, 0.0); + float2 inTexCoord6 = float2(0.0, 0.0); + float2 inTexCoord7 = float2(0.0, 0.0); float4 inColor0 = float4(1.0, 1.0, 1.0, 1.0); float4 inColor1 = float4(0.0, 0.0, 0.0, 0.0); int iCurrentAttribute = 0; @@ -241,6 +263,12 @@ vertex VertexOut vertex_main( if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TANGENT) { inTangent = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute]; iCurrentAttribute++;} if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0){ inTexCoord0 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1){ inTexCoord1 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2){ inTexCoord2 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3){ inTexCoord3 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4){ inTexCoord4 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5){ inTexCoord5 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6){ inTexCoord6 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7){ inTexCoord7 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_COLOR_0) { inColor0 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute]; iCurrentAttribute++;} if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_COLOR_1) { inColor1 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute]; iCurrentAttribute++;} @@ -264,7 +292,14 @@ vertex VertexOut vertex_main( float4 pos = tObjectInfo.tModel * inPosition; tShaderOut.tPosition = pos.xyz / pos.w; tShaderOut.tPositionOut = bg0.data->tCameraViewProjection * pos; - tShaderOut.tUV = inTexCoord0; + tShaderOut.tUV0 = inTexCoord0; + tShaderOut.tUV1 = inTexCoord1; + tShaderOut.tUV2 = inTexCoord2; + tShaderOut.tUV3 = inTexCoord3; + tShaderOut.tUV4 = inTexCoord4; + tShaderOut.tUV5 = inTexCoord5; + tShaderOut.tUV6 = inTexCoord6; + tShaderOut.tUV7 = inTexCoord7; tShaderOut.tWorldPosition = tShaderOut.tPositionOut / tShaderOut.tPositionOut.w; tShaderOut.tColor = inColor0; @@ -280,9 +315,9 @@ struct NormalInfo { float3 ntex; // Normal from texture, scaling is accounted for. }; -NormalInfo pl_get_normal_info(device const BindGroup_0& bg0, device const BindGroup_1& bg1, VertexOut tShaderIn, bool front_facing) +NormalInfo +pl_get_normal_info(device const BindGroup_0& bg0, device const BindGroup_1& bg1, VertexOut tShaderIn, bool front_facing, float2 UV) { - float2 UV = tShaderIn.tUV; float2 uv_dx = dfdx(UV); float2 uv_dy = dfdy(UV); @@ -300,29 +335,29 @@ NormalInfo pl_get_normal_info(device const BindGroup_0& bg0, device const BindGr float3 t, b, ng; // Compute geometrical TBN: - if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_NORMAL) + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_NORMAL)) { - if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TANGENT) + 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.tTBN0); - b = normalize(tShaderIn.tTBN1); - ng = normalize(tShaderIn.tTBN2); + t = fast::normalize(tShaderIn.tTBN0); + b = fast::normalize(tShaderIn.tTBN1); + ng = fast::normalize(tShaderIn.tTBN2); } else { // Normals are either present as vertex attributes or approximated. - ng = normalize(tShaderIn.tWorldNormal); - t = normalize(t_ - ng * dot(ng, t_)); + ng = fast::normalize(tShaderIn.tWorldNormal); + t = fast::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_)); + ng = fast::normalize(cross(dfdx(tShaderIn.tPosition), dfdy(tShaderIn.tPosition))); + t = fast::normalize(t_ - ng * dot(ng, t_)); b = cross(ng, t); } @@ -338,13 +373,13 @@ NormalInfo pl_get_normal_info(device const BindGroup_0& bg0, device const BindGr // Compute normals: NormalInfo info; info.ng = ng; - if(iTextureMappingFlags & PL_HAS_NORMAL_MAP) + if(bool(iTextureMappingFlags & PL_HAS_NORMAL_MAP)) { info.ntex = bg1.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 = normalize(info.ntex); - info.n = normalize(float3x3(t, b, ng) * info.ntex); + info.ntex = fast::normalize(info.ntex); + info.n = fast::normalize(float3x3(t, b, ng) * info.ntex); } else { @@ -356,7 +391,7 @@ NormalInfo pl_get_normal_info(device const BindGroup_0& bg0, device const BindGr } float4 -getBaseColor(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float4 u_ColorFactor, VertexOut tShaderIn) +getBaseColor(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float4 u_ColorFactor, VertexOut tShaderIn, float2 UV) { float4 baseColor = float4(1); @@ -380,23 +415,19 @@ 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, tShaderIn.tUV); + baseColor *= bg1.tBaseColorTexture.sample(bg0.tDefaultSampler, UV); } return baseColor * tShaderIn.tColor; } -constant const float GAMMA = 2.2; -constant const float INV_GAMMA = 1.0 / GAMMA; - -// linear to sRGB approximation -// see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html -float3 linearTosRGB(float3 color) +float3 +linearTosRGB(float3 color) { return pow(color, float3(INV_GAMMA)); } MaterialInfo -getMetallicRoughnessInfo(VertexOut in, device const BindGroup_0& bg0, device const BindGroup_1& bg1, MaterialInfo info, float u_MetallicFactor, float u_RoughnessFactor, int UVSet) +getMetallicRoughnessInfo(VertexOut in, device const BindGroup_0& bg0, device const BindGroup_1& bg1, MaterialInfo info, float u_MetallicFactor, float u_RoughnessFactor, float2 UV) { info.metallic = u_MetallicFactor; info.perceptualRoughness = u_RoughnessFactor; @@ -405,7 +436,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, in.tUV).rgb, 1.0); + float4 mrSample = float4(bg1.tMetallicRoughnessTexture.sample(bg0.tDefaultSampler, UV).rgb, 1.0); info.perceptualRoughness *= mrSample.g; info.metallic *= mrSample.b; } @@ -600,20 +631,31 @@ fragment plRenderTargets fragment_main( ) { + const float2 tUV[8] = { + in.tUV0, + in.tUV1, + in.tUV2, + in.tUV3, + in.tUV4, + in.tUV5, + in.tUV6, + 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); + float4 tBaseColor = getBaseColor(bg0, bg1, 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); + NormalInfo tNormalInfo = pl_get_normal_info(bg0, bg1, in, front_facing, tUV[material.NormalUVSet]); float3 n = tNormalInfo.n; @@ -627,7 +669,7 @@ fragment plRenderTargets fragment_main( if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS)) { - materialInfo = getMetallicRoughnessInfo(in, bg0, bg1, materialInfo, material.u_MetallicFactor, material.u_RoughnessFactor, 0); + materialInfo = getMetallicRoughnessInfo(in, bg0, bg1, materialInfo, material.u_MetallicFactor, material.u_RoughnessFactor, tUV[material.MetallicRoughnessUVSet]); } materialInfo.perceptualRoughness = fast::clamp(materialInfo.perceptualRoughness, 0.0, 1.0); @@ -647,14 +689,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, in.tUV).rgb; + f_emissive *= bg1.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, in.tUV).r; + ao = bg1.tOcclusionTexture.sample(bg0.tDefaultSampler, tUV[material.OcclusionUVSet]).r; } float3 v = normalize(bg0.data->tCameraPos.xyz - in.tPosition.xyz); From 94fbfd8bbbbf7b6bc8b472b6038528849b87f728 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 7 May 2024 15:48:34 -0500 Subject: [PATCH 05/23] refac: change material jobs to load all textures in same thread in ref renderer --- extensions/pl_ref_renderer_ext.c | 47 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/extensions/pl_ref_renderer_ext.c b/extensions/pl_ref_renderer_ext.c index 9279b964..6947f894 100644 --- a/extensions/pl_ref_renderer_ext.c +++ b/extensions/pl_ref_renderer_ext.c @@ -2081,7 +2081,7 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) .task = pl__refr_job, .pData = sbtMaterials }; - gptJob->dispatch_batch(uMaterialCount * PL_TEXTURE_SLOT_COUNT, 0, tJobDesc, &ptCounter); + gptJob->dispatch_batch(uMaterialCount, 0, tJobDesc, &ptCounter); gptJob->wait_for_counter(ptCounter); pl_end_profile_sample(); @@ -3821,33 +3821,34 @@ pl__refr_job(uint32_t uJobIndex, void* pData) { plMaterialComponent* sbtMaterials = pData; - const uint32_t uMaterialIndex = uJobIndex / PL_TEXTURE_SLOT_COUNT; - const uint32_t uTextureIndex = uJobIndex % PL_TEXTURE_SLOT_COUNT; - - plMaterialComponent* ptMaterial = &sbtMaterials[uMaterialIndex]; + plMaterialComponent* ptMaterial = &sbtMaterials[uJobIndex]; int texWidth, texHeight, texNumChannels; int texForceNumChannels = 4; - if(gptResource->is_resource_valid(ptMaterial->atTextureMaps[uTextureIndex].tResource)) + for(uint32_t i = 0; i < PL_TEXTURE_SLOT_COUNT; i++) { - if(uTextureIndex == PL_TEXTURE_SLOT_BASE_COLOR_MAP || uTextureIndex == PL_TEXTURE_SLOT_EMISSIVE_MAP || uTextureIndex == PL_TEXTURE_SLOT_SPECULAR_COLOR_MAP) - { - size_t szResourceSize = 0; - const char* pcFileData = gptResource->get_file_data(ptMaterial->atTextureMaps[uTextureIndex].tResource, &szResourceSize); - float* rawBytes = gptImage->load_hdr_from_memory((unsigned char*)pcFileData, (int)szResourceSize, &texWidth, &texHeight, &texNumChannels, texForceNumChannels); - gptResource->set_buffer_data(ptMaterial->atTextureMaps[uTextureIndex].tResource, sizeof(float) * texWidth * texHeight * 4, rawBytes); - ptMaterial->atTextureMaps[uTextureIndex].uWidth = texWidth; - ptMaterial->atTextureMaps[uTextureIndex].uHeight = texHeight; - } - else + + if(gptResource->is_resource_valid(ptMaterial->atTextureMaps[i].tResource)) { - size_t szResourceSize = 0; - const char* pcFileData = gptResource->get_file_data(ptMaterial->atTextureMaps[uTextureIndex].tResource, &szResourceSize); - unsigned char* rawBytes = gptImage->load_from_memory((unsigned char*)pcFileData, (int)szResourceSize, &texWidth, &texHeight, &texNumChannels, texForceNumChannels); - PL_ASSERT(rawBytes); - ptMaterial->atTextureMaps[uTextureIndex].uWidth = texWidth; - ptMaterial->atTextureMaps[uTextureIndex].uHeight = texHeight; - gptResource->set_buffer_data(ptMaterial->atTextureMaps[uTextureIndex].tResource, texWidth * texHeight * 4, rawBytes); + if(i == PL_TEXTURE_SLOT_BASE_COLOR_MAP || i == PL_TEXTURE_SLOT_EMISSIVE_MAP || i == PL_TEXTURE_SLOT_SPECULAR_COLOR_MAP) + { + size_t szResourceSize = 0; + const char* pcFileData = gptResource->get_file_data(ptMaterial->atTextureMaps[i].tResource, &szResourceSize); + float* rawBytes = gptImage->load_hdr_from_memory((unsigned char*)pcFileData, (int)szResourceSize, &texWidth, &texHeight, &texNumChannels, texForceNumChannels); + gptResource->set_buffer_data(ptMaterial->atTextureMaps[i].tResource, sizeof(float) * texWidth * texHeight * 4, rawBytes); + ptMaterial->atTextureMaps[i].uWidth = texWidth; + ptMaterial->atTextureMaps[i].uHeight = texHeight; + } + else + { + size_t szResourceSize = 0; + const char* pcFileData = gptResource->get_file_data(ptMaterial->atTextureMaps[i].tResource, &szResourceSize); + unsigned char* rawBytes = gptImage->load_from_memory((unsigned char*)pcFileData, (int)szResourceSize, &texWidth, &texHeight, &texNumChannels, texForceNumChannels); + PL_ASSERT(rawBytes); + ptMaterial->atTextureMaps[i].uWidth = texWidth; + ptMaterial->atTextureMaps[i].uHeight = texHeight; + gptResource->set_buffer_data(ptMaterial->atTextureMaps[i].tResource, texWidth * texHeight * 4, rawBytes); + } } } } From 755bc352ade948b411cc1cdff91faf49ed31f42a Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 7 May 2024 15:49:25 -0500 Subject: [PATCH 06/23] chore: model loader tweaks --- extensions/pl_model_loader_ext.c | 52 ++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/extensions/pl_model_loader_ext.c b/extensions/pl_model_loader_ext.c index 2e3d4aa8..76685852 100644 --- a/extensions/pl_model_loader_ext.c +++ b/extensions/pl_model_loader_ext.c @@ -198,15 +198,15 @@ pl__load_gltf(plComponentLibrary* ptLibrary, const char* pcPath, const plMat4* p for(size_t j = 0; j < ptGScene->nodes_count; j++) { const cgltf_node* ptNode = ptGScene->nodes[j]; - pl__refr_load_gltf_object(ptDataOut, &tLoadingData, acDirectory, (plEntity){UINT32_MAX, UINT32_MAX}, ptNode); + plEntity tRoot = {UINT32_MAX, UINT32_MAX}; if(ptTransform) { - const plEntity tNodeEntity = {.ulData = pl_hm_lookup(&tLoadingData.tNodeHashMap, (uint64_t)ptNode)}; - plTransformComponent* ptTransformComponent = gptECS->get_component(ptLibrary, PL_COMPONENT_TYPE_TRANSFORM, tNodeEntity); - ptTransformComponent->tWorld = pl_mul_mat4(ptTransform, &ptTransformComponent->tWorld); + tRoot = gptECS->create_transform(ptLibrary, "load transform"); + plTransformComponent* ptTransformComponent = gptECS->get_component(ptLibrary, PL_COMPONENT_TYPE_TRANSFORM, tRoot); + ptTransformComponent->tWorld = *ptTransform; pl_decompose_matrix(&ptTransformComponent->tWorld, &ptTransformComponent->tScale, &ptTransformComponent->tRotation, &ptTransformComponent->tTranslation); } - + pl__refr_load_gltf_object(ptDataOut, &tLoadingData, acDirectory, tRoot, ptNode); } } @@ -291,7 +291,7 @@ static void pl__refr_load_material(const char* pcDirectory, plMaterialComponent* ptMaterial, const cgltf_material* ptGltfMaterial) { ptMaterial->tShaderType = PL_SHADER_TYPE_PBR; - ptMaterial->tFlags = ptGltfMaterial->double_sided ? PL_MATERIAL_FLAG_DOUBLE_SIDED : PL_MATERIAL_FLAG_NONE; + ptMaterial->tFlags |= ptGltfMaterial->double_sided ? PL_MATERIAL_FLAG_DOUBLE_SIDED : PL_MATERIAL_FLAG_NONE; ptMaterial->fAlphaCutoff = ptGltfMaterial->alpha_cutoff; // blend mode @@ -416,10 +416,17 @@ pl__refr_load_attributes(plMeshComponent* ptMesh, const cgltf_primitive* ptPrimi case cgltf_attribute_type_normal: { pl_sb_resize(ptMesh->sbtVertexNormals, (uint32_t)szVertexCount); - for(size_t i = 0; i < szVertexCount; i++) + if(ptAttribute->data->component_type == cgltf_component_type_r_32f && ptAttribute->data->type == cgltf_type_vec3) { - plVec3* ptRawData = (plVec3*)&pucBufferStart[i * szStride]; - ptMesh->sbtVertexNormals[i] = *ptRawData; + for(size_t i = 0; i < szVertexCount; i++) + { + plVec3* ptRawData = (plVec3*)&pucBufferStart[i * szStride]; + ptMesh->sbtVertexNormals[i] = *ptRawData; + } + } + else + { + PL_ASSERT(false); } break; } @@ -427,10 +434,17 @@ pl__refr_load_attributes(plMeshComponent* ptMesh, const cgltf_primitive* ptPrimi case cgltf_attribute_type_tangent: { pl_sb_resize(ptMesh->sbtVertexTangents, (uint32_t)szVertexCount); - for(size_t i = 0; i < szVertexCount; i++) + if(ptAttribute->data->component_type == cgltf_component_type_r_32f && ptAttribute->data->type == cgltf_type_vec4) { - plVec4* ptRawData = (plVec4*)&pucBufferStart[i * szStride]; - ptMesh->sbtVertexTangents[i] = *ptRawData; + for(size_t i = 0; i < szVertexCount; i++) + { + plVec4* ptRawData = (plVec4*)&pucBufferStart[i * szStride]; + ptMesh->sbtVertexTangents[i] = *ptRawData; + } + } + else + { + PL_ASSERT(false); } break; } @@ -804,11 +818,12 @@ pl__refr_load_gltf_object(plModelLoaderData* ptData, plGltfLoadingData* ptSceneD for(size_t szPrimitiveIndex = 0; szPrimitiveIndex < ptNode->mesh->primitives_count; szPrimitiveIndex++) { // add mesh to our node - plEntity tNewObject = gptECS->create_object(ptLibrary, ptNode->mesh->name); - plObjectComponent* ptObject = gptECS->get_component(ptLibrary, PL_COMPONENT_TYPE_OBJECT, tNewObject); - plMeshComponent* ptMesh = gptECS->get_component(ptLibrary, PL_COMPONENT_TYPE_MESH, tNewObject); + plEntity tNewObject = gptECS->create_tag(ptLibrary, ptNode->mesh->name); + plObjectComponent* ptObject = gptECS->add_component(ptLibrary, PL_COMPONENT_TYPE_OBJECT, tNewObject); + plMeshComponent* ptMesh = gptECS->add_component(ptLibrary, PL_COMPONENT_TYPE_MESH, tNewObject); ptMesh->tSkinComponent = tSkinEntity; - + + ptObject->tMesh = tNewObject; ptObject->tTransform = tNewEntity; // TODO: delete unused entities (old transform) const cgltf_primitive* ptPrimitive = &ptNode->mesh->primitives[szPrimitiveIndex]; @@ -851,6 +866,9 @@ pl__refr_load_gltf_object(plModelLoaderData* ptData, plGltfLoadingData* ptSceneD if(ptMaterial->tBlendMode != PL_BLEND_MODE_OPAQUE) bOpaque = false; + if(ptMaterial->tFlags & PL_MATERIAL_FLAG_DOUBLE_SIDED) + bOpaque = false; + if(bOpaque) pl_sb_push(ptData->atOpaqueObjects, tNewObject); else @@ -861,7 +879,9 @@ pl__refr_load_gltf_object(plModelLoaderData* ptData, plGltfLoadingData* ptSceneD // recurse through children for(size_t i = 0; i < ptNode->children_count; i++) + { pl__refr_load_gltf_object(ptData, ptSceneData, pcDirectory, tNewEntity, ptNode->children[i]); + } } //----------------------------------------------------------------------------- From 832630efdae8ab2abfc1dc56d496a6b37d06aa25 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 7 May 2024 15:54:16 -0500 Subject: [PATCH 07/23] fix: skin texture staging buffer issue in ref renderer --- extensions/pl_ref_renderer_ext.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/extensions/pl_ref_renderer_ext.c b/extensions/pl_ref_renderer_ext.c index 6947f894..c49f03df 100644 --- a/extensions/pl_ref_renderer_ext.c +++ b/extensions/pl_ref_renderer_ext.c @@ -279,6 +279,8 @@ typedef struct _plRefRendererData // staging (more robust system should replace this) plBufferHandle tStagingBufferHandle[PL_FRAMES_IN_FLIGHT]; + uint32_t uStagingOffset; + uint32_t uCurrentStagingFrameIndex; } plRefRendererData; typedef struct _plMemCpyJobData @@ -2438,6 +2440,11 @@ pl_refr_update_skin_textures(plCommandBuffer tCommandBuffer, uint32_t uSceneHand plBlitEncoder tBlitEncoder = gptGfx->begin_blit_pass(ptDevice->ptGraphics, &tCommandBuffer); // update skin textures + if(gptData->uCurrentStagingFrameIndex != ptGraphics->uCurrentFrameIndex) + { + gptData->uStagingOffset = 0; + gptData->uCurrentStagingFrameIndex = ptGraphics->uCurrentFrameIndex; + } const uint32_t uSkinCount = pl_sb_size(ptScene->sbtSkinData); for(uint32_t i = 0; i < uSkinCount; i++) { @@ -2461,11 +2468,12 @@ pl_refr_update_skin_textures(plCommandBuffer tCommandBuffer, uint32_t uSceneHand plBufferImageCopy tBufferImageCopy = { .tImageExtent = {(size_t)ptSkinTexture->tDesc.tDimensions.x, (size_t)ptSkinTexture->tDesc.tDimensions.y, 1}, .uLayerCount = 1, - .szBufferOffset = uSceneHandle * sizeof(float) * 4 * (size_t)ptSkinTexture->tDesc.tDimensions.x * (size_t)ptSkinTexture->tDesc.tDimensions.y + .szBufferOffset = gptData->uStagingOffset }; + gptData->uStagingOffset += sizeof(float) * 4 * (size_t)ptSkinTexture->tDesc.tDimensions.x * (size_t)ptSkinTexture->tDesc.tDimensions.y; plSkinComponent* ptSkinComponent = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_SKIN, ptScene->sbtSkinData[i].tEntity); - memcpy(&ptStagingBuffer->tMemoryAllocation.pHostMapped[uSceneHandle * sizeof(float) * 4 * (size_t)ptSkinTexture->tDesc.tDimensions.x * (size_t)ptSkinTexture->tDesc.tDimensions.y], ptSkinComponent->sbtTextureData, sizeof(float) * 4 * (size_t)ptSkinTexture->tDesc.tDimensions.x * (size_t)ptSkinTexture->tDesc.tDimensions.y); + memcpy(&ptStagingBuffer->tMemoryAllocation.pHostMapped[tBufferImageCopy.szBufferOffset], ptSkinComponent->sbtTextureData, sizeof(float) * 4 * (size_t)ptSkinTexture->tDesc.tDimensions.x * (size_t)ptSkinTexture->tDesc.tDimensions.y); // memcpy(ptStagingBuffer->tMemoryAllocation.pHostMapped, ptSkinComponent->sbtTextureData, sizeof(float) * 4 * (size_t)ptSkinTexture->tDesc.tDimensions.x * (size_t)ptSkinTexture->tDesc.tDimensions.y); gptGfx->copy_buffer_to_texture(&tBlitEncoder, gptData->tStagingBufferHandle[ptGraphics->uCurrentFrameIndex], ptScene->sbtSkinData[i].atDynamicTexture[ptGraphics->uCurrentFrameIndex], 1, &tBufferImageCopy); } From b0d34c8aa6b29e9b435a495b4c1a0fcdfedf40c0 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 7 May 2024 15:54:22 -0500 Subject: [PATCH 08/23] chore: return app.c to default --- apps/app.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/apps/app.c b/apps/app.c index 159f97c5..6a1337c7 100644 --- a/apps/app.c +++ b/apps/app.c @@ -62,21 +62,26 @@ typedef struct plAppData_t bool bFrustumCulling; bool bAlwaysResize; - // selected entityes + // selected entityes bool bUpdateEntitySelection; plEntity tSelectedEntity; + // scene bool bDrawAllBoundingBoxes; bool bDrawVisibleBoundingBoxes; bool bFreezeCullCamera; plEntity tCullCamera; plEntity tMainCamera; + plEntity tMainCamera2; // views uint32_t uSceneHandle0; + uint32_t uSceneHandle1; uint32_t uViewHandle0; + uint32_t uViewHandle1; + uint32_t uViewHandle2; // drawing plDrawLayer* ptDrawLayer; @@ -222,13 +227,18 @@ 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("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 @@ -245,25 +255,40 @@ 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"); - plMat4 tTransform0 = pl_mat4_translate_xyz(2, 2, 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); 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.8f}, &tTransform0, &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); + gptModelLoader->free_data(&tLoaderData0); + pl_end_profile_sample(); + pl_begin_profile_sample("finalize scene 0"); 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 @@ -337,8 +362,6 @@ pl_app_update(plAppData* ptAppData) ptAppData->bResize = false; } - - if(!gptGfx->begin_frame(ptGraphics)) { gptGfx->resize(ptGraphics); @@ -369,8 +392,10 @@ pl_app_update(plAppData* ptAppData) // handle input plComponentLibrary* ptMainComponentLibrary = gptRenderer->get_component_library(ptAppData->uSceneHandle0); + plComponentLibrary* ptSecondaryComponentLibrary = gptRenderer->get_component_library(ptAppData->uSceneHandle1); 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; @@ -399,10 +424,12 @@ 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(); @@ -426,6 +453,7 @@ 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 = { @@ -443,6 +471,7 @@ 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 = { @@ -461,6 +490,15 @@ 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; @@ -474,6 +512,8 @@ 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); @@ -583,6 +623,8 @@ 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); From 49fdeeeb32e4a38f75a0fdf5773f60db8295e7e2 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Wed, 8 May 2024 15:42:52 -0500 Subject: [PATCH 09/23] feat: add light component to ECS extension --- apps/helper_windows.h | 15 +++ extensions/pl_ecs_ext.c | 75 ++++++++++++-- extensions/pl_ecs_ext.h | 114 +++++++++++++--------- extensions/pl_model_loader_ext.c | 3 - extensions/pl_ref_renderer_ext.c | 162 ++++++++++++++++++++++++++----- 5 files changed, 287 insertions(+), 82 deletions(-) diff --git a/apps/helper_windows.h b/apps/helper_windows.h index 5963390a..8d8ecefe 100644 --- a/apps/helper_windows.h +++ b/apps/helper_windows.h @@ -78,6 +78,7 @@ pl_show_ecs_window(const plEcsI* ptECS, plComponentLibrary* ptLibrary, bool* pbS plCameraComponent* ptCameraComp = ptECS->get_component(ptLibrary, PL_COMPONENT_TYPE_CAMERA, tSelectedEntity); plAnimationComponent* ptAnimationComp = ptECS->get_component(ptLibrary, PL_COMPONENT_TYPE_ANIMATION, tSelectedEntity); plInverseKinematicsComponent* ptIKComp = ptECS->get_component(ptLibrary, PL_COMPONENT_TYPE_INVERSE_KINEMATICS, tSelectedEntity); + plLightComponent* ptLightComp = ptECS->get_component(ptLibrary, PL_COMPONENT_TYPE_LIGHT, tSelectedEntity); pl_text("Entity: %u, %u", tSelectedEntity.uIndex, tSelectedEntity.uGeneration); @@ -142,6 +143,20 @@ pl_show_ecs_window(const plEcsI* ptECS, plComponentLibrary* ptLibrary, bool* pbS pl_end_collapsing_header(); } + if(ptLightComp && pl_collapsing_header("Light")) + { + static const char* apcLightTypes[] = { + "PL_LIGHT_TYPE_DIRECTIONAL", + "PL_LIGHT_TYPE_POINT" + }; + pl_text("Type: %s", apcLightTypes[ptLightComp->tType]); + pl_text("Position: (%0.3f, %0.3f, %0.3f)", ptLightComp->tPosition.r, ptLightComp->tPosition.g, ptLightComp->tPosition.b); + pl_text("Color: (%0.3f, %0.3f, %0.3f)", ptLightComp->tColor.r, ptLightComp->tColor.g, ptLightComp->tColor.b); + pl_text("Direction: (%0.3f, %0.3f, %0.3f)", ptLightComp->tDirection.r, ptLightComp->tDirection.g, ptLightComp->tDirection.b); + pl_text("Intensity: %0.3f", ptLightComp->fIntensity); + pl_text("Cast Shadow: %s", ptLightComp->tFlags & PL_LIGHT_FLAG_HAS_CAST_SHADOW ? "true" : "false"); + } + if(ptMaterialComp && pl_collapsing_header("Material")) { pl_text("Base Color: (%0.3f, %0.3f, %0.3f, %0.3f)", ptMaterialComp->tBaseColor.r, ptMaterialComp->tBaseColor.g, ptMaterialComp->tBaseColor.b, ptMaterialComp->tBaseColor.a); diff --git a/extensions/pl_ecs_ext.c b/extensions/pl_ecs_ext.c index 6c9421ff..38dff58e 100644 --- a/extensions/pl_ecs_ext.c +++ b/extensions/pl_ecs_ext.c @@ -64,16 +64,18 @@ static void* pl_ecs_get_component (plComponentLibrary* ptLibrary, plC static void* pl_ecs_add_component (plComponentLibrary* ptLibrary, plComponentType tType, plEntity tEntity); // components -static plEntity pl_ecs_create_tag (plComponentLibrary* ptLibrary, const char* pcName); -static plEntity pl_ecs_create_mesh (plComponentLibrary* ptLibrary, const char* pcName); -static plEntity pl_ecs_create_object (plComponentLibrary* ptLibrary, const char* pcName); -static plEntity pl_ecs_create_transform (plComponentLibrary* ptLibrary, const char* pcName); -static plEntity pl_ecs_create_material (plComponentLibrary* ptLibrary, const char* pcName); -static plEntity pl_ecs_create_skin (plComponentLibrary* ptLibrary, const char* pcName); -static plEntity pl_ecs_create_animation (plComponentLibrary* ptLibrary, const char* pcName); -static plEntity pl_ecs_create_animation_data (plComponentLibrary* ptLibrary, const char* pcName); -static plEntity pl_ecs_create_perspective_camera(plComponentLibrary* ptLibrary, const char* pcName, plVec3 tPos, float fYFov, float fAspect, float fNearZ, float fFarZ); +static plEntity pl_ecs_create_tag (plComponentLibrary* ptLibrary, const char* pcName); +static plEntity pl_ecs_create_mesh (plComponentLibrary* ptLibrary, const char* pcName); +static plEntity pl_ecs_create_object (plComponentLibrary* ptLibrary, const char* pcName); +static plEntity pl_ecs_create_transform (plComponentLibrary* ptLibrary, const char* pcName); +static plEntity pl_ecs_create_material (plComponentLibrary* ptLibrary, const char* pcName); +static plEntity pl_ecs_create_skin (plComponentLibrary* ptLibrary, const char* pcName); +static plEntity pl_ecs_create_animation (plComponentLibrary* ptLibrary, const char* pcName); +static plEntity pl_ecs_create_animation_data (plComponentLibrary* ptLibrary, const char* pcName); +static plEntity pl_ecs_create_perspective_camera (plComponentLibrary* ptLibrary, const char* pcName, plVec3 tPos, float fYFov, float fAspect, float fNearZ, float fFarZ); static plEntity pl_ecs_create_orthographic_camera(plComponentLibrary* ptLibrary, const char* pcName, plVec3 tPos, float fWidth, float fHeight, float fNearZ, float fFarZ); +static plEntity pl_ecs_create_directional_light (plComponentLibrary*, const char* pcName, plVec3 tDirection); +static plEntity pl_ecs_create_point_light (plComponentLibrary*, const char* pcName, plVec3 tPosition); // heirarchy static void pl_ecs_attach_component (plComponentLibrary* ptLibrary, plEntity tEntity, plEntity tParent); @@ -145,6 +147,8 @@ pl_load_ecs_api(void) .create_skin = pl_ecs_create_skin, .create_animation = pl_ecs_create_animation, .create_animation_data = pl_ecs_create_animation_data, + .create_directional_light = pl_ecs_create_directional_light, + .create_point_light = pl_ecs_create_point_light, .attach_component = pl_ecs_attach_component, .deattach_component = pl_ecs_deattach_component, .calculate_normals = pl_calculate_normals, @@ -216,6 +220,9 @@ pl_ecs_init_component_library(plComponentLibrary* ptLibrary) ptLibrary->tInverseKinematicsComponentManager.tComponentType = PL_COMPONENT_TYPE_INVERSE_KINEMATICS; ptLibrary->tInverseKinematicsComponentManager.szStride = sizeof(plInverseKinematicsComponent); + ptLibrary->tLightComponentManager.tComponentType = PL_COMPONENT_TYPE_LIGHT; + ptLibrary->tLightComponentManager.szStride = sizeof(plLightComponent); + ptLibrary->_ptManagers[0] = &ptLibrary->tTagComponentManager; ptLibrary->_ptManagers[1] = &ptLibrary->tTransformComponentManager; ptLibrary->_ptManagers[2] = &ptLibrary->tMeshComponentManager; @@ -227,6 +234,7 @@ pl_ecs_init_component_library(plComponentLibrary* ptLibrary) ptLibrary->_ptManagers[8] = &ptLibrary->tAnimationComponentManager; ptLibrary->_ptManagers[9] = &ptLibrary->tAnimationDataComponentManager; ptLibrary->_ptManagers[10] = &ptLibrary->tInverseKinematicsComponentManager; + ptLibrary->_ptManagers[11] = &ptLibrary->tLightComponentManager; for(uint32_t i = 0; i < PL_COMPONENT_TYPE_COUNT; i++) ptLibrary->_ptManagers[i]->ptParentLibrary = ptLibrary; @@ -433,6 +441,13 @@ pl_ecs_remove_entity(plComponentLibrary* ptLibrary, plEntity tEntity) pl_sb_del_swap(sbComponents, uEntityValue); break; } + + case PL_COMPONENT_TYPE_LIGHT: + { + plLightComponent* sbComponents = ptLibrary->_ptManagers[i]->pComponents; + pl_sb_del_swap(sbComponents, uEntityValue); + break; + } } } } @@ -650,6 +665,24 @@ pl_ecs_add_component(plComponentLibrary* ptLibrary, plComponentType tType, plEnt return &sbComponents[uComponentIndex]; } + case PL_COMPONENT_TYPE_LIGHT: + { + plLightComponent* sbComponents = ptManager->pComponents; + if(bAddSlot) + pl_sb_add(sbComponents); + ptManager->pComponents = sbComponents; + sbComponents[uComponentIndex] = (plLightComponent){ + .tPosition = {0.0f, 0.0f, 0.0f}, + .tColor = {1.0f, 1.0f, 1.0f}, + .tDirection = {0.0f, -1.0f, 0.0f}, + .fIntensity = 1.0f, + .fRange = 10.0f, + .tType = PL_LIGHT_TYPE_DIRECTIONAL, + .tFlags = 0 + }; + return &sbComponents[uComponentIndex]; + } + } return NULL; @@ -681,6 +714,30 @@ pl_ecs_create_mesh(plComponentLibrary* ptLibrary, const char* pcName) return tNewEntity; } +static plEntity +pl_ecs_create_directional_light(plComponentLibrary* ptLibrary, const char* pcName, plVec3 tDirection) +{ + pcName = pcName ? pcName : "unnamed directional light"; + pl_log_debug_to_f(uLogChannel, "created directional light: '%s'", pcName); + plEntity tNewEntity = pl_ecs_create_tag(ptLibrary, pcName); + plLightComponent* ptLight = pl_ecs_add_component(ptLibrary, PL_COMPONENT_TYPE_LIGHT, tNewEntity); + ptLight->tDirection = tDirection; + ptLight->tType = PL_LIGHT_TYPE_DIRECTIONAL; + return tNewEntity; +} + +static plEntity +pl_ecs_create_point_light(plComponentLibrary* ptLibrary, const char* pcName, plVec3 tPosition) +{ + pcName = pcName ? pcName : "unnamed point light"; + pl_log_debug_to_f(uLogChannel, "created point light: '%s'", pcName); + plEntity tNewEntity = pl_ecs_create_tag(ptLibrary, pcName); + plLightComponent* ptLight = pl_ecs_add_component(ptLibrary, PL_COMPONENT_TYPE_LIGHT, tNewEntity); + ptLight->tPosition = tPosition; + ptLight->tType = PL_LIGHT_TYPE_POINT; + return tNewEntity; +} + static plEntity pl_ecs_create_object(plComponentLibrary* ptLibrary, const char* pcName) { diff --git a/extensions/pl_ecs_ext.h b/extensions/pl_ecs_ext.h index 63711c83..8122d44d 100644 --- a/extensions/pl_ecs_ext.h +++ b/extensions/pl_ecs_ext.h @@ -22,8 +22,8 @@ Index of this file: #ifndef PL_ECS_EXT_H #define PL_ECS_EXT_H -#define PL_ECS_EXT_VERSION "0.9.0" -#define PL_ECS_EXT_VERSION_NUM 000900 +#define PL_ECS_EXT_VERSION "0.10.0" +#define PL_ECS_EXT_VERSION_NUM 001000 //----------------------------------------------------------------------------- // [SECTION] apis @@ -75,6 +75,7 @@ typedef struct _plCameraComponent plCameraComponent; typedef struct _plAnimationComponent plAnimationComponent; typedef struct _plAnimationDataComponent plAnimationDataComponent; typedef struct _plInverseKinematicsComponent plInverseKinematicsComponent; +typedef struct _plLightComponent plLightComponent; // enums typedef int plShaderType; @@ -87,6 +88,8 @@ typedef int plAnimationMode; typedef int plAnimationPath; typedef int plAnimationFlags; typedef int plMeshFormatFlags; +typedef int plLightFlags; +typedef int plLightType; typedef union _plEntity { @@ -112,57 +115,59 @@ const plCameraI* pl_load_camera_api(void); typedef struct _plEcsI { // setup/shutdown - void (*init_component_library) (plComponentLibrary* ptLibrary); - void (*cleanup_component_library)(plComponentLibrary* ptLibrary); + void (*init_component_library) (plComponentLibrary*); + void (*cleanup_component_library)(plComponentLibrary*); // misc - plEntity (*create_entity) (plComponentLibrary* ptLibrary); // prefer entity helpers below - void (*remove_entity) (plComponentLibrary* ptLibrary, plEntity tEntity); - bool (*is_entity_valid)(plComponentLibrary* ptLibrary, plEntity tEntity); - plEntity (*get_entity) (plComponentLibrary* ptLibrary, const char* pcName); - void* (*get_component) (plComponentLibrary* ptLibrary, plComponentType tType, plEntity tEntity); - void* (*add_component) (plComponentLibrary* ptLibrary, plComponentType tType, plEntity tEntity); - size_t (*get_index) (plComponentManager* ptManager, plEntity tEntity); + plEntity (*create_entity) (plComponentLibrary*); // prefer entity helpers below + void (*remove_entity) (plComponentLibrary*, plEntity); + bool (*is_entity_valid)(plComponentLibrary*, plEntity); + plEntity (*get_entity) (plComponentLibrary*, const char* pcName); + void* (*get_component) (plComponentLibrary*, plComponentType, plEntity); + void* (*add_component) (plComponentLibrary*, plComponentType, plEntity); + size_t (*get_index) (plComponentManager*, plEntity); // entity helpers (creates entity and necessary components) - plEntity (*create_tag) (plComponentLibrary* ptLibrary, const char* pcName); - plEntity (*create_mesh) (plComponentLibrary* ptLibrary, const char* pcName); - plEntity (*create_object) (plComponentLibrary* ptLibrary, const char* pcName); - plEntity (*create_transform) (plComponentLibrary* ptLibrary, const char* pcName); - plEntity (*create_material) (plComponentLibrary* ptLibrary, const char* pcName); - plEntity (*create_skin) (plComponentLibrary* ptLibrary, const char* pcName); - plEntity (*create_animation) (plComponentLibrary* ptLibrary, const char* pcName); - plEntity (*create_animation_data) (plComponentLibrary* ptLibrary, const char* pcName); - plEntity (*create_perspective_camera) (plComponentLibrary* ptLibrary, const char* pcName, plVec3 tPos, float fYFov, float fAspect, float fNearZ, float fFarZ); - plEntity (*create_orthographic_camera)(plComponentLibrary* ptLibrary, const char* pcName, plVec3 tPos, float fWidth, float fHeight, float fNearZ, float fFarZ); + plEntity (*create_tag) (plComponentLibrary*, const char* pcName); + plEntity (*create_mesh) (plComponentLibrary*, const char* pcName); + plEntity (*create_object) (plComponentLibrary*, const char* pcName); + plEntity (*create_transform) (plComponentLibrary*, const char* pcName); + plEntity (*create_material) (plComponentLibrary*, const char* pcName); + plEntity (*create_skin) (plComponentLibrary*, const char* pcName); + plEntity (*create_animation) (plComponentLibrary*, const char* pcName); + plEntity (*create_animation_data) (plComponentLibrary*, const char* pcName); + plEntity (*create_perspective_camera) (plComponentLibrary*, const char* pcName, plVec3 tPos, float fYFov, float fAspect, float fNearZ, float fFarZ); + plEntity (*create_orthographic_camera)(plComponentLibrary*, const char* pcName, plVec3 tPos, float fWidth, float fHeight, float fNearZ, float fFarZ); + plEntity (*create_directional_light) (plComponentLibrary*, const char* pcName, plVec3 tDirection); + plEntity (*create_point_light) (plComponentLibrary*, const char* pcName, plVec3 tPosition); // hierarchy - void (*attach_component) (plComponentLibrary* ptLibrary, plEntity tEntity, plEntity tParent); - void (*deattach_component) (plComponentLibrary* ptLibrary, plEntity tEntity); + void (*attach_component) (plComponentLibrary*, plEntity tEntity, plEntity tParent); + void (*deattach_component) (plComponentLibrary*, plEntity); // meshes - void (*calculate_normals) (plMeshComponent* atMeshes, uint32_t uComponentCount); - void (*calculate_tangents)(plMeshComponent* atMeshes, uint32_t uComponentCount); + void (*calculate_normals) (plMeshComponent*, uint32_t uMeshCount); + void (*calculate_tangents)(plMeshComponent*, uint32_t uMeshCount); // systems - void (*run_object_update_system) (plComponentLibrary* ptLibrary); - void (*run_transform_update_system) (plComponentLibrary* ptLibrary); - void (*run_skin_update_system) (plComponentLibrary* ptLibrary); - void (*run_hierarchy_update_system) (plComponentLibrary* ptLibrary); - void (*run_animation_update_system) (plComponentLibrary* ptLibrary, float fDeltaTime); - void (*run_inverse_kinematics_update_system)(plComponentLibrary* ptLibrary); + void (*run_object_update_system) (plComponentLibrary*); + void (*run_transform_update_system) (plComponentLibrary*); + void (*run_skin_update_system) (plComponentLibrary*); + void (*run_hierarchy_update_system) (plComponentLibrary*); + void (*run_animation_update_system) (plComponentLibrary*, float fDeltaTime); + void (*run_inverse_kinematics_update_system)(plComponentLibrary*); } plEcsI; typedef struct _plCameraI { - void (*set_fov) (plCameraComponent* ptCamera, float fYFov); - void (*set_clip_planes)(plCameraComponent* ptCamera, float fNearZ, float fFarZ); - void (*set_aspect) (plCameraComponent* ptCamera, float fAspect); - void (*set_pos) (plCameraComponent* ptCamera, float fX, float fY, float fZ); - void (*set_pitch_yaw) (plCameraComponent* ptCamera, float fPitch, float fYaw); - void (*translate) (plCameraComponent* ptCamera, float fDx, float fDy, float fDz); - void (*rotate) (plCameraComponent* ptCamera, float fDPitch, float fDYaw); - void (*update) (plCameraComponent* ptCamera); + void (*set_fov) (plCameraComponent*, float fYFov); + void (*set_clip_planes)(plCameraComponent*, float fNearZ, float fFarZ); + void (*set_aspect) (plCameraComponent*, float fAspect); + void (*set_pos) (plCameraComponent*, float fX, float fY, float fZ); + void (*set_pitch_yaw) (plCameraComponent*, float fPitch, float fYaw); + void (*translate) (plCameraComponent*, float fDx, float fDy, float fDz); + void (*rotate) (plCameraComponent*, float fDPitch, float fDYaw); + void (*update) (plCameraComponent*); } plCameraI; //----------------------------------------------------------------------------- @@ -182,6 +187,7 @@ enum _plComponentType PL_COMPONENT_TYPE_ANIMATION, PL_COMPONENT_TYPE_ANIMATION_DATA, PL_COMPONENT_TYPE_INVERSE_KINEMATICS, + PL_COMPONENT_TYPE_LIGHT, PL_COMPONENT_TYPE_COUNT }; @@ -283,6 +289,18 @@ enum _plMeshFormatFlags PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 = 1 << 16 }; +enum _plLightFlags +{ + PL_LIGHT_FLAG_NONE = 0, + PL_LIGHT_FLAG_HAS_CAST_SHADOW = 1 << 0, +}; + +enum _plLightType +{ + PL_LIGHT_TYPE_DIRECTIONAL, + PL_LIGHT_TYPE_POINT +}; + //----------------------------------------------------------------------------- // [SECTION] structs //----------------------------------------------------------------------------- @@ -346,6 +364,7 @@ typedef struct _plComponentLibrary plComponentManager tAnimationComponentManager; plComponentManager tAnimationDataComponentManager; plComponentManager tInverseKinematicsComponentManager; + plComponentManager tLightComponentManager; plComponentManager* _ptManagers[PL_COMPONENT_TYPE_COUNT]; // just for internal convenience void* pInternal; @@ -355,6 +374,17 @@ typedef struct _plComponentLibrary // [SECTION] components //----------------------------------------------------------------------------- +typedef struct _plLightComponent +{ + plLightType tType; + plLightFlags tFlags; + plVec3 tColor; + float fIntensity; + float fRange; + plVec3 tPosition; + plVec3 tDirection; +} plLightComponent; + typedef struct _plObjectComponent { plEntity tMesh; @@ -366,12 +396,6 @@ typedef struct _plHierarchyComponent plEntity tParent; } plHierarchyComponent; -typedef struct _plLightComponent -{ - plVec3 tPosition; - plVec3 tColor; -} plLightComponent; - typedef struct _plTagComponent { char acName[PL_MAX_NAME_LENGTH]; diff --git a/extensions/pl_model_loader_ext.c b/extensions/pl_model_loader_ext.c index 76685852..0b2720aa 100644 --- a/extensions/pl_model_loader_ext.c +++ b/extensions/pl_model_loader_ext.c @@ -866,9 +866,6 @@ pl__refr_load_gltf_object(plModelLoaderData* ptData, plGltfLoadingData* ptSceneD if(ptMaterial->tBlendMode != PL_BLEND_MODE_OPAQUE) bOpaque = false; - if(ptMaterial->tFlags & PL_MATERIAL_FLAG_DOUBLE_SIDED) - bOpaque = false; - if(bOpaque) pl_sb_push(ptData->atOpaqueObjects, tNewObject); else diff --git a/extensions/pl_ref_renderer_ext.c b/extensions/pl_ref_renderer_ext.c index c49f03df..a539868c 100644 --- a/extensions/pl_ref_renderer_ext.c +++ b/extensions/pl_ref_renderer_ext.c @@ -41,6 +41,7 @@ Index of this file: #include "pl_job_ext.h" #define PL_MAX_VIEWS_PER_SCENE 4 +#define PL_MAX_LIGHTS 1000 //----------------------------------------------------------------------------- // [SECTION] internal structs @@ -134,6 +135,18 @@ typedef struct _plGPUMaterial int iIridescenceThicknessUVSet; } plGPUMaterial; +typedef struct _plGPULight +{ + plVec3 tPosition; + float fIntensity; + + plVec3 tDirection; + int iType; + + plVec3 tColor; + float fRange; +} plGPULight; + typedef struct _BindGroup_0 { plVec4 tCameraPos; @@ -200,7 +213,7 @@ typedef struct _plRefScene // lighting (final quad to use for composition) plDrawable tLightingDrawable; - // skins + // shared bind groups plBindGroupHandle tSkinBindGroup0; // CPU buffers @@ -209,6 +222,7 @@ typedef struct _plRefScene uint32_t* sbuIndexBuffer; plGPUMaterial* sbtMaterialBuffer; plVec4* sbtSkinVertexDataBuffer; + plGPULight* sbtLightData; // GPU buffers plBufferHandle tVertexBuffer; @@ -216,6 +230,7 @@ typedef struct _plRefScene plBufferHandle tStorageBuffer; plBufferHandle tMaterialDataBuffer; plBufferHandle tSkinStorageBuffer; + plBufferHandle atLightBuffer[PL_MAX_VIEWS_PER_SCENE]; // views uint32_t uViewCount; @@ -732,6 +747,7 @@ pl_refr_create_scene(void) ptScene->tIndexBuffer = (plBufferHandle){UINT32_MAX, UINT32_MAX}; ptScene->tStorageBuffer = (plBufferHandle){UINT32_MAX, UINT32_MAX}; ptScene->tMaterialDataBuffer = (plBufferHandle){UINT32_MAX, UINT32_MAX}; + // ptScene->tLightBuffer = (plBufferHandle){UINT32_MAX, UINT32_MAX}; // skybox resources default values ptScene->tSkyboxTexture = (plTextureHandle) {UINT32_MAX, UINT32_MAX}; @@ -2280,6 +2296,14 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) .uByteSize = sizeof(plVec4) * pl_sb_size(ptScene->sbtSkinVertexDataBuffer) }; + const plBufferDescription tLightBufferDesc = { + .tUsage = PL_BUFFER_USAGE_UNIFORM, + .uByteSize = sizeof(plGPULight) * PL_MAX_LIGHTS + }; + + for(uint32_t i = 0; i < PL_FRAMES_IN_FLIGHT; i++) + ptScene->atLightBuffer[i] = pl__refr_create_staging_buffer(&tLightBufferDesc, "light", i); + ptScene->tMaterialDataBuffer = pl__refr_create_local_buffer(&tShaderBufferDesc, "shader", uSceneHandle, ptScene->sbtMaterialBuffer); ptScene->tIndexBuffer = pl__refr_create_local_buffer(&tIndexBufferDesc, "index", uSceneHandle, ptScene->sbuIndexBuffer); ptScene->tVertexBuffer = pl__refr_create_local_buffer(&tVertexBufferDesc, "vertex", uSceneHandle, ptScene->sbtVertexPosBuffer); @@ -2323,7 +2347,8 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) } // create lighting shader - int aiLightingConstantData[1] = {iSceneWideRenderingFlags}; + const plLightComponent* sbtLights = ptScene->tComponentLibrary.tLightComponentManager.pComponents; + int aiLightingConstantData[] = {iSceneWideRenderingFlags, pl_sb_size(sbtLights)}; plShaderDescription tLightingShaderDesc = { #ifdef PL_METAL_BACKEND .pcVertexShader = "../shaders/metal/lighting.metal", @@ -2354,12 +2379,12 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) .atBlendStates = { pl__get_blend_state(PL_BLEND_MODE_OPAQUE) }, - .uConstantCount = 1, + .uConstantCount = 2, .pTempConstantData = aiLightingConstantData, .uBlendStateCount = 1, .uSubpassIndex = 1, .tRenderPassLayout = gptData->tRenderPassLayout, - .uBindGroupLayoutCount = 2, + .uBindGroupLayoutCount = 3, .atBindGroupLayouts = { { .uBufferBindingCount = 3, @@ -2402,7 +2427,17 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) { .uSlot = 4, .tStages = PL_STAGE_PIXEL, .tType = PL_TEXTURE_BINDING_TYPE_INPUT_ATTACHMENT}, { .uSlot = 5, .tStages = PL_STAGE_PIXEL, .tType = PL_TEXTURE_BINDING_TYPE_INPUT_ATTACHMENT}, }, - } + }, + { + .uBufferBindingCount = 1, + .aBufferBindings = { + { + .tType = PL_BUFFER_BINDING_TYPE_UNIFORM, + .uSlot = 0, + .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL + } + }, + }, } }; for(uint32_t i = 0; i < tLightingShaderDesc.uConstantCount; i++) @@ -2565,7 +2600,7 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint plRefView* ptView = &ptScene->atViews[uViewHandle]; plCameraComponent* ptCamera = tOptions.ptViewCamera; - // handle culling + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~culling~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ const uint32_t uOpaqueDrawableCount = pl_sb_size(ptScene->sbtOpaqueDrawables); const uint32_t uTransparentDrawableCount = pl_sb_size(ptScene->sbtTransparentDrawables); @@ -2747,19 +2782,26 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint .uBindGroup0 = tGlobalBG.uIndex, }; - plRenderEncoder tEncoder = gptGfx->begin_render_pass(ptGraphics, &tCommandBuffer, ptView->tRenderPass); - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~visible meshes~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - static double* pdVisibleObjects = NULL; - if(!pdVisibleObjects) - pdVisibleObjects = gptStats->get_counter("visible objects"); + static double* pdVisibleOpaqueObjects = NULL; + static double* pdVisibleTransparentObjects = NULL; + if(!pdVisibleOpaqueObjects) + { + pdVisibleOpaqueObjects = gptStats->get_counter("visible opaque objects"); + pdVisibleTransparentObjects = gptStats->get_counter("visible transparent objects"); + } const uint32_t uVisibleOpaqueDrawCount = pl_sb_size(ptView->sbtVisibleOpaqueDrawables); const uint32_t uVisibleTransparentDrawCount = pl_sb_size(ptView->sbtVisibleTransparentDrawables); if(tOptions.bCullStats) - *pdVisibleObjects = (double)(uVisibleOpaqueDrawCount + uVisibleTransparentDrawCount); + { + *pdVisibleOpaqueObjects = (double)(uVisibleOpaqueDrawCount); + *pdVisibleTransparentObjects = (double)(uVisibleTransparentDrawCount); + } + + //~~~~~~~~~~~~~~~~~~~~~~~~~~subpass 0 - g buffer fill~~~~~~~~~~~~~~~~~~~~~~~~~~ + + plRenderEncoder tEncoder = gptGfx->begin_render_pass(ptGraphics, &tCommandBuffer, ptView->tRenderPass); for(uint32_t i = 0; i < uVisibleOpaqueDrawCount; i++) { @@ -2792,9 +2834,52 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint } gptGfx->draw_stream(&tEncoder, 1, &tArea); - gptGfx->reset_draw_stream(ptStream); + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~subpass 1 - lighting~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + gptGfx->next_subpass(&tEncoder); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~lights~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + const plLightComponent* sbtLights = ptScene->tComponentLibrary.tLightComponentManager.pComponents; + pl_sb_reset(ptScene->sbtLightData); + pl_sb_resize(ptScene->sbtLightData, pl_sb_size(sbtLights)); + + for(uint32_t i = 0; i < pl_sb_size(sbtLights); i++) + { + const plLightComponent* ptLight = &sbtLights[i]; + + const plGPULight tLight = { + .fIntensity = ptLight->fIntensity, + .fRange = ptLight->fRange, + .iType = ptLight->tType, + .tPosition = ptLight->tPosition, + .tDirection = ptLight->tDirection, + .tColor = ptLight->tColor + }; + ptScene->sbtLightData[i] = tLight; + } + + const plBindGroupLayout tLightBindGroupLayout2 = { + .uBufferBindingCount = 1, + .aBufferBindings = { + { .uSlot = 0, .tType = PL_BUFFER_BINDING_TYPE_UNIFORM, .tStages = PL_STAGE_PIXEL | PL_STAGE_VERTEX} + } + }; + plBindGroupHandle tLightBindGroup2 = gptDevice->get_temporary_bind_group(ptDevice, &tLightBindGroupLayout2, "light bind group 2"); + + const plBindGroupUpdateBufferData atLightBufferData[] = + { + { .uSlot = 0, .tBuffer = ptScene->atLightBuffer[ptGraphics->uCurrentFrameIndex], .szBufferRange = sizeof(plGPULight) * pl_sb_size(ptScene->sbtLightData)} + }; + plBindGroupUpdateData tBGData2 = { + .uBufferCount = 1, + .atBuffers = atLightBufferData, + }; + gptDevice->update_bind_group(&ptGraphics->tDevice, tLightBindGroup2, &tBGData2); + plBuffer* ptLightingBuffer = gptDevice->get_buffer(ptDevice, ptScene->atLightBuffer[ptGraphics->uCurrentFrameIndex]); + memcpy(ptLightingBuffer->tMemoryAllocation.pHostMapped, ptScene->sbtLightData, sizeof(plGPULight) * pl_sb_size(ptScene->sbtLightData)); + typedef struct _plLightingDynamicData{ int iDataOffset; int iVertexOffset; @@ -2814,17 +2899,17 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint .uIndexOffset = ptScene->tLightingDrawable.uIndexOffset, .uTriangleCount = 2, .uBindGroup1 = ptView->tLightingBindGroup[ptGraphics->uCurrentFrameIndex].uIndex, - .uBindGroup2 = UINT32_MAX, + .uBindGroup2 = tLightBindGroup2.uIndex, .uDynamicBufferOffset = tLightingDynamicData.uByteOffset, .uInstanceStart = 0, .uInstanceCount = 1 }); - gptGfx->next_subpass(&tEncoder); gptGfx->draw_stream(&tEncoder, 1, &tArea); gptGfx->reset_draw_stream(ptStream); + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~subpass 2 - forward~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + gptGfx->next_subpass(&tEncoder); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~skybox~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if(ptScene->tSkyboxTexture.uIndex != UINT32_MAX) { @@ -2851,9 +2936,9 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint tArea.uBindGroup0 = tGlobalBG.uIndex; gptGfx->draw_stream(&tEncoder, 1, &tArea); } - gptGfx->reset_draw_stream(ptStream); + // forward rendering for(uint32_t i = 0; i < uVisibleTransparentDrawCount; i++) { const plDrawable tDrawable = ptView->sbtVisibleTransparentDrawables[i]; @@ -2885,6 +2970,7 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint } gptGfx->draw_stream(&tEncoder, 1, &tArea); + // outlines const uint32_t uOutlineDrawableCount = pl_sb_size(ptScene->sbtOutlineDrawables); if(uOutlineDrawableCount > 0) { @@ -2963,6 +3049,17 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint gptGfx->draw_stream(&tEncoder, 1, &tArea); } + // light drawing + for(uint32_t i = 0; i < pl_sb_size(ptScene->sbtLightData); i++) + { + if(ptScene->sbtLightData[i].iType == PL_LIGHT_TYPE_POINT) + { + const plVec4 tColor = {.rgb = ptScene->sbtLightData[i].tColor, .a = 1.0f}; + gptGfx->add_3d_point(&ptView->t3DDrawList, ptScene->sbtLightData[i].tPosition, tColor, 0.25f, 0.02f); + } + } + + // debug drawing if(tOptions.bShowAllBoundingBoxes) { for(uint32_t i = 0; i < uOpaqueDrawableCount; i++) @@ -3026,6 +3123,7 @@ pl_add_drawable_objects_to_scene(uint32_t uSceneHandle, uint32_t uOpaqueCount, c { plRefScene* ptScene = &gptData->sbtScenes[uSceneHandle]; + #if 1 const uint32_t uTransparentStart = pl_sb_size(ptScene->sbtTransparentDrawables); pl_sb_add_n(ptScene->sbtTransparentDrawables, uTransparentCount); @@ -3037,15 +3135,29 @@ pl_add_drawable_objects_to_scene(uint32_t uSceneHandle, uint32_t uOpaqueCount, c for(uint32_t i = 0; i < uTransparentCount; i++) ptScene->sbtTransparentDrawables[uTransparentStart + i].tEntity = atTransparentObjects[i]; + #endif - // const uint32_t uTransparentStart = pl_sb_size(ptScene->sbtTransparentDrawables); - // pl_sb_add_n(ptScene->sbtTransparentDrawables, uTransparentCount + uOpaqueCount); + #if 0 // send through forward pass only + const uint32_t uTransparentStart = pl_sb_size(ptScene->sbtTransparentDrawables); + pl_sb_add_n(ptScene->sbtTransparentDrawables, uTransparentCount + uOpaqueCount); + + for(uint32_t i = 0; i < uOpaqueCount; i++) + ptScene->sbtTransparentDrawables[uTransparentStart + i].tEntity = atOpaqueObjects[i]; + + for(uint32_t i = 0; i < uTransparentCount; i++) + ptScene->sbtTransparentDrawables[uOpaqueCount + uTransparentStart + i].tEntity = atTransparentObjects[i]; + #endif + + #if 0 // send through deferred pass only + const uint32_t uTransparentStart = pl_sb_size(ptScene->sbtOpaqueDrawables); + pl_sb_add_n(ptScene->sbtOpaqueDrawables, uTransparentCount + uOpaqueCount); - // for(uint32_t i = 0; i < uOpaqueCount; i++) - // ptScene->sbtTransparentDrawables[uTransparentStart + i].tEntity = atOpaqueObjects[i]; + for(uint32_t i = 0; i < uOpaqueCount; i++) + ptScene->sbtOpaqueDrawables[uTransparentStart + i].tEntity = atOpaqueObjects[i]; - // for(uint32_t i = 0; i < uTransparentCount; i++) - // ptScene->sbtTransparentDrawables[uOpaqueCount + uTransparentStart + i].tEntity = atTransparentObjects[i]; + for(uint32_t i = 0; i < uTransparentCount; i++) + ptScene->sbtOpaqueDrawables[uOpaqueCount + uTransparentStart + i].tEntity = atTransparentObjects[i]; + #endif } //----------------------------------------------------------------------------- From 2336130c8b5bb72129471e7c86133df27e0df9e0 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Thu, 9 May 2024 08:36:42 -0500 Subject: [PATCH 10/23] refac: return bindgroup slot 0 to draw stream from area in graphics ext --- extensions/pl_graphics_ext.c | 9 ++++++ extensions/pl_graphics_ext.h | 2 +- extensions/pl_metal_ext.m | 48 ++++++++++++++------------------ extensions/pl_ref_renderer_ext.c | 13 +++++---- extensions/pl_vulkan_ext.c | 26 +++++++++-------- 5 files changed, 52 insertions(+), 46 deletions(-) diff --git a/extensions/pl_graphics_ext.c b/extensions/pl_graphics_ext.c index 66fe072b..a6682e37 100644 --- a/extensions/pl_graphics_ext.c +++ b/extensions/pl_graphics_ext.c @@ -495,6 +495,7 @@ enum plDrawStreamBits PL_DRAW_STREAM_BIT_DYNAMIC_BUFFER = 1 << 2, PL_DRAW_STREAM_BIT_BINDGROUP_2 = 1 << 3, PL_DRAW_STREAM_BIT_BINDGROUP_1 = 1 << 4, + PL_DRAW_STREAM_BIT_BINDGROUP_0 = 1 << 5, PL_DRAW_STREAM_BIT_INDEX_OFFSET = 1 << 6, PL_DRAW_STREAM_BIT_VERTEX_OFFSET = 1 << 7, PL_DRAW_STREAM_BIT_INDEX_BUFFER = 1 << 8, @@ -538,6 +539,12 @@ pl_drawstream_draw(plDrawStream* ptStream, plStreamDraw tDraw) uDirtyMask |= PL_DRAW_STREAM_BIT_DYNAMIC_OFFSET; } + if(ptStream->tCurrentDraw.uBindGroup0 != tDraw.uBindGroup0) + { + ptStream->tCurrentDraw.uBindGroup0 = tDraw.uBindGroup0; + uDirtyMask |= PL_DRAW_STREAM_BIT_BINDGROUP_0; + } + if(ptStream->tCurrentDraw.uBindGroup1 != tDraw.uBindGroup1) { ptStream->tCurrentDraw.uBindGroup1 = tDraw.uBindGroup1; @@ -603,6 +610,8 @@ pl_drawstream_draw(plDrawStream* ptStream, plStreamDraw tDraw) pl_sb_push(ptStream->sbtStream, ptStream->tCurrentDraw.uShaderVariant); if(uDirtyMask & PL_DRAW_STREAM_BIT_DYNAMIC_OFFSET) pl_sb_push(ptStream->sbtStream, ptStream->tCurrentDraw.uDynamicBufferOffset); + if(uDirtyMask & PL_DRAW_STREAM_BIT_BINDGROUP_0) + pl_sb_push(ptStream->sbtStream, ptStream->tCurrentDraw.uBindGroup0); if(uDirtyMask & PL_DRAW_STREAM_BIT_BINDGROUP_1) pl_sb_push(ptStream->sbtStream, ptStream->tCurrentDraw.uBindGroup1); if(uDirtyMask & PL_DRAW_STREAM_BIT_BINDGROUP_2) diff --git a/extensions/pl_graphics_ext.h b/extensions/pl_graphics_ext.h index 871322e5..e26cd3a4 100644 --- a/extensions/pl_graphics_ext.h +++ b/extensions/pl_graphics_ext.h @@ -684,7 +684,6 @@ typedef struct _plDrawArea { plRenderViewport tViewport; plScissor tScissor; - uint32_t uBindGroup0; plDrawStream* ptDrawStream; } plDrawArea; @@ -707,6 +706,7 @@ typedef struct _plStreamDraw uint32_t uIndexOffset; uint32_t uTriangleCount; uint32_t uShaderVariant; + uint32_t uBindGroup0; uint32_t uBindGroup1; uint32_t uBindGroup2; uint32_t uDynamicBufferOffset; diff --git a/extensions/pl_metal_ext.m b/extensions/pl_metal_ext.m index 46b2366b..b1012feb 100644 --- a/extensions/pl_metal_ext.m +++ b/extensions/pl_metal_ext.m @@ -2293,33 +2293,6 @@ - (instancetype)initWithBuffer:(id)buffer uint32_t uInstanceCount = 1; id tCurrentDepthStencilState = nil; - { - plMetalBindGroup* ptMetalBindGroup = &ptMetalGraphics->sbtBindGroupsHot[ptArea->uBindGroup0]; - - for(uint32 j = 0; j < ptMetalBindGroup->uHeapCount; j++) - { - [tRenderEncoder useHeap:ptMetalBindGroup->atRequiredHeaps[j] stages:MTLRenderStageVertex | MTLRenderStageFragment]; - } - - for(uint32_t k = 0; k < ptMetalBindGroup->tLayout.uTextureBindingCount; k++) - { - - const plTextureHandle tTextureHandle = ptMetalBindGroup->atTextureBindings[k]; - id tHeap = ptMetalGraphics->sbtTexturesHot[tTextureHandle.uIndex].tHeap; - [tRenderEncoder useResource:ptMetalGraphics->sbtTexturesHot[tTextureHandle.uIndex].tTexture - usage:MTLResourceUsageRead - stages:MTLRenderStageVertex | MTLRenderStageFragment]; - } - - [tRenderEncoder setVertexBuffer:ptMetalBindGroup->tShaderArgumentBuffer - offset:ptMetalBindGroup->uOffset - atIndex:1]; - - [tRenderEncoder setFragmentBuffer:ptMetalBindGroup->tShaderArgumentBuffer - offset:ptMetalBindGroup->uOffset - atIndex:1]; - } - uint32_t uDynamicSlot = UINT32_MAX; while(uCurrentStreamIndex < uTokens) { @@ -2351,6 +2324,27 @@ - (instancetype)initWithBuffer:(id)buffer uCurrentStreamIndex++; } + if(uDirtyMask & PL_DRAW_STREAM_BIT_BINDGROUP_0) + { + plMetalBindGroup* ptMetalBindGroup = &ptMetalGraphics->sbtBindGroupsHot[ptStream->sbtStream[uCurrentStreamIndex]]; + + for(uint32 j = 0; j < ptMetalBindGroup->uHeapCount; j++) + { + [tRenderEncoder useHeap:ptMetalBindGroup->atRequiredHeaps[j] stages:MTLRenderStageVertex | MTLRenderStageFragment]; + } + + for(uint32_t k = 0; k < ptMetalBindGroup->tLayout.uTextureBindingCount; k++) + { + const plTextureHandle tTextureHandle = ptMetalBindGroup->atTextureBindings[k]; + plTexture* ptTexture = pl__get_texture(&ptGraphics->tDevice, tTextureHandle); + [tRenderEncoder useResource:ptMetalGraphics->sbtTexturesHot[tTextureHandle.uIndex].tTexture usage:MTLResourceUsageRead stages:MTLRenderStageVertex | MTLRenderStageFragment]; + } + + [tRenderEncoder setVertexBuffer:ptMetalBindGroup->tShaderArgumentBuffer offset:ptMetalBindGroup->uOffset atIndex:1]; + [tRenderEncoder setFragmentBuffer:ptMetalBindGroup->tShaderArgumentBuffer offset:ptMetalBindGroup->uOffset atIndex:1]; + uCurrentStreamIndex++; + } + if(uDirtyMask & PL_DRAW_STREAM_BIT_BINDGROUP_1) { plMetalBindGroup* ptMetalBindGroup = &ptMetalGraphics->sbtBindGroupsHot[ptStream->sbtStream[uCurrentStreamIndex]]; diff --git a/extensions/pl_ref_renderer_ext.c b/extensions/pl_ref_renderer_ext.c index a539868c..4d0ebed9 100644 --- a/extensions/pl_ref_renderer_ext.c +++ b/extensions/pl_ref_renderer_ext.c @@ -2778,8 +2778,7 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint .fWidth = tDimensions.x, .fHeight = tDimensions.y, .fMaxDepth = 1.0f - }, - .uBindGroup0 = tGlobalBG.uIndex, + } }; static double* pdVisibleOpaqueObjects = NULL; @@ -2825,6 +2824,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 = tGlobalBG.uIndex, .uBindGroup1 = tDrawable.tMaterialBindGroup.uIndex, .uBindGroup2 = UINT32_MAX, .uDynamicBufferOffset = tDynamicBinding.uByteOffset, @@ -2898,6 +2898,7 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint .uIndexBuffer = ptScene->tIndexBuffer.uIndex, .uIndexOffset = ptScene->tLightingDrawable.uIndexOffset, .uTriangleCount = 2, + .uBindGroup0 = tGlobalBG.uIndex, .uBindGroup1 = ptView->tLightingBindGroup[ptGraphics->uCurrentFrameIndex].uIndex, .uBindGroup2 = tLightBindGroup2.uIndex, .uDynamicBufferOffset = tLightingDynamicData.uByteOffset, @@ -2926,14 +2927,13 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint .uIndexBuffer = ptScene->tIndexBuffer.uIndex, .uIndexOffset = ptScene->tSkyboxDrawable.uIndexOffset, .uTriangleCount = ptScene->tSkyboxDrawable.uIndexCount / 3, + .uBindGroup0 = tGlobalBG.uIndex, .uBindGroup1 = ptScene->tSkyboxBindGroup.uIndex, .uBindGroup2 = UINT32_MAX, .uDynamicBufferOffset = tSkyboxDynamicData.uByteOffset, .uInstanceStart = 0, .uInstanceCount = 1 }); - - tArea.uBindGroup0 = tGlobalBG.uIndex; gptGfx->draw_stream(&tEncoder, 1, &tArea); } gptGfx->reset_draw_stream(ptStream); @@ -2961,8 +2961,9 @@ 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, - .uBindGroup1 = tDrawable.tMaterialBindGroup.uIndex, - .uBindGroup2 = UINT32_MAX, + .uBindGroup0 = tGlobalBG.uIndex, + .uBindGroup1 = tLightBindGroup2.uIndex, + .uBindGroup2 = tDrawable.tMaterialBindGroup.uIndex, .uDynamicBufferOffset = tDynamicBinding.uByteOffset, .uInstanceStart = 0, .uInstanceCount = 1 diff --git a/extensions/pl_vulkan_ext.c b/extensions/pl_vulkan_ext.c index fd607f70..f40bb6d7 100644 --- a/extensions/pl_vulkan_ext.c +++ b/extensions/pl_vulkan_ext.c @@ -2832,14 +2832,14 @@ typedef struct _plBindGroupManagerData { uint32_t uFirstSlot; uint32_t uCount; - VkDescriptorSet auSlots[3]; + VkDescriptorSet auSlots[4]; uint32_t auOffsets[2]; } plBindGroupManagerData; static void pl__set_bind_group_count(plBindGroupManagerData* ptData, uint32_t uCount) { - ptData->uCount = uCount; - ptData->uFirstSlot = 1; + ptData->uCount = uCount + 1; + ptData->uFirstSlot = 0; } static void pl__set_bind_group(plBindGroupManagerData* ptData, uint32_t uIndex, VkDescriptorSet tSet) @@ -2857,10 +2857,10 @@ static void pl__set_dynamic_bind_group(plBindGroupManagerData* ptData, VkDescrip static void pl__update_bindings(plBindGroupManagerData* ptData, VkCommandBuffer tCmdBuffer, VkPipelineLayout tLayout) { - VkDescriptorSet atSets[3] = {VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE}; + VkDescriptorSet atSets[4] = {VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE}; for(uint32_t i = 0; i < ptData->uCount; i++) atSets[i] = ptData->auSlots[i]; - vkCmdBindDescriptorSets(tCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, tLayout, ptData->uFirstSlot + 1, ptData->uCount - ptData->uFirstSlot, &atSets[ptData->uFirstSlot], 1, ptData->auOffsets); + vkCmdBindDescriptorSets(tCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, tLayout, ptData->uFirstSlot, ptData->uCount - ptData->uFirstSlot, &atSets[ptData->uFirstSlot], 1, ptData->auOffsets); } static void @@ -2918,9 +2918,6 @@ pl_draw_stream(plRenderEncoder* ptEncoder, uint32_t uAreaCount, plDrawArea* atAr plVulkanShader* ptVulkanShader = NULL; plVulkanDynamicBuffer* ptVulkanDynamicBuffer = NULL; - plVulkanBindGroup* ptBindGroup0 = &ptVulkanGfx->sbtBindGroupsHot[ptArea->uBindGroup0]; - VkDescriptorSet atDescriptorSets[4] = {ptBindGroup0->tDescriptorSet, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE}; - plBindGroupManagerData tBindGroupManagerData = {0}; while(uCurrentStreamIndex < uTokens) @@ -2934,7 +2931,6 @@ pl_draw_stream(plRenderEncoder* ptEncoder, uint32_t uAreaCount, plDrawArea* atAr const plShader* ptShader= &ptGraphics->sbtShadersCold[ptStream->sbtStream[uCurrentStreamIndex]]; ptVulkanShader = &ptVulkanGfx->sbtShadersHot[ptStream->sbtStream[uCurrentStreamIndex]]; vkCmdBindPipeline(tCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ptVulkanShader->tPipeline); - vkCmdBindDescriptorSets(tCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ptVulkanShader->tPipelineLayout, 0, 1, &ptBindGroup0->tDescriptorSet, 0, NULL); pl__set_bind_group_count(&tBindGroupManagerData, ptShader->tDescription.uBindGroupLayoutCount); uCurrentStreamIndex++; } @@ -2946,23 +2942,29 @@ pl_draw_stream(plRenderEncoder* ptEncoder, uint32_t uAreaCount, plDrawArea* atAr uCurrentStreamIndex++; } + if(uDirtyMask & PL_DRAW_STREAM_BIT_BINDGROUP_0) + { + plVulkanBindGroup* ptBindGroup0 = &ptVulkanGfx->sbtBindGroupsHot[ptStream->sbtStream[uCurrentStreamIndex]]; + pl__set_bind_group(&tBindGroupManagerData, 0, ptBindGroup0->tDescriptorSet); + uCurrentStreamIndex++; + } + if(uDirtyMask & PL_DRAW_STREAM_BIT_BINDGROUP_1) { plVulkanBindGroup* ptBindGroup1 = &ptVulkanGfx->sbtBindGroupsHot[ptStream->sbtStream[uCurrentStreamIndex]]; - pl__set_bind_group(&tBindGroupManagerData, 0, ptBindGroup1->tDescriptorSet); + pl__set_bind_group(&tBindGroupManagerData, 1, ptBindGroup1->tDescriptorSet); uCurrentStreamIndex++; } if(uDirtyMask & PL_DRAW_STREAM_BIT_BINDGROUP_2) { plVulkanBindGroup* ptBindGroup2 = &ptVulkanGfx->sbtBindGroupsHot[ptStream->sbtStream[uCurrentStreamIndex]]; - pl__set_bind_group(&tBindGroupManagerData, 1, ptBindGroup2->tDescriptorSet); + pl__set_bind_group(&tBindGroupManagerData, 2, ptBindGroup2->tDescriptorSet); uCurrentStreamIndex++; } if(uDirtyMask & PL_DRAW_STREAM_BIT_DYNAMIC_BUFFER) { - // uDescriptorStart = 3; ptVulkanDynamicBuffer = &ptCurrentFrame->sbtDynamicBuffers[ptStream->sbtStream[uCurrentStreamIndex]]; pl__set_dynamic_bind_group(&tBindGroupManagerData, ptVulkanDynamicBuffer->tDescriptorSet, uDynamicBufferOffset); uCurrentStreamIndex++; From 796a6fb860b16b5b682f6f46330bcb8d7744cc2c Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Thu, 9 May 2024 08:37:18 -0500 Subject: [PATCH 11/23] 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 From cd238d49e65c15fa166cbc1f3f939ee4f7e23f7e Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 11:00:36 -0500 Subject: [PATCH 12/23] feat: add "camera look at" function to ecs ext --- extensions/pl_ecs_ext.c | 13 ++++++++++++- extensions/pl_ecs_ext.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/extensions/pl_ecs_ext.c b/extensions/pl_ecs_ext.c index 38dff58e..6608485a 100644 --- a/extensions/pl_ecs_ext.c +++ b/extensions/pl_ecs_ext.c @@ -102,6 +102,7 @@ static void pl_camera_set_pitch_yaw (plCameraComponent* ptCamera, float fPitch, static void pl_camera_translate (plCameraComponent* ptCamera, float fDx, float fDy, float fDz); static void pl_camera_rotate (plCameraComponent* ptCamera, float fDPitch, float fDYaw); static void pl_camera_update (plCameraComponent* ptCamera); +static void pl_camera_look_at (plCameraComponent* ptCamera, plVec3 tEye, plVec3 tTarget); static inline float pl__wrap_angle(float tTheta) @@ -174,7 +175,8 @@ pl_load_camera_api(void) .set_pitch_yaw = pl_camera_set_pitch_yaw, .translate = pl_camera_translate, .rotate = pl_camera_rotate, - .update = pl_camera_update + .update = pl_camera_update, + .look_at = pl_camera_look_at, }; return &tApi; } @@ -1419,6 +1421,15 @@ pl_camera_rotate(plCameraComponent* ptCamera, float fDPitch, float fDYaw) ptCamera->fPitch = pl_clampf(0.995f * -PL_PI_2, ptCamera->fPitch, 0.995f * PL_PI_2); } +static void +pl_camera_look_at(plCameraComponent* ptCamera, plVec3 tEye, plVec3 tTarget) +{ + const plVec3 tDirection = pl_norm_vec3(pl_sub_vec3(tTarget, tEye)); + ptCamera->fYaw = atan2f(tDirection.x, tDirection.z); + ptCamera->fPitch = asinf(tDirection.y); + ptCamera->tPos = tEye; +} + static void pl_camera_update(plCameraComponent* ptCamera) { diff --git a/extensions/pl_ecs_ext.h b/extensions/pl_ecs_ext.h index 8122d44d..245afa35 100644 --- a/extensions/pl_ecs_ext.h +++ b/extensions/pl_ecs_ext.h @@ -167,6 +167,7 @@ typedef struct _plCameraI void (*set_pitch_yaw) (plCameraComponent*, float fPitch, float fYaw); void (*translate) (plCameraComponent*, float fDx, float fDy, float fDz); void (*rotate) (plCameraComponent*, float fDPitch, float fDYaw); + void (*look_at) (plCameraComponent*, plVec3 tEye, plVec3 tTarget); void (*update) (plCameraComponent*); } plCameraI; From 304677d36f7318cf0462300019e167617b0d92d9 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 11:01:30 -0500 Subject: [PATCH 13/23] feat: add max anisotropy option to samplers in graphics ext --- extensions/pl_graphics_ext.h | 3 ++- extensions/pl_metal_ext.m | 3 +++ extensions/pl_vulkan_ext.c | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/pl_graphics_ext.h b/extensions/pl_graphics_ext.h index e26cd3a4..5ea451c3 100644 --- a/extensions/pl_graphics_ext.h +++ b/extensions/pl_graphics_ext.h @@ -553,7 +553,8 @@ typedef struct _plSamplerDesc plWrapMode tVerticalWrap; float fMipBias; float fMinMip; - float fMaxMip; + float fMaxMip; + float fMaxAnisotropy; } plSamplerDesc; typedef struct _plSampler diff --git a/extensions/pl_metal_ext.m b/extensions/pl_metal_ext.m index b1012feb..edcb1062 100644 --- a/extensions/pl_metal_ext.m +++ b/extensions/pl_metal_ext.m @@ -1010,6 +1010,9 @@ - (instancetype)initWithBuffer:(id)buffer samplerDesc.lodMaxClamp = ptDesc->fMaxMip; samplerDesc.label = [NSString stringWithUTF8String:pcName]; samplerDesc.compareFunction = MTLCompareFunctionNever; + samplerDesc.maxAnisotropy = ptDesc->fMaxAnisotropy; + if(ptDesc->fMaxAnisotropy == 0.0f) + samplerDesc.maxAnisotropy = 16.0f; plMetalSampler tMetalSampler = { .tSampler = [ptMetalDevice->tDevice newSamplerStateWithDescriptor:samplerDesc] diff --git a/extensions/pl_vulkan_ext.c b/extensions/pl_vulkan_ext.c index f40bb6d7..9befebe4 100644 --- a/extensions/pl_vulkan_ext.c +++ b/extensions/pl_vulkan_ext.c @@ -1276,7 +1276,7 @@ pl_create_sampler(plDevice* ptDevice, const plSamplerDesc* ptDesc, const char* p .addressModeU = pl__vulkan_wrap(ptDesc->tHorizontalWrap), .addressModeV = pl__vulkan_wrap(ptDesc->tVerticalWrap), .anisotropyEnable = (bool)ptVulkanDevice->tDeviceFeatures.samplerAnisotropy, - .maxAnisotropy = ptVulkanDevice->tDeviceProps.limits.maxSamplerAnisotropy, + .maxAnisotropy = ptDesc->fMaxAnisotropy == 0 ? ptVulkanDevice->tDeviceProps.limits.maxSamplerAnisotropy : ptDesc->fMaxAnisotropy, .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, .unnormalizedCoordinates = VK_FALSE, .compareEnable = VK_FALSE, From a34eb9e28400b4c6e5bf65cb2ea6896c7c094982 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 11:02:58 -0500 Subject: [PATCH 14/23] refac: add variable descriptor count option to texture bindings --- extensions/pl_graphics_ext.h | 1 + extensions/pl_vulkan_ext.c | 51 +++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/extensions/pl_graphics_ext.h b/extensions/pl_graphics_ext.h index 5ea451c3..e0c6e9a7 100644 --- a/extensions/pl_graphics_ext.h +++ b/extensions/pl_graphics_ext.h @@ -611,6 +611,7 @@ typedef struct _plTextureBinding uint32_t uSlot; uint32_t uDescriptorCount; // 0 - will become 1 plStageFlags tStages; + bool bVariableDescriptorCount; } plTextureBinding; typedef struct _plSamplerBinding diff --git a/extensions/pl_vulkan_ext.c b/extensions/pl_vulkan_ext.c index 9befebe4..c6c91aa7 100644 --- a/extensions/pl_vulkan_ext.c +++ b/extensions/pl_vulkan_ext.c @@ -1346,7 +1346,9 @@ pl_create_bind_group_layout(plDevice* ptDevice, plBindGroupLayout* ptLayout, con }; if(tBinding.descriptorCount == 0) tBinding.descriptorCount = 1; - atDescriptorSetLayoutFlags[uCurrentBinding] = tBinding.descriptorCount > 1 ? VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT : 0; + atDescriptorSetLayoutFlags[uCurrentBinding] = 0; + if(ptLayout->atTextureBindings[i].bVariableDescriptorCount) + atDescriptorSetLayoutFlags[uCurrentBinding] |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; atDescriptorSetLayoutBindings[uCurrentBinding++] = tBinding; } @@ -1419,6 +1421,7 @@ pl_create_bind_group(plDevice* ptDevice, const plBindGroupLayout* ptLayout, cons VkDescriptorSetLayoutBinding* atDescriptorSetLayoutBindings = pl_temp_allocator_alloc(&ptVulkanGraphics->tTempAllocator, uDescriptorBindingCount * sizeof(VkDescriptorSetLayoutBinding)); VkDescriptorBindingFlagsEXT* atDescriptorSetLayoutFlags = pl_temp_allocator_alloc(&ptVulkanGraphics->tTempAllocator, uDescriptorBindingCount * sizeof(VkDescriptorBindingFlagsEXT)); uint32_t tDescriptorCount = 1; + bool bHasVariableDescriptors = false; for(uint32_t i = 0; i < ptLayout->uBufferBindingCount; i++) { @@ -1446,7 +1449,12 @@ pl_create_bind_group(plDevice* ptDevice, const plBindGroupLayout* ptLayout, cons tDescriptorCount = tBinding.descriptorCount; else if(tBinding.descriptorCount == 0) tBinding.descriptorCount = 1; - atDescriptorSetLayoutFlags[uCurrentBinding] = tBinding.descriptorCount > 1 ? VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT : 0; + atDescriptorSetLayoutFlags[uCurrentBinding] = 0; + if(ptLayout->atTextureBindings[i].bVariableDescriptorCount) + { + atDescriptorSetLayoutFlags[uCurrentBinding] |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; + bHasVariableDescriptors = true; + } atDescriptorSetLayoutBindings[uCurrentBinding++] = tBinding; } @@ -1499,7 +1507,7 @@ pl_create_bind_group(plDevice* ptDevice, const plBindGroupLayout* ptLayout, cons .descriptorPool = ptVulkanGraphics->tDescriptorPool, .descriptorSetCount = 1, .pSetLayouts = &tDescriptorSetLayout, - .pNext = &variableDescriptorCountAllocInfo + .pNext = bHasVariableDescriptors ? &variableDescriptorCountAllocInfo : NULL }; PL_VULKAN(vkAllocateDescriptorSets(ptVulkanDevice->tLogicalDevice, &tAllocInfo, &tVulkanBindGroup.tDescriptorSet)); @@ -1542,6 +1550,9 @@ pl_get_temporary_bind_group(plDevice* ptDevice, const plBindGroupLayout* ptLayou uint32_t uCurrentBinding = 0; const uint32_t uDescriptorBindingCount = ptLayout->uTextureBindingCount + ptLayout->uBufferBindingCount + ptLayout->uSamplerBindingCount; VkDescriptorSetLayoutBinding* atDescriptorSetLayoutBindings = pl_temp_allocator_alloc(&ptVulkanGraphics->tTempAllocator, uDescriptorBindingCount * sizeof(VkDescriptorSetLayoutBinding)); + VkDescriptorBindingFlagsEXT* atDescriptorSetLayoutFlags = pl_temp_allocator_alloc(&ptVulkanGraphics->tTempAllocator, uDescriptorBindingCount * sizeof(VkDescriptorBindingFlagsEXT)); + uint32_t tDescriptorCount = 1; + bool bHasVariableDescriptors = false; for(uint32_t i = 0; i < ptLayout->uBufferBindingCount; i++) { @@ -1552,6 +1563,7 @@ pl_get_temporary_bind_group(plDevice* ptDevice, const plBindGroupLayout* ptLayou .stageFlags = pl__vulkan_stage_flags(ptLayout->aBufferBindings[i].tStages), .pImmutableSamplers = NULL }; + atDescriptorSetLayoutFlags[uCurrentBinding] = 0; atDescriptorSetLayoutBindings[uCurrentBinding++] = tBinding; } @@ -1560,10 +1572,20 @@ pl_get_temporary_bind_group(plDevice* ptDevice, const plBindGroupLayout* ptLayou VkDescriptorSetLayoutBinding tBinding = { .binding = ptLayout->atTextureBindings[i].uSlot, .descriptorType = ptLayout->atTextureBindings[i].tType == PL_TEXTURE_BINDING_TYPE_SAMPLED ? VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE : VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, - .descriptorCount = 1, + .descriptorCount = ptLayout->atTextureBindings[i].uDescriptorCount, .stageFlags = pl__vulkan_stage_flags(ptLayout->atTextureBindings[i].tStages), .pImmutableSamplers = NULL }; + if(tBinding.descriptorCount > 1) + tDescriptorCount = tBinding.descriptorCount; + else if(tBinding.descriptorCount == 0) + tBinding.descriptorCount = 1; + atDescriptorSetLayoutFlags[uCurrentBinding] = 0; + if(ptLayout->atTextureBindings[i].bVariableDescriptorCount) + { + atDescriptorSetLayoutFlags[uCurrentBinding] |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; + bHasVariableDescriptors = true; + } atDescriptorSetLayoutBindings[uCurrentBinding++] = tBinding; } @@ -1576,16 +1598,26 @@ pl_get_temporary_bind_group(plDevice* ptDevice, const plBindGroupLayout* ptLayou .stageFlags = pl__vulkan_stage_flags(ptLayout->atSamplerBindings[i].tStages), .pImmutableSamplers = NULL }; + atDescriptorSetLayoutFlags[uCurrentBinding] = 0; atDescriptorSetLayoutBindings[uCurrentBinding++] = tBinding; } + VkDescriptorSetLayoutBindingFlagsCreateInfoEXT setLayoutBindingFlags = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT, + .bindingCount = uDescriptorBindingCount, + .pBindingFlags = atDescriptorSetLayoutFlags, + .pNext = NULL + }; + // create descriptor set layout - VkDescriptorSetLayout tDescriptorSetLayout = VK_NULL_HANDLE; const VkDescriptorSetLayoutCreateInfo tDescriptorSetLayoutInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .bindingCount = uDescriptorBindingCount, .pBindings = atDescriptorSetLayoutBindings, + .pNext = &setLayoutBindingFlags, + .flags = ptDevice->bDescriptorIndexing ? VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT : 0 }; + VkDescriptorSetLayout tDescriptorSetLayout = VK_NULL_HANDLE; PL_VULKAN(vkCreateDescriptorSetLayout(ptVulkanDevice->tLogicalDevice, &tDescriptorSetLayoutInfo, NULL, &tDescriptorSetLayout)); pl_temp_allocator_reset(&ptVulkanGraphics->tTempAllocator); @@ -1594,12 +1626,19 @@ pl_get_temporary_bind_group(plDevice* ptDevice, const plBindGroupLayout* ptLayou .tDescriptorSetLayout = tDescriptorSetLayout }; + VkDescriptorSetVariableDescriptorCountAllocateInfoEXT variableDescriptorCountAllocInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT, + .descriptorSetCount = 1, + .pDescriptorCounts = &tDescriptorCount, + }; + // allocate descriptor sets const VkDescriptorSetAllocateInfo tAllocInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, .descriptorPool = ptCurrentFrame->tDynamicDescriptorPool, .descriptorSetCount = 1, - .pSetLayouts = &tDescriptorSetLayout + .pSetLayouts = &tDescriptorSetLayout, + .pNext = bHasVariableDescriptors ? &variableDescriptorCountAllocInfo : NULL }; PL_VULKAN(vkAllocateDescriptorSets(ptVulkanDevice->tLogicalDevice, &tAllocInfo, &tVulkanBindGroup.tDescriptorSet)); From 04dc82dca1b5598a2505a3c12aedc07248224862 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 11:04:12 -0500 Subject: [PATCH 15/23] feat: add support for texture arrays for graphics ext --- extensions/pl_graphics_ext.h | 3 ++- extensions/pl_metal_ext.m | 4 +++- extensions/pl_vulkan_ext.c | 27 +++++++++++++++++++++------ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/extensions/pl_graphics_ext.h b/extensions/pl_graphics_ext.h index e0c6e9a7..be33b4aa 100644 --- a/extensions/pl_graphics_ext.h +++ b/extensions/pl_graphics_ext.h @@ -1049,7 +1049,8 @@ enum _plTextureType { PL_TEXTURE_TYPE_UNSPECIFIED, PL_TEXTURE_TYPE_2D, - PL_TEXTURE_TYPE_CUBE + PL_TEXTURE_TYPE_CUBE, + PL_TEXTURE_TYPE_2D_ARRAY }; enum _plBufferUsage diff --git a/extensions/pl_metal_ext.m b/extensions/pl_metal_ext.m index edcb1062..8f5d3c69 100644 --- a/extensions/pl_metal_ext.m +++ b/extensions/pl_metal_ext.m @@ -843,7 +843,7 @@ - (instancetype)initWithBuffer:(id)buffer ptTextureDescriptor.width = tDesc.tDimensions.x; ptTextureDescriptor.height = tDesc.tDimensions.y; ptTextureDescriptor.mipmapLevelCount = tDesc.uMips; - ptTextureDescriptor.arrayLength = 1; + ptTextureDescriptor.arrayLength = tDesc.tType == PL_TEXTURE_TYPE_2D_ARRAY ? tDesc.uLayers : 1; ptTextureDescriptor.depth = tDesc.tDimensions.z; ptTextureDescriptor.sampleCount = 1; @@ -858,6 +858,8 @@ - (instancetype)initWithBuffer:(id)buffer ptTextureDescriptor.textureType = MTLTextureType2D; else if(tDesc.tType == PL_TEXTURE_TYPE_CUBE) ptTextureDescriptor.textureType = MTLTextureTypeCube; + else if(tDesc.tType == PL_TEXTURE_TYPE_2D_ARRAY) + ptTextureDescriptor.textureType = MTLTextureType2DArray; else { PL_ASSERT(false && "unsupported texture type"); diff --git a/extensions/pl_vulkan_ext.c b/extensions/pl_vulkan_ext.c index c6c91aa7..d544e9a3 100644 --- a/extensions/pl_vulkan_ext.c +++ b/extensions/pl_vulkan_ext.c @@ -1006,11 +1006,12 @@ pl_create_texture(plDevice* ptDevice, const plTextureDesc* ptDesc, const char* p tImageViewType = VK_IMAGE_VIEW_TYPE_CUBE; else if(tDesc.tType == PL_TEXTURE_TYPE_2D) tImageViewType = VK_IMAGE_VIEW_TYPE_2D; + else if(tDesc.tType == PL_TEXTURE_TYPE_2D_ARRAY) + tImageViewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; else { PL_ASSERT(false && "unsupported texture type"); } - PL_ASSERT((tDesc.uLayers == 1 || tDesc.uLayers == 6) && "unsupported layer count"); VkImageUsageFlags tUsageFlags = 0; if(tDesc.tUsage & PL_TEXTURE_USAGE_SAMPLED) tUsageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; @@ -1115,11 +1116,12 @@ pl_bind_texture_to_memory(plDevice* ptDevice, plTextureHandle tHandle, const plD tImageViewType = VK_IMAGE_VIEW_TYPE_CUBE; else if(ptTexture->tDesc.tType == PL_TEXTURE_TYPE_2D) tImageViewType = VK_IMAGE_VIEW_TYPE_2D; + else if(ptTexture->tDesc.tType == PL_TEXTURE_TYPE_2D_ARRAY) + tImageViewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; else { PL_ASSERT(false && "unsupported texture type"); } - PL_ASSERT((ptTexture->tDesc.uLayers == 1 || ptTexture->tDesc.uLayers == 6) && "unsupported layer count"); VkImageViewCreateInfo tViewInfo = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, @@ -1218,8 +1220,18 @@ pl_create_texture_view(plDevice* ptDevice, const plTextureViewDesc* ptViewDesc, //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~create view~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - const VkImageViewType tImageViewType = ptViewDesc->uLayerCount == 6 ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D; - PL_ASSERT((ptViewDesc->uLayerCount == 1 || ptViewDesc->uLayerCount == 6) && "unsupported layer count"); + VkImageViewType tImageViewType = 0; + if(ptTexture->tDesc.tType == PL_TEXTURE_TYPE_CUBE) + tImageViewType = VK_IMAGE_VIEW_TYPE_CUBE; + else if(ptTexture->tDesc.tType == PL_TEXTURE_TYPE_2D) + tImageViewType = VK_IMAGE_VIEW_TYPE_2D; + else if(ptTexture->tDesc.tType == PL_TEXTURE_TYPE_2D_ARRAY) + tImageViewType = VK_IMAGE_VIEW_TYPE_2D; + // tImageViewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + else + { + PL_ASSERT(false && "unsupported texture type"); + } VkImageAspectFlags tImageAspectFlags = ptTexture->tDesc.tUsage & PL_TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; @@ -3720,6 +3732,10 @@ pl_initialize_graphics(plWindow* ptWindow, const plGraphicsDesc* ptDesc, plGraph .poolSizeCount = 6, .pPoolSizes = atDynamicPoolSizes, }; + if(ptGraphics->tDevice.bDescriptorIndexing) + { + tDynamicDescriptorPoolInfo.flags |= VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; + } PL_VULKAN(vkCreateDescriptorPool(ptVulkanDevice->tLogicalDevice, &tDynamicDescriptorPoolInfo, NULL, &tFrame.tDynamicDescriptorPool)); ptVulkanGfx->sbFrames[i] = tFrame; @@ -3862,6 +3878,7 @@ pl_begin_frame(plGraphics* ptGraphics) ptCurrentFrame->uCurrentBufferIndex = UINT32_MAX; PL_VULKAN(vkWaitForFences(ptVulkanDevice->tLogicalDevice, 1, &ptCurrentFrame->tInFlight, VK_TRUE, UINT64_MAX)); + pl__garbage_collect(ptGraphics); VkResult err = vkAcquireNextImageKHR(ptVulkanDevice->tLogicalDevice, ptVulkanSwapchain->tSwapChain, UINT64_MAX, ptCurrentFrame->tImageAvailable, VK_NULL_HANDLE, &ptGraphics->tSwapchain.uCurrentImageIndex); if(err == VK_SUBOPTIMAL_KHR || err == VK_ERROR_OUT_OF_DATE_KHR) @@ -4022,9 +4039,7 @@ pl_present(plGraphics* ptGraphics, plCommandBuffer* ptCmdBuffer, const plSubmitI { PL_VULKAN(tResult); } - ptGraphics->uCurrentFrameIndex = (ptGraphics->uCurrentFrameIndex + 1) % ptGraphics->uFramesInFlight; - pl__garbage_collect(ptGraphics); pl_sb_push(ptCurrentFrame->sbtPendingCommandBuffers, tCmdBuffer); pl_end_profile_sample(); return true; From aaa07e9d243b8469aa8653c7b771db0a458fbfc0 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 11:04:45 -0500 Subject: [PATCH 16/23] feat: add buffer binding offset options for graphics ext. vulkan backend --- extensions/pl_graphics_ext.h | 1 + extensions/pl_vulkan_ext.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/pl_graphics_ext.h b/extensions/pl_graphics_ext.h index be33b4aa..538e124a 100644 --- a/extensions/pl_graphics_ext.h +++ b/extensions/pl_graphics_ext.h @@ -390,6 +390,7 @@ typedef struct _plBindGroupUpdateBufferData { plBufferHandle tBuffer; uint32_t uSlot; + size_t szOffset; size_t szBufferRange; } plBindGroupUpdateBufferData; diff --git a/extensions/pl_vulkan_ext.c b/extensions/pl_vulkan_ext.c index d544e9a3..099ecc66 100644 --- a/extensions/pl_vulkan_ext.c +++ b/extensions/pl_vulkan_ext.c @@ -1690,7 +1690,7 @@ pl_update_bind_group(plDevice* ptDevice, plBindGroupHandle tHandle, const plBind const plVulkanBuffer* ptVulkanBuffer = &ptVulkanGraphics->sbtBuffersHot[ptData->atBuffers[i].tBuffer.uIndex]; sbtBufferDescInfos[i].buffer = ptVulkanBuffer->tBuffer; - sbtBufferDescInfos[i].offset = 0; + sbtBufferDescInfos[i].offset = ptData->atBuffers[i].szOffset; sbtBufferDescInfos[i].range = ptData->atBuffers[i].szBufferRange; sbtWrites[uCurrentWrite].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; From cf1287655376ab1f19e04dbe381f8cc263303ea6 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 11:05:21 -0500 Subject: [PATCH 17/23] fix: allow no pixel shader option to vulkan backend --- extensions/pl_vulkan_ext.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/extensions/pl_vulkan_ext.c b/extensions/pl_vulkan_ext.c index 099ecc66..d5e7ae84 100644 --- a/extensions/pl_vulkan_ext.c +++ b/extensions/pl_vulkan_ext.c @@ -1898,16 +1898,13 @@ pl_create_shader(plDevice* ptDevice, const plShaderDescription* ptDescription) ptVulkanShader->atDescriptorSetLayouts[tShader.tDescription.uBindGroupLayoutCount] = ptVulkanGfx->tDynamicDescriptorSetLayout; uint32_t uVertShaderSize0 = 0u; - uint32_t uPixelShaderSize0 = 0u; - gptFile->read(tShader.tDescription.pcVertexShader, &uVertShaderSize0, NULL, "rb"); - gptFile->read(tShader.tDescription.pcPixelShader, &uPixelShaderSize0, NULL, "rb"); - char* vertexShaderCode = pl_temp_allocator_alloc(&ptVulkanGfx->tTempAllocator, uVertShaderSize0); - char* pixelShaderCode = pl_temp_allocator_alloc(&ptVulkanGfx->tTempAllocator, uPixelShaderSize0); - gptFile->read(tShader.tDescription.pcVertexShader, &uVertShaderSize0, vertexShaderCode, "rb"); - gptFile->read(tShader.tDescription.pcPixelShader, &uPixelShaderSize0, pixelShaderCode, "rb"); + + + + uint32_t uStageCount = 1; VkShaderModuleCreateInfo tVertexShaderCreateInfo = { .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, @@ -1916,13 +1913,23 @@ pl_create_shader(plDevice* ptDevice, const plShaderDescription* ptDescription) }; PL_VULKAN(vkCreateShaderModule(ptVulkanDevice->tLogicalDevice, &tVertexShaderCreateInfo, NULL, &ptVulkanShader->tVertexShaderModule)); - VkShaderModuleCreateInfo tPixelShaderCreateInfo = { - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .codeSize = uPixelShaderSize0, - .pCode = (const uint32_t*)(pixelShaderCode), - }; - PL_VULKAN(vkCreateShaderModule(ptVulkanDevice->tLogicalDevice, &tPixelShaderCreateInfo, NULL, &ptVulkanShader->tPixelShaderModule)); + if(tShader.tDescription.pcPixelShader) + { + uStageCount++; + uint32_t uPixelShaderSize0 = 0u; + gptFile->read(tShader.tDescription.pcPixelShader, &uPixelShaderSize0, NULL, "rb"); + char* pixelShaderCode = pl_temp_allocator_alloc(&ptVulkanGfx->tTempAllocator, uPixelShaderSize0); + gptFile->read(tShader.tDescription.pcPixelShader, &uPixelShaderSize0, pixelShaderCode, "rb"); + + VkShaderModuleCreateInfo tPixelShaderCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = uPixelShaderSize0, + .pCode = (const uint32_t*)(pixelShaderCode), + }; + + PL_VULKAN(vkCreateShaderModule(ptVulkanDevice->tLogicalDevice, &tPixelShaderCreateInfo, NULL, &ptVulkanShader->tPixelShaderModule)); + } pl_temp_allocator_reset(&ptVulkanGfx->tTempAllocator); @@ -2137,7 +2144,7 @@ pl_create_shader(plDevice* ptDevice, const plShaderDescription* ptDescription) VkGraphicsPipelineCreateInfo tPipelineInfo = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .stageCount = 2, + .stageCount = uStageCount, .pStages = shaderStages, .pVertexInputState = &tVertexInputInfo, .pInputAssemblyState = &tInputAssembly, From bb94b89710a12a0a9c25b9ca541842e9dfdad4e6 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 11:06:11 -0500 Subject: [PATCH 18/23] fix: stencil buffer support in metal backend --- extensions/pl_metal_ext.m | 56 ++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/extensions/pl_metal_ext.m b/extensions/pl_metal_ext.m index 8f5d3c69..5640fa0b 100644 --- a/extensions/pl_metal_ext.m +++ b/extensions/pl_metal_ext.m @@ -235,6 +235,7 @@ - (instancetype)initWithBuffer:(id)buffer static MTLDataType pl__metal_data_type (plDataType tType); static MTLRenderStages pl__metal_stage_flags(plStageFlags tFlags); static bool pl__is_depth_format (plFormat tFormat); +static bool pl__is_stencil_format (plFormat tFormat); static MTLBlendFactor pl__metal_blend_factor(plBlendFactor tFactor); static MTLBlendOperation pl__metal_blend_op(plBlendOp tOp); @@ -360,7 +361,11 @@ - (instancetype)initWithBuffer:(id)buffer if(pl__is_depth_format(ptLayout->tDesc.atRenderTargets[uTargetIndex].tFormat)) { ptRenderPassDescriptor.depthAttachment.texture = ptMetalGraphics->sbtTexturesHot[uTextureIndex].tTexture; - ptRenderPassDescriptor.stencilAttachment.texture = ptMetalGraphics->sbtTexturesHot[uTextureIndex].tTexture; + ptRenderPassDescriptor.depthAttachment.slice = ptGraphics->sbtTexturesCold[uTextureIndex].tView.uBaseLayer; + if(pl__is_stencil_format(ptLayout->tDesc.atRenderTargets[uTargetIndex].tFormat)) + { + ptRenderPassDescriptor.stencilAttachment.texture = ptMetalGraphics->sbtTexturesHot[uTextureIndex].tTexture; + } } else { @@ -466,7 +471,6 @@ - (instancetype)initWithBuffer:(id)buffer const plSubpass* ptSubpass = &ptLayout->tDesc.atSubpasses[i]; MTLRenderPassDescriptor* ptRenderPassDescriptor = [MTLRenderPassDescriptor new]; - // uint32_t auLastFrames[PL_MAX_RENDER_TARGETS] = {0}; uint32_t uCurrentColorAttachment = 0; @@ -476,16 +480,23 @@ - (instancetype)initWithBuffer:(id)buffer const uint32_t uTextureIndex = ptAttachments[uFrameIndex].atViewAttachments[uTargetIndex].uIndex; if(pl__is_depth_format(ptLayout->tDesc.atRenderTargets[uTargetIndex].tFormat)) { + bool bStencilIncluded = pl__is_stencil_format(ptLayout->tDesc.atRenderTargets[uTargetIndex].tFormat); if(abTargetSeen[uTargetIndex]) { ptRenderPassDescriptor.depthAttachment.loadAction = MTLLoadActionLoad; - ptRenderPassDescriptor.stencilAttachment.loadAction = MTLLoadActionLoad; + if(bStencilIncluded) + { + ptRenderPassDescriptor.stencilAttachment.loadAction = MTLLoadActionLoad; + } } else { ptRenderPassDescriptor.depthAttachment.loadAction = pl__metal_load_op(ptDesc->tDepthTarget.tLoadOp); - ptRenderPassDescriptor.stencilAttachment.loadAction = pl__metal_load_op(ptDesc->tDepthTarget.tStencilLoadOp); + if(bStencilIncluded) + { + ptRenderPassDescriptor.stencilAttachment.loadAction = pl__metal_load_op(ptDesc->tDepthTarget.tStencilLoadOp); + } abTargetSeen[uTargetIndex] = true; } @@ -493,19 +504,29 @@ - (instancetype)initWithBuffer:(id)buffer if(i == ptLayout->tDesc.uSubpassCount - 1) { ptRenderPassDescriptor.depthAttachment.storeAction = pl__metal_store_op(ptDesc->tDepthTarget.tStoreOp); - ptRenderPassDescriptor.stencilAttachment.storeAction = pl__metal_store_op(ptDesc->tDepthTarget.tStencilStoreOp); + if(bStencilIncluded) + { + ptRenderPassDescriptor.stencilAttachment.storeAction = pl__metal_store_op(ptDesc->tDepthTarget.tStencilStoreOp); + } } else { ptRenderPassDescriptor.depthAttachment.storeAction = MTLStoreActionStore; - ptRenderPassDescriptor.stencilAttachment.storeAction = MTLStoreActionStore; + if(bStencilIncluded) + { + ptRenderPassDescriptor.stencilAttachment.storeAction = MTLStoreActionStore; + } } ptRenderPassDescriptor.depthAttachment.clearDepth = ptDesc->tDepthTarget.fClearZ; - ptRenderPassDescriptor.stencilAttachment.clearStencil = ptDesc->tDepthTarget.uClearStencil; + + if(bStencilIncluded) + { + ptRenderPassDescriptor.stencilAttachment.clearStencil = ptDesc->tDepthTarget.uClearStencil; + ptRenderPassDescriptor.stencilAttachment.texture = ptMetalGraphics->sbtTexturesHot[uTextureIndex].tTexture; + } ptRenderPassDescriptor.depthAttachment.texture = ptMetalGraphics->sbtTexturesHot[uTextureIndex].tTexture; - ptRenderPassDescriptor.stencilAttachment.texture = ptMetalGraphics->sbtTexturesHot[uTextureIndex].tTexture; - + ptRenderPassDescriptor.depthAttachment.slice = ptGraphics->sbtTexturesCold[uTextureIndex].tView.uBaseLayer; ptLayout->tDesc.atSubpasses[i]._bHasDepth = true; } else @@ -1520,7 +1541,10 @@ - (instancetype)initWithBuffer:(id)buffer if(pl__is_depth_format(ptLayout->tDesc.atRenderTargets[uTargetIndex].tFormat)) { pipelineDescriptor.depthAttachmentPixelFormat = pl__metal_format(ptLayout->tDesc.atRenderTargets[uTargetIndex].tFormat); - pipelineDescriptor.stencilAttachmentPixelFormat = pipelineDescriptor.depthAttachmentPixelFormat; + if(pl__is_stencil_format(ptLayout->tDesc.atRenderTargets[uTargetIndex].tFormat)) + { + pipelineDescriptor.stencilAttachmentPixelFormat = pipelineDescriptor.depthAttachmentPixelFormat; + } } else { @@ -2651,6 +2675,18 @@ - (instancetype)initWithBuffer:(id)buffer return false; } +static bool +pl__is_stencil_format(plFormat tFormat) +{ + switch(tFormat) + { + case PL_FORMAT_D32_FLOAT_S8_UINT: + case PL_FORMAT_D24_UNORM_S8_UINT: + case PL_FORMAT_D16_UNORM_S8_UINT: return true; + } + return false; +} + static MTLBlendFactor pl__metal_blend_factor(plBlendFactor tFactor) { From c5a98ded6d687fc20bbb5141737a3056ff7dc3cc Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 11:06:46 -0500 Subject: [PATCH 19/23] refac: change metal texture views to be emulated --- extensions/pl_metal_ext.m | 87 ++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 34 deletions(-) diff --git a/extensions/pl_metal_ext.m b/extensions/pl_metal_ext.m index 5640fa0b..ff77c0c5 100644 --- a/extensions/pl_metal_ext.m +++ b/extensions/pl_metal_ext.m @@ -131,6 +131,7 @@ - (instancetype)initWithBuffer:(id)buffer id tTexture; id tHeap; MTLTextureDescriptor* ptTextureDescriptor; + bool bOriginalView; } plMetalTexture; typedef struct _plMetalSampler @@ -891,7 +892,8 @@ - (instancetype)initWithBuffer:(id)buffer tTexture.tMemoryRequirements.ulSize = tSizeAndAlign.size; tTexture.tMemoryRequirements.uMemoryTypeBits = 0; plMetalTexture tMetalTexture = { - .ptTextureDescriptor = ptTextureDescriptor + .ptTextureDescriptor = ptTextureDescriptor, + .bOriginalView = true }; ptMetalGraphics->sbtTexturesHot[uTextureIndex] = tMetalTexture; ptGraphics->sbtTexturesCold[uTextureIndex] = tTexture; @@ -953,40 +955,56 @@ - (instancetype)initWithBuffer:(id)buffer plTexture* ptTexture = pl__get_texture(ptDevice, ptViewDesc->tTexture); plMetalTexture* ptOldMetalTexture = &ptMetalGraphics->sbtTexturesHot[ptViewDesc->tTexture.uIndex]; + plMetalTexture* ptNewMetalTexture = &ptMetalGraphics->sbtTexturesHot[uTextureIndex]; + ptNewMetalTexture->bOriginalView = false; + + // MTLTextureType tTextureType = MTLTextureType2D; + + // if(tTexture.tDesc.tType == PL_TEXTURE_TYPE_2D) + // tTextureType = MTLTextureType2D; + // else if(tTexture.tDesc.tType == PL_TEXTURE_TYPE_CUBE) + // tTextureType = MTLTextureTypeCube; + // else if(tTexture.tDesc.tType == PL_TEXTURE_TYPE_2D_ARRAY) + // tTextureType = MTLTextureType2DArray; + // // tTextureType = MTLTextureType2D; + // else + // { + // PL_ASSERT(false && "unsupported texture type"); + // } + + // NSRange tLevelRange = { + // .length = ptViewDesc->uMips == 0 ? ptTexture->tDesc.uMips - ptViewDesc->uBaseMip : ptViewDesc->uMips, + // .location = ptViewDesc->uBaseMip + // }; + + // NSRange tSliceRange = { + // .length = ptViewDesc->uLayerCount, + // .location = ptViewDesc->uBaseLayer + // }; + + // NSRange tLevelRange = { + // .length = ptTexture->tView.uMips, + // .location = ptTexture->tView.uBaseMip + // }; + + // NSRange tSliceRange = { + // .length = ptTexture->tView.uLayerCount, + // .location = ptTexture->tView.uBaseLayer + // }; + + // plMetalTexture tMetalTexture = { + // .tTexture = [ptOldMetalTexture->tTexture newTextureViewWithPixelFormat:pl__metal_format(ptViewDesc->tFormat) + // textureType:tTextureType + // levels:tLevelRange + // slices:tSliceRange], + // .tHeap = ptOldMetalTexture->tHeap + // }; + // if(pcName == NULL) + // pcName = "unnamed texture"; + // tMetalTexture.tTexture.label = [NSString stringWithUTF8String:pcName]; + ptNewMetalTexture->tTexture = ptOldMetalTexture->tTexture; + ptNewMetalTexture->tHeap = ptOldMetalTexture->tHeap; - MTLTextureType tTextureType = MTLTextureType2D; - - if(tTexture.tDesc.tType == PL_TEXTURE_TYPE_2D) - tTextureType = MTLTextureType2D; - else if(tTexture.tDesc.tType == PL_TEXTURE_TYPE_CUBE) - tTextureType = MTLTextureTypeCube; - else - { - PL_ASSERT(false && "unsupported texture type"); - } - - NSRange tLevelRange = { - .length = ptViewDesc->uMips == 0 ? ptTexture->tDesc.uMips - ptViewDesc->uBaseMip : ptViewDesc->uMips, - .location = ptViewDesc->uBaseMip - }; - - NSRange tSliceRange = { - .length = ptViewDesc->uLayerCount, - .location = ptViewDesc->uBaseLayer - }; - - plMetalTexture tMetalTexture = { - .tTexture = [ptOldMetalTexture->tTexture newTextureViewWithPixelFormat:pl__metal_format(ptViewDesc->tFormat) - textureType:tTextureType - levels:tLevelRange - slices:tSliceRange], - .tHeap = ptOldMetalTexture->tHeap - }; - if(pcName == NULL) - pcName = "unnamed texture"; - tMetalTexture.tTexture.label = [NSString stringWithUTF8String:pcName]; - - ptMetalGraphics->sbtTexturesHot[uTextureIndex] = tMetalTexture; ptGraphics->sbtTexturesCold[uTextureIndex] = tTexture; return tHandle; } @@ -1213,6 +1231,7 @@ - (instancetype)initWithBuffer:(id)buffer for(uint32_t i = 0; i < ptData->uTextureCount; i++) { const plBindGroupUpdateTextureData* ptUpdate = &ptData->atTextures[i]; + plTexture* ptTexture = &ptGraphics->sbtTexturesCold[ptUpdate->tTexture.uIndex]; plMetalTexture* ptMetalTexture = &ptMetalGraphics->sbtTexturesHot[ptUpdate->tTexture.uIndex]; MTLResourceID* pptDestination = (MTLResourceID*)&pulDescriptorStart[ptUpdate->uSlot + ptUpdate->uIndex]; *pptDestination = ptMetalTexture->tTexture.gpuResourceID; From 3dd2470116b329f96a7af83d0963c228abbbe2c3 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 11:08:41 -0500 Subject: [PATCH 20/23] feat: add cascaded shadow support to lights in ecs ext --- apps/helper_windows.h | 2 +- extensions/pl_ecs_ext.c | 18 +++++++++++------- extensions/pl_ecs_ext.h | 6 +++++- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/apps/helper_windows.h b/apps/helper_windows.h index 8d8ecefe..b5b47fd4 100644 --- a/apps/helper_windows.h +++ b/apps/helper_windows.h @@ -154,7 +154,7 @@ pl_show_ecs_window(const plEcsI* ptECS, plComponentLibrary* ptLibrary, bool* pbS pl_text("Color: (%0.3f, %0.3f, %0.3f)", ptLightComp->tColor.r, ptLightComp->tColor.g, ptLightComp->tColor.b); pl_text("Direction: (%0.3f, %0.3f, %0.3f)", ptLightComp->tDirection.r, ptLightComp->tDirection.g, ptLightComp->tDirection.b); pl_text("Intensity: %0.3f", ptLightComp->fIntensity); - pl_text("Cast Shadow: %s", ptLightComp->tFlags & PL_LIGHT_FLAG_HAS_CAST_SHADOW ? "true" : "false"); + pl_text("Cast Shadow: %s", ptLightComp->tFlags & PL_LIGHT_FLAG_CAST_SHADOW ? "true" : "false"); } if(ptMaterialComp && pl_collapsing_header("Material")) diff --git a/extensions/pl_ecs_ext.c b/extensions/pl_ecs_ext.c index 6608485a..123f5ef5 100644 --- a/extensions/pl_ecs_ext.c +++ b/extensions/pl_ecs_ext.c @@ -674,14 +674,18 @@ pl_ecs_add_component(plComponentLibrary* ptLibrary, plComponentType tType, plEnt pl_sb_add(sbComponents); ptManager->pComponents = sbComponents; sbComponents[uComponentIndex] = (plLightComponent){ - .tPosition = {0.0f, 0.0f, 0.0f}, - .tColor = {1.0f, 1.0f, 1.0f}, - .tDirection = {0.0f, -1.0f, 0.0f}, - .fIntensity = 1.0f, - .fRange = 10.0f, - .tType = PL_LIGHT_TYPE_DIRECTIONAL, - .tFlags = 0 + .tPosition = {0.0f, 0.0f, 0.0f}, + .tColor = {1.0f, 1.0f, 1.0f}, + .tDirection = {0.0f, -1.0f, 0.0f}, + .fIntensity = 1.0f, + .fRange = 10.0f, + .tType = PL_LIGHT_TYPE_DIRECTIONAL, + .uCascadeCount = 0, + .tFlags = 0, + .afCascadeSplits = {0} }; + for(uint32_t i = 0; i < PL_MAX_SHADOW_CASCADES; i++) + sbComponents[uComponentIndex].afCascadeSplits[i] = 8 * powf(10.0f, (float)i); return &sbComponents[uComponentIndex]; } diff --git a/extensions/pl_ecs_ext.h b/extensions/pl_ecs_ext.h index 245afa35..aa83b1d2 100644 --- a/extensions/pl_ecs_ext.h +++ b/extensions/pl_ecs_ext.h @@ -43,6 +43,8 @@ typedef struct _plCameraI plCameraI; #define PL_MAX_NAME_LENGTH 1024 #endif +#define PL_MAX_SHADOW_CASCADES 4 + //----------------------------------------------------------------------------- // [SECTION] includes //----------------------------------------------------------------------------- @@ -293,7 +295,7 @@ enum _plMeshFormatFlags enum _plLightFlags { PL_LIGHT_FLAG_NONE = 0, - PL_LIGHT_FLAG_HAS_CAST_SHADOW = 1 << 0, + PL_LIGHT_FLAG_CAST_SHADOW = 1 << 0, }; enum _plLightType @@ -384,6 +386,8 @@ typedef struct _plLightComponent float fRange; plVec3 tPosition; plVec3 tDirection; + float afCascadeSplits[PL_MAX_SHADOW_CASCADES]; + uint32_t uCascadeCount; } plLightComponent; typedef struct _plObjectComponent From 99f0a77470fb2b0e3583c9309eb5a0bd9ab3d724 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 11:09:28 -0500 Subject: [PATCH 21/23] build: remove gltf environment repo --- scripts/download_assets.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/download_assets.py b/scripts/download_assets.py index c745c61a..2e794cfc 100644 --- a/scripts/download_assets.py +++ b/scripts/download_assets.py @@ -28,5 +28,4 @@ def download_zip(url, filename, description): os.remove(filename) download_zip('https://github.com/KhronosGroup/glTF-Sample-Assets/archive/refs/heads/main.zip', '../data/gltf-sample-assets.zip', "sample gltf assets") -download_zip('https://github.com/KhronosGroup/glTF-Sample-Environments/archive/refs/heads/master.zip', '../data/gltf-sample-environments.zip', "sample environments") download_zip('https://github.com/PilotLightTech/pilotlight-assets/archive/refs/heads/master.zip', '../data/pilotlight-assets.zip', "test assets") \ No newline at end of file From e77cfa63dbefba68eeec7f1c11d510fa9c6658f9 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 11:09:59 -0500 Subject: [PATCH 22/23] feat: add support for directional light cascaded shadow mapping --- apps/app.c | 113 +++--- extensions/pl_ref_renderer_ext.c | 635 +++++++++++++++++++++++++++++-- extensions/pl_ref_renderer_ext.h | 4 + scripts/gen_build.py | 3 + shaders/glsl/lighting.frag | 94 ++++- shaders/glsl/lights.glsl | 9 + shaders/glsl/shadow.frag | 108 ++++++ shaders/glsl/shadow.vert | 120 ++++++ shaders/glsl/skinning.comp | 2 +- shaders/glsl/skybox.frag | 5 - shaders/glsl/skybox.vert | 7 +- shaders/glsl/transparent.frag | 95 ++++- shaders/metal/lighting.metal | 109 +++++- shaders/metal/shadow.metal | 283 ++++++++++++++ shaders/metal/transparent.metal | 111 +++++- 15 files changed, 1592 insertions(+), 106 deletions(-) create mode 100644 shaders/glsl/shadow.frag create mode 100644 shaders/glsl/shadow.vert create mode 100644 shaders/metal/shadow.metal diff --git a/apps/app.c b/apps/app.c index b4ace879..d5c90f51 100644 --- a/apps/app.c +++ b/apps/app.c @@ -41,8 +41,6 @@ Index of this file: // misc #include "helper_windows.h" -#define LIGHT_COUNT 100 - //----------------------------------------------------------------------------- // [SECTION] structs //----------------------------------------------------------------------------- @@ -77,7 +75,9 @@ typedef struct plAppData_t plEntity tCullCamera; plEntity tMainCamera; plEntity tSunlight; - plEntity atPointLight[LIGHT_COUNT]; + + // shadows + float fCascadeSplitLambda; // views uint32_t uSceneHandle0; @@ -161,6 +161,7 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData) memset(ptAppData, 0, sizeof(plAppData)); ptAppData->bFrustumCulling = true; + ptAppData->fCascadeSplitLambda = 0.95f; gptDataRegistry->set_data("profile", ptProfileCtx); gptDataRegistry->set_data("log", ptLogCtx); @@ -229,7 +230,7 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData) ptAppData->uSceneHandle0 = gptRenderer->create_scene(); // pl_begin_profile_sample("load environments"); - // gptRenderer->load_skybox_from_panorama(ptAppData->uSceneHandle0, "../data/glTF-Sample-Environments-main/field.jpg", 1024); + // gptRenderer->load_skybox_from_panorama(ptAppData->uSceneHandle0, "../data/pilotlight-assets-master/environments/helipad.hdr", 1024); // pl_end_profile_sample(); pl_begin_profile_sample("create scene views"); @@ -241,50 +242,32 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData) plComponentLibrary* ptMainComponentLibrary = gptRenderer->get_component_library(ptAppData->uSceneHandle0); - // 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); + ptAppData->tMainCamera = gptEcs->create_perspective_camera(ptMainComponentLibrary, "main camera", (plVec3){-9.6f, 2.096f, 0.86f}, PL_PI_3, ptIO->afMainViewportSize[0] / ptIO->afMainViewportSize[1], 0.1f, 30.0f); + gptCamera->set_pitch_yaw(gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tMainCamera), -0.245f, 1.816f); gptCamera->update(gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tMainCamera)); // create cull camera - ptAppData->tCullCamera = gptEcs->create_perspective_camera(ptMainComponentLibrary, "cull camera", (plVec3){0, 0, 5.0f}, PL_PI_3, ptIO->afMainViewportSize[0] / ptIO->afMainViewportSize[1], 0.1f, 106.0f); + ptAppData->tCullCamera = gptEcs->create_perspective_camera(ptMainComponentLibrary, "cull camera", (plVec3){0, 0, 5.0f}, PL_PI_3, ptIO->afMainViewportSize[0] / ptIO->afMainViewportSize[1], 0.1f, 50.0f); 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)); + // create lights + gptEcs->create_point_light(ptMainComponentLibrary, "light", (plVec3){6.0f, 4.0f, -3.0f}); + ptAppData->tSunlight = gptEcs->create_directional_light(ptMainComponentLibrary, "sunlight", (plVec3){-0.375f, -1.0f, -0.085f}); + plLightComponent* ptLight = gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_LIGHT, ptAppData->tSunlight); + ptLight->uCascadeCount = 4; + ptLight->tFlags |= PL_LIGHT_FLAG_CAST_SHADOW; + // load models plModelLoaderData tLoaderData0 = {0}; pl_begin_profile_sample("load models 0"); - // 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); + // const plMat4 tTransform0 = pl_mat4_translate_xyz(0.0f, 1.0f, 0.0f); // 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); - - // for(uint32_t i = 0; i < 1; i++) - // gptModelLoader->load_gltf(ptMainComponentLibrary, "../data/oaktree.gltf", &atTransforms[i], &tLoaderData0); + gptModelLoader->load_gltf(ptMainComponentLibrary, "../data/glTF-Sample-Assets-main/Models/CesiumMan/glTF/CesiumMan.gltf", NULL, &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(); @@ -397,27 +380,6 @@ pl_app_update(plAppData* ptAppData) // handle input plComponentLibrary* ptMainComponentLibrary = gptRenderer->get_component_library(ptAppData->uSceneHandle0); - // 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* ptCullCamera = gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_CAMERA, ptAppData->tCullCamera); @@ -460,7 +422,8 @@ pl_app_update(plAppData* ptAppData) uint64_t ulValue2 = ulValue0 + 2; uint64_t ulValue3 = ulValue0 + 3; uint64_t ulValue4 = ulValue0 + 4; - ptAppData->aulNextTimelineValue[ptGraphics->uCurrentFrameIndex] = ulValue4; + uint64_t ulValue5 = ulValue0 + 5; + ptAppData->aulNextTimelineValue[ptGraphics->uCurrentFrameIndex] = ulValue5; // first set of work @@ -500,10 +463,30 @@ pl_app_update(plAppData* ptAppData) }; gptGfx->submit_command_buffer(ptGraphics, &tCommandBuffer, &tSubmitInfo00); + + + const plBeginCommandInfo tBeginInfo11 = { + .uWaitSemaphoreCount = 1, + .atWaitSempahores = {ptAppData->atSempahore[ptGraphics->uCurrentFrameIndex]}, + .auWaitSemaphoreValues = {ulValue2} + }; + tCommandBuffer = gptGfx->begin_command_recording(ptGraphics, &tBeginInfo11); + + gptRenderer->generate_cascaded_shadow_map(tCommandBuffer, ptAppData->uSceneHandle0, ptAppData->uViewHandle0, ptAppData->tMainCamera, ptAppData->tSunlight, ptAppData->fCascadeSplitLambda); + + gptGfx->end_command_recording(ptGraphics, &tCommandBuffer); + + const plSubmitInfo tSubmitInfo11 = { + .uSignalSemaphoreCount = 1, + .atSignalSempahores = {ptAppData->atSempahore[ptGraphics->uCurrentFrameIndex]}, + .auSignalSemaphoreValues = {ulValue3} + }; + gptGfx->submit_command_buffer(ptGraphics, &tCommandBuffer, &tSubmitInfo11); + plViewOptions tViewOptions = { .bShowAllBoundingBoxes = ptAppData->bDrawAllBoundingBoxes, .bShowVisibleBoundingBoxes = ptAppData->bDrawVisibleBoundingBoxes, - .bShowOrigin = false, + .bShowOrigin = true, .bCullStats = true, .ptViewCamera = ptCamera, .ptCullCamera = ptAppData->bFrustumCulling ? ptCamera : NULL @@ -512,13 +495,12 @@ pl_app_update(plAppData* ptAppData) if(ptAppData->bFrustumCulling && ptAppData->bFreezeCullCamera) tViewOptions.ptCullCamera = ptCullCamera; - // second set of work const plBeginCommandInfo tBeginInfo1 = { .uWaitSemaphoreCount = 1, .atWaitSempahores = {ptAppData->atSempahore[ptGraphics->uCurrentFrameIndex]}, - .auWaitSemaphoreValues = {ulValue2} + .auWaitSemaphoreValues = {ulValue3} }; tCommandBuffer = gptGfx->begin_command_recording(ptGraphics, &tBeginInfo1); gptRenderer->render_scene(tCommandBuffer, ptAppData->uSceneHandle0, ptAppData->uViewHandle0, tViewOptions); @@ -528,7 +510,7 @@ pl_app_update(plAppData* ptAppData) const plSubmitInfo tSubmitInfo1 = { .uSignalSemaphoreCount = 1, .atSignalSempahores = {ptAppData->atSempahore[ptGraphics->uCurrentFrameIndex]}, - .auSignalSemaphoreValues = {ulValue3} + .auSignalSemaphoreValues = {ulValue4} }; gptGfx->submit_command_buffer(ptGraphics, &tCommandBuffer, &tSubmitInfo1); @@ -537,7 +519,7 @@ pl_app_update(plAppData* ptAppData) const plBeginCommandInfo tBeginInfo2 = { .uWaitSemaphoreCount = 1, .atWaitSempahores = {ptAppData->atSempahore[ptGraphics->uCurrentFrameIndex]}, - .auWaitSemaphoreValues = {ulValue3}, + .auWaitSemaphoreValues = {ulValue4}, }; tCommandBuffer = gptGfx->begin_command_recording(ptGraphics, &tBeginInfo2); @@ -593,6 +575,13 @@ pl_app_update(plAppData* ptAppData) if(pl_button("resize")) ptAppData->bResize = true; pl_checkbox("Always Resize", &ptAppData->bAlwaysResize); + + plLightComponent* ptLight = gptEcs->get_component(ptMainComponentLibrary, PL_COMPONENT_TYPE_LIGHT, ptAppData->tSunlight); + pl_slider_float("split", &ptAppData->fCascadeSplitLambda, 0.0f, 1.0f); + pl_slider_float("x", &ptLight->tDirection.x, -1.0f, 1.0f); + pl_slider_float("y", &ptLight->tDirection.y, -1.0f, 1.0f); + pl_slider_float("z", &ptLight->tDirection.z, -1.0f, 1.0f); + pl_end_collapsing_header(); } @@ -647,7 +636,7 @@ pl_app_update(plAppData* ptAppData) const plSubmitInfo tSubmitInfo2 = { .uSignalSemaphoreCount = 1, .atSignalSempahores = {ptAppData->atSempahore[ptGraphics->uCurrentFrameIndex]}, - .auSignalSemaphoreValues = {ulValue4}, + .auSignalSemaphoreValues = {ulValue5}, }; gptGfx->end_command_recording(ptGraphics, &tCommandBuffer); if(!gptGfx->present(ptGraphics, &tCommandBuffer, &tSubmitInfo2)) diff --git a/extensions/pl_ref_renderer_ext.c b/extensions/pl_ref_renderer_ext.c index ba4eaa3f..2a3ed2ee 100644 --- a/extensions/pl_ref_renderer_ext.c +++ b/extensions/pl_ref_renderer_ext.c @@ -74,6 +74,7 @@ typedef struct _plDrawable { plEntity tEntity; plBindGroupHandle tMaterialBindGroup; + plBindGroupHandle tShadowMaterialBindGroup; uint32_t uDataOffset; uint32_t uVertexOffset; uint32_t uVertexCount; @@ -81,6 +82,7 @@ typedef struct _plDrawable uint32_t uIndexCount; uint32_t uMaterialIndex; plShaderHandle tShader; + plShaderHandle tShadowShader; uint32_t uSkinIndex; bool bCulled; } plDrawable; @@ -145,8 +147,18 @@ typedef struct _plGPULight plVec3 tColor; float fRange; + + int iShadowIndex; + int iCascadeCount; + int _unused[2]; } plGPULight; +typedef struct _plGPULightShadowData +{ + plVec4 cascadeSplits; + plMat4 cascadeViewProjMat[4]; +} plGPULightShadowData; + typedef struct _BindGroup_0 { plVec4 tCameraPos; @@ -164,6 +176,17 @@ typedef struct _DynamicData plMat4 tModel; } DynamicData; +typedef struct _plShadowData +{ + plVec2 tResolution; + plTextureHandle tDepthTexture[PL_FRAMES_IN_FLIGHT]; + plTextureHandle atDepthTextureViews[PL_MAX_SHADOW_CASCADES][PL_FRAMES_IN_FLIGHT]; + + plRenderPassHandle atOpaqueRenderPasses[PL_MAX_SHADOW_CASCADES]; + + plBufferHandle atCameraBuffers[PL_FRAMES_IN_FLIGHT]; +} plShadowData; + typedef struct _plRefView { // main renderpass @@ -195,6 +218,11 @@ typedef struct _plRefView // drawing api plDrawList3D t3DDrawList; plDrawList3D t3DSelectionDrawList; + + // shadows + plShadowData tShadowData; + plBufferHandle atLightShadowDataBuffer[PL_FRAMES_IN_FLIGHT]; + plGPULightShadowData* sbtLightShadowData; } plRefView; typedef struct _plRefScene @@ -259,8 +287,10 @@ typedef struct _plRefRendererData // main renderpass layout (used as a template for views) plRenderPassLayoutHandle tRenderPassLayout; + plRenderPassLayoutHandle tDepthRenderPassLayout; // shader templates (variants are made from these) + plShaderHandle tShadowShader; plShaderHandle tOpaqueShader; plShaderHandle tTransparentShader; plShaderHandle tSkyboxShader; @@ -282,6 +312,7 @@ typedef struct _plRefRendererData // default textures & samplers & bindgroups plSamplerHandle tDefaultSampler; + plSamplerHandle tShadowSampler; plSamplerHandle tEnvSampler; plTextureHandle tDummyTexture; plTextureHandle tDummyTextureCube; @@ -399,7 +430,7 @@ pl_refr_initialize(plWindow* ptWindow) // create staging buffer const plBufferDescription tStagingBufferDesc = { .tUsage = PL_BUFFER_USAGE_STAGING, - .uByteSize = 268435456 + .uByteSize = 268435456 * 2 }; for(uint32_t i = 0; i < PL_FRAMES_IN_FLIGHT; i++) gptData->tStagingBufferHandle[i] = pl__refr_create_staging_buffer(&tStagingBufferDesc, "staging", i); @@ -442,6 +473,17 @@ pl_refr_initialize(plWindow* ptWindow) }; gptData->tDefaultSampler = gptDevice->create_sampler(&ptGraphics->tDevice, &tSamplerDesc, "default sampler"); + const plSamplerDesc tShadowSamplerDesc = { + .tFilter = PL_FILTER_LINEAR, + .fMinMip = 0.0f, + .fMaxMip = 1.0f, + .fMaxAnisotropy = 1.0f, + .tVerticalWrap = PL_WRAP_MODE_CLAMP, + .tHorizontalWrap = PL_WRAP_MODE_CLAMP, + .tMipmapMode = PL_MIPMAP_MODE_NEAREST + }; + gptData->tShadowSampler = gptDevice->create_sampler(&ptGraphics->tDevice, &tShadowSamplerDesc, "shadow sampler"); + const plSamplerDesc tEnvSamplerDesc = { .tFilter = PL_FILTER_NEAREST, .fMinMip = 0.0f, @@ -484,6 +526,21 @@ pl_refr_initialize(plWindow* ptWindow) }; gptData->tRenderPassLayout = gptDevice->create_render_pass_layout(&gptData->tGraphics.tDevice, &tRenderPassLayoutDesc); + // create main render pass layout + const plRenderPassLayoutDescription tDepthRenderPassLayoutDesc = { + .atRenderTargets = { + { .tFormat = PL_FORMAT_D32_FLOAT }, // depth buffer + }, + .uSubpassCount = 1, + .atSubpasses = { + { + .uRenderTargetCount = 1, + .auRenderTargets = {0}, + } + } + }; + gptData->tDepthRenderPassLayout = gptDevice->create_render_pass_layout(&gptData->tGraphics.tDevice, &tDepthRenderPassLayoutDesc); + // create template shaders int aiConstantData[6] = {0, 0, 0, 0, 0, 1}; @@ -652,13 +709,18 @@ pl_refr_initialize(plWindow* ptWindow) } }, { - .uBufferBindingCount = 1, + .uBufferBindingCount = 2, .aBufferBindings = { - { - .tType = PL_BUFFER_BINDING_TYPE_UNIFORM, - .uSlot = 0, - .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL - } + { .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} + }, + .uTextureBindingCount = 1, + .atTextureBindings = { + {.uSlot = 2, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL, .tType = PL_TEXTURE_BINDING_TYPE_SAMPLED, .uDescriptorCount = 4}, + }, + .uSamplerBindingCount = 1, + .atSamplerBindings = { + {.uSlot = 3, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL} }, }, { @@ -739,6 +801,69 @@ pl_refr_initialize(plWindow* ptWindow) tOutlineShaderDescription.atConstants[i].tType = PL_DATA_TYPE_INT; } gptData->tOutlineShader = gptDevice->create_shader(&gptData->tGraphics.tDevice, &tOutlineShaderDescription); + + plShaderDescription tShadowShaderDescription = { + + #ifdef PL_METAL_BACKEND + .pcVertexShader = "../shaders/metal/shadow.metal", + .pcPixelShader = "../shaders/metal/shadow.metal", + #else + .pcVertexShader = "shadow.vert.spv", + .pcPixelShader = "shadow.frag.spv", + #endif + .tGraphicsState = { + .ulDepthWriteEnabled = 1, + .ulDepthMode = PL_COMPARE_MODE_LESS_OR_EQUAL, + .ulCullMode = PL_CULL_MODE_NONE, + .ulWireframe = 0, + .ulStencilMode = PL_COMPARE_MODE_ALWAYS, + .ulStencilRef = 0xff, + .ulStencilMask = 0xff, + .ulStencilOpFail = PL_STENCIL_OP_KEEP, + .ulStencilOpDepthFail = PL_STENCIL_OP_KEEP, + .ulStencilOpPass = PL_STENCIL_OP_KEEP + }, + .tVertexBufferBinding = { + .uByteStride = sizeof(float) * 3, + .atAttributes = { {.uByteOffset = 0, .tFormat = PL_FORMAT_R32G32B32_FLOAT}} + }, + .uConstantCount = 4, + .pTempConstantData = aiConstantData, + .atBlendStates = { + pl__get_blend_state(PL_BLEND_MODE_ALPHA) + }, + .uBlendStateCount = 1, + .tRenderPassLayout = gptData->tDepthRenderPassLayout, + .uSubpassIndex = 0, + .uBindGroupLayoutCount = 2, + .atBindGroupLayouts = { + { + .uBufferBindingCount = 3, + .aBufferBindings = { + { .uSlot = 0, .tType = PL_BUFFER_BINDING_TYPE_STORAGE, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL}, + { .uSlot = 1, .tType = PL_BUFFER_BINDING_TYPE_STORAGE, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL}, + { .uSlot = 2, .tType = PL_BUFFER_BINDING_TYPE_STORAGE, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL}, + }, + .uSamplerBindingCount = 1, + .atSamplerBindings = { + {.uSlot = 3, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL} + }, + }, + { + .uTextureBindingCount = 1, + .atTextureBindings = { + {.uSlot = 0, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL, .tType = PL_TEXTURE_BINDING_TYPE_SAMPLED, .uDescriptorCount = 1}, + } + } + } + }; + for(uint32_t i = 0; i < tShadowShaderDescription.uConstantCount; i++) + { + tShadowShaderDescription.atConstants[i].uID = i; + tShadowShaderDescription.atConstants[i].uOffset = i * sizeof(int); + tShadowShaderDescription.atConstants[i].tType = PL_DATA_TYPE_INT; + } + gptData->tShadowShader = gptDevice->create_shader(&gptData->tGraphics.tDevice, &tShadowShaderDescription); } static uint32_t @@ -785,6 +910,8 @@ pl_refr_create_view(uint32_t uSceneHandle, plVec2 tDimensions) plRefView* ptView = &ptScene->atViews[uViewHandle]; ptView->tTargetSize = tDimensions; + ptView->tShadowData.tResolution.x = 1024.0f * 4.0f; + ptView->tShadowData.tResolution.y = 1024.0f * 4.0f; // create offscreen per-frame resources const plTextureDesc tFinalTextureDesc = { @@ -817,11 +944,31 @@ pl_refr_create_view(uint32_t uSceneHandle, plVec2 tDimensions) .tInitialUsage = PL_TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT }; + const plTextureDesc tShadowDepthTextureDesc = { + .tDimensions = {ptView->tShadowData.tResolution.x, ptView->tShadowData.tResolution.y, 1}, + .tFormat = PL_FORMAT_D32_FLOAT, + .uLayers = 4, + .uMips = 1, + .tType = PL_TEXTURE_TYPE_2D_ARRAY, + .tUsage = PL_TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT | PL_TEXTURE_USAGE_SAMPLED, + .tInitialUsage = PL_TEXTURE_USAGE_SAMPLED + }; + const plBufferDescription atGlobalBuffersDesc = { .tUsage = PL_BUFFER_USAGE_UNIFORM | PL_BUFFER_USAGE_STAGING, .uByteSize = PL_DEVICE_ALLOCATION_BLOCK_SIZE }; + const plBufferDescription atCameraBuffersDesc = { + .tUsage = PL_BUFFER_USAGE_STORAGE | PL_BUFFER_USAGE_STAGING, + .uByteSize = 4096 + }; + + const plBufferDescription atLightShadowDataBufferDesc = { + .tUsage = PL_BUFFER_USAGE_STORAGE | PL_BUFFER_USAGE_STAGING, + .uByteSize = PL_DEVICE_ALLOCATION_BLOCK_SIZE + }; + const plBindGroupLayout tLightingBindGroupLayout = { .uTextureBindingCount = 6, .atTextureBindings = { @@ -836,6 +983,7 @@ pl_refr_create_view(uint32_t uSceneHandle, plVec2 tDimensions) // create offscreen render pass plRenderPassAttachments atAttachmentSets[PL_FRAMES_IN_FLIGHT] = {0}; + plRenderPassAttachments atShadowAttachmentSets[PL_MAX_SHADOW_CASCADES][PL_FRAMES_IN_FLIGHT] = {0}; for(uint32_t i = 0; i < PL_FRAMES_IN_FLIGHT; i++) { @@ -847,13 +995,13 @@ pl_refr_create_view(uint32_t uSceneHandle, plVec2 tDimensions) ptView->tEmissiveTexture[i] = pl__refr_create_texture(&tAttachmentTextureDesc, "emissive original", i); ptView->tAOMetalRoughnessTexture[i] = pl__refr_create_texture(&tAttachmentTextureDesc, "metalroughness original", i); ptView->tDepthTexture[i] = pl__refr_create_texture(&tDepthTextureDesc, "offscreen depth original", i); - + // texture IDs ptView->tFinalTextureID[i] = gptGfx->get_ui_texture_handle(ptGraphics, ptView->tFinalTexture[i], gptData->tDefaultSampler); // buffers ptView->atGlobalBuffers[i] = pl__refr_create_staging_buffer(&atGlobalBuffersDesc, "global", i); - + // lighting bind group plTempAllocator tTempAllocator = {0}; ptView->tLightingBindGroup[i] = gptDevice->create_bind_group(&ptGraphics->tDevice, &tLightingBindGroupLayout, pl_temp_allocator_sprintf(&tTempAllocator, "lighting bind group%u", i)); @@ -905,6 +1053,27 @@ pl_refr_create_view(uint32_t uSceneHandle, plVec2 tDimensions) atAttachmentSets[i].atViewAttachments[4] = ptView->tPositionTexture[i]; atAttachmentSets[i].atViewAttachments[5] = ptView->tEmissiveTexture[i]; atAttachmentSets[i].atViewAttachments[6] = ptView->tAOMetalRoughnessTexture[i]; + + + ptView->atLightShadowDataBuffer[i] = pl__refr_create_staging_buffer(&atLightShadowDataBufferDesc, "shadow", i); + ptView->tShadowData.atCameraBuffers[i] = pl__refr_create_staging_buffer(&atCameraBuffersDesc, "shadow buffer", i); + ptView->tShadowData.tDepthTexture[i] = pl__refr_create_texture(&tShadowDepthTextureDesc, "shadow map", i); + + plTextureViewDesc tShadowDepthView = { + .tFormat = PL_FORMAT_D32_FLOAT, + .uBaseMip = 0, + .uMips = 1, + .uBaseLayer = 0, + .uLayerCount = 1, + .tTexture = ptView->tShadowData.tDepthTexture[i] + }; + for(uint32_t j = 0; j < 4; j++) + { + // atDepthTextureViews + tShadowDepthView.uBaseLayer = j; + (ptView->tShadowData.atDepthTextureViews[j])[i] = gptDevice->create_texture_view(&ptGraphics->tDevice, &tShadowDepthView, "shadow view"); + (atShadowAttachmentSets[j])[i].atViewAttachments[0] = (ptView->tShadowData.atDepthTextureViews[j])[i]; + } } const plRenderPassDescription tRenderPassDesc = { @@ -998,6 +1167,25 @@ pl_refr_create_view(uint32_t uSceneHandle, plVec2 tDimensions) pl_sb_push(ptScene->sbtVertexDataBuffer, ((plVec4){ 1.0f, 1.0f})); pl_sb_push(ptScene->sbtVertexDataBuffer, ((plVec4){ 1.0f, 0.0f})); + const plRenderPassDescription tDepthRenderPassDesc = { + .tLayout = gptData->tDepthRenderPassLayout, + .tDepthTarget = { + .tLoadOp = PL_LOAD_OP_CLEAR, + .tStoreOp = PL_STORE_OP_STORE, + .tStencilLoadOp = PL_LOAD_OP_CLEAR, + .tStencilStoreOp = PL_STORE_OP_DONT_CARE, + .tCurrentUsage = PL_TEXTURE_USAGE_SAMPLED, + .tNextUsage = PL_TEXTURE_USAGE_SAMPLED, + .fClearZ = 1.0f + }, + .tDimensions = {.x = ptView->tShadowData.tResolution.x, .y = ptView->tShadowData.tResolution.y} + }; + + for(uint32_t i = 0; i < 4; i++) + { + ptView->tShadowData.atOpaqueRenderPasses[i] = gptDevice->create_render_pass(&ptGraphics->tDevice, &tDepthRenderPassDesc, atShadowAttachmentSets[i]); + } + return uViewHandle; } @@ -1067,6 +1255,8 @@ pl_refr_resize_view(uint32_t uSceneHandle, uint32_t uViewHandle, plVec2 tDimensi gptDevice->queue_texture_for_deletion(ptDevice, ptView->tAlbedoTexture[i]); gptDevice->queue_texture_for_deletion(ptDevice, ptView->tNormalTexture[i]); gptDevice->queue_texture_for_deletion(ptDevice, ptView->tPositionTexture[i]); + gptDevice->queue_texture_for_deletion(ptDevice, ptView->tEmissiveTexture[i]); + gptDevice->queue_texture_for_deletion(ptDevice, ptView->tAOMetalRoughnessTexture[i]); gptDevice->queue_texture_for_deletion(ptDevice, ptView->tDepthTexture[i]); gptDevice->queue_bind_group_for_deletion(ptDevice, ptView->tLightingBindGroup[i]); @@ -1481,7 +1671,7 @@ pl_refr_load_skybox_from_panorama(uint32_t uSceneHandle, const char* pcPath, int pl_sb_push(ptScene->sbuIndexBuffer, uStartIndex + 4); // vertices (position) - const float fCubeSide = 0.5f; + const float fCubeSide = 1.0f; pl_sb_push(ptScene->sbtVertexPosBuffer, ((plVec3){-fCubeSide, -fCubeSide, -fCubeSide})); pl_sb_push(ptScene->sbtVertexPosBuffer, ((plVec3){ fCubeSide, -fCubeSide, -fCubeSide})); pl_sb_push(ptScene->sbtVertexPosBuffer, ((plVec3){-fCubeSide, fCubeSide, -fCubeSide})); @@ -2275,6 +2465,44 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) }; (sbtDrawables[uDrawableBatchIndex])[i].tShader = pl__get_shader_variant(uSceneHandle, atTemplateShaders[uDrawableBatchIndex], &tVariant); + + if(uDrawableBatchIndex > 0) + { + const plShaderVariant tShadowVariant = { + .pTempConstantData = aiConstantData0, + .tGraphicsState = { + .ulDepthWriteEnabled = 1, + .ulDepthMode = PL_COMPARE_MODE_LESS_OR_EQUAL, + .ulCullMode = PL_CULL_MODE_NONE, + .ulWireframe = 0, + .ulStencilMode = PL_COMPARE_MODE_ALWAYS, + .ulStencilRef = 0xff, + .ulStencilMask = 0xff, + .ulStencilOpFail = PL_STENCIL_OP_KEEP, + .ulStencilOpDepthFail = PL_STENCIL_OP_KEEP, + .ulStencilOpPass = PL_STENCIL_OP_KEEP + } + }; + (sbtDrawables[uDrawableBatchIndex])[i].tShadowShader = pl__get_shader_variant(uSceneHandle, gptData->tShadowShader, &tShadowVariant); + + plBindGroupLayout tMaterialBindGroupLayout = { + .uTextureBindingCount = 1, + .atTextureBindings = { + {.uSlot = 0, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL, .tType = PL_TEXTURE_BINDING_TYPE_SAMPLED} + } + }; + (sbtDrawables[uDrawableBatchIndex])[i].tShadowMaterialBindGroup = gptDevice->create_bind_group(ptDevice, &tMaterialBindGroupLayout, "material bind group"); + + const plBindGroupUpdateTextureData tTextureData[] = + { + {.tTexture = pl__create_texture_helper(ptMaterial, PL_TEXTURE_SLOT_BASE_COLOR_MAP, true, 0), .uSlot = 0, .tType = PL_TEXTURE_BINDING_TYPE_SAMPLED}, + }; + const plBindGroupUpdateData tBGData1 = { + .uTextureCount = 1, + .atTextures = tTextureData + }; + gptDevice->update_bind_group(ptDevice, (sbtDrawables[uDrawableBatchIndex])[i].tShadowMaterialBindGroup, &tBGData1); + } } } @@ -2444,13 +2672,18 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) }, }, { - .uBufferBindingCount = 1, + .uBufferBindingCount = 2, .aBufferBindings = { - { - .tType = PL_BUFFER_BINDING_TYPE_UNIFORM, - .uSlot = 0, - .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL - } + { .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} + }, + .uTextureBindingCount = 1, + .atTextureBindings = { + {.uSlot = 2, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL, .tType = PL_TEXTURE_BINDING_TYPE_SAMPLED, .uDescriptorCount = 4}, + }, + .uSamplerBindingCount = 1, + .atSamplerBindings = { + {.uSlot = 3, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL} }, } } @@ -2602,6 +2835,316 @@ pl__refr_cull_job(uint32_t uJobIndex, void* pData) } } +static void +pl_refr_generate_cascaded_shadow_map(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint32_t uViewHandle, plEntity tCamera, plEntity tLight, float fCascadeSplitLambda) +{ + pl_begin_profile_sample(__FUNCTION__); + + // for convience + plGraphics* ptGraphics = &gptData->tGraphics; + plDevice* ptDevice = &ptGraphics->tDevice; + plDrawStream* ptStream = &gptData->tDrawStream; + plRefScene* ptScene = &gptData->sbtScenes[uSceneHandle]; + plRefView* ptView = &ptScene->atViews[uViewHandle]; + + plCameraComponent* ptSceneCamera = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_CAMERA, tCamera); + plLightComponent* ptLight = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_LIGHT, tLight); + + + if(!(ptLight->tFlags & PL_LIGHT_FLAG_CAST_SHADOW)) + { + pl_end_profile_sample(); + return; + } + pl_sb_reset(ptView->sbtLightShadowData); + pl_sb_add(ptView->sbtLightShadowData); + plGPULightShadowData* ptShadowData = &ptView->sbtLightShadowData[pl_sb_size(ptView->sbtLightShadowData) - 1]; + + const float fNearClip = ptSceneCamera->fNearZ; + const float fFarClip = ptSceneCamera->fFarZ; + const float fClipRange = fFarClip - fNearClip; + + const float fMinZ = fNearClip; + const float fMaxZ = fNearClip + fClipRange; + + const float fRange = fMaxZ - fMinZ; + const float fRatio = fMaxZ / fMinZ; + + BindGroup_0 atBindGroupBuffer[PL_MAX_SHADOW_CASCADES] = {0}; + float fLastSplitDist = 0.0; + float afLambdaCascadeSplits[PL_MAX_SHADOW_CASCADES] = {0}; + for(uint32_t uCascade = 0; uCascade < ptLight->uCascadeCount; uCascade++) + { + float fSplitDist = 0.0f; + if(fCascadeSplitLambda > 0.0f) + { + const float p = (uCascade + 1) / (float)ptLight->uCascadeCount; + const float fLog = fMinZ * powf(fRatio, p); + const float fUniform = fMinZ + fRange * p; + const float fD = fCascadeSplitLambda * (fLog - fUniform) + fUniform; + afLambdaCascadeSplits[uCascade] = (fD - fNearClip) / fClipRange; + fSplitDist = afLambdaCascadeSplits[uCascade]; + ptShadowData->cascadeSplits.d[uCascade] = (fNearClip + fSplitDist * fClipRange); + } + else + { + fSplitDist = ptLight->afCascadeSplits[uCascade] / fClipRange; + ptShadowData->cascadeSplits.d[uCascade] = ptLight->afCascadeSplits[uCascade]; + } + + plVec3 atCameraCorners[] = { + { -1.0f, 1.0f, 0.0f }, + { -1.0f, -1.0f, 0.0f }, + { 1.0f, -1.0f, 0.0f }, + { 1.0f, 1.0f, 0.0f }, + { -1.0f, 1.0f, 1.0f }, + { -1.0f, -1.0f, 1.0f }, + { 1.0f, -1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f }, + }; + plMat4 tCameraInversion = pl_mul_mat4(&ptSceneCamera->tProjMat, &ptSceneCamera->tViewMat); + tCameraInversion = pl_mat4_invert(&tCameraInversion); + for(uint32_t i = 0; i < 8; i++) + { + plVec4 tInvCorner = pl_mul_mat4_vec4(&tCameraInversion, (plVec4){.xyz = atCameraCorners[i], .w = 1.0f}); + atCameraCorners[i] = pl_div_vec3_scalarf(tInvCorner.xyz, tInvCorner.w); + } + + for(uint32_t i = 0; i < 4; i++) + { + const plVec3 tDist = pl_sub_vec3(atCameraCorners[i + 4], atCameraCorners[i]); + atCameraCorners[i + 4] = pl_add_vec3(atCameraCorners[i], pl_mul_vec3_scalarf(tDist, fSplitDist)); + atCameraCorners[i] = pl_add_vec3(atCameraCorners[i], pl_mul_vec3_scalarf(tDist, fLastSplitDist)); + } + + // get frustum center + plVec3 tFrustumCenter = {0}; + for(uint32_t i = 0; i < 8; i++) + tFrustumCenter = pl_add_vec3(tFrustumCenter, atCameraCorners[i]); + tFrustumCenter = pl_div_vec3_scalarf(tFrustumCenter, 8.0f); + + float fRadius = 0.0f; + for (uint32_t i = 0; i < 8; i++) + { + float fDistance = pl_length_vec3(pl_sub_vec3(atCameraCorners[i], tFrustumCenter)); + fRadius = pl_max(fRadius, fDistance); + } + fRadius = ceilf(fRadius * 16.0f) / 16.0f; + + plVec3 tDirection = ptLight->tDirection; + + tDirection = pl_norm_vec3(tDirection); + plVec3 tEye = pl_sub_vec3(tFrustumCenter, pl_mul_vec3_scalarf(tDirection, fRadius + 50.0f)); + + plCameraComponent tShadowCamera = { + .tType = PL_CAMERA_TYPE_ORTHOGRAPHIC + }; + gptCamera->look_at(&tShadowCamera, tEye, tFrustumCenter); + tShadowCamera.fWidth = fRadius * 2.0f; + tShadowCamera.fHeight = fRadius * 2.0f; + tShadowCamera.fNearZ = 0; + tShadowCamera.fFarZ = fRadius * 2.0f + 50.0f; + gptCamera->update(&tShadowCamera); + fLastSplitDist = fSplitDist; + + atBindGroupBuffer[uCascade].tCameraPos.xyz = tShadowCamera.tPos; + atBindGroupBuffer[uCascade].tCameraProjection = tShadowCamera.tProjMat; + atBindGroupBuffer[uCascade].tCameraView = tShadowCamera.tViewMat; + atBindGroupBuffer[uCascade].tCameraViewProjection = pl_mul_mat4(&tShadowCamera.tProjMat, &tShadowCamera.tViewMat); + ptShadowData->cascadeViewProjMat[uCascade] = atBindGroupBuffer[uCascade].tCameraViewProjection; + } + + char* pcBufferStart = ptGraphics->sbtBuffersCold[ptView->tShadowData.atCameraBuffers[ptGraphics->uCurrentFrameIndex].uIndex].tMemoryAllocation.pHostMapped; + memcpy(pcBufferStart, atBindGroupBuffer, sizeof(BindGroup_0) * ptLight->uCascadeCount); + + plBindGroupLayout tBindGroupLayout0 = { + .uBufferBindingCount = 3, + .aBufferBindings = { + { + .tType = PL_BUFFER_BINDING_TYPE_STORAGE, + .uSlot = 0, + .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL + }, + { + .tType = PL_BUFFER_BINDING_TYPE_STORAGE, + .uSlot = 1, + .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL + }, + { + .tType = PL_BUFFER_BINDING_TYPE_STORAGE, + .uSlot = 2, + .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL + }, + }, + .uSamplerBindingCount = 1, + .atSamplerBindings = { + {.uSlot = 3, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL} + }, + }; + plBindGroupHandle tGlobalBG = gptDevice->get_temporary_bind_group(ptDevice, &tBindGroupLayout0, "temporary global bind group"); + + const plBindGroupUpdateBufferData atBufferData[] = + { + { + .tBuffer = ptView->tShadowData.atCameraBuffers[ptGraphics->uCurrentFrameIndex], + .uSlot = 0, + .szBufferRange = sizeof(BindGroup_0) * ptLight->uCascadeCount + }, + { + .tBuffer = ptScene->tStorageBuffer, + .uSlot = 1, + .szBufferRange = sizeof(plVec4) * pl_sb_size(ptScene->sbtVertexDataBuffer) + }, + { + .tBuffer = ptScene->tMaterialDataBuffer, + .uSlot = 2, + .szBufferRange = sizeof(plGPUMaterial) * pl_sb_size(ptScene->sbtMaterialBuffer) + }, + }; + + plBindGroupUpdateSamplerData tSamplerData[] = { + { + .tSampler = gptData->tDefaultSampler, + .uSlot = 3 + } + }; + + plBindGroupUpdateData tBGData0 = { + .uBufferCount = 3, + .atBuffers = atBufferData, + .uSamplerCount = 1, + .atSamplerBindings = tSamplerData + }; + gptDevice->update_bind_group(&ptGraphics->tDevice, tGlobalBG, &tBGData0); + + + plBindGroupLayout tOpaqueBG1Layout = { + .uTextureBindingCount = 1, + .atTextureBindings = { + {.uSlot = 0, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL, .tType = PL_TEXTURE_BINDING_TYPE_SAMPLED, .uDescriptorCount = 1}, + } + }; + plBindGroupHandle tOpaqueBG1 = gptDevice->get_temporary_bind_group(ptDevice, &tOpaqueBG1Layout, "temporary opaque bind group"); + const plBindGroupUpdateTextureData tTextureData[] = { + { + .tTexture = gptData->tDummyTexture, + .uSlot = 0, + .tType = PL_TEXTURE_BINDING_TYPE_SAMPLED, + .uIndex = 0 + } + }; + + plBindGroupUpdateData tBGData1 = { + .uTextureCount = 1, + .atTextures = tTextureData + }; + gptDevice->update_bind_group(&ptGraphics->tDevice, tOpaqueBG1, &tBGData1); + + gptGfx->reset_draw_stream(ptStream); + + const uint32_t uOpaqueDrawableCount = pl_sb_size(ptScene->sbtOpaqueDrawables); + const uint32_t uTransparentDrawableCount = pl_sb_size(ptScene->sbtTransparentDrawables); + + const plVec2 tDimensions = ptGraphics->sbtRenderPassesCold[ptView->tShadowData.atOpaqueRenderPasses[0].uIndex].tDesc.tDimensions; + + plDrawArea tArea = { + .ptDrawStream = ptStream, + .tScissor = { + .uWidth = (uint32_t)tDimensions.x, + .uHeight = (uint32_t)tDimensions.y, + }, + .tViewport = { + .fWidth = tDimensions.x, + .fHeight = tDimensions.y, + .fMaxDepth = 1.0f + } + }; + + typedef struct _plShadowDynamicData + { + int iIndex; + int iDataOffset; + int iVertexOffset; + int iMaterialIndex; + plMat4 tModel; + } plShadowDynamicData; + + for(uint32_t uCascade = 0; uCascade < ptLight->uCascadeCount; uCascade++) + { + plRenderEncoder tEncoder = gptGfx->begin_render_pass(ptGraphics, &tCommandBuffer, ptView->tShadowData.atOpaqueRenderPasses[uCascade]); + + for(uint32_t i = 0; i < uOpaqueDrawableCount; i++) + { + const plDrawable tDrawable = ptScene->sbtOpaqueDrawables[i]; + plObjectComponent* ptObject = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_OBJECT, tDrawable.tEntity); + plTransformComponent* ptTransform = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_TRANSFORM, ptObject->tTransform); + + plDynamicBinding tDynamicBinding = gptDevice->allocate_dynamic_data(ptDevice, sizeof(plShadowDynamicData)); + + plShadowDynamicData* ptDynamicData = (plShadowDynamicData*)tDynamicBinding.pcData; + ptDynamicData->iDataOffset = tDrawable.uDataOffset; + ptDynamicData->iVertexOffset = tDrawable.uVertexOffset; + ptDynamicData->tModel = ptTransform->tWorld; + ptDynamicData->iMaterialIndex = tDrawable.uMaterialIndex; + ptDynamicData->iIndex = (int)uCascade; + + gptGfx->add_to_stream(ptStream, (plStreamDraw) + { + .uShaderVariant = gptData->tShadowShader.uIndex, + .uDynamicBuffer = tDynamicBinding.uBufferHandle, + .uVertexBuffer = ptScene->tVertexBuffer.uIndex, + .uIndexBuffer = tDrawable.uIndexCount == 0 ? UINT32_MAX : ptScene->tIndexBuffer.uIndex, + .uIndexOffset = tDrawable.uIndexOffset, + .uTriangleCount = tDrawable.uIndexCount == 0 ? tDrawable.uVertexCount / 3 : tDrawable.uIndexCount / 3, + .uBindGroup0 = tGlobalBG.uIndex, + .uBindGroup1 = tOpaqueBG1.uIndex, + .uBindGroup2 = UINT32_MAX, + .uDynamicBufferOffset = tDynamicBinding.uByteOffset, + .uInstanceStart = 0, + .uInstanceCount = 1 + }); + } + + for(uint32_t i = 0; i < uTransparentDrawableCount; i++) + { + const plDrawable tDrawable = ptScene->sbtTransparentDrawables[i]; + plObjectComponent* ptObject = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_OBJECT, tDrawable.tEntity); + plTransformComponent* ptTransform = gptECS->get_component(&ptScene->tComponentLibrary, PL_COMPONENT_TYPE_TRANSFORM, ptObject->tTransform); + + plDynamicBinding tDynamicBinding = gptDevice->allocate_dynamic_data(ptDevice, sizeof(plShadowDynamicData)); + + plShadowDynamicData* ptDynamicData = (plShadowDynamicData*)tDynamicBinding.pcData; + ptDynamicData->iDataOffset = tDrawable.uDataOffset; + ptDynamicData->iVertexOffset = tDrawable.uVertexOffset; + ptDynamicData->tModel = ptTransform->tWorld; + ptDynamicData->iMaterialIndex = tDrawable.uMaterialIndex; + ptDynamicData->iIndex = (int)uCascade; + + gptGfx->add_to_stream(ptStream, (plStreamDraw) + { + .uShaderVariant = tDrawable.tShadowShader.uIndex, + .uDynamicBuffer = tDynamicBinding.uBufferHandle, + .uVertexBuffer = ptScene->tVertexBuffer.uIndex, + .uIndexBuffer = tDrawable.uIndexCount == 0 ? UINT32_MAX : ptScene->tIndexBuffer.uIndex, + .uIndexOffset = tDrawable.uIndexOffset, + .uTriangleCount = tDrawable.uIndexCount == 0 ? tDrawable.uVertexCount / 3 : tDrawable.uIndexCount / 3, + .uBindGroup0 = tGlobalBG.uIndex, + .uBindGroup1 = tDrawable.tShadowMaterialBindGroup.uIndex, + .uBindGroup2 = UINT32_MAX, + .uDynamicBufferOffset = tDynamicBinding.uByteOffset, + .uInstanceStart = 0, + .uInstanceCount = 1 + }); + } + + gptGfx->draw_stream(&tEncoder, 1, &tArea); + gptGfx->reset_draw_stream(ptStream); + gptGfx->end_render_pass(&tEncoder); + } + + pl_end_profile_sample(); +} + static void pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint32_t uViewHandle, plViewOptions tOptions) { @@ -2856,10 +3399,14 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint gptGfx->next_subpass(&tEncoder); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~lights~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + plBuffer* ptShadowDataBuffer = gptDevice->get_buffer(ptDevice, ptView->atLightShadowDataBuffer[ptGraphics->uCurrentFrameIndex]); + memcpy(ptShadowDataBuffer->tMemoryAllocation.pHostMapped, ptView->sbtLightShadowData, sizeof(plGPULightShadowData) * pl_sb_size(ptView->sbtLightShadowData)); + const plLightComponent* sbtLights = ptScene->tComponentLibrary.tLightComponentManager.pComponents; pl_sb_reset(ptScene->sbtLightData); pl_sb_resize(ptScene->sbtLightData, pl_sb_size(sbtLights)); - + int iShadowIndex = 0; for(uint32_t i = 0; i < pl_sb_size(sbtLights); i++) { const plLightComponent* ptLight = &sbtLights[i]; @@ -2870,26 +3417,58 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint .iType = ptLight->tType, .tPosition = ptLight->tPosition, .tDirection = ptLight->tDirection, - .tColor = ptLight->tColor + .tColor = ptLight->tColor, + .iShadowIndex = ptLight->tFlags & PL_LIGHT_FLAG_CAST_SHADOW ? iShadowIndex++ : 0, + .iCascadeCount = (int)ptLight->uCascadeCount }; ptScene->sbtLightData[i] = tLight; } const plBindGroupLayout tLightBindGroupLayout2 = { - .uBufferBindingCount = 1, + .uBufferBindingCount = 2, .aBufferBindings = { - { .uSlot = 0, .tType = PL_BUFFER_BINDING_TYPE_UNIFORM, .tStages = PL_STAGE_PIXEL | PL_STAGE_VERTEX} - } + { .uSlot = 0, .tType = PL_BUFFER_BINDING_TYPE_UNIFORM, .tStages = PL_STAGE_PIXEL | PL_STAGE_VERTEX}, + { .uSlot = 1, .tType = PL_BUFFER_BINDING_TYPE_STORAGE, .tStages = PL_STAGE_PIXEL | PL_STAGE_VERTEX} + }, + .uTextureBindingCount = 1, + .atTextureBindings = { + {.uSlot = 2, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL, .tType = PL_TEXTURE_BINDING_TYPE_SAMPLED, .uDescriptorCount = 4}, + }, + .uSamplerBindingCount = 1, + .atSamplerBindings = { + {.uSlot = 3, .tStages = PL_STAGE_VERTEX | PL_STAGE_PIXEL} + }, }; plBindGroupHandle tLightBindGroup2 = gptDevice->get_temporary_bind_group(ptDevice, &tLightBindGroupLayout2, "light bind group 2"); const plBindGroupUpdateBufferData atLightBufferData[] = { - { .uSlot = 0, .tBuffer = ptScene->atLightBuffer[ptGraphics->uCurrentFrameIndex], .szBufferRange = sizeof(plGPULight) * pl_sb_size(ptScene->sbtLightData)} + { .uSlot = 0, .tBuffer = ptScene->atLightBuffer[ptGraphics->uCurrentFrameIndex], .szBufferRange = sizeof(plGPULight) * pl_sb_size(ptScene->sbtLightData)}, + { .uSlot = 1, .tBuffer = ptView->atLightShadowDataBuffer[ptGraphics->uCurrentFrameIndex], .szBufferRange = sizeof(plGPULightShadowData) * pl_sb_size(ptView->sbtLightShadowData)} }; + plBindGroupUpdateTextureData atBGTextureData[4] = {0}; + for(uint32_t i = 0; i < 4; i++) + { + atBGTextureData[i].tTexture = (ptView->tShadowData.atDepthTextureViews[i])[ptGraphics->uCurrentFrameIndex]; + atBGTextureData[i].uSlot = 2; + atBGTextureData[i].uIndex = i; + atBGTextureData[i].tType = PL_TEXTURE_BINDING_TYPE_SAMPLED; + } + + plBindGroupUpdateSamplerData tShadowSamplerData[] = { + { + .tSampler = gptData->tShadowSampler, + .uSlot = 3 + } + }; + plBindGroupUpdateData tBGData2 = { - .uBufferCount = 1, + .uBufferCount = 2, .atBuffers = atLightBufferData, + .uTextureCount = 4, + .atTextures = atBGTextureData, + .uSamplerCount = 1, + .atSamplerBindings = tShadowSamplerData }; gptDevice->update_bind_group(&ptGraphics->tDevice, tLightBindGroup2, &tBGData2); plBuffer* ptLightingBuffer = gptDevice->get_buffer(ptDevice, ptScene->atLightBuffer[ptGraphics->uCurrentFrameIndex]); @@ -3126,6 +3705,14 @@ pl_refr_render_scene(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint pl_end_profile_sample(); } +static plDrawList3D* +pl_refr_get_debug_drawlist(uint32_t uSceneHandle, uint32_t uViewHandle) +{ + plRefScene* ptScene = &gptData->sbtScenes[uSceneHandle]; + plRefView* ptView = &ptScene->atViews[uViewHandle]; + return &ptView->t3DDrawList; +} + static plTextureId pl_refr_get_view_texture_id(uint32_t uSceneHandle, uint32_t uViewHandle) { @@ -4193,6 +4780,8 @@ pl_load_ref_renderer_api(void) .render_scene = pl_refr_render_scene, .get_view_texture_id = pl_refr_get_view_texture_id, .resize_view = pl_refr_resize_view, + .get_debug_drawlist = pl_refr_get_debug_drawlist, + .generate_cascaded_shadow_map = pl_refr_generate_cascaded_shadow_map, }; return &tApi; } diff --git a/extensions/pl_ref_renderer_ext.h b/extensions/pl_ref_renderer_ext.h index a32910c3..ef5dacf3 100644 --- a/extensions/pl_ref_renderer_ext.h +++ b/extensions/pl_ref_renderer_ext.h @@ -84,11 +84,15 @@ typedef struct _plRefRendererI void (*update_skin_textures)(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle); void (*perform_skinning)(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle); void (*render_scene)(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint32_t uViewHandle, plViewOptions tOptions); + + + void (*generate_cascaded_shadow_map)(plCommandBuffer tCommandBuffer, uint32_t uSceneHandle, uint32_t uViewHandle, plEntity tCamera, plEntity tLight, float fCascadeSplitLambda); // misc void (*select_entities)(uint32_t uSceneHandle, uint32_t uCount, plEntity*); plComponentLibrary* (*get_component_library)(uint32_t uSceneHandle); plGraphics* (*get_graphics)(void); + plDrawList3D* (*get_debug_drawlist)(uint32_t uSceneHandle, uint32_t uViewHandle); } plRefRendererI; diff --git a/scripts/gen_build.py b/scripts/gen_build.py index eb39126a..cd9c5694 100644 --- a/scripts/gen_build.py +++ b/scripts/gen_build.py @@ -161,6 +161,8 @@ def add_plugin_to_metal_app(name, reloadable, objc = False, binary_name = None): "skinning.comp", "outline.vert", "outline.frag", + "shadow.vert", + "shadow.frag", ] metal_shaders = [ @@ -173,6 +175,7 @@ def add_plugin_to_metal_app(name, reloadable, objc = False, binary_name = None): "filter_environment.metal", "transparent.metal", "skinning.metal", + "shadow.metal", "outline.metal" ] diff --git a/shaders/glsl/lighting.frag b/shaders/glsl/lighting.frag index 194147c5..12cd1075 100644 --- a/shaders/glsl/lighting.frag +++ b/shaders/glsl/lighting.frag @@ -60,6 +60,14 @@ layout(set = 2, binding = 0) uniform _plLightInfo plLightData atData[iLightCount]; } tLightInfo; +layout(set = 2, binding = 1) readonly buffer plShadowData +{ + plLightShadowData atData[]; +} tShadowData; + +layout (set = 2, binding = 2) uniform texture2D shadowmap[4]; +layout(set = 2, binding = 3) uniform sampler tShadowSampler; + //----------------------------------------------------------------------------- // [SECTION] dynamic bind group //----------------------------------------------------------------------------- @@ -274,6 +282,46 @@ vec3 getIBLRadianceLambertian(vec3 n, vec3 v, float roughness, vec3 diffuseColor return (FmsEms + k_D) * irradiance; } +const mat4 biasMat = mat4( + 0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.5, 0.5, 0.0, 1.0 +); + +float textureProj(vec4 shadowCoord, vec2 offset, uint cascadeIndex) +{ + float shadow = 1.0; + float bias = 0.0005; + + if ( shadowCoord.z > -1.0 && shadowCoord.z < 1.0 ) { + float dist = texture(sampler2D(shadowmap[cascadeIndex], tShadowSampler), shadowCoord.st + offset).r; + if (shadowCoord.w > 0 && dist < shadowCoord.z - bias) { + shadow = 0.1; // ambient + } + } + return shadow; +} + +float filterPCF(vec4 sc, uint cascadeIndex) +{ + ivec2 texDim = textureSize(sampler2D(shadowmap[cascadeIndex], tShadowSampler), 0).xy; + float scale = 0.75; + float dx = scale * 1.0 / float(texDim.x); + float dy = scale * 1.0 / float(texDim.y); + + float shadowFactor = 0.0; + int count = 0; + int range = 1; + + for (int x = -range; x <= range; x++) { + for (int y = -range; y <= range; y++) { + shadowFactor += textureProj(sc, vec2(dx*x, dy*y), cascadeIndex); + count++; + } + } + return shadowFactor / count; +} void main() { @@ -322,6 +370,7 @@ void main() f_sheen = vec3(0.0); f_clearcoat = vec3(0.0); + uint cascadeIndex = 0; if(bool(iRenderingFlags & PL_RENDERING_FLAG_USE_PUNCTUAL)) { @@ -330,6 +379,29 @@ void main() plLightData tLightData = tLightInfo.atData[i]; vec3 pointToLight; + float shadow = 1.0; + + if(tLightData.iCascadeCount > 0) + { + plLightShadowData tShadowData = tShadowData.atData[tLightData.iShadowIndex]; + + // Get cascade index for the current fragment's view position + + vec4 inViewPos = tGlobalInfo.tCameraView * vec4(tPosition.xyz, 1.0); + for(uint j = 0; j < tLightData.iCascadeCount - 1; ++j) + { + if(inViewPos.z > tShadowData.cascadeSplits[j]) + { + cascadeIndex = j + 1; + } + } + + // Depth compare for shadowing + vec4 shadowCoord = (biasMat * tShadowData.cascadeViewProjMat[cascadeIndex]) * vec4(tPosition.xyz, 1.0); + shadow = 0; + shadow = textureProj(shadowCoord / shadowCoord.w, vec2(0.0), cascadeIndex); + // shadow = filterPCF(shadowCoord / shadowCoord.w, cascadeIndex); + } if(tLightData.iType != PL_LIGHT_TYPE_DIRECTIONAL) { @@ -351,8 +423,8 @@ void main() 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); + f_diffuse += shadow * intensity * NdotL * BRDF_lambertian(f0, f90, c_diff, specularWeight, VdotH); + f_specular += shadow * intensity * NdotL * BRDF_specularGGX(f0, f90, fAlphaRoughness, specularWeight, VdotH, NdotL, NdotV, NdotH); } } @@ -391,4 +463,22 @@ void main() color = color * (1.0 - clearcoatFactor * clearcoatFresnel) + clearcoat; outColor = vec4(linearTosRGB(color.rgb), tBaseColor.a); + + // if(gl_FragCoord.x < 600.0) + // { + // switch(cascadeIndex) { + // case 0 : + // outColor.rgb *= vec3(1.0f, 0.25f, 0.25f); + // break; + // case 1 : + // outColor.rgb *= vec3(0.25f, 1.0f, 0.25f); + // break; + // case 2 : + // outColor.rgb *= vec3(0.25f, 0.25f, 1.0f); + // break; + // case 3 : + // outColor.rgb *= vec3(1.0f, 1.0f, 0.25f); + // break; + // } + // } } \ No newline at end of file diff --git a/shaders/glsl/lights.glsl b/shaders/glsl/lights.glsl index f409129b..4c20a5f6 100644 --- a/shaders/glsl/lights.glsl +++ b/shaders/glsl/lights.glsl @@ -9,6 +9,15 @@ struct plLightData vec3 tColor; float fRange; + + int iShadowIndex; + int iCascadeCount; +}; + +struct plLightShadowData +{ + vec4 cascadeSplits; + mat4 cascadeViewProjMat[4]; }; float diff --git a/shaders/glsl/shadow.frag b/shaders/glsl/shadow.frag new file mode 100644 index 00000000..dd60ef93 --- /dev/null +++ b/shaders/glsl/shadow.frag @@ -0,0 +1,108 @@ +#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; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 0 +//----------------------------------------------------------------------------- + +struct plCameraInfo +{ + vec4 tCameraPos; + mat4 tCameraView; + mat4 tCameraProjection; + mat4 tCameraViewProjection; +}; + +layout(set = 0, binding = 0) readonly buffer _plGlobalInfo +{ + plCameraInfo atInfo[]; +} 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; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 0 +//----------------------------------------------------------------------------- + +layout(set = 1, binding = 0) uniform texture2D tBaseColorTexture; + +//----------------------------------------------------------------------------- +// [SECTION] dynamic bind group +//----------------------------------------------------------------------------- + +layout(std140, set = 2, binding = 0) uniform _plObjectInfo +{ + int iIndex; + int iDataOffset; + int iVertexOffset; + int iMaterialIndex; + mat4 tModel; +} tObjectInfo; + +//----------------------------------------------------------------------------- +// [SECTION] input & output +//----------------------------------------------------------------------------- + +// output +layout(location = 0) in struct plShaderIn { + vec2 tUV[8]; +} tShaderIn; + + +//----------------------------------------------------------------------------- +// [SECTION] helpers +//----------------------------------------------------------------------------- + +vec4 getBaseColor(vec4 u_ColorFactor, int iUVSet) +{ + vec4 baseColor = vec4(1); + + if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS)) + { + // baseColor = u_BaseColorFactor; + baseColor = u_ColorFactor; + } + + if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS) && bool(iTextureMappingFlags & PL_HAS_BASE_COLOR_MAP)) + { + baseColor *= texture(sampler2D(tBaseColorTexture, tDefaultSampler), tShaderIn.tUV[iUVSet]); + } + return baseColor; +} + +//----------------------------------------------------------------------------- +// [SECTION] entry +//----------------------------------------------------------------------------- + +void main() +{ + tMaterial material = tMaterialInfo.atMaterials[tObjectInfo.iMaterialIndex]; + vec4 tBaseColor = getBaseColor(material.u_BaseColorFactor, material.BaseColorUVSet); + + if(tBaseColor.a < material.u_AlphaCutoff) + { + discard; + } +} \ No newline at end of file diff --git a/shaders/glsl/shadow.vert b/shaders/glsl/shadow.vert new file mode 100644 index 00000000..87f57a8d --- /dev/null +++ b/shaders/glsl/shadow.vert @@ -0,0 +1,120 @@ +#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; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 0 +//----------------------------------------------------------------------------- + +struct plCameraInfo +{ + vec4 tCameraPos; + mat4 tCameraView; + mat4 tCameraProjection; + mat4 tCameraViewProjection; +}; + +layout(set = 0, binding = 0) readonly buffer _plGlobalInfo +{ + plCameraInfo atInfo[]; +} 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; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 0 +//----------------------------------------------------------------------------- + +layout(set = 1, binding = 0) uniform texture2D tBaseColorTexture; + +//----------------------------------------------------------------------------- +// [SECTION] dynamic bind group +//----------------------------------------------------------------------------- + +layout(std140, set = 2, binding = 0) uniform _plObjectInfo +{ + int iIndex; + 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 { + vec2 tUV[8]; +} tShaderIn; + +//----------------------------------------------------------------------------- +// [SECTION] entry +//----------------------------------------------------------------------------- + +void main() +{ + + vec4 inPosition = vec4(inPos, 1.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); + + 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)) { iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_NORMAL)) { iCurrentAttribute++;} + if(bool(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TANGENT)) { 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++;} + + vec4 pos = tObjectInfo.tModel * inPosition; + gl_Position = tGlobalInfo.atInfo[tObjectInfo.iIndex].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; +} \ No newline at end of file diff --git a/shaders/glsl/skinning.comp b/shaders/glsl/skinning.comp index 42857d0b..cebb3eff 100644 --- a/shaders/glsl/skinning.comp +++ b/shaders/glsl/skinning.comp @@ -19,7 +19,7 @@ layout(std140, set = 0, binding = 0) readonly buffer _tInputDataBuffer vec4 atVertexData[]; } tInputDataBuffer; -layout(std140, set = 0, binding = 1, scalar) buffer _tOutputPosBuffer +layout(scalar, set = 0, binding = 1) buffer _tOutputPosBuffer { vec3 atVertexData[]; } tOutputPosBuffer; diff --git a/shaders/glsl/skybox.frag b/shaders/glsl/skybox.frag index b0cb9ba6..dff8033f 100644 --- a/shaders/glsl/skybox.frag +++ b/shaders/glsl/skybox.frag @@ -16,10 +16,6 @@ layout(set = 0, binding = 0) uniform _plGlobalInfo layout(std140, set = 0, binding = 1) readonly buffer _tVertexBuffer{ vec4 atVertexData[]; } tVertexBuffer; 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 @@ -38,7 +34,6 @@ layout(set = 2, binding = 0) uniform _plObjectInfo { mat4 tModel;} tObjectInfo; //----------------------------------------------------------------------------- layout(location = 0) in struct plShaderOut { - vec3 tPosition; vec3 tWorldPosition; } tShaderIn; diff --git a/shaders/glsl/skybox.vert b/shaders/glsl/skybox.vert index 786bbdab..31b749a2 100644 --- a/shaders/glsl/skybox.vert +++ b/shaders/glsl/skybox.vert @@ -16,10 +16,6 @@ layout(set = 0, binding = 0) uniform _plGlobalInfo layout(std140, set = 0, binding = 1) readonly buffer _tVertexBuffer{ vec4 atVertexData[]; } tVertexBuffer; 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 @@ -44,7 +40,6 @@ layout(location = 0) in vec3 inPos; //----------------------------------------------------------------------------- layout(location = 0) out struct plShaderOut { - vec3 tPosition; vec3 tWorldPosition; } tShaderOut; @@ -57,6 +52,6 @@ main() { gl_Position = tGlobalInfo.tCameraProjection * tGlobalInfo.tCameraView * tObjectInfo.tModel * vec4(inPos, 1.0); gl_Position.w = gl_Position.z; - tShaderOut.tPosition = gl_Position.xyz; tShaderOut.tWorldPosition = inPos; + // tShaderOut.tWorldPosition.z = -inPos.z; } \ No newline at end of file diff --git a/shaders/glsl/transparent.frag b/shaders/glsl/transparent.frag index d189d1fd..abda1b83 100644 --- a/shaders/glsl/transparent.frag +++ b/shaders/glsl/transparent.frag @@ -54,6 +54,14 @@ layout(set = 1, binding = 0) uniform _plLightInfo plLightData atData[iLightCount]; } tLightInfo; +layout(set = 1, binding = 1) readonly buffer plShadowData +{ + plLightShadowData atData[]; +} tShadowData; + +layout (set = 1, binding = 2) uniform texture2D shadowmap[4]; +layout(set = 1, binding = 3) uniform sampler tShadowSampler; + //----------------------------------------------------------------------------- // [SECTION] bind group 2 //----------------------------------------------------------------------------- @@ -428,6 +436,47 @@ vec3 getIBLRadianceLambertian(vec3 n, vec3 v, float roughness, vec3 diffuseColor return (FmsEms + k_D) * irradiance; } +const mat4 biasMat = mat4( + 0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.5, 0.5, 0.0, 1.0 +); + +float textureProj(vec4 shadowCoord, vec2 offset, uint cascadeIndex) +{ + float shadow = 1.0; + float bias = 0.0005; + + if ( shadowCoord.z > -1.0 && shadowCoord.z < 1.0 ) { + float dist = texture(sampler2D(shadowmap[cascadeIndex], tShadowSampler), shadowCoord.st + offset).r; + if (shadowCoord.w > 0 && dist < shadowCoord.z - bias) { + shadow = 0.1; // ambient + } + } + return shadow; +} + +float filterPCF(vec4 sc, uint cascadeIndex) +{ + ivec2 texDim = textureSize(sampler2D(shadowmap[cascadeIndex], tShadowSampler), 0).xy; + float scale = 0.75; + float dx = scale * 1.0 / float(texDim.x); + float dy = scale * 1.0 / float(texDim.y); + + float shadowFactor = 0.0; + int count = 0; + int range = 1; + + for (int x = -range; x <= range; x++) { + for (int y = -range; y <= range; y++) { + shadowFactor += textureProj(sc, vec2(dx*x, dy*y), cascadeIndex); + count++; + } + } + return shadowFactor / count; +} + //----------------------------------------------------------------------------- // [SECTION] entry //----------------------------------------------------------------------------- @@ -522,6 +571,7 @@ void main() f_sheen = vec3(0.0); f_clearcoat = vec3(0.0); + uint cascadeIndex = 0; if(bool(iRenderingFlags & PL_RENDERING_FLAG_USE_PUNCTUAL)) { for(int i = 0; i < iLightCount; i++) @@ -529,6 +579,29 @@ void main() plLightData tLightData = tLightInfo.atData[i]; vec3 pointToLight; + float shadow = 1.0; + + if(tLightData.iCascadeCount > 0) + { + plLightShadowData tShadowData = tShadowData.atData[tLightData.iShadowIndex]; + + // Get cascade index for the current fragment's view position + + vec4 inViewPos = tGlobalInfo.tCameraView * vec4(tShaderIn.tPosition.xyz, 1.0); + for(uint j = 0; j < tLightData.iCascadeCount - 1; ++j) + { + if(inViewPos.z > tShadowData.cascadeSplits[j]) + { + cascadeIndex = j + 1; + } + } + + // Depth compare for shadowing + vec4 shadowCoord = (biasMat * tShadowData.cascadeViewProjMat[cascadeIndex]) * vec4(tShaderIn.tPosition.xyz, 1.0); + shadow = 0; + shadow = textureProj(shadowCoord / shadowCoord.w, vec2(0.0), cascadeIndex); + // shadow = filterPCF(shadowCoord / shadowCoord.w, cascadeIndex); + } if(tLightData.iType != PL_LIGHT_TYPE_DIRECTIONAL) { @@ -550,8 +623,8 @@ void main() 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); + f_diffuse += shadow * intensity * NdotL * BRDF_lambertian(materialInfo.f0, materialInfo.f90, materialInfo.c_diff, materialInfo.specularWeight, VdotH); + f_specular += shadow * intensity * NdotL * BRDF_specularGGX(materialInfo.f0, materialInfo.f90, materialInfo.alphaRoughness, materialInfo.specularWeight, VdotH, NdotL, NdotV, NdotH); } } @@ -590,4 +663,22 @@ void main() color = color * (1.0 - clearcoatFactor * clearcoatFresnel) + clearcoat; outColor = vec4(linearTosRGB(color.rgb), tBaseColor.a); + + // if(gl_FragCoord.x < 600.0) + // { + // switch(cascadeIndex) { + // case 0 : + // outColor.rgb *= vec3(1.0f, 0.25f, 0.25f); + // break; + // case 1 : + // outColor.rgb *= vec3(0.25f, 1.0f, 0.25f); + // break; + // case 2 : + // outColor.rgb *= vec3(0.25f, 0.25f, 1.0f); + // break; + // case 3 : + // outColor.rgb *= vec3(1.0f, 1.0f, 0.25f); + // break; + // } + // } } \ No newline at end of file diff --git a/shaders/metal/lighting.metal b/shaders/metal/lighting.metal index 50b5440f..f7543fa9 100644 --- a/shaders/metal/lighting.metal +++ b/shaders/metal/lighting.metal @@ -140,11 +140,24 @@ struct plLightData packed_float3 tColor; float fRange; + + int iShadowIndex; + int iCascadeCount; + int padding[2]; +}; + +struct plLightShadowData +{ + float4 cascadeSplits; + float4x4 cascadeViewProjMat[4]; }; struct BindGroup_2 { device plLightData* atData; + device plLightShadowData* atShadowData; + texture2d_array shadowmap; + sampler tShadowSampler; }; //----------------------------------------------------------------------------- @@ -371,6 +384,56 @@ static float3 getLighIntensity(device const plLightData& light, thread const flo return rangeAttenuation * light.fIntensity * light.tColor; } +constant const float4x4 biasMat = float4x4( + 0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.5, 0.5, 0.0, 1.0 +); + +float textureProj(device const BindGroup_2& bg2, float4 shadowCoord, float2 offset, uint cascadeIndex) +{ + float shadow = 1.0; + float bias = 0.0005; + + if ( shadowCoord.z > -1.0 && shadowCoord.z < 1.0 ) + { + // float dist = bg2.shadowmap[cascadeIndex].sample(bg2.tShadowSampler, shadowCoord.xy + offset).r; + float dist = bg2.shadowmap.sample(bg2.tShadowSampler, shadowCoord.xy + offset, cascadeIndex).r; + if (shadowCoord.w > 0 && dist < shadowCoord.z - bias) + { + shadow = 0.1; // ambient + } + } + return shadow; +} + +float filterPCF(device const BindGroup_2& bg2, float4 sc, uint cascadeIndex) +{ + int2 texDim = int2(0, 0); + // texDim.x = bg2.shadowmap[cascadeIndex].get_width(); + // texDim.y = bg2.shadowmap[cascadeIndex].get_height(); + texDim.x = bg2.shadowmap.get_width(); + texDim.y = bg2.shadowmap.get_height(); + float scale = 0.75; + float dx = scale * 1.0 / float(texDim.x); + float dy = scale * 1.0 / float(texDim.y); + + float shadowFactor = 0.0; + int count = 0; + int range = 1; + + for (int x = -range; x <= range; x++) + { + for (int y = -range; y <= range; y++) + { + shadowFactor += textureProj(bg2, sc, float2(dx*x, dy*y), cascadeIndex); + count++; + } + } + return shadowFactor / count; +} + //----------------------------------------------------------------------------- // [SECTION] output //----------------------------------------------------------------------------- @@ -461,12 +524,36 @@ fragment float4 fragment_main( f_sheen = float3(0.0); f_clearcoat = float3(0.0); + uint cascadeIndex = 0; if(bool(iRenderingFlags & PL_RENDERING_FLAG_USE_PUNCTUAL)) { for(int i = 0; i < iLightCount; i++) { device const plLightData& tLightData = bg2.atData[i]; float3 pointToLight; + float shadow = 1.0; + + if(tLightData.iCascadeCount > 0) + { + plLightShadowData tShadowData = bg2.atShadowData[tLightData.iShadowIndex]; + + // Get cascade index for the current fragment's view position + + float4 inViewPos = bg0.data->tCameraView * float4(tPosition.xyz, 1.0); + for(uint j = 0; j < tLightData.iCascadeCount - 1; ++j) + { + if(inViewPos.z > tShadowData.cascadeSplits[j]) + { + cascadeIndex = j + 1; + } + } + + // Depth compare for shadowing + float4 shadowCoord = (biasMat * tShadowData.cascadeViewProjMat[cascadeIndex]) * float4(tPosition.xyz, 1.0); + shadow = 0; + shadow = textureProj(bg2, shadowCoord / shadowCoord.w, float2(0.0), cascadeIndex); + // shadow = filterPCF(shadowCoord / shadowCoord.w, cascadeIndex); + } if(tLightData.iType != PL_LIGHT_TYPE_DIRECTIONAL) { @@ -487,8 +574,8 @@ fragment float4 fragment_main( 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); + f_diffuse += shadow * intensity * NdotL * BRDF_lambertian(f0, f90, c_diff, specularWeight, VdotH); + f_specular += shadow * intensity * NdotL * BRDF_specularGGX(f0, f90, fAlphaRoughness, specularWeight, VdotH, NdotL, NdotV, NdotH); } } @@ -528,5 +615,23 @@ fragment float4 fragment_main( outColor = float4(linearTosRGB(color.rgb), tBaseColor.a); + // if(in.tPositionOut.x < 600.0) + // { + // switch(cascadeIndex) { + // case 0 : + // outColor.rgb *= float3(1.0f, 0.25f, 0.25f); + // break; + // case 1 : + // outColor.rgb *= float3(0.25f, 1.0f, 0.25f); + // break; + // case 2 : + // outColor.rgb *= float3(0.25f, 0.25f, 1.0f); + // break; + // case 3 : + // outColor.rgb *= float3(1.0f, 1.0f, 0.25f); + // break; + // } + // } + return outColor; } \ No newline at end of file diff --git a/shaders/metal/shadow.metal b/shaders/metal/shadow.metal new file mode 100644 index 00000000..5e877ee3 --- /dev/null +++ b/shaders/metal/shadow.metal @@ -0,0 +1,283 @@ +#include +#include + +using namespace metal; + +//----------------------------------------------------------------------------- +// [SECTION] specialization constants +//----------------------------------------------------------------------------- + +constant int iMeshVariantFlags [[ function_constant(0) ]]; +constant int iDataStride [[ function_constant(1) ]]; +constant int iTextureMappingFlags [[ function_constant(2) ]]; +constant int iMaterialFlags [[ function_constant(3) ]]; + +//----------------------------------------------------------------------------- +// [SECTION] defines & structs +//----------------------------------------------------------------------------- + +constant const float GAMMA = 2.2; +constant const float INV_GAMMA = 1.0 / GAMMA; + +// iMeshVariantFlags +#define PL_MESH_FORMAT_FLAG_NONE 0 +#define PL_MESH_FORMAT_FLAG_HAS_POSITION 1 << 0 +#define PL_MESH_FORMAT_FLAG_HAS_NORMAL 1 << 1 +#define PL_MESH_FORMAT_FLAG_HAS_TANGENT 1 << 2 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0 1 << 3 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1 1 << 4 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2 1 << 5 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3 1 << 6 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4 1 << 7 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5 1 << 8 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6 1 << 9 +#define PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7 1 << 10 +#define PL_MESH_FORMAT_FLAG_HAS_COLOR_0 1 << 11 +#define PL_MESH_FORMAT_FLAG_HAS_COLOR_1 1 << 12 +#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_0 1 << 13 +#define PL_MESH_FORMAT_FLAG_HAS_JOINTS_1 1 << 14 +#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_0 1 << 15 +#define PL_MESH_FORMAT_FLAG_HAS_WEIGHTS_1 1 << 16 + +// iTextureMappingFlags +#define PL_HAS_BASE_COLOR_MAP 1 << 0 +#define PL_HAS_NORMAL_MAP 1 << 1 +#define PL_HAS_EMISSIVE_MAP 1 << 2 +#define PL_HAS_OCCLUSION_MAP 1 << 3 +#define PL_HAS_METALLIC_ROUGHNESS_MAP 1 << 4 + +// iMaterialFlags +#define PL_MATERIAL_METALLICROUGHNESS 1 << 0 + +// iRenderingFlags +#define PL_RENDERING_FLAG_USE_PUNCTUAL 1 << 0 +#define PL_RENDERING_FLAG_USE_IBL 1 << 1 + +struct tMaterial +{ + // Metallic Roughness + int u_MipCount; + float u_MetallicFactor; + float u_RoughnessFactor; + //-------------------------- ( 16 bytes ) + + float4 u_BaseColorFactor; + //-------------------------- ( 16 bytes ) + + // Clearcoat + float u_ClearcoatFactor; + float u_ClearcoatRoughnessFactor; + int _unused2[2]; + //-------------------------- ( 16 bytes ) + + // Specular + packed_float3 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 + packed_float3 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 +//----------------------------------------------------------------------------- + +struct BindGroupData_0 +{ + float4 tCameraPosition; + float4x4 tCameraView; + float4x4 tCameraProjection; + float4x4 tCameraViewProjection; +}; + +struct BindGroup_0 +{ + device BindGroupData_0 *data; + device float4 *atVertexData; + device tMaterial *atMaterials; + sampler tDefaultSampler; +}; + +//----------------------------------------------------------------------------- +// [SECTION] bind group 1 +//----------------------------------------------------------------------------- + +struct BindGroup_1 +{ + texture2d tBaseColorTexture; +}; + +//----------------------------------------------------------------------------- +// [SECTION] dynamic bind group +//----------------------------------------------------------------------------- + +struct DynamicData +{ + int iIndex; + int iDataOffset; + int iVertexOffset; + int iMaterialIndex; + float4x4 tModel; +}; + +//----------------------------------------------------------------------------- +// [SECTION] input +//----------------------------------------------------------------------------- + +struct VertexIn { + float3 tPosition [[attribute(0)]]; +}; + +//----------------------------------------------------------------------------- +// [SECTION] output +//----------------------------------------------------------------------------- + +struct VertexOut { + float4 tPositionOut [[position]]; + float2 tUV0; + float2 tUV1; + float2 tUV2; + float2 tUV3; + float2 tUV4; + float2 tUV5; + float2 tUV6; + float2 tUV7; +}; + +//----------------------------------------------------------------------------- +// [SECTION] helpers +//----------------------------------------------------------------------------- + +float4 +getBaseColor(device const BindGroup_0& bg0, device const BindGroup_1& bg1, float4 u_ColorFactor, VertexOut tShaderIn, float2 UV) +{ + float4 baseColor = float4(1); + + if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS)) + { + baseColor = u_ColorFactor; + } + + if(bool(iMaterialFlags & PL_MATERIAL_METALLICROUGHNESS) && bool(iTextureMappingFlags & PL_HAS_BASE_COLOR_MAP)) + { + baseColor *= bg1.tBaseColorTexture.sample(bg0.tDefaultSampler, UV); + } + return baseColor; +} + +//----------------------------------------------------------------------------- +// [SECTION] entry +//----------------------------------------------------------------------------- + +vertex VertexOut vertex_main( + uint vertexID [[ vertex_id ]], + VertexIn in [[stage_in]], + device const BindGroup_0& bg0 [[ buffer(1) ]], + device const BindGroup_1& bg1 [[ buffer(2) ]], + device const DynamicData& tObjectInfo [[ buffer(3) ]] + ) +{ + + VertexOut tShaderOut; + float4 inPosition = float4(in.tPosition, 1.0); + float2 inTexCoord0 = float2(0.0, 0.0); + float2 inTexCoord1 = float2(0.0, 0.0); + float2 inTexCoord2 = float2(0.0, 0.0); + float2 inTexCoord3 = float2(0.0, 0.0); + float2 inTexCoord4 = float2(0.0, 0.0); + float2 inTexCoord5 = float2(0.0, 0.0); + float2 inTexCoord6 = float2(0.0, 0.0); + float2 inTexCoord7 = float2(0.0, 0.0); + int iCurrentAttribute = 0; + + const uint iVertexDataOffset = iDataStride * (vertexID - tObjectInfo.iVertexOffset) + tObjectInfo.iDataOffset; + + + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_POSITION) { iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_NORMAL) { iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TANGENT) { iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_0){ inTexCoord0 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_1){ inTexCoord1 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_2){ inTexCoord2 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_3){ inTexCoord3 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_4){ inTexCoord4 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_5){ inTexCoord5 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_6){ inTexCoord6 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + if(iMeshVariantFlags & PL_MESH_FORMAT_FLAG_HAS_TEXCOORD_7){ inTexCoord7 = bg0.atVertexData[iVertexDataOffset + iCurrentAttribute].xy; iCurrentAttribute++;} + + float4 pos = tObjectInfo.tModel * inPosition; + tShaderOut.tPositionOut = bg0.data[tObjectInfo.iIndex].tCameraViewProjection * pos; + tShaderOut.tUV0 = inTexCoord0; + tShaderOut.tUV1 = inTexCoord1; + tShaderOut.tUV2 = inTexCoord2; + tShaderOut.tUV3 = inTexCoord3; + tShaderOut.tUV4 = inTexCoord4; + tShaderOut.tUV5 = inTexCoord5; + tShaderOut.tUV6 = inTexCoord6; + tShaderOut.tUV7 = inTexCoord7; + tShaderOut.tPositionOut.y = tShaderOut.tPositionOut.y * -1.0; + return tShaderOut; +} + +fragment void 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) ]] + ) +{ + const float2 tUV[8] = { + in.tUV0, + in.tUV1, + in.tUV2, + in.tUV3, + in.tUV4, + in.tUV5, + in.tUV6, + in.tUV7 + }; + tMaterial material = bg0.atMaterials[tObjectInfo.iMaterialIndex]; + float4 tBaseColor = getBaseColor(bg0, bg1, material.u_BaseColorFactor, in, tUV[material.BaseColorUVSet]); + if(tBaseColor.a < material.u_AlphaCutoff) + { + discard_fragment(); + } +} \ No newline at end of file diff --git a/shaders/metal/transparent.metal b/shaders/metal/transparent.metal index 3c846f09..3ea7398d 100644 --- a/shaders/metal/transparent.metal +++ b/shaders/metal/transparent.metal @@ -204,11 +204,24 @@ struct plLightData packed_float3 tColor; float fRange; + + int iShadowIndex; + int iCascadeCount; + int padding[2]; +}; + +struct plLightShadowData +{ + float4 cascadeSplits; + float4x4 cascadeViewProjMat[4]; }; struct BindGroup_1 { device plLightData* atData; + device plLightShadowData* atShadowData; + texture2d_array shadowmap; + sampler tShadowSampler; }; //----------------------------------------------------------------------------- @@ -662,7 +675,6 @@ float getRangeAttenuation(float range, float distance) 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; @@ -676,6 +688,56 @@ static float3 getLighIntensity(device const plLightData& light, thread const flo return rangeAttenuation * light.fIntensity * light.tColor; } +constant const float4x4 biasMat = float4x4( + 0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.5, 0.5, 0.0, 1.0 +); + +float textureProj(device const BindGroup_1& bg2, float4 shadowCoord, float2 offset, uint cascadeIndex) +{ + float shadow = 1.0; + float bias = 0.0005; + + if ( shadowCoord.z > -1.0 && shadowCoord.z < 1.0 ) + { + // float dist = bg2.shadowmap[cascadeIndex].sample(bg2.tShadowSampler, shadowCoord.xy + offset).r; + float dist = bg2.shadowmap.sample(bg2.tShadowSampler, shadowCoord.xy + offset, cascadeIndex).r; + if (shadowCoord.w > 0 && dist < shadowCoord.z - bias) + { + shadow = 0.1; // ambient + } + } + return shadow; +} + +float filterPCF(device const BindGroup_1& bg2, float4 sc, uint cascadeIndex) +{ + int2 texDim = int2(0, 0); + // texDim.x = bg2.shadowmap[cascadeIndex].get_width(); + // texDim.y = bg2.shadowmap[cascadeIndex].get_height(); + texDim.x = bg2.shadowmap.get_width(); + texDim.y = bg2.shadowmap.get_height(); + float scale = 0.75; + float dx = scale * 1.0 / float(texDim.x); + float dy = scale * 1.0 / float(texDim.y); + + float shadowFactor = 0.0; + int count = 0; + int range = 1; + + for (int x = -range; x <= range; x++) + { + for (int y = -range; y <= range; y++) + { + shadowFactor += textureProj(bg2, sc, float2(dx*x, dy*y), cascadeIndex); + count++; + } + } + return shadowFactor / count; +} + struct plRenderTargets { float4 outColor [[ color(0) ]]; @@ -779,12 +841,36 @@ fragment plRenderTargets fragment_main( f_sheen = float3(0.0); f_clearcoat = float3(0.0); + uint cascadeIndex = 0; if(bool(iRenderingFlags & PL_RENDERING_FLAG_USE_PUNCTUAL)) { for(int i = 0; i < iLightCount; i++) { device const plLightData& tLightData = bg1.atData[i]; float3 pointToLight; + float shadow = 1.0; + + if(tLightData.iCascadeCount > 0) + { + plLightShadowData tShadowData = bg1.atShadowData[tLightData.iShadowIndex]; + + // Get cascade index for the current fragment's view position + + float4 inViewPos = bg0.data->tCameraView * float4(in.tPosition.xyz, 1.0); + for(uint j = 0; j < tLightData.iCascadeCount - 1; ++j) + { + if(inViewPos.z > tShadowData.cascadeSplits[j]) + { + cascadeIndex = j + 1; + } + } + + // Depth compare for shadowing + float4 shadowCoord = (biasMat * tShadowData.cascadeViewProjMat[cascadeIndex]) * float4(in.tPosition.xyz, 1.0); + shadow = 0; + shadow = textureProj(bg1, shadowCoord / shadowCoord.w, float2(0.0), cascadeIndex); + // shadow = filterPCF(shadowCoord / shadowCoord.w, cascadeIndex); + } if(tLightData.iType != PL_LIGHT_TYPE_DIRECTIONAL) { @@ -805,8 +891,8 @@ fragment plRenderTargets fragment_main( 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); + f_diffuse += shadow * intensity * NdotL * BRDF_lambertian(materialInfo.f0, materialInfo.f90, materialInfo.c_diff, materialInfo.specularWeight, VdotH); + f_specular += shadow * intensity * NdotL * BRDF_specularGGX(materialInfo.f0, materialInfo.f90, materialInfo.alphaRoughness, materialInfo.specularWeight, VdotH, NdotL, NdotV, NdotH); } } } @@ -846,6 +932,25 @@ fragment plRenderTargets fragment_main( plRenderTargets tMRT; tMRT.outColor.rgb = linearTosRGB(color); tMRT.outColor.a = tBaseColor.a; + + // if(in.tPositionOut.x < 600.0) + // { + // switch(cascadeIndex) { + // case 0 : + // tMRT.outColor.rgb *= float3(1.0f, 0.25f, 0.25f); + // break; + // case 1 : + // tMRT.outColor.rgb *= float3(0.25f, 1.0f, 0.25f); + // break; + // case 2 : + // tMRT.outColor.rgb *= float3(0.25f, 0.25f, 1.0f); + // break; + // case 3 : + // tMRT.outColor.rgb *= float3(1.0f, 1.0f, 0.25f); + // break; + // } + // } + return tMRT; } \ No newline at end of file From 33a4f5ff6c57e133830e3e8b45a7fc749998a908 Mon Sep 17 00:00:00 2001 From: jonathan hoffstadt Date: Tue, 14 May 2024 13:10:05 -0500 Subject: [PATCH 23/23] chore: add quick bubble sort for shaders --- extensions/pl_ref_renderer_ext.c | 36 ++++++++++++++++++++++++++++++++ extensions/pl_vulkan_ext.c | 8 +++---- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/extensions/pl_ref_renderer_ext.c b/extensions/pl_ref_renderer_ext.c index 2a3ed2ee..6f36f6a6 100644 --- a/extensions/pl_ref_renderer_ext.c +++ b/extensions/pl_ref_renderer_ext.c @@ -1339,7 +1339,9 @@ pl_refr_cleanup(void) plRefView* ptView = &ptScene->atViews[j]; pl_sb_free(ptView->sbtVisibleOpaqueDrawables); pl_sb_free(ptView->sbtVisibleTransparentDrawables); + pl_sb_free(ptView->sbtLightShadowData); } + pl_sb_free(ptScene->sbtLightData); pl_sb_free(ptScene->sbtVertexPosBuffer); pl_sb_free(ptScene->sbtVertexDataBuffer); pl_sb_free(ptScene->sbuIndexBuffer); @@ -2511,6 +2513,40 @@ pl_refr_finalize_scene(uint32_t uSceneHandle) pl_hm_free(&tMaterialBindGroupDict); pl_sb_free(sbtMaterialBindGroups); + pl_begin_profile_sample("shader sort"); + + for(uint32_t uDrawableBatchIndex = 0; uDrawableBatchIndex < 2; uDrawableBatchIndex++) + { + const uint32_t uDrawableCount = pl_sb_size(sbtDrawables[uDrawableBatchIndex]); + uint32_t i = 0; + uint32_t j = 0; + bool bSwapped = false; + if(uDrawableCount == 0) + continue; + for(i = 0; i < uDrawableCount - 1; i++) + { + bSwapped = false; + for (j = 0; j < uDrawableCount - i - 1; j++) + { + if ((sbtDrawables[uDrawableBatchIndex])[j].tShader.uIndex > (sbtDrawables[uDrawableBatchIndex])[j + 1].tShader.uIndex) + { + plDrawable tFirst = (sbtDrawables[uDrawableBatchIndex])[j]; + plDrawable tSecond = (sbtDrawables[uDrawableBatchIndex])[j + 1]; + (sbtDrawables[uDrawableBatchIndex])[j] = tSecond; + (sbtDrawables[uDrawableBatchIndex])[j + 1] = tFirst; + bSwapped = true; + } + } + + // If no two elements were swapped + // by inner loop, then break + if (bSwapped == false) + break; + } + } + + pl_end_profile_sample(); + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~GPU Buffers~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pl_begin_profile_sample("fill GPU buffers"); diff --git a/extensions/pl_vulkan_ext.c b/extensions/pl_vulkan_ext.c index d5e7ae84..29c0bb5c 100644 --- a/extensions/pl_vulkan_ext.c +++ b/extensions/pl_vulkan_ext.c @@ -2894,26 +2894,26 @@ typedef struct _plBindGroupManagerData uint32_t auOffsets[2]; } plBindGroupManagerData; -static void pl__set_bind_group_count(plBindGroupManagerData* ptData, uint32_t uCount) +static inline void pl__set_bind_group_count(plBindGroupManagerData* ptData, uint32_t uCount) { ptData->uCount = uCount + 1; ptData->uFirstSlot = 0; } -static void pl__set_bind_group(plBindGroupManagerData* ptData, uint32_t uIndex, VkDescriptorSet tSet) +static inline void pl__set_bind_group(plBindGroupManagerData* ptData, uint32_t uIndex, VkDescriptorSet tSet) { ptData->uFirstSlot = pl_min(ptData->uFirstSlot, uIndex); ptData->auSlots[uIndex] = tSet; } -static void pl__set_dynamic_bind_group(plBindGroupManagerData* ptData, VkDescriptorSet tSet, uint32_t uOffset) +static inline void pl__set_dynamic_bind_group(plBindGroupManagerData* ptData, VkDescriptorSet tSet, uint32_t uOffset) { ptData->auOffsets[0] = uOffset; ptData->uFirstSlot = pl_min(ptData->uFirstSlot, ptData->uCount - 1); ptData->auSlots[ptData->uCount - 1] = tSet; } -static void pl__update_bindings(plBindGroupManagerData* ptData, VkCommandBuffer tCmdBuffer, VkPipelineLayout tLayout) +static inline void pl__update_bindings(plBindGroupManagerData* ptData, VkCommandBuffer tCmdBuffer, VkPipelineLayout tLayout) { VkDescriptorSet atSets[4] = {VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE}; for(uint32_t i = 0; i < ptData->uCount; i++)