Decals packed into texture atlas, enabled for tiled render path
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
#ifndef WICKEDENGINE_COMMONINCLUDE_H
|
||||
#define WICKEDENGINE_COMMONINCLUDE_H
|
||||
|
||||
// NOTE:
|
||||
// Do not include engine features in this file!
|
||||
|
||||
#include <SDKDDKVer.h>
|
||||
#include <DirectXMath.h>
|
||||
#include <DirectXCollision.h>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
int __editorVersion = 0;
|
||||
|
||||
using namespace wiGraphicsTypes;
|
||||
|
||||
using namespace wiRectPacker;
|
||||
|
||||
Editor::Editor()
|
||||
{
|
||||
@@ -777,8 +777,10 @@ void EditorComponent::FixedUpdate()
|
||||
if (wiInputManager::GetInstance()->press(VK_LBUTTON))
|
||||
{
|
||||
// if not water, put a decal instead:
|
||||
static int decalselector = 0;
|
||||
decalselector = (decalselector + 1) % 2;
|
||||
Decal* decal = new Decal(hovered.position, XMFLOAT3(4,4,4), wiRenderer::getCamera()->rotation,
|
||||
wiHelper::GetOriginalWorkingDirectory() + "images/leaf.png");
|
||||
wiHelper::GetOriginalWorkingDirectory() + (decalselector == 0 ? "images/leaf.png" : "images/blood1.png"));
|
||||
decal->attachTo(hovered.object);
|
||||
wiRenderer::PutDecal(decal);
|
||||
}
|
||||
|
||||
@@ -31,30 +31,31 @@
|
||||
#define TEXSLOT_ENV0 8
|
||||
#define TEXSLOT_ENV1 9
|
||||
#define TEXSLOT_ENV2 10
|
||||
#define TEXSLOT_DECALATLAS 11
|
||||
|
||||
#define TEXSLOT_SHADOWARRAY_2D 11
|
||||
#define TEXSLOT_SHADOWARRAY_CUBE 12
|
||||
#define TEXSLOT_SHADOWARRAY_2D 12
|
||||
#define TEXSLOT_SHADOWARRAY_CUBE 13
|
||||
|
||||
#define TEXSLOT_ONDEMAND0 13
|
||||
#define TEXSLOT_ONDEMAND1 14
|
||||
#define TEXSLOT_ONDEMAND2 15
|
||||
#define TEXSLOT_ONDEMAND3 16
|
||||
#define TEXSLOT_ONDEMAND4 17
|
||||
#define TEXSLOT_ONDEMAND5 18
|
||||
#define TEXSLOT_ONDEMAND6 19
|
||||
#define TEXSLOT_ONDEMAND7 20
|
||||
#define TEXSLOT_ONDEMAND8 21
|
||||
#define TEXSLOT_ONDEMAND9 22
|
||||
#define TEXSLOT_ONDEMAND0 14
|
||||
#define TEXSLOT_ONDEMAND1 15
|
||||
#define TEXSLOT_ONDEMAND2 16
|
||||
#define TEXSLOT_ONDEMAND3 17
|
||||
#define TEXSLOT_ONDEMAND4 18
|
||||
#define TEXSLOT_ONDEMAND5 19
|
||||
#define TEXSLOT_ONDEMAND6 20
|
||||
#define TEXSLOT_ONDEMAND7 21
|
||||
#define TEXSLOT_ONDEMAND8 22
|
||||
#define TEXSLOT_ONDEMAND9 23
|
||||
#define TEXSLOT_ONDEMAND_COUNT (TEXSLOT_ONDEMAND9 - TEXSLOT_ONDEMAND0 + 1)
|
||||
|
||||
#define TEXSLOT_LIGHTGRID 23
|
||||
#define TEXSLOT_LIGHTGRID 24
|
||||
|
||||
#define TEXSLOT_COUNT TEXSLOT_LIGHTGRID
|
||||
|
||||
#define SBSLOT_BONE 0
|
||||
#define SBSLOT_TILEFRUSTUMS 23
|
||||
#define SBSLOT_LIGHTINDEXLIST 24
|
||||
#define SBSLOT_LIGHTARRAY 25
|
||||
#define SBSLOT_TILEFRUSTUMS 24
|
||||
#define SBSLOT_LIGHTINDEXLIST 25
|
||||
#define SBSLOT_LIGHTARRAY 26
|
||||
|
||||
|
||||
///////////////////////////
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#ifndef WICKED_ENGINE
|
||||
#define WICKED_ENGINE
|
||||
|
||||
// NOTE:
|
||||
// The purpose of this file is to expose all engine features.
|
||||
// It should be included in the engine's implementing project not the engine itself!
|
||||
// It should be included in the precompiled header if available.
|
||||
|
||||
#include "CommonInclude.h"
|
||||
|
||||
#include "wiVersion.h"
|
||||
@@ -50,6 +55,7 @@
|
||||
#include "wiTranslator.h"
|
||||
#include "wiArchive.h"
|
||||
#include "wiSpinLock.h"
|
||||
#include "wiRectPacker.h"
|
||||
|
||||
#include "RenderableComponent.h"
|
||||
#include "Renderable2DComponent.h"
|
||||
|
||||
Binary file not shown.
@@ -203,6 +203,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="fonts\basic.dds" />
|
||||
<Image Include="images\blood1.png" />
|
||||
<Image Include="images\directional_light.dds" />
|
||||
<Image Include="images\leaf.png">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
|
||||
@@ -230,6 +230,9 @@
|
||||
<Image Include="images\spotlight.dds">
|
||||
<Filter>images</Filter>
|
||||
</Image>
|
||||
<Image Include="images\blood1.png">
|
||||
<Filter>images</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="WickedEngineEditor.rc">
|
||||
|
||||
@@ -332,6 +332,7 @@
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)wiPHYSICS.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)wiRandom.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)wiRawInput.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)wiRectPacker.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)wiRenderer.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)wiRenderer_BindLua.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)wiRenderTarget.h" />
|
||||
@@ -667,6 +668,7 @@
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)wiParticle.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)wiRandom.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)wiRawInput.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)wiRectPacker.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)wiRenderer.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)wiRenderer_BindLua.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)wiRenderTarget.cpp" />
|
||||
|
||||
@@ -1083,6 +1083,9 @@
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)wiSpinLock.h">
|
||||
<Filter>ENGINE\Helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)wiRectPacker.h">
|
||||
<Filter>ENGINE\Helpers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)LUA\lapi.c">
|
||||
@@ -1862,6 +1865,9 @@
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)TiledForwardRenderableComponent_BindLua.cpp">
|
||||
<Filter>ENGINE\Scripting\LuaBindings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)wiRectPacker.cpp">
|
||||
<Filter>ENGINE\Helpers</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="$(MSBuildThisFileDirectory)logo\logo.png">
|
||||
|
||||
@@ -17,6 +17,7 @@ TEXTURECUBE(texture_env1, float4, TEXSLOT_ENV1)
|
||||
TEXTURECUBE(texture_env2, float4, TEXSLOT_ENV2)
|
||||
TEXTURE2DARRAY(texture_shadowarray_2d, float, TEXSLOT_SHADOWARRAY_2D)
|
||||
TEXTURECUBEARRAY(texture_shadowarray_cube, float, TEXSLOT_SHADOWARRAY_CUBE)
|
||||
TEXTURE2D(texture_decalatlas, float4, TEXSLOT_DECALATLAS)
|
||||
TEXTURE2D(texture_0, float4, TEXSLOT_ONDEMAND0)
|
||||
TEXTURE2D(texture_1, float4, TEXSLOT_ONDEMAND1)
|
||||
TEXTURE2D(texture_2, float4, TEXSLOT_ONDEMAND2)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#define DISABLE_DECALS
|
||||
#include "grassHF_GS.hlsli"
|
||||
#include "grassHF_PS.hlsli"
|
||||
#include "ditherHF.hlsli"
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.3 KiB |
@@ -104,8 +104,8 @@ void main(ComputeShaderInput IN)
|
||||
|
||||
if (IN.groupIndex == 0)
|
||||
{
|
||||
float3 minAABB = ScreenToView(float4(float2(IN.groupID.x, IN.groupID.y + 1) * BLOCK_SIZE, fMinDepth, 1.0f));
|
||||
float3 maxAABB = ScreenToView(float4(float2(IN.groupID.x + 1, IN.groupID.y) * BLOCK_SIZE, fMaxDepth, 1.0f));
|
||||
float3 minAABB = ScreenToView(float4(float2(IN.groupID.x, IN.groupID.y + 1) * BLOCK_SIZE, fMinDepth, 1.0f)).xyz;
|
||||
float3 maxAABB = ScreenToView(float4(float2(IN.groupID.x + 1, IN.groupID.y) * BLOCK_SIZE, fMaxDepth, 1.0f)).xyz;
|
||||
|
||||
GroupAABB.c = (minAABB + maxAABB)*0.5f;
|
||||
GroupAABB.e = abs(maxAABB - GroupAABB.c);
|
||||
@@ -170,7 +170,7 @@ void main(ComputeShaderInput IN)
|
||||
// Add light to light list for opaque geometry.
|
||||
o_AppendLight(i);
|
||||
#ifdef DEBUG_TILEDLIGHTCULLING
|
||||
//InterlockedAdd(_counter.x, 1);
|
||||
InterlockedAdd(_counter.x, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -184,6 +184,30 @@ void main(ComputeShaderInput IN)
|
||||
o_AppendLight(i);
|
||||
}
|
||||
break;
|
||||
case 100:/*DECAL*/
|
||||
{
|
||||
Sphere sphere = { light.positionVS.xyz, light.range };
|
||||
if (SphereInsideFrustum(sphere, GroupFrustum, nearClipVS, maxDepthVS))
|
||||
{
|
||||
// Add decal to light list for transparent geometry.
|
||||
t_AppendLight(i);
|
||||
|
||||
#ifdef DEBUG_TILEDLIGHTCULLING
|
||||
InterlockedAdd(_counter.z, 1);
|
||||
#endif
|
||||
|
||||
if (SphereInsideFrustum(sphere, GroupFrustum, minDepthVS, maxDepthVS))
|
||||
{
|
||||
// Add decal to light list for opaque geometry.
|
||||
o_AppendLight(i);
|
||||
|
||||
#ifdef DEBUG_TILEDLIGHTCULLING
|
||||
InterlockedAdd(_counter.x, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ struct LightArrayType
|
||||
float coneAngle;
|
||||
float coneAngleCos;
|
||||
// --
|
||||
float4 texMulAdd;
|
||||
// --
|
||||
float4x4 shadowMat[3];
|
||||
};
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ inline void DirectionalLight(in float3 N, in float3 V, in float3 P, in float3 f0
|
||||
}
|
||||
|
||||
|
||||
inline void TiledLighting(in float2 pixel, in float3 N, in float3 V, in float3 P, in float3 f0, in float3 albedo, in float roughness,
|
||||
inline void TiledLighting(in float2 pixel, in float3 N, in float3 V, in float3 P, in float3 f0, inout float3 albedo, in float roughness,
|
||||
inout float3 diffuse, out float3 specular)
|
||||
{
|
||||
uint2 tileIndex = uint2(floor(pixel / BLOCK_SIZE));
|
||||
@@ -137,7 +137,7 @@ inline void TiledLighting(in float2 pixel, in float3 N, in float3 V, in float3 P
|
||||
|
||||
float3 L = light.positionWS - P;
|
||||
float lightDistance = length(L);
|
||||
if (light.type > 0 && lightDistance > light.range)
|
||||
if (light.type > 0 && light.type != 100 && lightDistance > light.range)
|
||||
continue;
|
||||
L /= lightDistance;
|
||||
|
||||
@@ -159,6 +159,26 @@ inline void TiledLighting(in float2 pixel, in float3 N, in float3 V, in float3 P
|
||||
result = SpotLight(light, L, lightDistance, N, V, P, roughness, f0);
|
||||
}
|
||||
break;
|
||||
#ifndef DISABLE_DECALS
|
||||
case 100/*DECAL*/:
|
||||
{
|
||||
float3 clipSpace = mul(float4(P, 1), light.shadowMat[0]).xyz;
|
||||
float3 projTex = clipSpace.xyz*float3(0.5f, -0.5f, 0.5f) + 0.5f;
|
||||
[branch]
|
||||
if ((saturate(projTex.x) == projTex.x) && (saturate(projTex.y) == projTex.y) && (saturate(projTex.z) == projTex.z))
|
||||
{
|
||||
// can't do mipmapping here because of the variable length loop :(
|
||||
float4 decalColor = texture_decalatlas.SampleLevel(sampler_linear_clamp, projTex.xy*light.texMulAdd.xy + light.texMulAdd.zw, 0);
|
||||
float3 edgeBlend = clipSpace.xyz;
|
||||
edgeBlend = saturate(abs(edgeBlend));
|
||||
decalColor.a *= 1 - pow(max(max(edgeBlend.x, edgeBlend.y), edgeBlend.z), 8);
|
||||
decalColor *= light.color;
|
||||
albedo.rgb = lerp(albedo.rgb, decalColor.rgb, decalColor.a);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:break;
|
||||
}
|
||||
|
||||
diffuse += max(0.0f, result.diffuse);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#define DISABLE_DECALS
|
||||
#define DIRECTIONALLIGHT_SOFT
|
||||
#define DISABLE_ALPHATEST
|
||||
#include "objectHF.hlsli"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#define DISABLE_DECALS
|
||||
#include "grassHF_GS.hlsli"
|
||||
#include "grassHF_PS.hlsli"
|
||||
#include "ditherHF.hlsli"
|
||||
|
||||
@@ -255,4 +255,4 @@ enum BSTYPES
|
||||
BSTYPE_ADDITIVE,
|
||||
BSTYPE_COLORWRITEDISABLE,
|
||||
BSTYPE_LAST
|
||||
};
|
||||
};
|
||||
|
||||
@@ -127,6 +127,7 @@ namespace wiGraphicsTypes
|
||||
virtual void Dispatch(UINT threadGroupCountX, UINT threadGroupCountY, UINT threadGroupCountZ, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) = 0;
|
||||
virtual void GenerateMips(Texture* texture, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) = 0;
|
||||
virtual void CopyTexture2D(Texture2D* pDst, const Texture2D* pSrc, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) = 0;
|
||||
virtual void CopyTexture2D_Region(Texture2D* pDst, UINT dstMip, UINT dstX, UINT dstY, const Texture2D* pSrc, UINT srcMip, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) = 0;
|
||||
virtual void MSAAResolve(Texture2D* pDst, const Texture2D* pSrc, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) = 0;
|
||||
virtual void UpdateBuffer(GPUBuffer* buffer, const void* data, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE, int dataSize = -1) = 0;
|
||||
virtual GPUBuffer* DownloadBuffer(GPUBuffer* buffer, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) = 0;
|
||||
|
||||
@@ -2521,6 +2521,11 @@ void GraphicsDevice_DX11::CopyTexture2D(Texture2D* pDst, const Texture2D* pSrc,
|
||||
{
|
||||
deviceContexts[threadID]->CopyResource(pDst->texture2D_DX11, pSrc->texture2D_DX11);
|
||||
}
|
||||
void GraphicsDevice_DX11::CopyTexture2D_Region(Texture2D* pDst, UINT dstMip, UINT dstX, UINT dstY, const Texture2D* pSrc, UINT srcMip, GRAPHICSTHREAD threadID)
|
||||
{
|
||||
deviceContexts[threadID]->CopySubresourceRegion(pDst->texture2D_DX11, D3D11CalcSubresource(dstMip, 0, pDst->GetDesc().MipLevels), dstX, dstY, 0,
|
||||
pSrc->texture2D_DX11, D3D11CalcSubresource(srcMip, 0, pSrc->GetDesc().MipLevels), nullptr);
|
||||
}
|
||||
void GraphicsDevice_DX11::MSAAResolve(Texture2D* pDst, const Texture2D* pSrc, GRAPHICSTHREAD threadID)
|
||||
{
|
||||
deviceContexts[threadID]->ResolveSubresource(pDst->texture2D_DX11, 0, pSrc->texture2D_DX11, 0, _ConvertFormat(pDst->desc.Format));
|
||||
|
||||
@@ -121,6 +121,7 @@ namespace wiGraphicsTypes
|
||||
virtual void Dispatch(UINT threadGroupCountX, UINT threadGroupCountY, UINT threadGroupCountZ, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) override;
|
||||
virtual void GenerateMips(Texture* texture, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) override;
|
||||
virtual void CopyTexture2D(Texture2D* pDst, const Texture2D* pSrc, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) override;
|
||||
virtual void CopyTexture2D_Region(Texture2D* pDst, UINT dstMip, UINT dstX, UINT dstY, const Texture2D* pSrc, UINT srcMip, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) override;
|
||||
virtual void MSAAResolve(Texture2D* pDst, const Texture2D* pSrc, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) override;
|
||||
virtual void UpdateBuffer(GPUBuffer* buffer, const void* data, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE, int dataSize = -1) override;
|
||||
virtual GPUBuffer* DownloadBuffer(GPUBuffer* buffer, GRAPHICSTHREAD threadID = GRAPHICSTHREAD_IMMEDIATE) override;
|
||||
|
||||
@@ -255,7 +255,7 @@ namespace wiGraphicsTypes
|
||||
Texture2D();
|
||||
virtual ~Texture2D();
|
||||
|
||||
Texture2DDesc GetDesc() { return desc; }
|
||||
Texture2DDesc GetDesc() const { return desc; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -3594,6 +3594,8 @@ Decal::Decal(const XMFLOAT3& tra, const XMFLOAT3& sca, const XMFLOAT4& rot, cons
|
||||
|
||||
life = -2; //persistent
|
||||
fadeStart=0;
|
||||
|
||||
atlasMulAdd = XMFLOAT4(1, 1, 0, 0);
|
||||
}
|
||||
Decal::~Decal() {
|
||||
wiResourceManager::GetGlobal()->del(texName);
|
||||
@@ -3629,6 +3631,10 @@ void Decal::UpdateDecal()
|
||||
life -= wiRenderer::GetGameSpeed();
|
||||
}
|
||||
}
|
||||
float Decal::GetOpacity() const
|
||||
{
|
||||
return wiMath::Clamp((life <= -2 ? 1 : life < fadeStart ? life / fadeStart : 1), 0, 1);
|
||||
}
|
||||
void Decal::Serialize(wiArchive& archive)
|
||||
{
|
||||
Cullable::Serialize(archive);
|
||||
|
||||
@@ -771,6 +771,7 @@ struct Decal : public Cullable, public Transform
|
||||
wiGraphicsTypes::Texture2D* texture,*normal;
|
||||
XMFLOAT3 front;
|
||||
float life,fadeStart;
|
||||
XMFLOAT4 atlasMulAdd;
|
||||
|
||||
Decal(const XMFLOAT3& tra=XMFLOAT3(0,0,0), const XMFLOAT3& sca=XMFLOAT3(1,1,1), const XMFLOAT4& rot=XMFLOAT4(0,0,0,1), const string& tex="", const string& nor="");
|
||||
virtual ~Decal();
|
||||
@@ -779,6 +780,7 @@ struct Decal : public Cullable, public Transform
|
||||
void addNormal(const string& nor);
|
||||
virtual void UpdateTransform();
|
||||
void UpdateDecal();
|
||||
float GetOpacity() const;
|
||||
void Serialize(wiArchive& archive);
|
||||
};
|
||||
struct WorldInfo{
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
#pragma once
|
||||
#include "wiRectPacker.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace wiRectPacker
|
||||
{
|
||||
|
||||
bool area(rect_xywhf* a, rect_xywhf* b) {
|
||||
return a->area() > b->area();
|
||||
}
|
||||
|
||||
bool perimeter(rect_xywhf* a, rect_xywhf* b) {
|
||||
return a->perimeter() > b->perimeter();
|
||||
}
|
||||
|
||||
bool max_side(rect_xywhf* a, rect_xywhf* b) {
|
||||
return std::max(a->w, a->h) > std::max(b->w, b->h);
|
||||
}
|
||||
|
||||
bool max_width(rect_xywhf* a, rect_xywhf* b) {
|
||||
return a->w > b->w;
|
||||
}
|
||||
|
||||
bool max_height(rect_xywhf* a, rect_xywhf* b) {
|
||||
return a->h > b->h;
|
||||
}
|
||||
|
||||
|
||||
// just add another comparing function name to cmpf to perform another packing attempt
|
||||
// more functions == slower but probably more efficient cases covered and hence less area wasted
|
||||
|
||||
bool(*cmpf[])(rect_xywhf*, rect_xywhf*) = {
|
||||
area,
|
||||
perimeter,
|
||||
max_side,
|
||||
max_width,
|
||||
max_height
|
||||
};
|
||||
|
||||
// if you find the algorithm running too slow you may double this factor to increase speed but also decrease efficiency
|
||||
// 1 == most efficient, slowest
|
||||
// efficiency may be still satisfying at 64 or even 256 with nice speedup
|
||||
|
||||
int discard_step = 128;
|
||||
|
||||
/*
|
||||
|
||||
For every sorting function, algorithm will perform packing attempts beginning with a bin with width and height equal to max_side,
|
||||
and decreasing its dimensions if it finds out that rectangles did actually fit, increasing otherwise.
|
||||
Although, it's doing that in sort of binary search manner, so for every comparing function it will perform at most log2(max_side) packing attempts looking for the smallest possible bin size.
|
||||
discard_step = 128 means that the algorithm will break of the searching loop if the rectangles fit but "it may be possible to fit them in a bin smaller by 128"
|
||||
the bigger the value, the sooner the algorithm will finish but the rectangles will be packed less tightly.
|
||||
use discard_step = 1 for maximum tightness.
|
||||
|
||||
the algorithm was based on http://www.blackpawn.com/texts/lightmaps/default.html
|
||||
the algorithm reuses the node tree so it doesn't reallocate them between searching attempts
|
||||
|
||||
*/
|
||||
|
||||
/*************************************************************************** CHAOS BEGINS HERE */
|
||||
|
||||
struct node {
|
||||
struct pnode {
|
||||
node* pn;
|
||||
bool fill;
|
||||
|
||||
pnode() : fill(false), pn(0) {}
|
||||
void set(int l, int t, int r, int b) {
|
||||
if (!pn) pn = new node(rect_ltrb(l, t, r, b));
|
||||
else {
|
||||
(*pn).rc = rect_ltrb(l, t, r, b);
|
||||
(*pn).id = false;
|
||||
}
|
||||
fill = true;
|
||||
}
|
||||
};
|
||||
|
||||
pnode c[2];
|
||||
rect_ltrb rc;
|
||||
bool id;
|
||||
node(rect_ltrb rc = rect_ltrb()) : id(false), rc(rc) {}
|
||||
|
||||
void reset(const rect_wh& r) {
|
||||
id = false;
|
||||
rc = rect_ltrb(0, 0, r.w, r.h);
|
||||
delcheck();
|
||||
}
|
||||
|
||||
node* insert(rect_xywhf& img) {
|
||||
if (c[0].pn && c[0].fill) {
|
||||
node* newn;
|
||||
if (newn = c[0].pn->insert(img)) return newn;
|
||||
return c[1].pn->insert(img);
|
||||
}
|
||||
|
||||
if (id) return 0;
|
||||
int f = img.fits(rect_xywh(rc));
|
||||
|
||||
switch (f) {
|
||||
case 0: return 0;
|
||||
case 1: img.flipped = false; break;
|
||||
case 2: img.flipped = true; break;
|
||||
case 3: id = true; img.flipped = false; return this;
|
||||
case 4: id = true; img.flipped = true; return this;
|
||||
}
|
||||
|
||||
int iw = (img.flipped ? img.h : img.w), ih = (img.flipped ? img.w : img.h);
|
||||
|
||||
if (rc.w() - iw > rc.h() - ih) {
|
||||
c[0].set(rc.l, rc.t, rc.l + iw, rc.b);
|
||||
c[1].set(rc.l + iw, rc.t, rc.r, rc.b);
|
||||
}
|
||||
else {
|
||||
c[0].set(rc.l, rc.t, rc.r, rc.t + ih);
|
||||
c[1].set(rc.l, rc.t + ih, rc.r, rc.b);
|
||||
}
|
||||
|
||||
return c[0].pn->insert(img);
|
||||
}
|
||||
|
||||
void delcheck() {
|
||||
if (c[0].pn) { c[0].fill = false; c[0].pn->delcheck(); }
|
||||
if (c[1].pn) { c[1].fill = false; c[1].pn->delcheck(); }
|
||||
}
|
||||
|
||||
~node() {
|
||||
if (c[0].pn) delete c[0].pn;
|
||||
if (c[1].pn) delete c[1].pn;
|
||||
}
|
||||
};
|
||||
|
||||
rect_wh _rect2D(rect_xywhf* const * v, int n, int max_s, vector<rect_xywhf*>& succ, vector<rect_xywhf*>& unsucc) {
|
||||
node root;
|
||||
|
||||
const int funcs = (sizeof(cmpf) / sizeof(bool(*)(rect_xywhf*, rect_xywhf*)));
|
||||
|
||||
rect_xywhf** order[funcs];
|
||||
|
||||
for (int f = 0; f < funcs; ++f) {
|
||||
order[f] = new rect_xywhf*[n];
|
||||
memcpy(order[f], v, sizeof(rect_xywhf*) * n);
|
||||
sort(order[f], order[f] + n, cmpf[f]);
|
||||
}
|
||||
|
||||
rect_wh min_bin = rect_wh(max_s, max_s);
|
||||
int min_func = -1, best_func = 0, best_area = 0, _area = 0, step, fit, i;
|
||||
|
||||
bool fail = false;
|
||||
|
||||
for (int f = 0; f < funcs; ++f) {
|
||||
v = order[f];
|
||||
step = min_bin.w / 2;
|
||||
root.reset(min_bin);
|
||||
|
||||
while (true) {
|
||||
if (root.rc.w() > min_bin.w) {
|
||||
if (min_func > -1) break;
|
||||
_area = 0;
|
||||
|
||||
root.reset(min_bin);
|
||||
for (i = 0; i < n; ++i)
|
||||
if (root.insert(*v[i]))
|
||||
_area += v[i]->area();
|
||||
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
|
||||
fit = -1;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
if (!root.insert(*v[i])) {
|
||||
fit = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fit == -1 && step <= discard_step)
|
||||
break;
|
||||
|
||||
root.reset(rect_wh(root.rc.w() + fit*step, root.rc.h() + fit*step));
|
||||
|
||||
step /= 2;
|
||||
if (!step)
|
||||
step = 1;
|
||||
}
|
||||
|
||||
if (!fail && (min_bin.area() >= root.rc.area())) {
|
||||
min_bin = rect_wh(root.rc);
|
||||
min_func = f;
|
||||
}
|
||||
|
||||
else if (fail && (_area > best_area)) {
|
||||
best_area = _area;
|
||||
best_func = f;
|
||||
}
|
||||
fail = false;
|
||||
}
|
||||
|
||||
v = order[min_func == -1 ? best_func : min_func];
|
||||
|
||||
int clip_x = 0, clip_y = 0;
|
||||
node* ret;
|
||||
|
||||
root.reset(min_bin);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (ret = root.insert(*v[i])) {
|
||||
v[i]->x = ret->rc.l;
|
||||
v[i]->y = ret->rc.t;
|
||||
|
||||
if (v[i]->flipped) {
|
||||
v[i]->flipped = false;
|
||||
v[i]->flip();
|
||||
}
|
||||
|
||||
clip_x = std::max(clip_x, ret->rc.r);
|
||||
clip_y = std::max(clip_y, ret->rc.b);
|
||||
|
||||
succ.push_back(v[i]);
|
||||
}
|
||||
else {
|
||||
unsucc.push_back(v[i]);
|
||||
|
||||
v[i]->flipped = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int f = 0; f < funcs; ++f)
|
||||
delete[] order[f];
|
||||
|
||||
return rect_wh(clip_x, clip_y);
|
||||
}
|
||||
|
||||
|
||||
bool pack(rect_xywhf* const * v, int n, int max_s, vector<bin>& bins) {
|
||||
rect_wh _rect(max_s, max_s);
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
if (!v[i]->fits(_rect)) return false;
|
||||
|
||||
vector<rect_xywhf*> vec[2], *p[2] = { vec, vec + 1 };
|
||||
vec[0].resize(n);
|
||||
vec[1].clear();
|
||||
memcpy(&vec[0][0], v, sizeof(rect_xywhf*)*n);
|
||||
|
||||
bin* b = 0;
|
||||
|
||||
while (true) {
|
||||
bins.push_back(bin());
|
||||
b = &bins[bins.size() - 1];
|
||||
|
||||
b->size = _rect2D(&((*p[0])[0]), p[0]->size(), max_s, b->rects, *p[1]);
|
||||
b->rects.shrink_to_fit();
|
||||
p[0]->clear();
|
||||
|
||||
if (!p[1]->size()) break;
|
||||
|
||||
std::swap(p[0], p[1]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
rect_wh::rect_wh(const rect_ltrb& rr) : w(rr.w()), h(rr.h()) {}
|
||||
rect_wh::rect_wh(const rect_xywh& rr) : w(rr.w), h(rr.h) {}
|
||||
rect_wh::rect_wh(int w, int h) : w(w), h(h) {}
|
||||
|
||||
int rect_wh::fits(const rect_wh& r) const {
|
||||
if (w == r.w && h == r.h) return 3;
|
||||
if (h == r.w && w == r.h) return 4;
|
||||
if (w <= r.w && h <= r.h) return 1;
|
||||
if (h <= r.w && w <= r.h) return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rect_ltrb::rect_ltrb() : l(0), t(0), r(0), b(0) {}
|
||||
rect_ltrb::rect_ltrb(int l, int t, int r, int b) : l(l), t(t), r(r), b(b) {}
|
||||
|
||||
int rect_ltrb::w() const {
|
||||
return r - l;
|
||||
}
|
||||
|
||||
int rect_ltrb::h() const {
|
||||
return b - t;
|
||||
}
|
||||
|
||||
int rect_ltrb::area() const {
|
||||
return w()*h();
|
||||
}
|
||||
|
||||
int rect_ltrb::perimeter() const {
|
||||
return 2 * w() + 2 * h();
|
||||
}
|
||||
|
||||
void rect_ltrb::w(int ww) {
|
||||
r = l + ww;
|
||||
}
|
||||
|
||||
void rect_ltrb::h(int hh) {
|
||||
b = t + hh;
|
||||
}
|
||||
|
||||
rect_xywh::rect_xywh() : x(0), y(0) {}
|
||||
rect_xywh::rect_xywh(const rect_ltrb& rc) : x(rc.l), y(rc.t) { b(rc.b); r(rc.r); }
|
||||
rect_xywh::rect_xywh(int x, int y, int w, int h) : x(x), y(y), rect_wh(w, h) {}
|
||||
|
||||
rect_xywh::operator rect_ltrb() {
|
||||
rect_ltrb rr(x, y, 0, 0);
|
||||
rr.w(w); rr.h(h);
|
||||
return rr;
|
||||
}
|
||||
|
||||
int rect_xywh::r() const {
|
||||
return x + w;
|
||||
};
|
||||
|
||||
int rect_xywh::b() const {
|
||||
return y + h;
|
||||
}
|
||||
|
||||
void rect_xywh::r(int right) {
|
||||
w = right - x;
|
||||
}
|
||||
|
||||
void rect_xywh::b(int bottom) {
|
||||
h = bottom - y;
|
||||
}
|
||||
|
||||
int rect_wh::area() {
|
||||
return w*h;
|
||||
}
|
||||
|
||||
int rect_wh::perimeter() {
|
||||
return 2 * w + 2 * h;
|
||||
}
|
||||
|
||||
|
||||
rect_xywhf::rect_xywhf(const rect_ltrb& rr) : rect_xywh(rr), flipped(false) {}
|
||||
rect_xywhf::rect_xywhf(int x, int y, int width, int height) : rect_xywh(x, y, width, height), flipped(false) {}
|
||||
rect_xywhf::rect_xywhf() : flipped(false) {}
|
||||
|
||||
void rect_xywhf::flip() {
|
||||
flipped = !flipped;
|
||||
std::swap(w, h);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
|
||||
// NOTE:
|
||||
// This is based on the rectpack2D library hosted here: https://github.com/TeamHypersomnia/rectpack2D
|
||||
|
||||
/* of your interest:
|
||||
|
||||
1. rect_xywhf - structure representing your rectangle object
|
||||
members:
|
||||
int x, y, w, h;
|
||||
bool flipped;
|
||||
|
||||
2. bin - structure representing resultant bin object
|
||||
3. bool pack(rect_xywhf* const * v, int n, int max_side, std::vector<bin>& bins) - actual packing function
|
||||
Arguments:
|
||||
input/output: v - pointer to array of pointers to your rectangles (const here means that the pointers will point to the same rectangles after the call)
|
||||
input: n - rectangles count
|
||||
|
||||
input: max_side - maximum bins' side - algorithm works with square bins (in the end it may trim them to rectangular form).
|
||||
for the algorithm to finish faster, pass a reasonable value (unreasonable would be passing 1 000 000 000 for packing 4 50x50 rectangles).
|
||||
output: bins - vector to which the function will push_back() created bins, each of them containing vector to pointers of rectangles from "v" belonging to that particular bin.
|
||||
Every bin also keeps information about its width and height of course, none of the dimensions is bigger than max_side.
|
||||
|
||||
returns true on success, false if one of the rectangles' dimension was bigger than max_side
|
||||
|
||||
You want to your rectangles representing your textures/glyph objects with GL_MAX_TEXTURE_SIZE as max_side,
|
||||
then for each bin iterate through its rectangles, typecast each one to your own structure (or manually add userdata) and then memcpy its pixel contents (rotated by 90 degrees if "flipped" rect_xywhf's member is true)
|
||||
to the array representing your texture atlas to the place specified by the rectangle, then finally upload it with glTexImage2D.
|
||||
|
||||
Algorithm doesn't create any new rectangles.
|
||||
You just pass an array of pointers - rectangles' x/y/w/h/flipped are modified in place.
|
||||
There is a vector of pointers for every resultant bin to let you know which ones belong to the particular bin.
|
||||
The algorithm may swap the w and h fields for the sake of better fitting, the flag "flipped" will be set to true whenever this occurs.
|
||||
|
||||
For description how to tune the algorithm and how it actually works see the .cpp file.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
namespace wiRectPacker
|
||||
{
|
||||
|
||||
struct rect_ltrb;
|
||||
struct rect_xywh;
|
||||
|
||||
struct rect_wh {
|
||||
rect_wh(const rect_ltrb&);
|
||||
rect_wh(const rect_xywh&);
|
||||
rect_wh(int w = 0, int h = 0);
|
||||
int w, h, area(), perimeter(),
|
||||
fits(const rect_wh& bigger) const; // 0 - no, 1 - yes, 2 - flipped, 3 - perfectly, 4 perfectly flipped
|
||||
};
|
||||
|
||||
// rectangle implementing left/top/right/bottom behaviour
|
||||
|
||||
struct rect_ltrb {
|
||||
rect_ltrb();
|
||||
rect_ltrb(int left, int top, int right, int bottom);
|
||||
int l, t, r, b, w() const, h() const, area() const, perimeter() const;
|
||||
void w(int), h(int);
|
||||
};
|
||||
|
||||
struct rect_xywh : public rect_wh {
|
||||
rect_xywh();
|
||||
rect_xywh(const rect_ltrb&);
|
||||
rect_xywh(int x, int y, int width, int height);
|
||||
operator rect_ltrb();
|
||||
|
||||
int x, y, r() const, b() const;
|
||||
void r(int), b(int);
|
||||
};
|
||||
|
||||
struct rect_xywhf : public rect_xywh {
|
||||
rect_xywhf(const rect_ltrb&);
|
||||
rect_xywhf(int x, int y, int width, int height);
|
||||
rect_xywhf();
|
||||
void flip();
|
||||
bool flipped;
|
||||
};
|
||||
|
||||
|
||||
struct bin {
|
||||
rect_wh size;
|
||||
std::vector<rect_xywhf*> rects;
|
||||
};
|
||||
|
||||
bool pack(rect_xywhf* const * v, int n, int max_side, std::vector<bin>& bins);
|
||||
|
||||
}
|
||||
+146
-27
@@ -23,6 +23,8 @@
|
||||
#include "wiGraphicsDevice_DX11.h"
|
||||
#include "wiTranslator.h"
|
||||
#include "lightCullingCSInterop.h"
|
||||
#include "wiRectPacker.h"
|
||||
#include "wiBackLog.h"
|
||||
|
||||
using namespace wiGraphicsTypes;
|
||||
|
||||
@@ -1409,6 +1411,7 @@ void wiRenderer::UpdatePerFrameData()
|
||||
culling.culledLights.clear();
|
||||
culling.culledLight_count = 0;
|
||||
culling.culledEmittedParticleSystems.clear();
|
||||
culling.culledDecals.clear();
|
||||
|
||||
if (spTree != nullptr)
|
||||
{
|
||||
@@ -1506,6 +1509,20 @@ void wiRenderer::UpdatePerFrameData()
|
||||
std::sort(culling.culledEmittedParticleSystems.begin(), culling.culledEmittedParticleSystems.end(), [&](const wiEmittedParticle* a, const wiEmittedParticle* b) {
|
||||
return wiMath::DistanceSquared(camera->translation, a->bounding_box->getCenter()) > wiMath::DistanceSquared(camera->translation,b->bounding_box->getCenter());
|
||||
});
|
||||
|
||||
for (Model* model : GetScene().models)
|
||||
{
|
||||
if (model->decals.empty())
|
||||
continue;
|
||||
|
||||
for (Decal* decal : model->decals)
|
||||
{
|
||||
if ((decal->texture || decal->normal) && getCamera()->frustum.CheckBox(decal->bounds))
|
||||
{
|
||||
x.second.culledDecals.push_back(decal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
refCam->Reflect(cam, waterPlane.getXMFLOAT4());
|
||||
@@ -1644,6 +1661,8 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID)
|
||||
|
||||
|
||||
const FrameCulling& mainCameraCulling = frameCullings[getCamera()];
|
||||
|
||||
ManageDecalAtlas(threadID);
|
||||
|
||||
// Fill Light Array with lights in the frustum
|
||||
{
|
||||
@@ -1703,11 +1722,30 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID)
|
||||
lightCounter++;
|
||||
if (lightCounter == MAX_LIGHTS)
|
||||
{
|
||||
assert(0 && "Maximum Lightcount exceeded for a single tiled lightculling pass! Please redefine MAX_LIGHTS to fit!");
|
||||
lightCounter--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lightCounter < MAX_LIGHTS)
|
||||
{
|
||||
for (Decal* decal : mainCameraCulling.culledDecals)
|
||||
{
|
||||
XMStoreFloat3(&lightArray[lightCounter].posVS, XMVector3TransformCoord(XMLoadFloat3(&decal->translation), viewMatrix));
|
||||
lightArray[lightCounter].distance = max(decal->scale.x, max(decal->scale.y, decal->scale.z)) * 2;
|
||||
lightArray[lightCounter].shadowMatrix[0] = XMMatrixTranspose(XMMatrixInverse(nullptr, XMLoadFloat4x4(&decal->world)));
|
||||
lightArray[lightCounter].texMulAdd = decal->atlasMulAdd;
|
||||
lightArray[lightCounter].col = XMFLOAT4(1, 1, 1, decal->GetOpacity());
|
||||
lightArray[lightCounter].type = 100;
|
||||
|
||||
lightCounter++;
|
||||
if (lightCounter == MAX_LIGHTS)
|
||||
{
|
||||
lightCounter--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(lightCounter < MAX_LIGHTS && "Maximum Lightcount exceeded for a single tiled lightculling pass! Please redefine MAX_LIGHTS to fit!");
|
||||
GetDevice()->UpdateBuffer(resourceBuffers[RBTYPE_LIGHTARRAY], lightArray, threadID, (int)(sizeof(LightArrayType)*lightCounter));
|
||||
}
|
||||
|
||||
@@ -1817,7 +1855,8 @@ void wiRenderer::OcclusionCulling_Read()
|
||||
GetDevice()->EventEnd();
|
||||
}
|
||||
}
|
||||
void wiRenderer::UpdateImages(){
|
||||
void wiRenderer::UpdateImages()
|
||||
{
|
||||
for (wiSprite* x : images)
|
||||
x->Update(GameSpeed);
|
||||
for (wiSprite* x : waterRipples)
|
||||
@@ -1826,12 +1865,13 @@ void wiRenderer::UpdateImages(){
|
||||
ManageImages();
|
||||
ManageWaterRipples();
|
||||
}
|
||||
void wiRenderer::ManageImages(){
|
||||
while(
|
||||
!images.empty() &&
|
||||
(images.front()->effects.opacity <= 0 + FLT_EPSILON || images.front()->effects.fade==1)
|
||||
)
|
||||
images.pop_front();
|
||||
void wiRenderer::ManageImages()
|
||||
{
|
||||
while (!images.empty() &&
|
||||
(images.front()->effects.opacity <= 0 + FLT_EPSILON || images.front()->effects.fade == 1))
|
||||
{
|
||||
images.pop_front();
|
||||
}
|
||||
}
|
||||
void wiRenderer::PutDecal(Decal* decal)
|
||||
{
|
||||
@@ -3492,41 +3532,43 @@ void wiRenderer::DrawSun(GRAPHICSTHREAD threadID)
|
||||
|
||||
void wiRenderer::DrawDecals(Camera* camera, GRAPHICSTHREAD threadID)
|
||||
{
|
||||
GraphicsDevice* device = GetDevice();
|
||||
|
||||
bool boundCB = false;
|
||||
for (Model* model : GetScene().models)
|
||||
{
|
||||
if (model->decals.empty())
|
||||
continue;
|
||||
|
||||
GetDevice()->EventBegin(L"Decals", threadID);
|
||||
device->EventBegin(L"Decals", threadID);
|
||||
|
||||
if (!boundCB)
|
||||
{
|
||||
boundCB = true;
|
||||
GetDevice()->BindConstantBufferPS(constantBuffers[CBTYPE_DECAL], CB_GETBINDSLOT(DecalCB),threadID);
|
||||
device->BindConstantBufferPS(constantBuffers[CBTYPE_DECAL], CB_GETBINDSLOT(DecalCB),threadID);
|
||||
}
|
||||
|
||||
//BindResourcePS(depth, 1, threadID);
|
||||
GetDevice()->BindVS(vertexShaders[VSTYPE_DECAL], threadID);
|
||||
GetDevice()->BindPS(pixelShaders[PSTYPE_DECAL], threadID);
|
||||
GetDevice()->BindRasterizerState(rasterizers[RSTYPE_BACK], threadID);
|
||||
GetDevice()->BindBlendState(blendStates[BSTYPE_TRANSPARENT], threadID);
|
||||
GetDevice()->BindDepthStencilState(depthStencils[DSSTYPE_STENCILREAD_MATCH], STENCILREF::STENCILREF_DEFAULT, threadID);
|
||||
GetDevice()->BindVertexLayout(nullptr, threadID);
|
||||
GetDevice()->BindPrimitiveTopology(PRIMITIVETOPOLOGY::TRIANGLELIST, threadID);
|
||||
device->BindVS(vertexShaders[VSTYPE_DECAL], threadID);
|
||||
device->BindPS(pixelShaders[PSTYPE_DECAL], threadID);
|
||||
device->BindRasterizerState(rasterizers[RSTYPE_BACK], threadID);
|
||||
device->BindBlendState(blendStates[BSTYPE_TRANSPARENT], threadID);
|
||||
device->BindDepthStencilState(depthStencils[DSSTYPE_STENCILREAD_MATCH], STENCILREF::STENCILREF_DEFAULT, threadID);
|
||||
device->BindVertexLayout(nullptr, threadID);
|
||||
device->BindPrimitiveTopology(PRIMITIVETOPOLOGY::TRIANGLELIST, threadID);
|
||||
|
||||
for (Decal* decal : model->decals) {
|
||||
for (Decal* decal : model->decals)
|
||||
{
|
||||
|
||||
if ((decal->texture || decal->normal) && camera->frustum.CheckBox(decal->bounds)) {
|
||||
|
||||
GetDevice()->BindResourcePS(decal->texture, TEXSLOT_ONDEMAND0, threadID);
|
||||
GetDevice()->BindResourcePS(decal->normal, TEXSLOT_ONDEMAND1, threadID);
|
||||
device->BindResourcePS(decal->texture, TEXSLOT_ONDEMAND0, threadID);
|
||||
device->BindResourcePS(decal->normal, TEXSLOT_ONDEMAND1, threadID);
|
||||
|
||||
XMMATRIX decalWorld = XMLoadFloat4x4(&decal->world);
|
||||
|
||||
MiscCB dcbvs;
|
||||
dcbvs.mTransform =XMMatrixTranspose(decalWorld*camera->GetViewProjection());
|
||||
GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_MISC], &dcbvs, threadID);
|
||||
device->UpdateBuffer(constantBuffers[CBTYPE_MISC], &dcbvs, threadID);
|
||||
|
||||
DecalCB dcbps;
|
||||
dcbps.mDecalVP = XMMatrixTranspose(XMMatrixInverse(nullptr, decalWorld));
|
||||
@@ -3536,17 +3578,17 @@ void wiRenderer::DrawDecals(Camera* camera, GRAPHICSTHREAD threadID)
|
||||
if (decal->normal != nullptr)
|
||||
dcbps.hasTexNor |= 0x0000010;
|
||||
XMStoreFloat3(&dcbps.eye, camera->GetEye());
|
||||
dcbps.opacity = wiMath::Clamp((decal->life <= -2 ? 1 : decal->life < decal->fadeStart ? decal->life / decal->fadeStart : 1), 0, 1);
|
||||
dcbps.opacity = decal->GetOpacity();
|
||||
dcbps.front = decal->front;
|
||||
GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_DECAL], &dcbps, threadID);
|
||||
device->UpdateBuffer(constantBuffers[CBTYPE_DECAL], &dcbps, threadID);
|
||||
|
||||
GetDevice()->Draw(36, threadID);
|
||||
device->Draw(36, threadID);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GetDevice()->EventEnd(threadID);
|
||||
device->EventEnd(threadID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3668,7 +3710,7 @@ void wiRenderer::ComputeTiledLightCulling(GRAPHICSTHREAD threadID)
|
||||
dispatchParams.numThreadGroups[0] = (UINT)ceilf(dispatchParams.numThreads[0] / (float)BLOCK_SIZE);
|
||||
dispatchParams.numThreadGroups[1] = (UINT)ceilf(dispatchParams.numThreads[1] / (float)BLOCK_SIZE);
|
||||
dispatchParams.numThreadGroups[2] = 1;
|
||||
dispatchParams.value0 = frameCullings[getCamera()].culledLight_count; // light count (forward_list does not have size())
|
||||
dispatchParams.value0 = frameCullings[getCamera()].culledLight_count + (UINT)frameCullings[getCamera()].culledDecals.size(); // light count (forward_list does not have size())
|
||||
device->UpdateBuffer(constantBuffers[CBTYPE_DISPATCHPARAMS], &dispatchParams, threadID);
|
||||
device->BindConstantBufferCS(constantBuffers[CBTYPE_DISPATCHPARAMS], CB_GETBINDSLOT(DispatchParamsCB), threadID);
|
||||
}
|
||||
@@ -3834,6 +3876,83 @@ void wiRenderer::ResolveMSAADepthBuffer(Texture2D* dst, Texture2D* src, GRAPHICS
|
||||
GetDevice()->EventEnd();
|
||||
}
|
||||
|
||||
void wiRenderer::ManageDecalAtlas(GRAPHICSTHREAD threadID)
|
||||
{
|
||||
GraphicsDevice* device = GetDevice();
|
||||
|
||||
static Texture2D* atlasTexture = nullptr;
|
||||
|
||||
for (Model* model : GetScene().models)
|
||||
{
|
||||
if (model->decals.empty())
|
||||
continue;
|
||||
|
||||
for (Decal* decal : model->decals)
|
||||
{
|
||||
using namespace wiRectPacker;
|
||||
static map<Texture2D*, rect_xywhf> storedTextures;
|
||||
|
||||
if (storedTextures.find(decal->texture) == storedTextures.end())
|
||||
{
|
||||
// we need to pack this decal texture into the atlas
|
||||
rect_xywhf newRect = rect_xywhf(0, 0, decal->texture->GetDesc().Width, decal->texture->GetDesc().Height);
|
||||
storedTextures[decal->texture] = newRect;
|
||||
|
||||
rect_xywhf** out_rects = new rect_xywhf*[storedTextures.size()];
|
||||
int i = 0;
|
||||
for (auto& it : storedTextures)
|
||||
{
|
||||
out_rects[i] = &it.second;
|
||||
i++;
|
||||
}
|
||||
|
||||
vector<bin> bins;
|
||||
if (pack(out_rects, (int)storedTextures.size(), 16384, bins))
|
||||
{
|
||||
assert(bins.size() == 1 && "Decal atlas packing into single texture failed!");
|
||||
|
||||
SAFE_DELETE(atlasTexture);
|
||||
|
||||
Texture2DDesc desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.Width = (UINT)bins[0].size.w;
|
||||
desc.Height = (UINT)bins[0].size.h;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = FORMAT_B8G8R8A8_UNORM; // png decals are loaded into this format! todo: DXT!
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Usage = USAGE_DEFAULT;
|
||||
desc.BindFlags = BIND_SHADER_RESOURCE;
|
||||
desc.CPUAccessFlags = 0;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
device->CreateTexture2D(&desc, nullptr, &atlasTexture);
|
||||
|
||||
for (auto& it : storedTextures)
|
||||
{
|
||||
device->CopyTexture2D_Region(atlasTexture, 0, it.second.x, it.second.y, it.first, 0, threadID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wiBackLog::post("Decal atlas packing failed!");
|
||||
}
|
||||
}
|
||||
|
||||
rect_xywhf rect = storedTextures[decal->texture];
|
||||
Texture2DDesc desc = atlasTexture->GetDesc();
|
||||
decal->atlasMulAdd = XMFLOAT4((float)rect.w / (float)desc.Width, (float)rect.h / (float)desc.Height, (float)rect.x / (float)desc.Width, (float)rect.y / (float)desc.Height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (atlasTexture != nullptr)
|
||||
{
|
||||
device->BindResourcePS(atlasTexture, TEXSLOT_DECALATLAS, threadID);
|
||||
}
|
||||
}
|
||||
|
||||
void wiRenderer::UpdateWorldCB(GRAPHICSTHREAD threadID)
|
||||
{
|
||||
static WorldCB prevcb[GRAPHICSTHREAD_COUNT];
|
||||
|
||||
@@ -251,6 +251,7 @@ public:
|
||||
int shadowMap_index;
|
||||
float coneAngle;
|
||||
float coneAngleCos;
|
||||
XMFLOAT4 texMulAdd;
|
||||
XMMATRIX shadowMatrix[3];
|
||||
|
||||
STRUCTUREDBUFFER_SETBINDSLOT(SBSLOT_LIGHTARRAY)
|
||||
@@ -364,6 +365,7 @@ public:
|
||||
CulledList culledLights;
|
||||
UINT culledLight_count; // because forward_list doesn't have size()
|
||||
vector<wiEmittedParticle*> culledEmittedParticleSystems;
|
||||
list<Decal*> culledDecals;
|
||||
};
|
||||
static unordered_map<Camera*, FrameCulling> frameCullings;
|
||||
|
||||
@@ -409,6 +411,8 @@ public:
|
||||
|
||||
static void ComputeTiledLightCulling(GRAPHICSTHREAD threadID);
|
||||
static void ResolveMSAADepthBuffer(wiGraphicsTypes::Texture2D* dst, wiGraphicsTypes::Texture2D* src, GRAPHICSTHREAD threadID);
|
||||
|
||||
static void ManageDecalAtlas(GRAPHICSTHREAD threadID);
|
||||
|
||||
static XMVECTOR GetSunPosition();
|
||||
static XMFLOAT4 GetSunColor();
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace wiVersion
|
||||
// minor features, major updates
|
||||
const int minor = 9;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 51;
|
||||
const int revision = 52;
|
||||
|
||||
|
||||
long GetVersion()
|
||||
|
||||
Reference in New Issue
Block a user