Implemented async gpu query with frame shifting
This commit is contained in:
Binary file not shown.
@@ -44,6 +44,10 @@ runProcess(function()
|
||||
if(input.Press(VK_F6)) then
|
||||
main.GetActiveComponent().SetPreferredThreadingCount(4);
|
||||
end
|
||||
|
||||
if(input.Press(VK_F7)) then
|
||||
LoadModel("C:\\PROJECTS\\WickedEngine\\WickedEngine\\Scene\\Sample\\","scene");
|
||||
end
|
||||
|
||||
update()
|
||||
end
|
||||
|
||||
@@ -42,7 +42,8 @@ namespace wiGraphicsTypes
|
||||
virtual HRESULT CreateDepthStencilState(const DepthStencilStateDesc *pDepthStencilStateDesc, DepthStencilState *pDepthStencilState) = 0;
|
||||
virtual HRESULT CreateRasterizerState(const RasterizerStateDesc *pRasterizerStateDesc, RasterizerState *pRasterizerState) = 0;
|
||||
virtual HRESULT CreateSamplerState(const SamplerDesc *pSamplerDesc, Sampler *pSamplerState) = 0;
|
||||
virtual HRESULT CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery) = 0;
|
||||
// async: don't flush GPU pipeline when performing query, but introduce latency of two frames
|
||||
virtual HRESULT CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery, bool async = true) = 0;
|
||||
|
||||
virtual void PresentBegin() = 0;
|
||||
virtual void PresentEnd() = 0;
|
||||
|
||||
@@ -1308,6 +1308,11 @@ inline Texture2DDesc _ConvertTexture2DDesc_Inv(const D3D11_TEXTURE2D_DESC* pDesc
|
||||
}
|
||||
|
||||
|
||||
// Local Helpers:
|
||||
const void* const __nullBlob[1024] = { 0 }; // this is initialized to nullptrs!
|
||||
#define REQUESTQUERYID ((GetFrameCount() + GPUQuery::ASYNC_LATENCY - 1) % GPUQuery::ASYNC_LATENCY)
|
||||
#define READQUERYID ((GetFrameCount()) % GPUQuery::ASYNC_LATENCY)
|
||||
|
||||
|
||||
|
||||
// Engine functions
|
||||
@@ -1335,11 +1340,7 @@ GraphicsDevice_DX11::GraphicsDevice_DX11(wiWindowRegistration::window_type windo
|
||||
}
|
||||
|
||||
UINT createDeviceFlags = 0;
|
||||
#ifdef _DEBUG
|
||||
#ifndef WINSTORE_SUPPORT
|
||||
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
D3D_DRIVER_TYPE driverTypes[] =
|
||||
{
|
||||
@@ -1532,7 +1533,7 @@ HRESULT GraphicsDevice_DX11::CreateBuffer(const GPUBufferDesc *pDesc, const Subr
|
||||
|
||||
ppBuffer->desc = *pDesc;
|
||||
HRESULT hr = device->CreateBuffer(&desc, data, &ppBuffer->resource_DX11);
|
||||
assert(SUCCEEDED(hr) && "GPUBuffer Creation failed!");
|
||||
assert(SUCCEEDED(hr) && "GPUBuffer creation failed!");
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
@@ -1627,7 +1628,7 @@ HRESULT GraphicsDevice_DX11::CreateTexture2D(const Texture2DDesc* pDesc, const S
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
hr = device->CreateTexture2D(&desc, data, &((*ppTexture2D)->texture2D_DX11));
|
||||
assert(SUCCEEDED(hr) && "Texture2D creating failed!");
|
||||
assert(SUCCEEDED(hr) && "Texture2D creation failed!");
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
@@ -2168,9 +2169,10 @@ HRESULT GraphicsDevice_DX11::CreateSamplerState(const SamplerDesc *pSamplerDesc,
|
||||
pSamplerState->desc = *pSamplerDesc;
|
||||
return device->CreateSamplerState(&desc, &pSamplerState->resource_DX11);
|
||||
}
|
||||
HRESULT GraphicsDevice_DX11::CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery)
|
||||
HRESULT GraphicsDevice_DX11::CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery, bool async)
|
||||
{
|
||||
pQuery->desc = *pDesc;
|
||||
pQuery->async = async;
|
||||
|
||||
D3D11_QUERY_DESC desc;
|
||||
desc.MiscFlags = 0;
|
||||
@@ -2179,7 +2181,23 @@ HRESULT GraphicsDevice_DX11::CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQ
|
||||
{
|
||||
desc.Query = D3D11_QUERY_OCCLUSION;
|
||||
}
|
||||
return device->CreateQuery(&desc, &pQuery->resource_DX11);
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
if (async)
|
||||
{
|
||||
for (int i = 0; i < GPUQuery::ASYNC_LATENCY; ++i)
|
||||
{
|
||||
hr = device->CreateQuery(&desc, &pQuery->resource_DX11[i]);
|
||||
assert(SUCCEEDED(hr) && "GPUQuery creation failed!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = device->CreateQuery(&desc, &pQuery->resource_DX11[0]);
|
||||
assert(SUCCEEDED(hr) && "GPUQuery creation failed!");
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
@@ -2308,7 +2326,6 @@ void GraphicsDevice_DX11::BindUnorderedAccessResourceCS(const GPUUnorderedResour
|
||||
if (resource != nullptr)
|
||||
deviceContexts[threadID]->CSSetUnorderedAccessViews(slot, 1, &resource->unorderedAccessView_DX11, nullptr);
|
||||
}
|
||||
const void* const __nullBlob[1024] = { 0 }; // this is initialized to nullptrs!
|
||||
void GraphicsDevice_DX11::UnBindResources(int slot, int num, GRAPHICSTHREAD threadID)
|
||||
{
|
||||
assert(num <= ARRAYSIZE(__nullBlob) && "Extend nullBlob to support more resource unbinding!");
|
||||
@@ -2599,31 +2616,46 @@ void GraphicsDevice_DX11::SetScissorRects(UINT numRects, const Rect* rects, GRAP
|
||||
deviceContexts[threadID]->RSSetScissorRects(numRects, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsDevice_DX11::QueryBegin(GPUQuery *query, GRAPHICSTHREAD threadID)
|
||||
{
|
||||
//query->result_passed = FALSE;
|
||||
//query->result_passed_sample_count = 0;
|
||||
deviceContexts[threadID]->Begin(query->resource_DX11);
|
||||
const int _requestQueryID = (query->async ? REQUESTQUERYID : 0);
|
||||
deviceContexts[threadID]->Begin(query->resource_DX11[_requestQueryID]);
|
||||
query->active[_requestQueryID] = true;
|
||||
}
|
||||
void GraphicsDevice_DX11::QueryEnd(GPUQuery *query, GRAPHICSTHREAD threadID)
|
||||
{
|
||||
deviceContexts[threadID]->End(query->resource_DX11);
|
||||
const int _requestQueryID = (query->async ? REQUESTQUERYID : 0);
|
||||
deviceContexts[threadID]->End(query->resource_DX11[_requestQueryID]);
|
||||
query->active[_requestQueryID] = true;
|
||||
}
|
||||
bool GraphicsDevice_DX11::QueryRead(GPUQuery *query, GRAPHICSTHREAD threadID)
|
||||
{
|
||||
const int _readQueryID = (query->async ? READQUERYID : 0);
|
||||
const UINT _flags = (query->async ? D3D11_ASYNC_GETDATA_DONOTFLUSH : 0);
|
||||
|
||||
if (!query->active[_readQueryID])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(threadID == GRAPHICSTHREAD_IMMEDIATE && "A query can only be read on the immediate graphics thread!");
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
switch (query->desc.Type)
|
||||
{
|
||||
case GPU_QUERY_TYPE_OCCLUSION:
|
||||
hr = deviceContexts[threadID]->GetData(query->resource_DX11, &query->result_passed_sample_count, sizeof(query->result_passed_sample_count), 0/*D3D11_ASYNC_GETDATA_DONOTFLUSH*/);
|
||||
hr = deviceContexts[threadID]->GetData(query->resource_DX11[_readQueryID], &query->result_passed_sample_count, sizeof(query->result_passed_sample_count), _flags);
|
||||
query->result_passed = query->result_passed_sample_count != 0;
|
||||
break;
|
||||
case GPU_QUERY_TYPE_OCCLUSION_PREDICATE:
|
||||
default:
|
||||
hr = deviceContexts[threadID]->GetData(query->resource_DX11, &query->result_passed, sizeof(query->result_passed), 0/*D3D11_ASYNC_GETDATA_DONOTFLUSH*/);
|
||||
hr = deviceContexts[threadID]->GetData(query->resource_DX11[_readQueryID], &query->result_passed, sizeof(query->result_passed), _flags);
|
||||
break;
|
||||
}
|
||||
|
||||
query->active[_readQueryID] = false;
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace wiGraphicsTypes
|
||||
virtual HRESULT CreateDepthStencilState(const DepthStencilStateDesc *pDepthStencilStateDesc, DepthStencilState *pDepthStencilState) override;
|
||||
virtual HRESULT CreateRasterizerState(const RasterizerStateDesc *pRasterizerStateDesc, RasterizerState *pRasterizerState) override;
|
||||
virtual HRESULT CreateSamplerState(const SamplerDesc *pSamplerDesc, Sampler *pSamplerState) override;
|
||||
virtual HRESULT CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery) override;
|
||||
virtual HRESULT CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery, bool async = true) override;
|
||||
|
||||
virtual void PresentBegin() override;
|
||||
virtual void PresentEnd() override;
|
||||
|
||||
@@ -193,10 +193,18 @@ namespace wiGraphicsTypes
|
||||
|
||||
GPUQuery::GPUQuery()
|
||||
{
|
||||
SAFE_INIT(resource_DX11);
|
||||
for (int i = 0; i < ASYNC_LATENCY; ++i)
|
||||
{
|
||||
SAFE_INIT(resource_DX11[i]);
|
||||
active[i] = false;
|
||||
}
|
||||
async = false;
|
||||
}
|
||||
GPUQuery::~GPUQuery()
|
||||
{
|
||||
SAFE_RELEASE(resource_DX11);
|
||||
for (int i = 0; i < ASYNC_LATENCY; ++i)
|
||||
{
|
||||
SAFE_RELEASE(resource_DX11[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,17 +264,22 @@ namespace wiGraphicsTypes
|
||||
class GPUQuery
|
||||
{
|
||||
friend class GraphicsDevice_DX11;
|
||||
public:
|
||||
static const int ASYNC_LATENCY = 4;
|
||||
private:
|
||||
ID3D11Query* resource_DX11;
|
||||
ID3D11Query* resource_DX11[ASYNC_LATENCY];
|
||||
GPUQueryDesc desc;
|
||||
bool active;
|
||||
bool active[ASYNC_LATENCY];
|
||||
|
||||
// async: shift query frames to avoid pipeline stalls from waiting for the GPU:
|
||||
// we always request queries for some frames forward in time (QueryBegin, QueryEnd)
|
||||
// so we always read the query which occured some frames behind because of that (QueryRead)
|
||||
bool async;
|
||||
public:
|
||||
GPUQuery();
|
||||
virtual ~GPUQuery();
|
||||
|
||||
bool IsValid() { return resource_DX11 != nullptr; }
|
||||
bool IsActive() { return active; }
|
||||
void SetActive(bool value) { active = value; }
|
||||
bool IsValid() { return resource_DX11[0] != nullptr; }
|
||||
GPUQueryDesc GetDesc() { return desc; }
|
||||
|
||||
BOOL result_passed;
|
||||
|
||||
@@ -3677,11 +3677,8 @@ Object::Object(const string& name) :Transform()
|
||||
GPUQueryDesc desc;
|
||||
desc.Type = GPU_QUERY_TYPE_OCCLUSION_PREDICATE;
|
||||
desc.MiscFlags = 0;
|
||||
for (int i = 0; i < ARRAYSIZE(occlusionQueries); ++i)
|
||||
{
|
||||
wiRenderer::GetDevice()->CreateQuery(&desc, &occlusionQueries[i]);
|
||||
occlusionQueries[i].result_passed = TRUE;
|
||||
}
|
||||
wiRenderer::GetDevice()->CreateQuery(&desc, &occlusionQuery, true);
|
||||
occlusionQuery.result_passed = TRUE;
|
||||
}
|
||||
Object::~Object() {
|
||||
}
|
||||
|
||||
@@ -443,8 +443,9 @@ struct Object : public Streamable, public Transform
|
||||
|
||||
int physicsObjectI;
|
||||
|
||||
// occlusion results for the previous 3 frames
|
||||
wiGraphicsTypes::GPUQuery occlusionQueries[3];
|
||||
// occlusion result
|
||||
wiGraphicsTypes::GPUQuery occlusionQuery;
|
||||
bool skipOcclusionQuery;
|
||||
|
||||
// Is it deformed with an armature?
|
||||
bool isArmatureDeformed() const
|
||||
@@ -477,6 +478,7 @@ struct Object : public Streamable, public Transform
|
||||
color = XMFLOAT3(1, 1, 1);
|
||||
trailDistortTex = nullptr;
|
||||
trailTex = nullptr;
|
||||
skipOcclusionQuery;
|
||||
}
|
||||
void EmitTrail(const XMFLOAT3& color, float fadeSpeed = 0.06f);
|
||||
void FadeTrail();
|
||||
|
||||
+23
-25
@@ -87,6 +87,7 @@ wiWaterPlane wiRenderer::waterPlane;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
wiRenderer::wiRenderer()
|
||||
{
|
||||
}
|
||||
@@ -110,11 +111,11 @@ void wiRenderer::Present(function<void()> drawToScreen1,function<void()> drawToS
|
||||
if(drawToScreen3!=nullptr)
|
||||
drawToScreen3();
|
||||
|
||||
wiFrameRate::Frame();
|
||||
|
||||
GetDevice()->PresentEnd();
|
||||
|
||||
*prevFrameCam = *cam;
|
||||
|
||||
wiFrameRate::Frame();
|
||||
}
|
||||
|
||||
|
||||
@@ -1389,6 +1390,7 @@ void wiRenderer::UpdatePerFrameData()
|
||||
FrameCulling& culling = x.second;
|
||||
|
||||
culling.culledRenderer.clear();
|
||||
culling.culledRenderer_opaque.clear();
|
||||
culling.culledRenderer_transparent.clear();
|
||||
culling.culledHairParticleSystems.clear();
|
||||
culling.culledLights.clear();
|
||||
@@ -1404,6 +1406,7 @@ void wiRenderer::UpdatePerFrameData()
|
||||
for (Cullable* x : culledObjects)
|
||||
{
|
||||
Object* object = (Object*)x;
|
||||
culling.culledRenderer[object->mesh].push_front(object);
|
||||
for (wiHairParticle* hair : object->hParticleSystems)
|
||||
{
|
||||
culling.culledHairParticleSystems.push_back(hair);
|
||||
@@ -1411,7 +1414,7 @@ void wiRenderer::UpdatePerFrameData()
|
||||
}
|
||||
if (object->GetRenderTypes() & RENDERTYPE_OPAQUE)
|
||||
{
|
||||
culling.culledRenderer[object->mesh].push_front(object);
|
||||
culling.culledRenderer_opaque[object->mesh].push_front(object);
|
||||
}
|
||||
if (!foundClosestReflector && camera == getCamera() && object->IsReflector())
|
||||
{
|
||||
@@ -1733,15 +1736,15 @@ void wiRenderer::OcclusionCulling_Render(GRAPHICSTHREAD threadID)
|
||||
MiscCB cb;
|
||||
for (Object* instance : visibleInstances)
|
||||
{
|
||||
GPUQuery& query = instance->occlusionQueries[0];
|
||||
GPUQuery& query = instance->occlusionQuery;
|
||||
|
||||
if (instance->bounds.intersects(getCamera()->translation))
|
||||
{
|
||||
// if the camera is inside the bounding box, then the object is most likely visible, so skip occlusion query
|
||||
query.result_passed = true;
|
||||
query.SetActive(false);
|
||||
instance->skipOcclusionQuery = true;
|
||||
}
|
||||
else
|
||||
else if(!instance->skipOcclusionQuery)
|
||||
{
|
||||
// render bounding box to later read the occlusion status
|
||||
GetDevice()->QueryBegin(&query, threadID);
|
||||
@@ -1749,7 +1752,7 @@ void wiRenderer::OcclusionCulling_Render(GRAPHICSTHREAD threadID)
|
||||
GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_MISC], &cb, threadID);
|
||||
GetDevice()->Draw(36, threadID);
|
||||
GetDevice()->QueryEnd(&query, threadID);
|
||||
query.SetActive(true);
|
||||
instance->skipOcclusionQuery = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1778,18 +1781,8 @@ void wiRenderer::OcclusionCulling_Read()
|
||||
|
||||
for (Object* instance : visibleInstances)
|
||||
{
|
||||
GPUQuery& query = instance->occlusionQueries[0];
|
||||
if (!query.IsActive())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int queryFailCount = 0;
|
||||
while (!GetDevice()->QueryRead(&query, GRAPHICSTHREAD_IMMEDIATE))
|
||||
{
|
||||
queryFailCount++;
|
||||
}
|
||||
query.SetActive(false);
|
||||
GPUQuery& query = instance->occlusionQuery;
|
||||
while (!GetDevice()->QueryRead(&query, GRAPHICSTHREAD_IMMEDIATE)) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3115,7 +3108,7 @@ void wiRenderer::RenderMeshes(const XMFLOAT3& eye, const CulledCollection& culle
|
||||
if (dither > 1.0f - FLT_EPSILON)
|
||||
continue;
|
||||
|
||||
if (disableOcclusionCulling || instance->occlusionQueries[0].result_passed == TRUE)
|
||||
if (disableOcclusionCulling || instance->occlusionQuery.result_passed == TRUE)
|
||||
{
|
||||
mesh->AddRenderableInstance(Instance(XMMatrixTranspose(mesh->aabb.getAsBoxMatrix()*XMLoadFloat4x4(&instance->world)), dither, instance->color), k, threadID);
|
||||
++k;
|
||||
@@ -3228,7 +3221,7 @@ void wiRenderer::RenderMeshes(const XMFLOAT3& eye, const CulledCollection& culle
|
||||
if (dither > 1.0f - FLT_EPSILON)
|
||||
continue;
|
||||
|
||||
if (disableOcclusionCulling || instance->occlusionQueries[0].result_passed == TRUE)
|
||||
if (disableOcclusionCulling || instance->occlusionQuery.result_passed == TRUE)
|
||||
{
|
||||
if (mesh->softBody || instance->isArmatureDeformed())
|
||||
mesh->AddRenderableInstance(Instance(XMMatrixIdentity(), dither, instance->color), k, threadID);
|
||||
@@ -3342,7 +3335,7 @@ void wiRenderer::DrawWorld(Camera* camera, bool tessellation, GRAPHICSTHREAD thr
|
||||
{
|
||||
|
||||
const FrameCulling& culling = frameCullings[camera];
|
||||
const CulledCollection& culledRenderer = culling.culledRenderer;
|
||||
const CulledCollection& culledRenderer = culling.culledRenderer_opaque;
|
||||
|
||||
GetDevice()->EventBegin(L"DrawWorld");
|
||||
|
||||
@@ -3999,7 +3992,7 @@ wiRenderer::Picked wiRenderer::Pick(RAY& ray, int pickType, const string& layer,
|
||||
|
||||
vector<Picked> pickPoints;
|
||||
|
||||
RayIntersectMeshes(ray, culledObjects, pickPoints, pickType, true, layer, layerDisable);
|
||||
RayIntersectMeshes(ray, culledObjects, pickPoints, pickType, true, layer, layerDisable, true);
|
||||
|
||||
for (auto& model : GetScene().models)
|
||||
{
|
||||
@@ -4104,7 +4097,7 @@ RAY wiRenderer::getPickRay(long cursorX, long cursorY){
|
||||
}
|
||||
|
||||
void wiRenderer::RayIntersectMeshes(const RAY& ray, const CulledList& culledObjects, vector<Picked>& points,
|
||||
int pickType, bool dynamicObjects, const string& layer, const string& layerDisable)
|
||||
int pickType, bool dynamicObjects, const string& layer, const string& layerDisable, bool onlyVisible)
|
||||
{
|
||||
if (culledObjects.empty())
|
||||
{
|
||||
@@ -4125,7 +4118,8 @@ void wiRenderer::RayIntersectMeshes(const RAY& ray, const CulledList& culledObje
|
||||
XMVECTOR& rayOrigin = XMLoadFloat3(&ray.origin);
|
||||
XMVECTOR& rayDirection = XMVector3Normalize(XMLoadFloat3(&ray.direction));
|
||||
|
||||
for (Cullable* culled : culledObjects){
|
||||
for (Cullable* culled : culledObjects)
|
||||
{
|
||||
Object* object = (Object*)culled;
|
||||
|
||||
if (!(pickType & object->GetRenderTypes()))
|
||||
@@ -4136,6 +4130,10 @@ void wiRenderer::RayIntersectMeshes(const RAY& ray, const CulledList& culledObje
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (onlyVisible && object->occlusionQuery.result_passed != TRUE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// layer support
|
||||
if (checkLayers || dontcheckLayers)
|
||||
|
||||
@@ -76,13 +76,9 @@ public:
|
||||
static wiGraphicsTypes::Texture *textures[TEXTYPE_LAST];
|
||||
|
||||
|
||||
//static int SHADOWMAPRES,SOFTSHADOW,POINTLIGHTSHADOW,POINTLIGHTSHADOWRES,SPOTLIGHTSHADOW,SPOTLIGHTSHADOWRES;
|
||||
static int SHADOWRES_2D, SHADOWRES_CUBE, SHADOWCOUNT_2D, SHADOWCOUNT_CUBE, SOFTSHADOWQUALITY_2D;
|
||||
static bool HAIRPARTICLEENABLED, EMITTERSENABLED;
|
||||
|
||||
//static void SetDirectionalLightShadowProps(int resolution, int softShadowQuality);
|
||||
//static void SetPointLightShadowProps(int shadowMapCount, int resolution);
|
||||
//static void SetSpotLightShadowProps(int count, int resolution);
|
||||
static void SetShadowProps2D(int resolution, int count, int softShadowQuality);
|
||||
static void SetShadowPropsCube(int resolution, int count);
|
||||
|
||||
@@ -361,6 +357,7 @@ public:
|
||||
struct FrameCulling
|
||||
{
|
||||
CulledCollection culledRenderer;
|
||||
CulledCollection culledRenderer_opaque;
|
||||
CulledCollection culledRenderer_transparent;
|
||||
vector<wiHairParticle*> culledHairParticleSystems;
|
||||
CulledList culledLights;
|
||||
@@ -491,7 +488,7 @@ public:
|
||||
static Picked Pick(RAY& ray, int pickType = PICK_OPAQUE, const string& layer = "", const string& layerDisable = "");
|
||||
static RAY getPickRay(long cursorX, long cursorY);
|
||||
static void RayIntersectMeshes(const RAY& ray, const CulledList& culledObjects, vector<Picked>& points,
|
||||
int pickType = PICK_OPAQUE, bool dynamicObjects = true, const string& layer = "", const string& layerDisable = "");
|
||||
int pickType = PICK_OPAQUE, bool dynamicObjects = true, const string& layer = "", const string& layerDisable = "", bool onlyVisible = false);
|
||||
static void CalculateVertexAO(Object* object);
|
||||
|
||||
static PHYSICS* physicsEngine;
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace wiVersion
|
||||
// minor features, major updates
|
||||
const int minor = 9;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 37;
|
||||
const int revision = 38;
|
||||
|
||||
|
||||
long GetVersion()
|
||||
|
||||
+3
-2
@@ -37,7 +37,7 @@ Spotlights + shadow maps
|
||||
Point lights + shadow cubemaps
|
||||
Diffuse, specular lighting for all lights
|
||||
Soft shadows
|
||||
Rigid body physics simulation (HAVOK) [NOT PUBLIC]
|
||||
Rigid body physics simulation (HAVOK) [PRIVATE]
|
||||
Rigid body physics simulation (BULLET)
|
||||
Soft body physics simulation (BULLET)
|
||||
Sound (Xaudio2)
|
||||
@@ -56,4 +56,5 @@ Color Grading
|
||||
Lua Scripting
|
||||
Dynamic environment mapping
|
||||
Impostor system
|
||||
Tiled forward rendering
|
||||
Tiled forward (Forward+) rendering
|
||||
Occlusion culling with gpu queries
|
||||
|
||||
Reference in New Issue
Block a user