diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index fac7fb3c2..37eeaf51b 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -390,6 +390,7 @@ void EditorComponent::Load() translator = new Translator; translator->enabled = false; + Translator::LoadShaders(); float screenW = (float)wiRenderer::GetDevice()->GetScreenWidth(); @@ -849,6 +850,8 @@ void EditorComponent::Load() wiRenderer::ReloadShaders(); + Translator::LoadShaders(); + }); GetGUI().AddWidget(shaderButton); @@ -1417,15 +1420,6 @@ void EditorComponent::Update(float dt) assert(picked->entity != INVALID_ENTITY); - if (picked->subsetIndex >= 0) - { - const ObjectComponent* object = scene.objects.GetComponent(picked->entity); - meshWnd->SetEntity(object->meshID); - - const MeshComponent* mesh = scene.meshes.GetComponent(object->meshID); - materialWnd->SetEntity(mesh->subsets[picked->subsetIndex].materialID); - } - objectWnd->SetEntity(picked->entity); emitterWnd->SetEntity(picked->entity); hairWnd->SetEntity(picked->entity); @@ -1434,7 +1428,20 @@ void EditorComponent::Update(float dt) envProbeWnd->SetEntity(picked->entity); forceFieldWnd->SetEntity(picked->entity); cameraWnd->SetEntity(picked->entity); - materialWnd->SetEntity(picked->entity); + + if (picked->subsetIndex >= 0) + { + const ObjectComponent* object = scene.objects.GetComponent(picked->entity); + meshWnd->SetEntity(object->meshID); + + const MeshComponent* mesh = scene.meshes.GetComponent(object->meshID); + materialWnd->SetEntity(mesh->subsets[picked->subsetIndex].materialID); + } + else + { + materialWnd->SetEntity(picked->entity); + } + } //// Delete diff --git a/Editor/HairParticleWindow.cpp b/Editor/HairParticleWindow.cpp index 6d07bbf21..3ede291cf 100644 --- a/Editor/HairParticleWindow.cpp +++ b/Editor/HairParticleWindow.cpp @@ -69,9 +69,37 @@ HairParticleWindow::HairParticleWindow(wiGUI* gui) : GUI(gui) lengthSlider->SetTooltip("Set hair strand length"); hairWindow->AddWidget(lengthSlider); + stiffnessSlider = new wiSlider(0, 20, 5, 100000, "Particle Stiffness: "); + stiffnessSlider->SetSize(XMFLOAT2(360, 30)); + stiffnessSlider->SetPos(XMFLOAT2(x, y += step * 2)); + stiffnessSlider->OnSlide([&](wiEventArgs args) { + auto hair = GetHair(); + if (hair != nullptr) + { + hair->stiffness = args.fValue; + } + }); + stiffnessSlider->SetEnabled(false); + stiffnessSlider->SetTooltip("Set hair strand stiffness, how much it tries to get back to rest position."); + hairWindow->AddWidget(stiffnessSlider); + + randomnessSlider = new wiSlider(0, 1, 0.2f, 100000, "Particle Randomness: "); + randomnessSlider->SetSize(XMFLOAT2(360, 30)); + randomnessSlider->SetPos(XMFLOAT2(x, y += step)); + randomnessSlider->OnSlide([&](wiEventArgs args) { + auto hair = GetHair(); + if (hair != nullptr) + { + hair->randomness = args.fValue; + } + }); + randomnessSlider->SetEnabled(false); + randomnessSlider->SetTooltip("Set hair length randomization factor"); + hairWindow->AddWidget(randomnessSlider); + countSlider = new wiSlider(0, 100000, 1000, 100000, "Particle Count: "); countSlider->SetSize(XMFLOAT2(360, 30)); - countSlider->SetPos(XMFLOAT2(x, y += step * 2)); + countSlider->SetPos(XMFLOAT2(x, y += step)); countSlider->OnSlide([&](wiEventArgs args) { auto hair = GetHair(); if (hair != nullptr) @@ -130,6 +158,8 @@ void HairParticleWindow::SetEntity(Entity entity) if (hair != nullptr) { lengthSlider->SetValue(hair->length); + stiffnessSlider->SetValue(hair->stiffness); + randomnessSlider->SetValue(hair->randomness); countSlider->SetValue((float)hair->particleCount); } else diff --git a/Editor/HairParticleWindow.h b/Editor/HairParticleWindow.h index 20d108db6..1f1b42bc6 100644 --- a/Editor/HairParticleWindow.h +++ b/Editor/HairParticleWindow.h @@ -31,6 +31,8 @@ public: wiButton* addButton; wiComboBox* meshComboBox; wiSlider* lengthSlider; + wiSlider* stiffnessSlider; + wiSlider* randomnessSlider; wiSlider* countSlider; wiButton* generateButton; diff --git a/Editor/Translator.cpp b/Editor/Translator.cpp index 1afd79136..f0424745c 100644 --- a/Editor/Translator.cpp +++ b/Editor/Translator.cpp @@ -18,6 +18,43 @@ int vertexCount_Axis = 0; int vertexCount_Plane = 0; int vertexCount_Origin = 0; +void Translator::LoadShaders() +{ + GraphicsDevice* device = wiRenderer::GetDevice(); + + SAFE_DELETE(pso_solidpart); + SAFE_DELETE(pso_wirepart); + + { + GraphicsPSODesc desc; + + desc.vs = wiRenderer::vertexShaders[VSTYPE_LINE]; + desc.ps = wiRenderer::pixelShaders[PSTYPE_LINE]; + desc.il = wiRenderer::vertexLayouts[VLTYPE_LINE]; + desc.dss = wiRenderer::depthStencils[DSSTYPE_XRAY]; + desc.rs = wiRenderer::rasterizers[RSTYPE_DOUBLESIDED]; + desc.bs = wiRenderer::blendStates[BSTYPE_ADDITIVE]; + desc.pt = TRIANGLELIST; + + pso_solidpart = new GraphicsPSO; + device->CreateGraphicsPSO(&desc, pso_solidpart); + } + + { + GraphicsPSODesc desc; + + desc.vs = wiRenderer::vertexShaders[VSTYPE_LINE]; + desc.ps = wiRenderer::pixelShaders[PSTYPE_LINE]; + desc.il = wiRenderer::vertexLayouts[VLTYPE_LINE]; + desc.dss = wiRenderer::depthStencils[DSSTYPE_XRAY]; + desc.rs = wiRenderer::rasterizers[RSTYPE_WIRE_DOUBLESIDED_SMOOTH]; + desc.bs = wiRenderer::blendStates[BSTYPE_TRANSPARENT]; + desc.pt = LINELIST; + + pso_wirepart = new GraphicsPSO; + device->CreateGraphicsPSO(&desc, pso_wirepart); + } +} Translator::Translator() { @@ -48,38 +85,6 @@ Translator::Translator() GraphicsDevice* device = wiRenderer::GetDevice(); - if (pso_solidpart == nullptr) - { - GraphicsPSODesc desc; - - desc.vs = wiRenderer::vertexShaders[VSTYPE_LINE]; - desc.ps = wiRenderer::pixelShaders[PSTYPE_LINE]; - desc.il = wiRenderer::vertexLayouts[VLTYPE_LINE]; - desc.dss = wiRenderer::depthStencils[DSSTYPE_XRAY]; - desc.rs = wiRenderer::rasterizers[RSTYPE_DOUBLESIDED]; - desc.bs = wiRenderer::blendStates[BSTYPE_ADDITIVE]; - desc.pt = TRIANGLELIST; - - pso_solidpart = new GraphicsPSO; - device->CreateGraphicsPSO(&desc, pso_solidpart); - } - - if (pso_wirepart == nullptr) - { - GraphicsPSODesc desc; - - desc.vs = wiRenderer::vertexShaders[VSTYPE_LINE]; - desc.ps = wiRenderer::pixelShaders[PSTYPE_LINE]; - desc.il = wiRenderer::vertexLayouts[VLTYPE_LINE]; - desc.dss = wiRenderer::depthStencils[DSSTYPE_XRAY]; - desc.rs = wiRenderer::rasterizers[RSTYPE_WIRE_DOUBLESIDED_SMOOTH]; - desc.bs = wiRenderer::blendStates[BSTYPE_TRANSPARENT]; - desc.pt = LINELIST; - - pso_wirepart = new GraphicsPSO; - device->CreateGraphicsPSO(&desc, pso_wirepart); - } - if (vertexBuffer_Axis == nullptr) { { diff --git a/Editor/Translator.h b/Editor/Translator.h index e9df9b141..abf8edf20 100644 --- a/Editor/Translator.h +++ b/Editor/Translator.h @@ -44,5 +44,7 @@ public: // Check if the drag ended in this exact frame bool IsDragEnded(); XMFLOAT4X4 GetDragEnd(); + + static void LoadShaders(); }; diff --git a/Editor/main.cpp b/Editor/main.cpp index 3b406a22b..c34b71e7a 100644 --- a/Editor/main.cpp +++ b/Editor/main.cpp @@ -206,6 +206,25 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } } break; + case WM_SIZE: + { + if (wiRenderer::graphicsDevice) + { + int width = LOWORD(lParam); + int height = HIWORD(lParam); + + wiRenderer::GetDevice()->SetResolution(width, height); + + wiSceneSystem::Scene& scene = wiRenderer::GetScene(); + + wiSceneSystem::CameraComponent* camera = scene.cameras.GetComponent(wiRenderer::getCameraID()); + if (camera != nullptr) + { + camera->CreatePerspective((float)wiRenderer::GetInternalResolution().x, (float)wiRenderer::GetInternalResolution().y, 0.1f, 800); + } + } + } + break; case WM_MBUTTONDOWN: ShowCursor(false); break; diff --git a/README.md b/README.md index 075a1e97e..b674f3e24 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Python script which will generate the SPIR-V shader building program "build_SPIR is automatic if you start the application with Vulkan support. This feature is experimental, not tested thoroughly yet. -* **To load HLSL 6 shaders, replicate the exact steps as with SPIR-V, but the pyhton script you should run is called "generate_shader_buildtask_spirv.py" which will generate "build_HLSL6.bat". +* **To load HLSL 6 shaders, replicate the exact steps as with SPIR-V, but the pyhton script you should run is called "generate_shader_buildtask_hlsl6.py" which will generate "build_HLSL6.bat". This feature is experimental, not tested thoroughly yet. ### Platforms: diff --git a/Template_Windows/main.cpp b/Template_Windows/main.cpp index 60590abfc..2d76f06d4 100644 --- a/Template_Windows/main.cpp +++ b/Template_Windows/main.cpp @@ -170,6 +170,25 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } } break; + case WM_SIZE: + { + if (wiRenderer::graphicsDevice) + { + int width = LOWORD(lParam); + int height = HIWORD(lParam); + + wiRenderer::GetDevice()->SetResolution(width, height); + + wiSceneSystem::Scene& scene = wiRenderer::GetScene(); + + wiSceneSystem::CameraComponent* camera = scene.cameras.GetComponent(wiRenderer::getCameraID()); + if (camera != nullptr) + { + camera->CreatePerspective((float)wiRenderer::GetInternalResolution().x, (float)wiRenderer::GetInternalResolution().y, 0.1f, 800); + } + } + } + break; case WM_KEYDOWN: switch (wParam) { diff --git a/Tests/main.cpp b/Tests/main.cpp index 3fb4468a3..786439ccf 100644 --- a/Tests/main.cpp +++ b/Tests/main.cpp @@ -159,6 +159,25 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } } break; + case WM_SIZE: + { + if (wiRenderer::graphicsDevice) + { + int width = LOWORD(lParam); + int height = HIWORD(lParam); + + wiRenderer::GetDevice()->SetResolution(width, height); + + wiSceneSystem::Scene& scene = wiRenderer::GetScene(); + + wiSceneSystem::CameraComponent* camera = scene.cameras.GetComponent(wiRenderer::getCameraID()); + if (camera != nullptr) + { + camera->CreatePerspective((float)wiRenderer::GetInternalResolution().x, (float)wiRenderer::GetInternalResolution().y, 0.1f, 800); + } + } + } + break; case WM_KEYDOWN: switch (wParam) { diff --git a/WickedEngine/Renderable2DComponent.cpp b/WickedEngine/Renderable2DComponent.cpp index 3f7ec5794..374cdbb04 100644 --- a/WickedEngine/Renderable2DComponent.cpp +++ b/WickedEngine/Renderable2DComponent.cpp @@ -22,6 +22,8 @@ Renderable2DComponent::~Renderable2DComponent() wiRenderTarget Renderable2DComponent::rtFinal; void Renderable2DComponent::ResizeBuffers() { + wiRenderer::GetDevice()->WaitForGPU(); + FORMAT defaultTextureFormat = wiRenderer::GetDevice()->GetBackBufferFormat(); // Protect against multiple buffer resizes when there is no change! diff --git a/WickedEngine/Renderable3DComponent.cpp b/WickedEngine/Renderable3DComponent.cpp index 92037e528..f0b0307bc 100644 --- a/WickedEngine/Renderable3DComponent.cpp +++ b/WickedEngine/Renderable3DComponent.cpp @@ -37,6 +37,8 @@ void Renderable3DComponent::ResizeBuffers() { Renderable2DComponent::ResizeBuffers(); + wiRenderer::GetDevice()->WaitForGPU(); + FORMAT defaultTextureFormat = wiRenderer::GetDevice()->GetBackBufferFormat(); // Protect against multiple buffer resizes when there is no change! diff --git a/WickedEngine/ShaderInterop_HairParticle.h b/WickedEngine/ShaderInterop_HairParticle.h index 76cf20fd0..8642b4b37 100644 --- a/WickedEngine/ShaderInterop_HairParticle.h +++ b/WickedEngine/ShaderInterop_HairParticle.h @@ -5,16 +5,32 @@ #define THREADCOUNT_SIMULATEHAIR 256 -static const uint particleBuffer_stride = 16 + 4 + 4; // pos, normal, tangent +struct Patch +{ + float3 position; + uint tangent_random; + float3 normal; + uint binormal_length; +}; + +struct PatchSimulationData +{ + float3 velocity; + uint target; +}; CBUFFER(HairParticleCB, CBSLOT_OTHER_HAIRPARTICLE) { float4x4 xWorld; float4 xColor; + float xLength; float LOD0; float LOD1; float LOD2; + + float xStiffness; + float3 pad; }; #endif // _SHADERINTEROP_HAIRPARTICLE_H_ diff --git a/WickedEngine/hairparticleVS.hlsl b/WickedEngine/hairparticleVS.hlsl index c35c91006..b92a5175c 100644 --- a/WickedEngine/hairparticleVS.hlsl +++ b/WickedEngine/hairparticleVS.hlsl @@ -21,7 +21,7 @@ static const float3 HAIRPATCH[] = { float3(0, 1, 1), }; -RAWBUFFER(particleBuffer, 0); +STRUCTUREDBUFFER(particleBuffer, Patch, 0); VertexToPixel main(uint fakeIndex : SV_VERTEXID) { @@ -31,28 +31,31 @@ VertexToPixel main(uint fakeIndex : SV_VERTEXID) uint vertexID = fakeIndex % 12; uint instanceID = fakeIndex / 12; - // load the raw particle data: - const uint fetchAddress = instanceID * particleBuffer_stride; - float4 posLen = asfloat(particleBuffer.Load4(fetchAddress)); - uint normalRand = particleBuffer.Load(fetchAddress + 16); - uint uTangent = particleBuffer.Load(fetchAddress + 16 + 4); - // convert the raw loaded particle data: - float3 pos = posLen.xyz; - float len = posLen.w * xLength; - float3 normal; - uint rand; - normal.x = (normalRand >> 0) & 0x000000FF; - normal.y = (normalRand >> 8) & 0x000000FF; - normal.z = (normalRand >> 16) & 0x000000FF; - normal = normal / 255.0f * 2 - 1; - rand = (normalRand >> 24) & 0x000000FF; + float3 position = particleBuffer[instanceID].position; + uint tangent_random = particleBuffer[instanceID].tangent_random; + float3 normal = particleBuffer[instanceID].normal; + uint binormal_length = particleBuffer[instanceID].binormal_length; + float3 tangent; - tangent.x = (uTangent >> 0) & 0x000000FF; - tangent.y = (uTangent >> 8) & 0x000000FF; - tangent.z = (uTangent >> 16) & 0x000000FF; + tangent.x = (tangent_random >> 0) & 0x000000FF; + tangent.y = (tangent_random >> 8) & 0x000000FF; + tangent.z = (tangent_random >> 16) & 0x000000FF; tangent = tangent / 255.0f * 2 - 1; + uint rand = (tangent_random >> 24) & 0x000000FF; + + float3 binormal; + binormal.x = (binormal_length >> 0) & 0x000000FF; + binormal.y = (binormal_length >> 8) & 0x000000FF; + binormal.z = (binormal_length >> 16) & 0x000000FF; + binormal = binormal / 255.0f * 2 - 1; + + float length = (binormal_length >> 24) & 0x000000FF; + length /= 255.0f; + length += 1; + length *= xLength; + // expand the particle into a billboard cross section, the patch: float3 patchPos = HAIRPATCH[vertexID]; float2 uv = vertexID < 6 ? patchPos.xy : patchPos.zy; @@ -64,28 +67,29 @@ VertexToPixel main(uint fakeIndex : SV_VERTEXID) float2 frame; texture_0.GetDimensions(frame.x, frame.y); frame.xy /= frame.y; - frame.xy *= len; + frame.xy *= length; patchPos.xyz *= frame.xyx * 0.5f; // simplistic wind effect only affects the top, but leaves the base as is: - float3 wind = sin(g_xFrame_Time + (pos.x + pos.y + pos.z))*g_xFrame_WindDirection.xyz * patchPos.y * 0.03f; - float3 windPrev = sin(g_xFrame_TimePrev + (pos.x + pos.y + pos.z))*g_xFrame_WindDirection.xyz * patchPos.y * 0.03f; + float3 wind = sin(g_xFrame_Time + (position.x + position.y + position.z))*g_xFrame_WindDirection.xyz * patchPos.y * 0.03f; + float3 windPrev = sin(g_xFrame_TimePrev + (position.x + position.y + position.z))*g_xFrame_WindDirection.xyz * patchPos.y * 0.03f; // transform particle by the emitter object matrix: - pos.xyz = mul(xWorld, float4(pos.xyz, 1)).xyz; - normal = mul((float3x3)xWorld, normal); - tangent = mul((float3x3)xWorld, tangent); + position.xyz = mul(xWorld, float4(position.xyz, 1)).xyz; + normal = normalize(mul((float3x3)xWorld, normal)); + tangent = normalize(mul((float3x3)xWorld, tangent)); // rotate the patch into the tangent space of the emitting triangle: - float3x3 TBN = float3x3(tangent, normal, cross(normal, tangent)); + //float3x3 TBN = float3x3(tangent, normal, cross(normal, tangent)); + float3x3 TBN = float3x3(tangent, normal, binormal); // don't derive binormal, because we want the shear! patchPos = mul(patchPos, TBN); // inset to the emitter a bit, to avoid disconnect: - pos.xyz -= normal * 0.1*len; + position.xyz -= normal * 0.1 * length; // copy to output: - Out.pos = float4(pos, 1); + Out.pos = float4(position, 1); Out.pos.xyz += patchPos; float3 savedPos = Out.pos.xyz; Out.pos.xyz += wind; @@ -95,7 +99,7 @@ VertexToPixel main(uint fakeIndex : SV_VERTEXID) Out.nor = normal; Out.tex = uv; - Out.fade = pow(saturate(distance(pos.xyz, g_xCamera_CamPos.xyz) / (LOD2*hairPopDistanceThreshold)), 10); + Out.fade = pow(saturate(distance(position.xyz, g_xCamera_CamPos.xyz) / (LOD2*hairPopDistanceThreshold)), 10); Out.pos2D = Out.pos; Out.pos2DPrev = mul(float4(savedPos + windPrev, 1), g_xFrame_MainCamera_PrevVP); diff --git a/WickedEngine/hairparticle_simulateCS.hlsl b/WickedEngine/hairparticle_simulateCS.hlsl index cce89864f..bd7b2883e 100644 --- a/WickedEngine/hairparticle_simulateCS.hlsl +++ b/WickedEngine/hairparticle_simulateCS.hlsl @@ -1,9 +1,8 @@ #include "globals.hlsli" #include "ShaderInterop_HairParticle.h" -RWRAWBUFFER(particleBuffer, 0); - -RAWBUFFER(targetBuffer, 0); +RWSTRUCTUREDBUFFER(particleBuffer, Patch, 0); +RWSTRUCTUREDBUFFER(simulationBuffer, PatchSimulationData, 1); #define NUM_LDS_FORCEFIELDS 32 struct LDS_ForceField @@ -38,24 +37,13 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex) const uint instanceID = DTid.x; - // Fetch from particle buffer: - const uint fetchAddress = instanceID * particleBuffer_stride; - float4 posLen = asfloat(particleBuffer.Load4(fetchAddress)); - uint normalRand = particleBuffer.Load(fetchAddress + 16); + // Particle buffer load: + float3 position = particleBuffer[instanceID].position; + float3 normal = particleBuffer[instanceID].normal; - // Decompress particle properties: - float3 pos = posLen.xyz; - float len = posLen.w * xLength; - float3 normal; - normal.x = (normalRand >> 0) & 0x000000FF; - normal.y = (normalRand >> 8) & 0x000000FF; - normal.z = (normalRand >> 16) & 0x000000FF; - normal = normal / 255.0f * 2 - 1; - - // Fetch from target buffer - uint uTarget = targetBuffer.Load(instanceID * 4); - - // Decompress target: + // Simulation buffer load: + float3 velocity = simulationBuffer[instanceID].velocity; + uint uTarget = simulationBuffer[instanceID].target; float3 target; target.x = (uTarget >> 0) & 0x000000FF; target.y = (uTarget >> 8) & 0x000000FF; @@ -63,9 +51,9 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex) target = target / 255.0f * 2 - 1; // transform particle by the emitter object matrix: - pos.xyz = mul(xWorld, float4(pos.xyz, 1)).xyz; - normal = mul((float3x3)xWorld, normal); - target = mul((float3x3)xWorld, target); + position.xyz = mul(xWorld, float4(position.xyz, 1)).xyz; + normal = normalize(mul((float3x3)xWorld, normal)); + target = normalize(mul((float3x3)xWorld, target)); // Accumulate forces: float3 force = 0; @@ -73,7 +61,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex) { LDS_ForceField forceField = forceFields[i]; - float3 dir = forceField.position - pos; + float3 dir = forceField.position - position; float dist; if (forceField.type == ENTITY_TYPE_FORCEFIELD_POINT) // point-based force field { @@ -88,22 +76,22 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex) force += dir * forceField.gravity * (1 - saturate(dist * forceField.range_inverse)); } - // Apply forces: - normal += force * g_xFrame_DeltaTime; + // Pull back to rest position: + force += (target - normal) * xStiffness; - // Apply rest: - normal = lerp(normal, target, 0.1f); + // Apply forces: + velocity += force * g_xFrame_DeltaTime; + normal += velocity * g_xFrame_DeltaTime; + + // Drag: + velocity *= 0.98f; // Transform back to mesh space and renormalize: - normal = mul(normal, (float3x3)xWorld); // transposed mul! - normal = normalize(normal); + normal = normalize(mul(normal, (float3x3)xWorld)); // transposed mul! + // Store particle normal: + particleBuffer[instanceID].normal = normal; - // Compress normal and store: - uint uNormal = 0; - uNormal |= (uint)((normal.x * 0.5f + 0.5f) * 255.0f) << 0; - uNormal |= (uint)((normal.y * 0.5f + 0.5f) * 255.0f) << 8; - uNormal |= (uint)((normal.z * 0.5f + 0.5f) * 255.0f) << 16; - uNormal |= normalRand & 0xFF000000; - particleBuffer.Store(fetchAddress + 16, uNormal); + // Store simulation data: + simulationBuffer[instanceID].velocity = velocity; } diff --git a/WickedEngine/wiGUI.cpp b/WickedEngine/wiGUI.cpp index 3a0196485..248d2f6f0 100644 --- a/WickedEngine/wiGUI.cpp +++ b/WickedEngine/wiGUI.cpp @@ -8,6 +8,10 @@ using namespace std; wiGUI::wiGUI(GRAPHICSTHREAD threadID) :threadID(threadID), activeWidget(nullptr), focus(false), visible(true), pointerpos(XMFLOAT2(0,0)) { + dirty = true; + scale_local.x = (float)wiRenderer::GetDevice()->GetScreenWidth(); + scale_local.y = (float)wiRenderer::GetDevice()->GetScreenHeight(); + UpdateTransform(); } @@ -23,6 +27,14 @@ void wiGUI::Update(float dt) return; } + if (wiRenderer::GetDevice()->ResolutionChanged()) + { + dirty = true; + scale_local.x = (float)wiRenderer::GetDevice()->GetScreenWidth(); + scale_local.y = (float)wiRenderer::GetDevice()->GetScreenHeight(); + UpdateTransform(); + } + XMFLOAT4 _p = wiInputManager::GetInstance()->getpointer(); pointerpos.x = _p.x; pointerpos.y = _p.y; @@ -39,7 +51,7 @@ void wiGUI::Update(float dt) focus = false; for (list::reverse_iterator it = widgets.rbegin(); it != widgets.rend(); ++it) { - if ((*it)->container == nullptr) + if ((*it)->parent == this) { // the contained child widgets will be updated by the containers (*it)->Update(this, dt); @@ -62,7 +74,7 @@ void wiGUI::Render() wiRenderer::GetDevice()->EventBegin("GUI", GetGraphicsThread()); for (auto&x : widgets) { - if (x->container == nullptr && x != activeWidget) + if (x->parent == this && x != activeWidget) { // the contained child widgets will be rendered by the containers x->Render(this); @@ -95,11 +107,13 @@ void wiGUI::ResetScissor() void wiGUI::AddWidget(wiWidget* widget) { + widget->AttachTo(this); widgets.push_back(widget); } void wiGUI::RemoveWidget(wiWidget* widget) { + widget->Detach(); widgets.remove(widget); } diff --git a/WickedEngine/wiGUI.h b/WickedEngine/wiGUI.h index 546f9deb2..9a8f077b2 100644 --- a/WickedEngine/wiGUI.h +++ b/WickedEngine/wiGUI.h @@ -1,6 +1,7 @@ #pragma once #include "CommonInclude.h" #include "wiEnums.h" +#include "wiSceneSystem.h" #include @@ -8,7 +9,7 @@ class wiHashString; class wiWidget; -class wiGUI +class wiGUI : public wiSceneSystem::TransformComponent { friend class wiWidget; private: diff --git a/WickedEngine/wiGraphicsDevice_DX11.cpp b/WickedEngine/wiGraphicsDevice_DX11.cpp index a31829180..965d010e4 100644 --- a/WickedEngine/wiGraphicsDevice_DX11.cpp +++ b/WickedEngine/wiGraphicsDevice_DX11.cpp @@ -1535,27 +1535,7 @@ GraphicsDevice_DX11::GraphicsDevice_DX11(wiWindowRegistration::window_type windo //D3D11_FEATURE_DATA_D3D11_OPTIONS3 features_3; //hr = device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS3, &features_3, sizeof(features_3)); - // Create a render target view - backBuffer = NULL; - hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBuffer); - if (FAILED(hr)) { - wiHelper::messageBox("BackBuffer creation Failed!", "Error!"); - exit(1); - } - - hr = device->CreateRenderTargetView(backBuffer, NULL, &renderTargetView); - if (FAILED(hr)) { - wiHelper::messageBox("Main Rendertarget creation Failed!", "Error!"); - exit(1); - } - - // Setup the main viewport - viewPort.Width = (FLOAT)SCREENWIDTH; - viewPort.Height = (FLOAT)SCREENHEIGHT; - viewPort.MinDepth = 0.0f; - viewPort.MaxDepth = 1.0f; - viewPort.TopLeftX = 0; - viewPort.TopLeftY = 0; + CreateBackBufferResources(); } GraphicsDevice_DX11::~GraphicsDevice_DX11() @@ -1571,13 +1551,40 @@ GraphicsDevice_DX11::~GraphicsDevice_DX11() SAFE_RELEASE(device); } +void GraphicsDevice_DX11::CreateBackBufferResources() +{ + SAFE_RELEASE(backBuffer); + SAFE_RELEASE(renderTargetView); + + HRESULT hr; + + hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBuffer); + if (FAILED(hr)) { + wiHelper::messageBox("BackBuffer creation Failed!", "Error!"); + exit(1); + } + + hr = device->CreateRenderTargetView(backBuffer, nullptr, &renderTargetView); + if (FAILED(hr)) { + wiHelper::messageBox("Main Rendertarget creation Failed!", "Error!"); + exit(1); + } +} + void GraphicsDevice_DX11::SetResolution(int width, int height) { if (width != SCREENWIDTH || height != SCREENHEIGHT) { SCREENWIDTH = width; SCREENHEIGHT = height; - swapChain->ResizeBuffers(2, width, height, _ConvertFormat(GetBackBufferFormat()), 0); + + SAFE_RELEASE(backBuffer); + SAFE_RELEASE(renderTargetView); + HRESULT hr = swapChain->ResizeBuffers(GetBackBufferCount(), width, height, _ConvertFormat(GetBackBufferFormat()), 0); + assert(SUCCEEDED(hr)); + + CreateBackBufferResources(); + RESOLUTIONCHANGED = true; } } @@ -2964,7 +2971,15 @@ void GraphicsDevice_DX11::SetName(GPUResource* pResource, const std::string& nam void GraphicsDevice_DX11::PresentBegin() { + ViewPort viewPort; + viewPort.Width = (FLOAT)SCREENWIDTH; + viewPort.Height = (FLOAT)SCREENHEIGHT; + viewPort.MinDepth = 0.0f; + viewPort.MaxDepth = 1.0f; + viewPort.TopLeftX = 0; + viewPort.TopLeftY = 0; BindViewports(1, &viewPort, GRAPHICSTHREAD_IMMEDIATE); + deviceContexts[GRAPHICSTHREAD_IMMEDIATE]->OMSetRenderTargets(1, &renderTargetView, 0); float ClearColor[4] = { 0, 0, 0, 1.0f }; // red,green,blue,alpha deviceContexts[GRAPHICSTHREAD_IMMEDIATE]->ClearRenderTargetView(renderTargetView, ClearColor); diff --git a/WickedEngine/wiGraphicsDevice_DX11.h b/WickedEngine/wiGraphicsDevice_DX11.h index 529928434..762a66012 100644 --- a/WickedEngine/wiGraphicsDevice_DX11.h +++ b/WickedEngine/wiGraphicsDevice_DX11.h @@ -21,16 +21,15 @@ namespace wiGraphicsTypes class GraphicsDevice_DX11 : public GraphicsDevice { private: - ID3D11Device* device; + ID3D11Device* device = nullptr; D3D_DRIVER_TYPE driverType; D3D_FEATURE_LEVEL featureLevel; - IDXGISwapChain1* swapChain; - ID3D11RenderTargetView* renderTargetView; - ID3D11Texture2D* backBuffer; - ViewPort viewPort; - ID3D11DeviceContext* deviceContexts[GRAPHICSTHREAD_COUNT]; - ID3D11CommandList* commandLists[GRAPHICSTHREAD_COUNT]; - ID3DUserDefinedAnnotation* userDefinedAnnotations[GRAPHICSTHREAD_COUNT]; + IDXGISwapChain1* swapChain = nullptr; + ID3D11RenderTargetView* renderTargetView = nullptr; + ID3D11Texture2D* backBuffer = nullptr; + ID3D11DeviceContext* deviceContexts[GRAPHICSTHREAD_COUNT] = {}; + ID3D11CommandList* commandLists[GRAPHICSTHREAD_COUNT] = {}; + ID3DUserDefinedAnnotation* userDefinedAnnotations[GRAPHICSTHREAD_COUNT] = {}; UINT stencilRef[GRAPHICSTHREAD_COUNT]; XMFLOAT4 blendFactor[GRAPHICSTHREAD_COUNT]; @@ -54,6 +53,8 @@ namespace wiGraphicsTypes uint8_t raster_uavs_count[GRAPHICSTHREAD_COUNT] = {}; void validate_raster_uavs(GRAPHICSTHREAD threadID); + void CreateBackBufferResources(); + public: GraphicsDevice_DX11(wiWindowRegistration::window_type window, bool fullscreen = false, bool debuglayer = false); diff --git a/WickedEngine/wiGraphicsDevice_DX12.cpp b/WickedEngine/wiGraphicsDevice_DX12.cpp index 7f488fcf3..8d26a127d 100644 --- a/WickedEngine/wiGraphicsDevice_DX12.cpp +++ b/WickedEngine/wiGraphicsDevice_DX12.cpp @@ -2038,7 +2038,24 @@ namespace wiGraphicsTypes { SCREENWIDTH = width; SCREENHEIGHT = height; - swapChain->ResizeBuffers(2, width, height, _ConvertFormat(GetBackBufferFormat()), 0); + + WaitForGPU(); + + for (UINT fr = 0; fr < BACKBUFFER_COUNT; ++fr) + { + SAFE_RELEASE(frames[fr].backBuffer); + } + + HRESULT hr = swapChain->ResizeBuffers(GetBackBufferCount(), width, height, _ConvertFormat(GetBackBufferFormat()), 0); + assert(SUCCEEDED(hr)); + + for (UINT fr = 0; fr < BACKBUFFER_COUNT; ++fr) + { + hr = swapChain->GetBuffer(fr, __uuidof(ID3D12Resource), (void**)&frames[fr].backBuffer); + assert(SUCCEEDED(hr)); + device->CreateRenderTargetView(frames[fr].backBuffer, nullptr, *frames[fr].backBufferRTV); + } + RESOLUTIONCHANGED = true; } } @@ -3349,7 +3366,6 @@ namespace wiGraphicsTypes { HRESULT result; - // Indicate that the back buffer will now be used to present. D3D12_RESOURCE_BARRIER barrier = {}; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; @@ -3416,7 +3432,6 @@ namespace wiGraphicsTypes GetFrameResources().SamplerDescriptorsGPU[threadID]->reset(device, nullDescriptors); GetFrameResources().resourceBuffer[threadID]->clear(); - D3D12_RECT pRects[8]; for (UINT i = 0; i < 8; ++i) { diff --git a/WickedEngine/wiHairParticle.cpp b/WickedEngine/wiHairParticle.cpp index d4c68b624..84e6186d8 100644 --- a/WickedEngine/wiHairParticle.cpp +++ b/WickedEngine/wiHairParticle.cpp @@ -241,16 +241,8 @@ void wiHairParticle::Settings(int l0,int l1,int l2) void wiHairParticle::Generate(const MeshComponent& mesh) { - struct Patch - { - XMFLOAT4 posLen; - UINT normalRand; - UINT tangent; - }; - static_assert(sizeof(Patch) == particleBuffer_stride, "Mismatch!"); - std::vector points(particleCount); - std::vector targets(particleCount); + std::vector simulationData(particleCount); // Now the distribution is uniform. TODO: bring back weight-based distribution, but make it more intuitive to set up! (vertex colors?) @@ -281,42 +273,45 @@ void wiHairParticle::Generate(const MeshComponent& mesh) XMVECTOR P = XMVectorBaryCentric(p0, p1, p2, f, g); XMVECTOR N = XMVectorBaryCentric(n0, n1, n2, f, g); XMVECTOR T = XMVector3Normalize(XMVectorSubtract(i % 2 == 0 ? p0 : p2, p1)); + XMVECTOR B = XMVector3Cross(N, T); - XMFLOAT3 position, normal, tangent; - XMStoreFloat3(&position, P); - XMStoreFloat3(&normal, N); + XMStoreFloat3(&points[i].position, P); + XMStoreFloat3(&points[i].normal, N); + + XMFLOAT3 tangent; XMStoreFloat3(&tangent, T); + points[i].tangent_random = wiMath::CompressNormal(tangent); + points[i].tangent_random |= (uint32_t)(wiRandom::getRandom(0, 255) << 24); - points[i].posLen = XMFLOAT4(position.x, position.y, position.z, 1.0f); + XMFLOAT3 binormal; + XMStoreFloat3(&binormal, B); + points[i].binormal_length = wiMath::CompressNormal(binormal); + points[i].binormal_length |= (uint32_t)(wiRandom::getRandom(0, 255) * wiMath::Clamp(randomness, 0, 1)) << 24; - uint32_t uNormal = wiMath::CompressNormal(normal); - points[i].normalRand = uNormal; - points[i].normalRand |= ((uint32_t)wiRandom::getRandom(0, 256)) << 24; - - points[i].tangent = wiMath::CompressNormal(tangent); - - targets[i] = uNormal; + simulationData[i].velocity = float3(0, 0, 0); + simulationData[i].target = wiMath::CompressNormal(points[i].normal); } cb.reset(new GPUBuffer); particleBuffer.reset(new GPUBuffer); - targetBuffer.reset(new GPUBuffer); + simulationBuffer.reset(new GPUBuffer); GPUBufferDesc bd; bd.Usage = USAGE_DEFAULT; - bd.ByteWidth = sizeof(Patch) * particleCount; bd.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS; bd.CPUAccessFlags = 0; - bd.MiscFlags = RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; - + bd.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED; SubresourceData data = {}; + + bd.StructureByteStride = sizeof(Patch); + bd.ByteWidth = bd.StructureByteStride * particleCount; data.pSysMem = points.data(); wiRenderer::GetDevice()->CreateBuffer(&bd, &data, particleBuffer.get()); - bd.BindFlags = BIND_SHADER_RESOURCE; - bd.ByteWidth = sizeof(uint32_t) * particleCount; - data.pSysMem = targets.data(); - wiRenderer::GetDevice()->CreateBuffer(&bd, &data, targetBuffer.get()); + bd.StructureByteStride = sizeof(PatchSimulationData); + bd.ByteWidth = bd.StructureByteStride * particleCount; + data.pSysMem = simulationData.data(); + wiRenderer::GetDevice()->CreateBuffer(&bd, &data, simulationBuffer.get()); bd.Usage = USAGE_DYNAMIC; bd.ByteWidth = sizeof(HairParticleCB); @@ -346,23 +341,19 @@ void wiHairParticle::UpdateRenderData(const MaterialComponent& material, GRAPHIC hcb.LOD0 = (float)LOD[0]; hcb.LOD1 = (float)LOD[1]; hcb.LOD2 = (float)LOD[2]; + hcb.xStiffness = stiffness; device->UpdateBuffer(cb.get(), &hcb, threadID); device->BindConstantBuffer(CS, cb.get(), CB_GETBINDSLOT(HairParticleCB), threadID); - GPUResource* res[] = { - targetBuffer.get() - }; - device->BindResources(CS, res, 0, ARRAYSIZE(res), threadID); - GPUResource* uavs[] = { - particleBuffer.get() + particleBuffer.get(), + simulationBuffer.get() }; device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID); device->Dispatch((UINT)ceilf((float)particleCount / (float)THREADCOUNT_SIMULATEHAIR), 1, 1, threadID); - device->UnbindResources(0, ARRAYSIZE(res), threadID); device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID); device->EventEnd(threadID); diff --git a/WickedEngine/wiHairParticle.h b/WickedEngine/wiHairParticle.h index e9880cbec..6bc6938c6 100644 --- a/WickedEngine/wiHairParticle.h +++ b/WickedEngine/wiHairParticle.h @@ -16,7 +16,7 @@ class wiHairParticle private: std::unique_ptr cb; std::unique_ptr particleBuffer; - std::unique_ptr targetBuffer; + std::unique_ptr simulationBuffer; static wiGraphicsTypes::VertexShader *vs; static wiGraphicsTypes::PixelShader *ps[SHADERTYPE_COUNT]; @@ -40,8 +40,11 @@ public: static void SetUpStatic(); static void Settings(int lod0,int lod1,int lod2); - float length = 1.0f; uint32_t particleCount = 0; + float length = 1.0f; + float stiffness = 10.0f; + float randomness = 0.2f; + wiECS::Entity meshID = wiECS::INVALID_ENTITY; XMFLOAT4X4 world; AABB aabb; diff --git a/WickedEngine/wiSceneSystem.cpp b/WickedEngine/wiSceneSystem.cpp index 1c7f0cb9e..1b0266b3c 100644 --- a/WickedEngine/wiSceneSystem.cpp +++ b/WickedEngine/wiSceneSystem.cpp @@ -1315,7 +1315,9 @@ namespace wiSceneSystem TransformComponent& transform = *transforms.GetComponent(channel.target); - XMMATRIX ANIM; + XMMATRIX W = XMLoadFloat4x4(&transform.world); + XMVECTOR S, R, T; + XMMatrixDecompose(&S, &R, &T, W); if (channel.mode == AnimationComponent::AnimationChannel::Mode::STEP || keyLeft == keyRight) { @@ -1325,19 +1327,19 @@ namespace wiSceneSystem case AnimationComponent::AnimationChannel::Type::TRANSLATION: { assert(channel.keyframe_data.size() == channel.keyframe_times.size() * 3); - ANIM = XMMatrixTranslationFromVector(XMLoadFloat3(&((const XMFLOAT3*)channel.keyframe_data.data())[keyLeft])); + T = XMLoadFloat3(&((const XMFLOAT3*)channel.keyframe_data.data())[keyLeft]); } break; case AnimationComponent::AnimationChannel::Type::ROTATION: { assert(channel.keyframe_data.size() == channel.keyframe_times.size() * 4); - ANIM = XMMatrixRotationQuaternion(XMLoadFloat4(&((const XMFLOAT4*)channel.keyframe_data.data())[keyLeft])); + R = XMLoadFloat4(&((const XMFLOAT4*)channel.keyframe_data.data())[keyLeft]); } break; case AnimationComponent::AnimationChannel::Type::SCALE: { assert(channel.keyframe_data.size() == channel.keyframe_times.size() * 3); - ANIM = XMMatrixScalingFromVector(XMLoadFloat3(&((const XMFLOAT3*)channel.keyframe_data.data())[keyLeft])); + S = XMLoadFloat3(&((const XMFLOAT3*)channel.keyframe_data.data())[keyLeft]); } break; } @@ -1357,7 +1359,7 @@ namespace wiSceneSystem XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft]); XMVECTOR vRight = XMLoadFloat3(&data[keyRight]); XMVECTOR vAnim = XMVectorLerp(vLeft, vRight, t); - ANIM = XMMatrixTranslationFromVector(vAnim); + T = vAnim; } break; case AnimationComponent::AnimationChannel::Type::ROTATION: @@ -1368,7 +1370,7 @@ namespace wiSceneSystem XMVECTOR vRight = XMLoadFloat4(&data[keyRight]); XMVECTOR vAnim = XMQuaternionSlerp(vLeft, vRight, t); vAnim = XMQuaternionNormalize(vAnim); - ANIM = XMMatrixRotationQuaternion(vAnim); + R = vAnim; } break; case AnimationComponent::AnimationChannel::Type::SCALE: @@ -1378,16 +1380,15 @@ namespace wiSceneSystem XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft]); XMVECTOR vRight = XMLoadFloat3(&data[keyRight]); XMVECTOR vAnim = XMVectorLerp(vLeft, vRight, t); - ANIM = XMMatrixScalingFromVector(vAnim); + S = vAnim; } break; } } - XMMATRIX W = XMLoadFloat4x4(&transform.world); - XMMATRIX M = W * ANIM; + W = XMMatrixScalingFromVector(S) * XMMatrixRotationQuaternion(R) * XMMatrixTranslationFromVector(T); - XMStoreFloat4x4(&transform.world, M); + XMStoreFloat4x4(&transform.world, W); transform.dirty = true; } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 2c19f1011..4640be8bc 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 20; // minor bug fixes, alterations, refactors, updates - const int revision = 3; + const int revision = 4; long GetVersion() diff --git a/WickedEngine/wiWidget.cpp b/WickedEngine/wiWidget.cpp index ba7178764..0e6dd71a6 100644 --- a/WickedEngine/wiWidget.cpp +++ b/WickedEngine/wiWidget.cpp @@ -32,7 +32,7 @@ wiWidget::wiWidget() : TransformComponent() scissorRect.left = 0; scissorRect.right = 0; scissorRect.top = 0; - container = nullptr; + parent = nullptr; tooltipTimer = 0; textColor = wiColor(255, 255, 255, 255); textShadowColor = wiColor(0, 0, 0, 255); @@ -57,9 +57,9 @@ void wiWidget::Update(wiGUI* gui, float dt) UpdateTransform(); - if (container != nullptr) + if (parent != nullptr) { - this->UpdateParentedTransform(*container, world_parent_bind); + this->UpdateParentedTransform(*parent, world_parent_bind); } XMVECTOR S, R, T; @@ -67,13 +67,18 @@ void wiWidget::Update(wiGUI* gui, float dt) XMStoreFloat3(&translation, T); XMStoreFloat3(&scale, S); } -void wiWidget::AttachTo(wiWidget* parent) +void wiWidget::AttachTo(TransformComponent* parent) { - container = parent; + this->parent = parent; - parent->UpdateTransform(); + this->parent->UpdateTransform(); XMStoreFloat4x4(&world_parent_bind, XMMatrixInverse(nullptr, XMLoadFloat4x4(&parent->world))); } +void wiWidget::Detach() +{ + this->parent = nullptr; + ApplyTransform(); +} void wiWidget::RenderTooltip(wiGUI* gui) { assert(gui != nullptr && "Ivalid GUI!"); @@ -657,7 +662,7 @@ wiSlider::wiSlider(float start, float end, float defaultValue, float step, const this->end = max(this->end, args.fValue); onSlide(args); }); - valueInputField->container = this; + valueInputField->parent = this; valueInputField->AttachTo(this); } wiSlider::~wiSlider() @@ -797,7 +802,7 @@ void wiSlider::Render(wiGUI* gui) wiImage::Draw(wiTextureHelper::getInstance()->getColor(color) , wiImageEffects(headPosX - headWidth * 0.5f, translation.y, headWidth, scale.y), gui->GetGraphicsThread()); - if (container != nullptr) + if (parent != gui) { wiRenderer::GetDevice()->BindScissorRects(1, &scissorRect, gui->GetGraphicsThread()); } @@ -934,7 +939,7 @@ void wiCheckBox::Render(wiGUI* gui) , gui->GetGraphicsThread()); } - if (container != nullptr) + if (parent != gui) { wiRenderer::GetDevice()->BindScissorRects(1, &scissorRect, gui->GetGraphicsThread()); } @@ -1122,7 +1127,7 @@ void wiComboBox::Render(wiGUI* gui) textColor, textShadowColor)).Draw(gui->GetGraphicsThread()); - if (container != nullptr) + if (parent != gui) { wiRenderer::GetDevice()->BindScissorRects(1, &scissorRect, gui->GetGraphicsThread()); } @@ -1340,7 +1345,6 @@ void wiWindow::AddWidget(wiWidget* widget) widget->SetVisible(this->IsVisible()); gui->AddWidget(widget); widget->AttachTo(this); - widget->container = this; childrenWidgets.push_back(widget); } diff --git a/WickedEngine/wiWidget.h b/WickedEngine/wiWidget.h index edd4c1871..ae648f66e 100644 --- a/WickedEngine/wiWidget.h +++ b/WickedEngine/wiWidget.h @@ -93,9 +93,10 @@ public: Hitbox2D hitBox; - wiWidget* container; + wiSceneSystem::TransformComponent* parent; XMFLOAT4X4 world_parent_bind; - void AttachTo(wiWidget* parent); + void AttachTo(wiSceneSystem::TransformComponent* parent); + void Detach(); static void LoadShaders(); };