diff --git a/Editor/CameraWindow.cpp b/Editor/CameraWindow.cpp index 0d2cdd479..9cdafe42b 100644 --- a/Editor/CameraWindow.cpp +++ b/Editor/CameraWindow.cpp @@ -16,6 +16,8 @@ CameraWindow::CameraWindow(wiGUI* gui) :GUI(gui) fpscamera = true; orbitalCamTarget = new Transform; + movespeed = 10.0f; + rotationspeed = 1.0f; cameraWindow = new wiWindow(GUI, "Camera Window"); cameraWindow->SetSize(XMFLOAT2(400, 300)); @@ -54,7 +56,25 @@ CameraWindow::CameraWindow(wiGUI* gui) :GUI(gui) }); cameraWindow->AddWidget(fovSlider); - resetButton = new wiButton("Reset Pos"); + movespeedSlider = new wiSlider(1, 100, 10, 10000, "Movement Speed: "); + movespeedSlider->SetSize(XMFLOAT2(100, 30)); + movespeedSlider->SetPos(XMFLOAT2(x, y += inc)); + movespeedSlider->OnSlide([&](wiEventArgs args) { + movespeed = args.fValue; + }); + movespeedSlider->SetValue(rotationspeed); + cameraWindow->AddWidget(movespeedSlider); + + rotationspeedSlider = new wiSlider(0.1f, 2, 1, 10000, "Rotation Speed: "); + rotationspeedSlider->SetSize(XMFLOAT2(100, 30)); + rotationspeedSlider->SetPos(XMFLOAT2(x, y += inc)); + rotationspeedSlider->OnSlide([&](wiEventArgs args) { + rotationspeed = args.fValue; + }); + rotationspeedSlider->SetValue(rotationspeed); + cameraWindow->AddWidget(rotationspeedSlider); + + resetButton = new wiButton("Reset Camera"); resetButton->SetSize(XMFLOAT2(140, 30)); resetButton->SetPos(XMFLOAT2(x, y += inc)); resetButton->OnClick([&](wiEventArgs args) { diff --git a/Editor/CameraWindow.h b/Editor/CameraWindow.h index 822008b90..1fe476d4a 100644 --- a/Editor/CameraWindow.h +++ b/Editor/CameraWindow.h @@ -17,6 +17,8 @@ public: bool fpscamera; Transform* orbitalCamTarget; + float movespeed; + float rotationspeed; wiGUI* GUI; @@ -24,6 +26,8 @@ public: wiSlider* farPlaneSlider; wiSlider* nearPlaneSlider; wiSlider* fovSlider; + wiSlider* movespeedSlider; + wiSlider* rotationspeedSlider; wiButton* resetButton; wiCheckBox* fpsCheckBox; }; diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index f481f619f..a13aa2910 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -308,6 +308,8 @@ void EditorComponent::DeleteWindows() SAFE_DELETE(objectWnd); SAFE_DELETE(meshWnd); SAFE_DELETE(cameraWnd); + SAFE_DELETE(rendererWnd); + SAFE_DELETE(envProbeWnd); SAFE_DELETE(decalWnd); SAFE_DELETE(lightWnd); SAFE_DELETE(animWnd); @@ -329,6 +331,7 @@ void EditorComponent::Initialize() SAFE_INIT(meshWnd); SAFE_INIT(cameraWnd); SAFE_INIT(rendererWnd); + SAFE_INIT(envProbeWnd); SAFE_INIT(decalWnd); SAFE_INIT(lightWnd); SAFE_INIT(animWnd); @@ -796,7 +799,7 @@ void EditorComponent::Load() stringstream ss(""); ss << "Help: " << endl << "############" << endl << endl; ss << "Move camera: WASD" << endl; - ss << "Look: Middle mouse button" << endl; + ss << "Look: Middle mouse button / arrow keys" << endl; ss << "Select: Right mouse button" << endl; ss << "Place decal/interact: Left mouse button when nothing is selected" << endl; ss << "Camera speed: SHIFT button" << endl; @@ -811,6 +814,7 @@ void EditorComponent::Load() ss << "Script Console / backlog: HOME button" << endl; ss << endl; ss << "You can find sample models in the models directory. Try to load one." << endl; + ss << "You can also import models from .OBJ files." << endl; ss << "You can also export models from Blender with the io_export_wicked_wi_bin.py script." << endl; ss << "You can find a program configuration file at Editor/config.ini" << endl; ss << "You can find a startup script at Editor/startup.lua (this will be executed on program start)" << endl; @@ -905,6 +909,9 @@ void EditorComponent::Update(float dt) yDif += buttonrotSpeed; } + xDif *= cameraWnd->rotationspeed; + yDif *= cameraWnd->rotationspeed; + Camera* cam = wiRenderer::getCamera(); if (cameraWnd->fpscamera) @@ -912,7 +919,7 @@ void EditorComponent::Update(float dt) // FPS Camera cam->detach(); - float speed = (wiInputManager::GetInstance()->down(VK_SHIFT) ? 100.0f : 10.0f) * dt; + const float speed = (wiInputManager::GetInstance()->down(VK_SHIFT) ? 10.0f : 1.0f) * cameraWnd->movespeed * dt; static XMVECTOR move = XMVectorSet(0, 0, 0, 0); XMVECTOR moveNew = XMVectorSet(0, 0, 0, 0); @@ -1709,8 +1716,7 @@ void ConsumeHistoryOperation(bool undo) object->mesh->subsets[i].material = new Material; object->mesh->subsets[i].material->Serialize(*archive); } - object->mesh->CreateVertexArrays(); - object->mesh->CreateBuffers(object); + object->mesh->CreateRenderData(); model->Add(object); } } diff --git a/Editor/EnvProbeWindow.cpp b/Editor/EnvProbeWindow.cpp index 471149906..db2bce33a 100644 --- a/Editor/EnvProbeWindow.cpp +++ b/Editor/EnvProbeWindow.cpp @@ -49,6 +49,21 @@ EnvProbeWindow::EnvProbeWindow(wiGUI* gui) : GUI(gui) }); envProbeWindow->AddWidget(refreshButton); + refreshAllButton = new wiButton("Refresh All"); + refreshAllButton->SetPos(XMFLOAT2(x, y += step)); + refreshAllButton->SetEnabled(true); + refreshAllButton->OnClick([&](wiEventArgs args) { + const Scene& scene = wiRenderer::GetScene(); + for (Model* x : scene.models) + { + for (EnvironmentProbe* probe : x->environmentProbes) + { + probe->isUpToDate = false; + } + } + }); + envProbeWindow->AddWidget(refreshAllButton); + diff --git a/Editor/EnvProbeWindow.h b/Editor/EnvProbeWindow.h index b95a288c3..f8ba6ff93 100644 --- a/Editor/EnvProbeWindow.h +++ b/Editor/EnvProbeWindow.h @@ -23,5 +23,6 @@ public: wiCheckBox* realTimeCheckBox; wiButton* generateButton; wiButton* refreshButton; + wiButton* refreshAllButton; }; diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index 68046654e..227699201 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -20,9 +20,10 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) float x = 200; float y = 0; + float step = 35; meshInfoLabel = new wiLabel("Mesh Info"); - meshInfoLabel->SetPos(XMFLOAT2(x, y += 30)); + meshInfoLabel->SetPos(XMFLOAT2(x, y += step)); meshInfoLabel->SetSize(XMFLOAT2(400, 150)); meshWindow->AddWidget(meshInfoLabel); @@ -30,7 +31,7 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) doubleSidedCheckBox = new wiCheckBox("Double Sided: "); doubleSidedCheckBox->SetTooltip("If enabled, the inside of the mesh will be visible."); - doubleSidedCheckBox->SetPos(XMFLOAT2(x, y += 30)); + doubleSidedCheckBox->SetPos(XMFLOAT2(x, y += step)); doubleSidedCheckBox->OnClick([&](wiEventArgs args) { if (mesh != nullptr) { @@ -42,7 +43,7 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) massSlider = new wiSlider(0, 5000, 0, 100000, "Mass: "); massSlider->SetTooltip("Set the mass amount for the physics engine."); massSlider->SetSize(XMFLOAT2(100, 30)); - massSlider->SetPos(XMFLOAT2(x, y += 30)); + massSlider->SetPos(XMFLOAT2(x, y += step)); massSlider->OnSlide([&](wiEventArgs args) { if (mesh != nullptr) { @@ -54,7 +55,7 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) frictionSlider = new wiSlider(0, 5000, 0, 100000, "Friction: "); frictionSlider->SetTooltip("Set the friction amount for the physics engine."); frictionSlider->SetSize(XMFLOAT2(100, 30)); - frictionSlider->SetPos(XMFLOAT2(x, y += 30)); + frictionSlider->SetPos(XMFLOAT2(x, y += step)); frictionSlider->OnSlide([&](wiEventArgs args) { if (mesh != nullptr) { @@ -66,7 +67,7 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) impostorCreateButton = new wiButton("Create Impostor"); impostorCreateButton->SetTooltip("Create an impostor image of the mesh. The mesh will be replaced by this image when far away, to render faster."); impostorCreateButton->SetSize(XMFLOAT2(240, 30)); - impostorCreateButton->SetPos(XMFLOAT2(x - 50, y += 30)); + impostorCreateButton->SetPos(XMFLOAT2(x - 50, y += step)); impostorCreateButton->OnClick([&](wiEventArgs args) { if (mesh != nullptr) { @@ -78,7 +79,7 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) impostorDistanceSlider = new wiSlider(0, 1000, 100, 10000, "Impostor Distance: "); impostorDistanceSlider->SetTooltip("Assign the distance where the mesh geometry should be switched to the impostor image."); impostorDistanceSlider->SetSize(XMFLOAT2(100, 30)); - impostorDistanceSlider->SetPos(XMFLOAT2(x, y += 30)); + impostorDistanceSlider->SetPos(XMFLOAT2(x, y += step)); impostorDistanceSlider->OnSlide([&](wiEventArgs args) { if (mesh != nullptr) { @@ -90,7 +91,7 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) tessellationFactorSlider = new wiSlider(0, 16, 0, 10000, "Tessellation Factor: "); tessellationFactorSlider->SetTooltip("Set the dynamic tessellation amount. Tessellation should be enabled in the Renderer window and your GPU must support it!"); tessellationFactorSlider->SetSize(XMFLOAT2(100, 30)); - tessellationFactorSlider->SetPos(XMFLOAT2(x, y += 30)); + tessellationFactorSlider->SetPos(XMFLOAT2(x, y += step)); tessellationFactorSlider->OnSlide([&](wiEventArgs args) { if (mesh != nullptr) { @@ -99,6 +100,58 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) }); meshWindow->AddWidget(tessellationFactorSlider); + flipCullingButton = new wiButton("Flip Culling"); + flipCullingButton->SetTooltip("Flip faces to reverse triangle culling order."); + flipCullingButton->SetSize(XMFLOAT2(240, 30)); + flipCullingButton->SetPos(XMFLOAT2(x - 50, y += step)); + flipCullingButton->OnClick([&](wiEventArgs args) { + if (mesh != nullptr) + { + mesh->FlipCulling(); + SetMesh(mesh); + } + }); + meshWindow->AddWidget(flipCullingButton); + + flipNormalsButton = new wiButton("Flip Normals"); + flipNormalsButton->SetTooltip("Flip surface normals."); + flipNormalsButton->SetSize(XMFLOAT2(240, 30)); + flipNormalsButton->SetPos(XMFLOAT2(x - 50, y += step)); + flipNormalsButton->OnClick([&](wiEventArgs args) { + if (mesh != nullptr) + { + mesh->FlipNormals(); + SetMesh(mesh); + } + }); + meshWindow->AddWidget(flipNormalsButton); + + computeNormalsSmoothButton = new wiButton("Compute Normals [SMOOTH]"); + computeNormalsSmoothButton->SetTooltip("Compute surface normals of the mesh. Resulting normals will be unique per vertex."); + computeNormalsSmoothButton->SetSize(XMFLOAT2(240, 30)); + computeNormalsSmoothButton->SetPos(XMFLOAT2(x - 50, y += step)); + computeNormalsSmoothButton->OnClick([&](wiEventArgs args) { + if (mesh != nullptr) + { + mesh->ComputeNormals(true); + SetMesh(mesh); + } + }); + meshWindow->AddWidget(computeNormalsSmoothButton); + + computeNormalsHardButton = new wiButton("Compute Normals [HARD]"); + computeNormalsHardButton->SetTooltip("Compute surface normals of the mesh. Resulting normals will be unique per face."); + computeNormalsHardButton->SetSize(XMFLOAT2(240, 30)); + computeNormalsHardButton->SetPos(XMFLOAT2(x - 50, y += step)); + computeNormalsHardButton->OnClick([&](wiEventArgs args) { + if (mesh != nullptr) + { + mesh->ComputeNormals(false); + SetMesh(mesh); + } + }); + meshWindow->AddWidget(computeNormalsHardButton); + @@ -118,9 +171,6 @@ MeshWindow::~MeshWindow() void MeshWindow::SetMesh(Mesh* mesh) { - if (this->mesh == mesh) - return; - this->mesh = mesh; if (mesh != nullptr) { diff --git a/Editor/MeshWindow.h b/Editor/MeshWindow.h index 8fdcf0f8d..7458ef1fb 100644 --- a/Editor/MeshWindow.h +++ b/Editor/MeshWindow.h @@ -30,5 +30,9 @@ public: wiButton* impostorCreateButton; wiSlider* impostorDistanceSlider; wiSlider* tessellationFactorSlider; + wiButton* flipCullingButton; + wiButton* flipNormalsButton; + wiButton* computeNormalsSmoothButton; + wiButton* computeNormalsHardButton; }; diff --git a/Editor/WorldWindow.cpp b/Editor/WorldWindow.cpp index 76447688a..3c76d8913 100644 --- a/Editor/WorldWindow.cpp +++ b/Editor/WorldWindow.cpp @@ -82,30 +82,28 @@ WorldWindow::WorldWindow(wiGUI* gui) : GUI(gui) if (x == nullptr) { - thread([&] { - char szFile[260]; + char szFile[260]; - OPENFILENAMEA ofn; - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = nullptr; - ofn.lpstrFile = szFile; - // Set lpstrFile[0] to '\0' so that GetOpenFileName does not - // use the contents of szFile to initialize itself. - ofn.lpstrFile[0] = '\0'; - ofn.nMaxFile = sizeof(szFile); - ofn.lpstrFilter = "Cubemap texture\0*.dds\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - if (GetOpenFileNameA(&ofn) == TRUE) { - string fileName = ofn.lpstrFile; - wiRenderer::SetEnviromentMap((Texture2D*)wiResourceManager::GetGlobal()->add(fileName)); - skyButton->SetText(fileName); - } - }).detach(); + OPENFILENAMEA ofn; + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = nullptr; + ofn.lpstrFile = szFile; + // Set lpstrFile[0] to '\0' so that GetOpenFileName does not + // use the contents of szFile to initialize itself. + ofn.lpstrFile[0] = '\0'; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFilter = "Cubemap texture\0*.dds\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + if (GetOpenFileNameA(&ofn) == TRUE) { + string fileName = ofn.lpstrFile; + wiRenderer::SetEnviromentMap((Texture2D*)wiResourceManager::GetGlobal()->add(fileName)); + skyButton->SetText(fileName); + } } else { @@ -113,11 +111,66 @@ WorldWindow::WorldWindow(wiGUI* gui) : GUI(gui) skyButton->SetText("Load Sky"); } + // Also, we invalidate all environment probes to reflect the sky changes. + const Scene& scene = wiRenderer::GetScene(); + for (Model* x : scene.models) + { + for (EnvironmentProbe* probe : x->environmentProbes) + { + probe->isUpToDate = false; + } + } + }); worldWindow->AddWidget(skyButton); + wiButton* convertDDSButton = new wiButton("HELPERSCRIPT - ConvertMaterialsDDS"); + convertDDSButton->SetTooltip("Every material in the scene will have its textures saved and renamed as DDS into textures_dds folder."); + convertDDSButton->SetSize(XMFLOAT2(240, 30)); + convertDDSButton->SetPos(XMFLOAT2(x - 100, y += step * 3)); + convertDDSButton->OnClick([=](wiEventArgs args) { + + const Scene& scene = wiRenderer::GetScene(); + for (Model* x : scene.models) + { + for (auto& y : x->materials) + { + Material* material = y.second; + + CreateDirectory(L"textures_dds", 0); + + if (!material->textureName.empty()) + { + string newName = wiHelper::GetFileNameFromPath(material->textureName.substr(0, material->textureName.length() - 4) + ".dds"); + wiRenderer::GetDevice()->SaveTextureDDS(wiHelper::GetWorkingDirectory() + "textures_dds/" + newName, material->GetBaseColorMap(), GRAPHICSTHREAD_IMMEDIATE); + material->textureName = newName; + } + if (!material->normalMapName.empty()) + { + string newName = wiHelper::GetFileNameFromPath(material->normalMapName.substr(0, material->normalMapName.length() - 4) + ".dds"); + wiRenderer::GetDevice()->SaveTextureDDS(wiHelper::GetWorkingDirectory() + "textures_dds/" + newName, material->GetNormalMap(), GRAPHICSTHREAD_IMMEDIATE); + material->normalMapName = newName; + } + if (!material->surfaceMapName.empty()) + { + string newName = wiHelper::GetFileNameFromPath(material->surfaceMapName.substr(0, material->surfaceMapName.length() - 4) + ".dds"); + wiRenderer::GetDevice()->SaveTextureDDS(wiHelper::GetWorkingDirectory() + "textures_dds/" + newName, material->GetSurfaceMap(), GRAPHICSTHREAD_IMMEDIATE); + material->surfaceMapName = newName; + } + if (!material->displacementMapName.empty()) + { + string newName = wiHelper::GetFileNameFromPath(material->displacementMapName.substr(0, material->displacementMapName.length() - 4) + ".dds"); + wiRenderer::GetDevice()->SaveTextureDDS(wiHelper::GetWorkingDirectory() + "textures_dds/" + newName, material->GetDisplacementMap(), GRAPHICSTHREAD_IMMEDIATE); + material->displacementMapName = newName; + } + } + } + + }); + worldWindow->AddWidget(convertDDSButton); + diff --git a/WickedEngine/wiEmittedParticle.cpp b/WickedEngine/wiEmittedParticle.cpp index 70d628d00..11bd06d3b 100644 --- a/WickedEngine/wiEmittedParticle.cpp +++ b/WickedEngine/wiEmittedParticle.cpp @@ -320,8 +320,8 @@ void wiEmittedParticle::UpdateRenderData(GRAPHICSTHREAD threadID) GPUResource* resources[] = { wiTextureHelper::getInstance()->getRandom64x64(), - &object->mesh->indexBuffer, - &object->mesh->vertexBuffer_POS, + object->mesh->indexBuffer, + object->mesh->vertexBuffer_POS, }; device->BindResources(CS, resources, TEXSLOT_ONDEMAND0, ARRAYSIZE(resources), threadID); diff --git a/WickedEngine/wiLoader.cpp b/WickedEngine/wiLoader.cpp index 846ad8190..22bf2a809 100644 --- a/WickedEngine/wiLoader.cpp +++ b/WickedEngine/wiLoader.cpp @@ -1477,6 +1477,56 @@ void VertexGroup::Serialize(wiArchive& archive) GPUBuffer Mesh::impostorVB_POS; GPUBuffer Mesh::impostorVB_TEX; +Mesh::Mesh(const string& name) : name(name) +{ + init(); +} +Mesh::~Mesh() +{ + SAFE_DELETE(indexBuffer); + SAFE_DELETE(vertexBuffer_POS); + SAFE_DELETE(vertexBuffer_TEX); + SAFE_DELETE(vertexBuffer_BON); + SAFE_DELETE(streamoutBuffer_POS); + SAFE_DELETE(streamoutBuffer_PRE); +} +void Mesh::init() +{ + parent = ""; + indices.resize(0); + renderable = false; + doubleSided = false; + aabb = AABB(); + trailInfo = RibbonTrail(); + armature = nullptr; + isBillboarded = false; + billboardAxis = XMFLOAT3(0, 0, 0); + vertexGroups.clear(); + softBody = false; + mass = friction = 1; + massVG = -1; + goalVG = -1; + softVG = -1; + goalPositions.clear(); + goalNormals.clear(); + renderDataComplete = false; + calculatedAO = false; + armatureName = ""; + impostorDistance = 100.0f; + tessellationFactor = 0.0f; + optimized = false; + bufferOffset_POS = 0; + bufferOffset_PRE = 0; + indexFormat = wiGraphicsTypes::INDEXFORMAT_16BIT; + + SAFE_INIT(indexBuffer); + SAFE_INIT(vertexBuffer_POS); + SAFE_INIT(vertexBuffer_TEX); + SAFE_INIT(vertexBuffer_BON); + SAFE_INIT(streamoutBuffer_POS); + SAFE_INIT(streamoutBuffer_PRE); +} + void Mesh::LoadFromFile(const std::string& newName, const std::string& fname , const MaterialCollection& materialColl, const unordered_set& armatures, const std::string& identifier) { name = newName; @@ -1772,44 +1822,150 @@ void Mesh::LoadFromFile(const std::string& newName, const std::string& fname } void Mesh::Optimize() { - if (optimized) - { - return; - } + // The optimizer is crashing for many models, remove for now (todo) - // Vertex cache optimization: - { - ForsythVertexIndexType* _indices_in = new ForsythVertexIndexType[this->indices.size()]; - ForsythVertexIndexType* _indices_out = new ForsythVertexIndexType[this->indices.size()]; - for (size_t i = 0; i < indices.size(); ++i) - { - _indices_in[i] = this->indices[i]; - } + //if (optimized) + //{ + // return; + //} - ForsythVertexIndexType* result = forsythReorderIndices(_indices_out, _indices_in, (int)(this->indices.size() / 3), (int)(this->vertices_FULL.size())); + //// Vertex cache optimization: + //{ + // ForsythVertexIndexType* _indices_in = new ForsythVertexIndexType[this->indices.size()]; + // ForsythVertexIndexType* _indices_out = new ForsythVertexIndexType[this->indices.size()]; + // for (size_t i = 0; i < indices.size(); ++i) + // { + // _indices_in[i] = this->indices[i]; + // } - for (size_t i = 0; i < indices.size(); ++i) - { - this->indices[i] = _indices_out[i]; - } - SAFE_DELETE_ARRAY(_indices_in); - SAFE_DELETE_ARRAY(_indices_out); - } + // ForsythVertexIndexType* result = forsythReorderIndices(_indices_out, _indices_in, (int)(this->indices.size() / 3), (int)(this->vertices_FULL.size())); - optimized = true; + // for (size_t i = 0; i < indices.size(); ++i) + // { + // this->indices[i] = _indices_out[i]; + // } + // SAFE_DELETE_ARRAY(_indices_in); + // SAFE_DELETE_ARRAY(_indices_out); + //} + + //optimized = true; } -void Mesh::CreateBuffers(Object* object) +void Mesh::CreateRenderData() { - if (!buffersComplete) + if (!renderDataComplete) { - if (vertices_POS.empty()) + // First, assemble vertex, index arrays: + + // In case of recreate, delete data first: + vertices_POS.clear(); + vertices_TEX.clear(); + vertices_BON.clear(); + + // De-interleave vertex arrays: + vertices_POS.resize(vertices_FULL.size()); + vertices_TEX.resize(vertices_FULL.size()); + // do not resize vertices_BON just yet, not every mesh will need bone vertex data! + for (size_t i = 0; i < vertices_FULL.size(); ++i) { - renderable = false; + // Normalize normals: + float alpha = vertices_FULL[i].nor.w; + XMVECTOR nor = XMLoadFloat4(&vertices_FULL[i].nor); + nor = XMVector3Normalize(nor); + XMStoreFloat4(&vertices_FULL[i].nor, nor); + vertices_FULL[i].nor.w = alpha; + + // Normalize bone weights: + XMFLOAT4& wei = vertices_FULL[i].wei; + float len = wei.x + wei.y + wei.z + wei.w; + if (len > 0) + { + wei.x /= len; + wei.y /= len; + wei.z /= len; + wei.w /= len; + + if (vertices_BON.empty()) + { + // Allocate full bone vertex data when we find a correct bone weight. + vertices_BON.resize(vertices_FULL.size()); + } + vertices_BON[i] = Vertex_BON(vertices_FULL[i]); + } + + // Split and type conversion: + vertices_POS[i] = Vertex_POS(vertices_FULL[i]); + vertices_TEX[i] = Vertex_TEX(vertices_FULL[i]); } - if (!renderable) + + // Save original vertices. This will be input for CPU skinning / soft bodies + vertices_Transformed_POS = vertices_POS; + vertices_Transformed_PRE = vertices_POS; // pre <- pos!! (previous positions will have the current positions initially) + + // Map subset indices: + for (auto& subset : subsets) { - return; + subset.subsetIndices.clear(); } + for (size_t i = 0; i < indices.size(); ++i) + { + uint32_t index = indices[i]; + const XMFLOAT4& tex = vertices_FULL[index].tex; + unsigned int materialIndex = (unsigned int)floor(tex.z); + + assert((materialIndex < (unsigned int)subsets.size()) && "Bad subset index!"); + + MeshSubset& subset = subsets[materialIndex]; + subset.subsetIndices.push_back(index); + + if (index >= 65536) + { + indexFormat = INDEXFORMAT_32BIT; + } + } + + + // Goal positions, normals are controlling blending between animation and physics states for soft body rendering: + goalPositions.clear(); + goalNormals.clear(); + if (goalVG >= 0) + { + goalPositions.resize(vertexGroups[goalVG].vertices.size()); + goalNormals.resize(vertexGroups[goalVG].vertices.size()); + } + + + // Mapping render vertices to physics vertex representation: + // the physics vertices contain unique position, not duplicated by texcoord or normals + // this way we can map several renderable vertices to one physics vertex + // but the mapping function will actually be indexed by renderable vertex index for efficient retrieval. + if (!physicsverts.empty() && physicalmapGP.empty()) + { + for (size_t i = 0; i < vertices_POS.size(); ++i) + { + for (size_t j = 0; j < physicsverts.size(); ++j) + { + if (fabs(vertices_POS[i].pos.x - physicsverts[j].x) < FLT_EPSILON + && fabs(vertices_POS[i].pos.y - physicsverts[j].y) < FLT_EPSILON + && fabs(vertices_POS[i].pos.z - physicsverts[j].z) < FLT_EPSILON + ) + { + physicalmapGP.push_back(static_cast(j)); + break; + } + } + } + } + + + + // Create actual GPU data: + + SAFE_DELETE(indexBuffer); + SAFE_DELETE(vertexBuffer_POS); + SAFE_DELETE(vertexBuffer_TEX); + SAFE_DELETE(vertexBuffer_BON); + SAFE_DELETE(streamoutBuffer_POS); + SAFE_DELETE(streamoutBuffer_PRE); GPUBufferDesc bd; SubresourceData InitData; @@ -1825,10 +1981,11 @@ void Mesh::CreateBuffers(Object* object) InitData.pSysMem = vertices_POS.data(); bd.ByteWidth = (UINT)(sizeof(Vertex_POS) * vertices_POS.size()); - wiRenderer::GetDevice()->CreateBuffer(&bd, &InitData, &vertexBuffer_POS); + vertexBuffer_POS = new GPUBuffer; + wiRenderer::GetDevice()->CreateBuffer(&bd, &InitData, vertexBuffer_POS); } - if (object->isArmatureDeformed()) + if (!vertices_BON.empty()) { ZeroMemory(&bd, sizeof(bd)); bd.Usage = USAGE_IMMUTABLE; @@ -1838,7 +1995,8 @@ void Mesh::CreateBuffers(Object* object) InitData.pSysMem = vertices_BON.data(); bd.ByteWidth = (UINT)(sizeof(Vertex_BON) * vertices_BON.size()); - wiRenderer::GetDevice()->CreateBuffer(&bd, &InitData, &vertexBuffer_BON); + vertexBuffer_BON = new GPUBuffer; + wiRenderer::GetDevice()->CreateBuffer(&bd, &InitData, vertexBuffer_BON); ZeroMemory(&bd, sizeof(bd)); bd.Usage = USAGE_DEFAULT; @@ -1847,10 +2005,12 @@ void Mesh::CreateBuffers(Object* object) bd.MiscFlags = RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; bd.ByteWidth = (UINT)(sizeof(Vertex_POS) * vertices_POS.size()); - wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, &streamoutBuffer_POS); + streamoutBuffer_POS = new GPUBuffer; + wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, streamoutBuffer_POS); bd.ByteWidth = (UINT)(sizeof(Vertex_POS) * vertices_POS.size()); - wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, &streamoutBuffer_PRE); + streamoutBuffer_PRE = new GPUBuffer; + wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, streamoutBuffer_PRE); } // texture coordinate buffers are always static: @@ -1861,25 +2021,8 @@ void Mesh::CreateBuffers(Object* object) bd.MiscFlags = 0; InitData.pSysMem = vertices_TEX.data(); bd.ByteWidth = (UINT)(sizeof(Vertex_TEX) * vertices_TEX.size()); - wiRenderer::GetDevice()->CreateBuffer(&bd, &InitData, &vertexBuffer_TEX); - - - //PHYSICALMAPPING - if (!physicsverts.empty() && physicalmapGP.empty()) - { - for (unsigned int i = 0; i < vertices_POS.size(); ++i) { - for (unsigned int j = 0; j < physicsverts.size(); ++j) { - if (fabs(vertices_POS[i].pos.x - physicsverts[j].x) < FLT_EPSILON - && fabs(vertices_POS[i].pos.y - physicsverts[j].y) < FLT_EPSILON - && fabs(vertices_POS[i].pos.z - physicsverts[j].z) < FLT_EPSILON - ) - { - physicalmapGP.push_back(j); - break; - } - } - } - } + vertexBuffer_TEX = new GPUBuffer; + wiRenderer::GetDevice()->CreateBuffer(&bd, &InitData, vertexBuffer_TEX); // Remap index buffer to be continuous across subsets and create gpu buffer data: @@ -1933,12 +2076,13 @@ void Mesh::CreateBuffers(Object* object) bd.Format = GetIndexFormat() == INDEXFORMAT_16BIT ? FORMAT_R16_UINT : FORMAT_R32_UINT; InitData.pSysMem = gpuIndexData; bd.ByteWidth = (UINT)(stride * indices.size()); - wiRenderer::GetDevice()->CreateBuffer(&bd, &InitData, &indexBuffer); + indexBuffer = new GPUBuffer; + wiRenderer::GetDevice()->CreateBuffer(&bd, &InitData, indexBuffer); SAFE_DELETE_ARRAY(gpuIndexData); - buffersComplete = true; + renderDataComplete = true; } } @@ -2125,71 +2269,193 @@ void Mesh::CreateImpostorVB() wiRenderer::GetDevice()->CreateBuffer(&bd, &InitData, &impostorVB_TEX); } } -void Mesh::CreateVertexArrays() +void Mesh::ComputeNormals(bool smooth) { - if (arraysComplete) - { - return; - } + // Start recalculating normals: - // De-interleave vertex arrays: - vertices_POS.resize(vertices_FULL.size()); - vertices_TEX.resize(vertices_FULL.size()); - vertices_BON.resize(vertices_FULL.size()); - for (size_t i = 0; i < vertices_FULL.size(); ++i) + if (smooth) { - // Normalize normals: - float alpha = vertices_FULL[i].nor.w; - XMVECTOR nor = XMLoadFloat4(&vertices_FULL[i].nor); - nor = XMVector3Normalize(nor); - XMStoreFloat4(&vertices_FULL[i].nor, nor); - vertices_FULL[i].nor.w = alpha; + // Compute smooth surface normals: - // Normalize bone weights: - XMFLOAT4& wei = vertices_FULL[i].wei; - float len = wei.x + wei.y + wei.z + wei.w; - if (len > 0) + // 1.) Zero normals, they will be averaged later + for (size_t i = 0; i < vertices_FULL.size() - 1; i++) { - wei.x /= len; - wei.y /= len; - wei.z /= len; - wei.w /= len; + vertices_FULL[i].nor = XMFLOAT4(0, 0, 0, 0); } - // Split and type conversion: - vertices_POS[i] = Vertex_POS(vertices_FULL[i]); - vertices_TEX[i] = Vertex_TEX(vertices_FULL[i]); - vertices_BON[i] = Vertex_BON(vertices_FULL[i]); - } - - // Save original vertices. This will be input for CPU skinning / soft bodies - vertices_Transformed_POS = vertices_POS; - vertices_Transformed_PRE = vertices_POS; // pre <- pos!! - - // Map subset indices: - for (size_t i = 0; i < indices.size(); ++i) - { - unsigned int index = indices[i]; - const XMFLOAT4& tex = vertices_FULL[index].tex; - unsigned int materialIndex = (unsigned int)floor(tex.z); - - assert((materialIndex < (unsigned int)subsets.size()) && "Bad subset index!"); - - MeshSubset& subset = subsets[materialIndex]; - subset.subsetIndices.push_back(index); - - if (index >= 65536) + // 2.) Find identical vertices by POSITION, accumulate face normals + for (size_t i = 0; i < vertices_FULL.size() - 1; i++) { - indexFormat = INDEXFORMAT_32BIT; + Vertex_FULL& v_search = vertices_FULL[i]; + + for (size_t ind = 0; ind < indices.size() / 3; ++ind) + { + uint32_t i0 = indices[ind * 3 + 0]; + uint32_t i1 = indices[ind * 3 + 1]; + uint32_t i2 = indices[ind * 3 + 2]; + + Vertex_FULL& v0 = vertices_FULL[i0]; + Vertex_FULL& v1 = vertices_FULL[i1]; + Vertex_FULL& v2 = vertices_FULL[i2]; + + bool match_pos0 = + fabs(v_search.pos.x - v0.pos.x) < FLT_EPSILON && + fabs(v_search.pos.y - v0.pos.y) < FLT_EPSILON && + fabs(v_search.pos.z - v0.pos.z) < FLT_EPSILON; + + bool match_pos1 = + fabs(v_search.pos.x - v1.pos.x) < FLT_EPSILON && + fabs(v_search.pos.y - v1.pos.y) < FLT_EPSILON && + fabs(v_search.pos.z - v1.pos.z) < FLT_EPSILON; + + bool match_pos2 = + fabs(v_search.pos.x - v2.pos.x) < FLT_EPSILON && + fabs(v_search.pos.y - v2.pos.y) < FLT_EPSILON && + fabs(v_search.pos.z - v2.pos.z) < FLT_EPSILON; + + if (match_pos0 || match_pos1 || match_pos2) + { + XMVECTOR U = XMLoadFloat4(&v2.pos) - XMLoadFloat4(&v0.pos); + XMVECTOR V = XMLoadFloat4(&v1.pos) - XMLoadFloat4(&v0.pos); + + XMVECTOR N = XMVector3Cross(U, V); + N = XMVector3Normalize(N); + + XMFLOAT3 normal; + XMStoreFloat3(&normal, N); + + v_search.nor.x += normal.x; + v_search.nor.y += normal.y; + v_search.nor.z += normal.z; + } + + } + } + + // 3.) Find unique vertices by POSITION and TEXCOORD and MATERIAL and remove duplicates + for (size_t i = 0; i < vertices_FULL.size() - 1; i++) + { + const Vertex_FULL& v0 = vertices_FULL[i]; + + for (size_t j = i + 1; j < vertices_FULL.size(); j++) + { + const Vertex_FULL& v1 = vertices_FULL[j]; + + bool unique_pos = + fabs(v0.pos.x - v1.pos.x) < FLT_EPSILON && + fabs(v0.pos.y - v1.pos.y) < FLT_EPSILON && + fabs(v0.pos.z - v1.pos.z) < FLT_EPSILON; + + bool unique_tex = + fabs(v0.tex.x - v1.tex.x) < FLT_EPSILON && + fabs(v0.tex.y - v1.tex.y) < FLT_EPSILON && + (int)v0.tex.z == (int)v1.tex.z; + + if (unique_pos && unique_tex) + { + for (size_t ind = 0; ind < indices.size(); ++ind) + { + if (indices[ind] == j) + { + indices[ind] = static_cast(i); + } + else if (indices[ind] > j && indices[ind] > 0) + { + indices[ind]--; + } + } + + vertices_FULL.erase(vertices_FULL.begin() + j); + } + + } } } + else + { + // Compute hard surface normals: - if (goalVG >= 0) { - goalPositions.resize(vertexGroups[goalVG].vertices.size()); - goalNormals.resize(vertexGroups[goalVG].vertices.size()); + vector newIndexBuffer; + vector newVertexBuffer; + + for (size_t face = 0; face < indices.size() / 3; face++) + { + uint32_t i0 = indices[face * 3 + 0]; + uint32_t i1 = indices[face * 3 + 1]; + uint32_t i2 = indices[face * 3 + 2]; + + Vertex_FULL& v0 = vertices_FULL[i0]; + Vertex_FULL& v1 = vertices_FULL[i1]; + Vertex_FULL& v2 = vertices_FULL[i2]; + + XMVECTOR U = XMLoadFloat4(&v2.pos) - XMLoadFloat4(&v0.pos); + XMVECTOR V = XMLoadFloat4(&v1.pos) - XMLoadFloat4(&v0.pos); + + XMVECTOR N = XMVector3Cross(U, V); + N = XMVector3Normalize(N); + + XMFLOAT3 normal; + XMStoreFloat3(&normal, N); + + v0.nor.x = normal.x; + v0.nor.y = normal.y; + v0.nor.z = normal.z; + + v1.nor.x = normal.x; + v1.nor.y = normal.y; + v1.nor.z = normal.z; + + v2.nor.x = normal.x; + v2.nor.y = normal.y; + v2.nor.z = normal.z; + + newVertexBuffer.push_back(v0); + newVertexBuffer.push_back(v1); + newVertexBuffer.push_back(v2); + + newIndexBuffer.push_back(static_cast(newIndexBuffer.size())); + newIndexBuffer.push_back(static_cast(newIndexBuffer.size())); + newIndexBuffer.push_back(static_cast(newIndexBuffer.size())); + } + + // For hard surface normals, we created a new mesh in the previous loop through faces, so swap data: + vertices_FULL = newVertexBuffer; + indices = newIndexBuffer; } - arraysComplete = true; + // force recreate: + renderDataComplete = false; + CreateRenderData(); +} +void Mesh::FlipCulling() +{ + for (size_t face = 0; face < indices.size() / 3; face++) + { + uint32_t i0 = indices[face * 3 + 0]; + uint32_t i1 = indices[face * 3 + 1]; + uint32_t i2 = indices[face * 3 + 2]; + + indices[face * 3 + 0] = i0; + indices[face * 3 + 1] = i2; + indices[face * 3 + 2] = i1; + } + + renderDataComplete = false; + CreateRenderData(); +} +void Mesh::FlipNormals() +{ + for (size_t i = 0; i < vertices_FULL.size() - 1; i++) + { + Vertex_FULL& v0 = vertices_FULL[i]; + + v0.nor.x *= -1; + v0.nor.y *= -1; + v0.nor.z *= -1; + } + + renderDataComplete = false; + CreateRenderData(); } int Mesh::GetRenderTypes() const @@ -2559,6 +2825,14 @@ void Model::LoadFromDisk(const std::string& fileName, const std::string& identif this->materials.insert(make_pair(material->name, material)); } + if (materialLibrary.empty()) + { + // Create default material if nothing was found: + Material* material = new Material("OBJImport_defaultMaterial"); + materialLibrary.push_back(material); + this->materials.insert(make_pair(material->name, material)); + } + // Load objects, meshes: for (auto& shape : obj_shapes) { @@ -2576,13 +2850,20 @@ void Model::LoadFromDisk(const std::string& fileName, const std::string& identif for (size_t i = 0; i < shape.mesh.indices.size(); i += 3) { - // Reorder face-winding to match defaults: tinyobj::index_t reordered_indices[] = { shape.mesh.indices[i + 0], - shape.mesh.indices[i + 2], shape.mesh.indices[i + 1], + shape.mesh.indices[i + 2], }; + // todo: option param would be better + bool flipCulling = false; + if (flipCulling) + { + reordered_indices[1] = shape.mesh.indices[i + 2]; + reordered_indices[2] = shape.mesh.indices[i + 1]; + } + for (auto& index : reordered_indices) { Mesh::Vertex_FULL vert; @@ -2604,7 +2885,7 @@ void Model::LoadFromDisk(const std::string& fileName, const std::string& identif ); } - if (!obj_attrib.texcoords.empty()) + if (index.texcoord_index >= 0 && !obj_attrib.texcoords.empty()) { vert.tex = XMFLOAT4( obj_attrib.texcoords[index.texcoord_index * 2 + 0], @@ -2613,7 +2894,7 @@ void Model::LoadFromDisk(const std::string& fileName, const std::string& identif ); } - int materialIndex = shape.mesh.material_ids[i / 3]; // this indexes the material library + int materialIndex = max(0, shape.mesh.material_ids[i / 3]); // this indexes the material library if (registered_materialIndices.count(materialIndex) == 0) { registered_materialIndices[materialIndex] = (int)mesh->subsets.size(); @@ -2624,13 +2905,22 @@ void Model::LoadFromDisk(const std::string& fileName, const std::string& identif } vert.tex.z = (float)registered_materialIndices[materialIndex]; // this indexes a mesh subset + // todo: option parameter would be better + const bool flipZ = true; + if (flipZ) + { + vert.pos.z *= -1; + vert.nor.z *= -1; + } + // eliminate duplicate vertices by means of hashing: size_t hashes[] = { hash{}(index.vertex_index), hash{}(index.normal_index), hash{}(index.texcoord_index), + hash{}(materialIndex), }; - size_t vertexHash = (hashes[0] ^ (hashes[1] << 1) >> 1) ^ (hashes[2] << 1); + size_t vertexHash = (((hashes[0] ^ (hashes[1] << 1) >> 1) ^ (hashes[2] << 1)) >> 1) ^ (hashes[3] << 1); if (uniqueVertices.count(vertexHash) == 0) { @@ -2645,6 +2935,19 @@ void Model::LoadFromDisk(const std::string& fileName, const std::string& identif } mesh->aabb.create(min, max); + // We need to eliminate colliding mesh names, because objects can reference them by names: + // Note: in engine, object is decoupled from mesh, for instancing support. OBJ file have only meshes and names can collide there. + string meshName = mesh->name; + uint32_t unique_counter = 0; + bool meshNameCollision = this->meshes.count(meshName) != 0; + while (meshNameCollision) + { + meshName = mesh->name + to_string(unique_counter); + meshNameCollision = this->meshes.count(meshName) != 0; + unique_counter++; + } + mesh->name = meshName; + object->meshName = mesh->name; this->objects.insert(object); @@ -2769,9 +3072,8 @@ void Model::FinishLoading() } // Mesh renderdata setup - x->mesh->CreateVertexArrays(); x->mesh->Optimize(); - x->mesh->CreateBuffers(x); + x->mesh->CreateRenderData(); if (x->mesh->armature != nullptr) { diff --git a/WickedEngine/wiLoader.h b/WickedEngine/wiLoader.h index b9bc0f097..198e42b60 100644 --- a/WickedEngine/wiLoader.h +++ b/WickedEngine/wiLoader.h @@ -446,12 +446,12 @@ public: std::vector subsets; std::vector materialNames; - wiGraphicsTypes::GPUBuffer indexBuffer; - wiGraphicsTypes::GPUBuffer vertexBuffer_POS; - wiGraphicsTypes::GPUBuffer vertexBuffer_TEX; - wiGraphicsTypes::GPUBuffer vertexBuffer_BON; - wiGraphicsTypes::GPUBuffer streamoutBuffer_POS; - wiGraphicsTypes::GPUBuffer streamoutBuffer_PRE; + wiGraphicsTypes::GPUBuffer* indexBuffer; + wiGraphicsTypes::GPUBuffer* vertexBuffer_POS; + wiGraphicsTypes::GPUBuffer* vertexBuffer_TEX; + wiGraphicsTypes::GPUBuffer* vertexBuffer_BON; + wiGraphicsTypes::GPUBuffer* streamoutBuffer_POS; + wiGraphicsTypes::GPUBuffer* streamoutBuffer_PRE; // Dynamic vertexbuffers write into a global pool, these will be the offsets into that: UINT bufferOffset_POS; @@ -488,54 +488,19 @@ public: float tessellationFactor; bool optimized; + bool renderDataComplete; - Mesh(){ - init(); - } - Mesh(const std::string& newName){ - name=newName; - init(); - } - ~Mesh() {} + Mesh(const std::string& newName = ""); + ~Mesh(); void LoadFromFile(const std::string& newName, const std::string& fname , const MaterialCollection& materialColl, const std::unordered_set& armatures, const std::string& identifier=""); - bool buffersComplete; void Optimize(); - // Object is needed in CreateBuffers because how else would we know if the mesh needs to be deformed? - void CreateBuffers(Object* object); + void CreateRenderData(); static void CreateImpostorVB(); - bool arraysComplete; - void CreateVertexArrays(); - void init() - { - parent=""; - indices.resize(0); - renderable=false; - doubleSided=false; - aabb=AABB(); - trailInfo=RibbonTrail(); - armature=nullptr; - isBillboarded=false; - billboardAxis=XMFLOAT3(0,0,0); - vertexGroups.clear(); - softBody=false; - mass=friction=1; - massVG=-1; - goalVG=-1; - softVG = -1; - goalPositions.clear(); - goalNormals.clear(); - buffersComplete = false; - arraysComplete = false; - calculatedAO = false; - armatureName = ""; - impostorDistance = 100.0f; - tessellationFactor = 0.0f; - optimized = false; - bufferOffset_POS = 0; - bufferOffset_PRE = 0; - indexFormat = wiGraphicsTypes::INDEXFORMAT_16BIT; - } + void ComputeNormals(bool smooth = false); + void FlipCulling(); + void FlipNormals(); + void init(); bool hasArmature() const { return armature != nullptr; } bool hasImpostor() const { return impostorTarget.IsInitialized(); } diff --git a/WickedEngine/wiMath.cpp b/WickedEngine/wiMath.cpp index fab0f7265..cf45e8c9e 100644 --- a/WickedEngine/wiMath.cpp +++ b/WickedEngine/wiMath.cpp @@ -90,6 +90,26 @@ namespace wiMath return ++x; } + float TriangleArea(const XMVECTOR& A, const XMVECTOR& B, const XMVECTOR& C) + { + // Heron's formula: + XMVECTOR a = XMVector3Length(B - A); + XMVECTOR b = XMVector3Length(C - A); + XMVECTOR c = XMVector3Length(C - B); + XMVECTOR p = (a + b + c) * 0.5f; + XMVECTOR areaSq = p * (p - a) * (p - b) * (p - c); + float area; + XMStoreFloat(&area, areaSq); + area = sqrtf(area); + return area; + } + float TriangleArea(float a, float b, float c) + { + // Heron's formula: + float p = (a + b + c) * 0.5f; + return sqrtf(p * (p - a) * (p - b) * (p - c)); + } + float InverseLerp(float value1, float value2, float pos) { diff --git a/WickedEngine/wiMath.h b/WickedEngine/wiMath.h index 87ba45307..f99572c81 100644 --- a/WickedEngine/wiMath.h +++ b/WickedEngine/wiMath.h @@ -27,6 +27,11 @@ namespace wiMath UINT GetNextPowerOfTwo(UINT x); float SmoothStep(float value1, float value2, float amount); + // A, B, C: trangle vertices + float TriangleArea(const XMVECTOR& A, const XMVECTOR& B, const XMVECTOR& C); + // a, b, c: trangle side lengths + float TriangleArea(float a, float b, float c); + XMFLOAT3 getCubicHermiteSplinePos(const XMFLOAT3& startPos, const XMFLOAT3& endPos , const XMFLOAT3& startTangent, const XMFLOAT3& endTangent , float atInterval); diff --git a/WickedEngine/wiOBJLoader.h b/WickedEngine/wiOBJLoader.h index 27fd05a9a..f38781ba5 100644 --- a/WickedEngine/wiOBJLoader.h +++ b/WickedEngine/wiOBJLoader.h @@ -1,7 +1,7 @@ /* The MIT License (MIT) -Copyright (c) 2012-2017 Syoyo Fujita and many contributors. +Copyright (c) 2012-2018 Syoyo Fujita and many contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -23,6 +23,7 @@ THE SOFTWARE. */ // +// version 1.1.1 : Support smoothing groups(#162) // version 1.1.0 : Support parsing vertex color(#144) // version 1.0.8 : Fix parsing `g` tag just after `usemtl`(#138) // version 1.0.7 : Support multiple tex options(#126) @@ -51,6 +52,16 @@ THE SOFTWARE. namespace tinyobj { +#ifdef __clang__ +#pragma clang diagnostic push +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#pragma clang diagnostic ignored "-Wpadded" + +#endif + // https://en.wikipedia.org/wiki/Wavefront_.obj_file says ... // // -blendu on | off # set horizontal texture blending @@ -218,7 +229,10 @@ namespace tinyobj { // face. 3 = polygon, 4 = quad, // ... Up to 255. std::vector material_ids; // per-face material ID - std::vector tags; // SubD tag + std::vector smoothing_group_ids; // per-face smoothing group + // ID(0 = off. positive value + // = group id) + std::vector tags; // SubD tag } mesh_t; typedef struct { @@ -358,6 +372,7 @@ namespace tinyobj { #include #include #include +#include #include #include @@ -366,14 +381,25 @@ namespace tinyobj { MaterialReader::~MaterialReader() {} - struct vertex_index { + struct vertex_index_t { int v_idx, vt_idx, vn_idx; - vertex_index() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} - explicit vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} - vertex_index(int vidx, int vtidx, int vnidx) + vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} + explicit vertex_index_t(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} + vertex_index_t(int vidx, int vtidx, int vnidx) : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {} }; + // Internal data structure for face representation + // index + smoothing group. + struct face_t { + unsigned int + smoothing_group_id; // smoothing group id. 0 = smoothing groupd is off. + int pad_; + std::vector vertex_indices; // face vertex indices. + + face_t() : smoothing_group_id(0) {} + }; + struct tag_sizes { tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {} int num_ints; @@ -667,9 +693,10 @@ namespace tinyobj { } // Extension: parse vertex with colors(6 items) - static inline bool parseVertexWithColor(real_t *x, real_t *y, real_t *z, real_t *r, - real_t *g, real_t *b, - const char **token, const double default_x = 0.0, + static inline bool parseVertexWithColor(real_t *x, real_t *y, real_t *z, + real_t *r, real_t *g, real_t *b, + const char **token, + const double default_x = 0.0, const double default_y = 0.0, const double default_z = 0.0) { (*x) = parseReal(token, default_x); @@ -741,7 +768,7 @@ namespace tinyobj { return ts; } - (*token)++; // Skip '/' + (*token)++; // Skip '/' (*token) += strspn((*token), " \t"); ts.num_reals = atoi((*token)); @@ -749,7 +776,7 @@ namespace tinyobj { if ((*token)[0] != '/') { return ts; } - (*token)++; // Skip '/' + (*token)++; // Skip '/' ts.num_strings = parseInt(token); @@ -758,12 +785,12 @@ namespace tinyobj { // Parse triples with index offsets: i, i/j/k, i//k, i/j static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize, - vertex_index *ret) { + vertex_index_t *ret) { if (!ret) { return false; } - vertex_index vi(-1); + vertex_index_t vi(-1); if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) { return false; @@ -811,8 +838,8 @@ namespace tinyobj { } // Parse raw triples: i, i/j/k, i//k, i/j - static vertex_index parseRawTriple(const char **token) { - vertex_index vi(static_cast(0)); // 0 is an invalid index in OBJ + static vertex_index_t parseRawTriple(const char **token) { + vertex_index_t vi(static_cast(0)); // 0 is an invalid index in OBJ vi.v_idx = atoi((*token)); (*token) += strcspn((*token), "/ \t\r"); @@ -857,22 +884,22 @@ namespace tinyobj { else { texopt->imfchan = 'm'; } - texopt->bump_multiplier = 1.0f; + texopt->bump_multiplier = static_cast(1.0); texopt->clamp = false; texopt->blendu = true; texopt->blendv = true; - texopt->sharpness = 1.0f; - texopt->brightness = 0.0f; - texopt->contrast = 1.0f; - texopt->origin_offset[0] = 0.0f; - texopt->origin_offset[1] = 0.0f; - texopt->origin_offset[2] = 0.0f; - texopt->scale[0] = 1.0f; - texopt->scale[1] = 1.0f; - texopt->scale[2] = 1.0f; - texopt->turbulence[0] = 0.0f; - texopt->turbulence[1] = 0.0f; - texopt->turbulence[2] = 0.0f; + texopt->sharpness = static_cast(1.0); + texopt->brightness = static_cast(0.0); + texopt->contrast = static_cast(1.0); + texopt->origin_offset[0] = static_cast(0.0); + texopt->origin_offset[1] = static_cast(0.0); + texopt->origin_offset[2] = static_cast(0.0); + texopt->scale[0] = static_cast(1.0); + texopt->scale[1] = static_cast(1.0); + texopt->scale[2] = static_cast(1.0); + texopt->turbulence[0] = static_cast(0.0); + texopt->turbulence[1] = static_cast(0.0); + texopt->turbulence[2] = static_cast(0.0); texopt->type = TEXTURE_TYPE_NONE; const char *token = linebuf; // Assume line ends with NULL @@ -970,24 +997,24 @@ namespace tinyobj { material->reflection_texname = ""; material->alpha_texname = ""; for (int i = 0; i < 3; i++) { - material->ambient[i] = 0.f; - material->diffuse[i] = 0.f; - material->specular[i] = 0.f; - material->transmittance[i] = 0.f; - material->emission[i] = 0.f; + material->ambient[i] = static_cast(0.0); + material->diffuse[i] = static_cast(0.0); + material->specular[i] = static_cast(0.0); + material->transmittance[i] = static_cast(0.0); + material->emission[i] = static_cast(0.0); } material->illum = 0; - material->dissolve = 1.f; - material->shininess = 1.f; - material->ior = 1.f; + material->dissolve = static_cast(1.0); + material->shininess = static_cast(1.0); + material->ior = static_cast(1.0); - material->roughness = 0.f; - material->metallic = 0.f; - material->sheen = 0.f; - material->clearcoat_thickness = 0.f; - material->clearcoat_roughness = 0.f; - material->anisotropy_rotation = 0.f; - material->anisotropy = 0.f; + material->roughness = static_cast(0.0); + material->metallic = static_cast(0.0); + material->sheen = static_cast(0.0); + material->clearcoat_thickness = static_cast(0.0); + material->clearcoat_roughness = static_cast(0.0); + material->anisotropy_rotation = static_cast(0.0); + material->anisotropy = static_cast(0.0); material->roughness_texname = ""; material->metallic_texname = ""; material->sheen_texname = ""; @@ -997,61 +1024,223 @@ namespace tinyobj { material->unknown_parameter.clear(); } - static bool exportFaceGroupToShape( - shape_t *shape, const std::vector > &faceGroup, - const std::vector &tags, const int material_id, - const std::string &name, bool triangulate) { + // code from https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html + template + static int pnpoly(int nvert, T *vertx, T *verty, T testx, + T testy) { + int i, j, c = 0; + for (i = 0, j = nvert - 1; i < nvert; j = i++) { + if (((verty[i] > testy) != (verty[j] > testy)) && + (testx < + (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + + vertx[i])) + c = !c; + } + return c; + } + + // TODO(syoyo): refactor function. + static bool exportFaceGroupToShape(shape_t *shape, + const std::vector &faceGroup, + const std::vector &tags, + const int material_id, + const std::string &name, bool triangulate, + const std::vector &v) { if (faceGroup.empty()) { return false; } // Flatten vertices and indices for (size_t i = 0; i < faceGroup.size(); i++) { - const std::vector &face = faceGroup[i]; + const face_t &face = faceGroup[i]; - vertex_index i0 = face[0]; - vertex_index i1(-1); - vertex_index i2 = face[1]; + if (face.vertex_indices.size() < 3) { + // Face must have 3+ vertices. + continue; + } - size_t npolys = face.size(); + vertex_index_t i0 = face.vertex_indices[0]; + vertex_index_t i1(-1); + vertex_index_t i2 = face.vertex_indices[1]; + + size_t npolys = face.vertex_indices.size(); if (triangulate) { - // Polygon -> triangle fan conversion - for (size_t k = 2; k < npolys; k++) { - i1 = i2; - i2 = face[k]; + // find the two axes to work in + size_t axes[2] = { 1, 2 }; + for (size_t k = 0; k < npolys; ++k) { + i0 = face.vertex_indices[(k + 0) % npolys]; + i1 = face.vertex_indices[(k + 1) % npolys]; + i2 = face.vertex_indices[(k + 2) % npolys]; + size_t vi0 = size_t(i0.v_idx); + size_t vi1 = size_t(i1.v_idx); + size_t vi2 = size_t(i2.v_idx); + real_t v0x = v[vi0 * 3 + 0]; + real_t v0y = v[vi0 * 3 + 1]; + real_t v0z = v[vi0 * 3 + 2]; + real_t v1x = v[vi1 * 3 + 0]; + real_t v1y = v[vi1 * 3 + 1]; + real_t v1z = v[vi1 * 3 + 2]; + real_t v2x = v[vi2 * 3 + 0]; + real_t v2y = v[vi2 * 3 + 1]; + real_t v2z = v[vi2 * 3 + 2]; + real_t e0x = v1x - v0x; + real_t e0y = v1y - v0y; + real_t e0z = v1z - v0z; + real_t e1x = v2x - v1x; + real_t e1y = v2y - v1y; + real_t e1z = v2z - v1z; + real_t cx = std::fabs(e0y * e1z - e0z * e1y); + real_t cy = std::fabs(e0z * e1x - e0x * e1z); + real_t cz = std::fabs(e0x * e1y - e0y * e1x); + const real_t epsilon = std::numeric_limits::epsilon(); + if (cx > epsilon || cy > epsilon || cz > epsilon) { + // found a corner + if (cx > cy && cx > cz) { + } + else { + axes[0] = 0; + if (cz > cx && cz > cy) axes[1] = 1; + } + break; + } + } - index_t idx0, idx1, idx2; - idx0.vertex_index = i0.v_idx; - idx0.normal_index = i0.vn_idx; - idx0.texcoord_index = i0.vt_idx; - idx1.vertex_index = i1.v_idx; - idx1.normal_index = i1.vn_idx; - idx1.texcoord_index = i1.vt_idx; - idx2.vertex_index = i2.v_idx; - idx2.normal_index = i2.vn_idx; - idx2.texcoord_index = i2.vt_idx; + real_t area = 0; + for (size_t k = 0; k < npolys; ++k) { + i0 = face.vertex_indices[(k + 0) % npolys]; + i1 = face.vertex_indices[(k + 1) % npolys]; + size_t vi0 = size_t(i0.v_idx); + size_t vi1 = size_t(i1.v_idx); + real_t v0x = v[vi0 * 3 + axes[0]]; + real_t v0y = v[vi0 * 3 + axes[1]]; + real_t v1x = v[vi1 * 3 + axes[0]]; + real_t v1y = v[vi1 * 3 + axes[1]]; + area += (v0x * v1y - v0y * v1x) * static_cast(0.5); + } - shape->mesh.indices.push_back(idx0); - shape->mesh.indices.push_back(idx1); - shape->mesh.indices.push_back(idx2); + int maxRounds = + 10; // arbitrary max loop count to protect against unexpected errors - shape->mesh.num_face_vertices.push_back(3); - shape->mesh.material_ids.push_back(material_id); + face_t remainingFace = face; // copy + size_t guess_vert = 0; + vertex_index_t ind[3]; + real_t vx[3]; + real_t vy[3]; + while (remainingFace.vertex_indices.size() > 3 && maxRounds > 0) { + npolys = remainingFace.vertex_indices.size(); + if (guess_vert >= npolys) { + maxRounds -= 1; + guess_vert -= npolys; + } + for (size_t k = 0; k < 3; k++) { + ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys]; + size_t vi = size_t(ind[k].v_idx); + vx[k] = v[vi * 3 + axes[0]]; + vy[k] = v[vi * 3 + axes[1]]; + } + real_t e0x = vx[1] - vx[0]; + real_t e0y = vy[1] - vy[0]; + real_t e1x = vx[2] - vx[1]; + real_t e1y = vy[2] - vy[1]; + real_t cross = e0x * e1y - e0y * e1x; + // if an internal angle + if (cross * area < static_cast(0.0)) { + guess_vert += 1; + continue; + } + + // check all other verts in case they are inside this triangle + bool overlap = false; + for (size_t otherVert = 3; otherVert < npolys; ++otherVert) { + size_t ovi = size_t( + remainingFace.vertex_indices[(guess_vert + otherVert) % npolys] + .v_idx); + real_t tx = v[ovi * 3 + axes[0]]; + real_t ty = v[ovi * 3 + axes[1]]; + if (pnpoly(3, vx, vy, tx, ty)) { + overlap = true; + break; + } + } + + if (overlap) { + guess_vert += 1; + continue; + } + + // this triangle is an ear + { + index_t idx0, idx1, idx2; + idx0.vertex_index = ind[0].v_idx; + idx0.normal_index = ind[0].vn_idx; + idx0.texcoord_index = ind[0].vt_idx; + idx1.vertex_index = ind[1].v_idx; + idx1.normal_index = ind[1].vn_idx; + idx1.texcoord_index = ind[1].vt_idx; + idx2.vertex_index = ind[2].v_idx; + idx2.normal_index = ind[2].vn_idx; + idx2.texcoord_index = ind[2].vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + } + + // remove v1 from the list + size_t removed_vert_index = (guess_vert + 1) % npolys; + while (removed_vert_index + 1 < npolys) { + remainingFace.vertex_indices[removed_vert_index] = + remainingFace.vertex_indices[removed_vert_index + 1]; + removed_vert_index += 1; + } + remainingFace.vertex_indices.pop_back(); + } + + if (remainingFace.vertex_indices.size() == 3) { + i0 = remainingFace.vertex_indices[0]; + i1 = remainingFace.vertex_indices[1]; + i2 = remainingFace.vertex_indices[2]; + { + index_t idx0, idx1, idx2; + idx0.vertex_index = i0.v_idx; + idx0.normal_index = i0.vn_idx; + idx0.texcoord_index = i0.vt_idx; + idx1.vertex_index = i1.v_idx; + idx1.normal_index = i1.vn_idx; + idx1.texcoord_index = i1.vt_idx; + idx2.vertex_index = i2.v_idx; + idx2.normal_index = i2.vn_idx; + idx2.texcoord_index = i2.vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + } } } else { for (size_t k = 0; k < npolys; k++) { index_t idx; - idx.vertex_index = face[k].v_idx; - idx.normal_index = face[k].vn_idx; - idx.texcoord_index = face[k].vt_idx; + idx.vertex_index = face.vertex_indices[k].v_idx; + idx.normal_index = face.vertex_indices[k].vn_idx; + idx.texcoord_index = face.vertex_indices[k].vt_idx; shape->mesh.indices.push_back(idx); } shape->mesh.num_face_vertices.push_back( static_cast(npolys)); shape->mesh.material_ids.push_back(material_id); // per face + shape->mesh.smoothing_group_ids.push_back( + face.smoothing_group_id); // per face } } @@ -1246,7 +1435,7 @@ namespace tinyobj { // We invert value of Tr(assume Tr is in range [0, 1]) // NOTE: Interpretation of Tr is application(exporter) dependent. For // some application(e.g. 3ds max obj exporter), Tr = d(Issue 43) - material.dissolve = 1.0f - parseReal(&token); + material.dissolve = static_cast(1.0) - parseReal(&token); } has_tr = true; continue; @@ -1562,13 +1751,17 @@ namespace tinyobj { std::vector vt; std::vector vc; std::vector tags; - std::vector > faceGroup; + std::vector faceGroup; std::string name; // material std::map material_map; int material = -1; + // smoothing group id + unsigned int current_smoothing_id = + 0; // Initial value. 0 means no smoothing. + shape_t shape; std::string linebuf; @@ -1641,11 +1834,13 @@ namespace tinyobj { token += 2; token += strspn(token, " \t"); - std::vector face; - face.reserve(3); + face_t face; + + face.smoothing_group_id = current_smoothing_id; + face.vertex_indices.reserve(3); while (!IS_NEW_LINE(token[0])) { - vertex_index vi; + vertex_index_t vi; if (!parseTriple(&token, static_cast(v.size() / 3), static_cast(vn.size() / 3), static_cast(vt.size() / 2), &vi)) { @@ -1655,14 +1850,13 @@ namespace tinyobj { return false; } - face.push_back(vi); + face.vertex_indices.push_back(vi); size_t n = strspn(token, " \t\r"); token += n; } // replace with emplace_back + std::move on C++11 - faceGroup.push_back(std::vector()); - faceGroup[faceGroup.size() - 1].swap(face); + faceGroup.push_back(face); continue; } @@ -1687,7 +1881,7 @@ namespace tinyobj { // this time. // just clear `faceGroup` after `exportFaceGroupToShape()` call. exportFaceGroupToShape(&shape, faceGroup, tags, material, name, - triangulate); + triangulate, v); faceGroup.clear(); material = newMaterialId; } @@ -1743,7 +1937,7 @@ namespace tinyobj { if (token[0] == 'g' && IS_SPACE((token[1]))) { // flush previous face group. bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, - triangulate); + triangulate, v); (void)ret; // return value not used. if (shape.mesh.indices.size() > 0) { @@ -1781,7 +1975,7 @@ namespace tinyobj { if (token[0] == 'o' && IS_SPACE((token[1]))) { // flush previous face group. bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, - triangulate); + triangulate, v); if (ret) { shapes->push_back(shape); } @@ -1825,13 +2019,51 @@ namespace tinyobj { } tags.push_back(tag); + + continue; } - // Ignore unknown command. + if (token[0] == 's' && IS_SPACE(token[1])) { + // smoothing group id + token += 2; + + // skip space. + token += strspn(token, " \t"); // skip space + + if (token[0] == '\0') { + continue; + } + + if (token[0] == '\r' || token[1] == '\n') { + continue; + } + + if (strlen(token) >= 3) { + if (token[0] == 'o' && token[1] == 'f' && token[2] == 'f') { + current_smoothing_id = 0; + } + } + else { + // assume number + int smGroupId = parseInt(&token); + if (smGroupId < 0) { + // parse error. force set to 0. + // FIXME(syoyo): Report warning. + current_smoothing_id = 0; + } + else { + current_smoothing_id = static_cast(smGroupId); + } + } + + continue; + } // smoothing group id + + // Ignore unknown command. } bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, - triangulate); + triangulate, v); // exportFaceGroupToShape return false when `usemtl` is called in the last // line. // we also add `shape` to `shapes` when `shape.mesh` has already some @@ -1939,7 +2171,7 @@ namespace tinyobj { indices.clear(); while (!IS_NEW_LINE(token[0])) { - vertex_index vi = parseRawTriple(&token); + vertex_index_t vi = parseRawTriple(&token); index_t idx; idx.vertex_index = vi.v_idx; @@ -2137,6 +2369,10 @@ namespace tinyobj { return true; } + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif } // namespace tinyobj #endif diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index a5015c3e1..19956cb4f 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -3074,6 +3074,8 @@ void wiRenderer::UpdatePerFrameData(float dt) Light* l = (Light*)c; l->entityArray_index = i; + l->UpdateLight(); + // Link shadowmaps to lights till there are free slots l->shadowMap_index = -1; @@ -3223,7 +3225,7 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID) matrixArray[shadowIndex + 0] = l->shadowCam_dirLight[0].getVP(); matrixArray[shadowIndex + 1] = l->shadowCam_dirLight[1].getVP(); matrixArray[shadowIndex + 2] = l->shadowCam_dirLight[2].getVP(); - matrixCounter = max(matrixCounter, (UINT)shadowIndex + 2); + matrixCounter = max(matrixCounter, (UINT)shadowIndex + 3); } } break; @@ -3237,7 +3239,7 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID) if (l->shadow && shadowIndex >= 0 && !l->shadowCam_spotLight.empty()) { matrixArray[shadowIndex + 0] = l->shadowCam_spotLight[0].getVP(); - matrixCounter = max(matrixCounter, (UINT)shadowIndex + 2); + matrixCounter = max(matrixCounter, (UINT)shadowIndex + 1); } } break; @@ -3402,7 +3404,7 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID) Mesh* mesh = iter->second; if (mesh->hasArmature() && !mesh->hasDynamicVB() && mesh->renderable && !mesh->vertices_POS.empty() - && mesh->streamoutBuffer_POS.IsValid() && mesh->vertexBuffer_POS.IsValid()) + && mesh->streamoutBuffer_POS != nullptr && mesh->vertexBuffer_POS != nullptr) { Armature* armature = mesh->armature; @@ -3444,12 +3446,12 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID) // Do the skinning GPUResource* vbs[] = { - &mesh->vertexBuffer_POS, - &mesh->vertexBuffer_BON, + mesh->vertexBuffer_POS, + mesh->vertexBuffer_BON, }; GPUResource* sos[] = { - &mesh->streamoutBuffer_POS, - &mesh->streamoutBuffer_PRE, + mesh->streamoutBuffer_POS, + mesh->streamoutBuffer_PRE, }; GetDevice()->BindResources(CS, vbs, SKINNINGSLOT_IN_VERTEX_POS, ARRAYSIZE(vbs), threadID); @@ -4154,13 +4156,13 @@ void wiRenderer::DrawDebugEmitters(Camera* camera, GRAPHICSTHREAD threadID) GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_MISC], &sb, threadID); GPUBuffer* vbs[] = { - &x->object->mesh->vertexBuffer_POS, + x->object->mesh->vertexBuffer_POS, }; const UINT strides[] = { sizeof(Mesh::Vertex_POS), }; GetDevice()->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, nullptr, threadID); - GetDevice()->BindIndexBuffer(&x->object->mesh->indexBuffer, x->object->mesh->GetIndexFormat(), 0, threadID); + GetDevice()->BindIndexBuffer(x->object->mesh->indexBuffer, x->object->mesh->GetIndexFormat(), 0, threadID); GetDevice()->DrawIndexed((int)x->object->mesh->indices.size(), 0, 0, threadID); } @@ -5244,7 +5246,7 @@ void wiRenderer::RenderMeshes(const XMFLOAT3& eye, const CulledCollection& culle if (k < 1) continue; - device->BindIndexBuffer(&mesh->indexBuffer, mesh->GetIndexFormat(), 0, threadID); + device->BindIndexBuffer(mesh->indexBuffer, mesh->GetIndexFormat(), 0, threadID); enum class BOUNDVERTEXBUFFERTYPE { @@ -5338,7 +5340,7 @@ void wiRenderer::RenderMeshes(const XMFLOAT3& eye, const CulledCollection& culle case BOUNDVERTEXBUFFERTYPE::POSITION: { GPUBuffer* vbs[] = { - mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_POS.IsValid() ? &mesh->streamoutBuffer_POS : &mesh->vertexBuffer_POS), + mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_POS != nullptr ? mesh->streamoutBuffer_POS : mesh->vertexBuffer_POS), dynamicVertexBufferPool }; UINT strides[] = { @@ -5355,8 +5357,8 @@ void wiRenderer::RenderMeshes(const XMFLOAT3& eye, const CulledCollection& culle case BOUNDVERTEXBUFFERTYPE::POSITION_TEXCOORD: { GPUBuffer* vbs[] = { - mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_POS.IsValid() ? &mesh->streamoutBuffer_POS : &mesh->vertexBuffer_POS), - &mesh->vertexBuffer_TEX, + mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_POS != nullptr ? mesh->streamoutBuffer_POS : mesh->vertexBuffer_POS), + mesh->vertexBuffer_TEX, dynamicVertexBufferPool }; UINT strides[] = { @@ -5375,9 +5377,9 @@ void wiRenderer::RenderMeshes(const XMFLOAT3& eye, const CulledCollection& culle case BOUNDVERTEXBUFFERTYPE::EVERYTHING: { GPUBuffer* vbs[] = { - mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_POS.IsValid() ? &mesh->streamoutBuffer_POS : &mesh->vertexBuffer_POS), - &mesh->vertexBuffer_TEX, - mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_PRE.IsValid() ? &mesh->streamoutBuffer_PRE : &mesh->vertexBuffer_POS), + mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_POS != nullptr ? mesh->streamoutBuffer_POS : mesh->vertexBuffer_POS), + mesh->vertexBuffer_TEX, + mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_PRE != nullptr ? mesh->streamoutBuffer_PRE : mesh->vertexBuffer_POS), dynamicVertexBufferPool, dynamicVertexBufferPool }; @@ -7196,9 +7198,9 @@ void wiRenderer::CreateImpostor(Mesh* mesh) GetDevice()->InvalidateBufferAccess(dynamicVertexBufferPool, threadID); GPUBuffer* vbs[] = { - mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_POS.IsValid() ? &mesh->streamoutBuffer_POS : &mesh->vertexBuffer_POS), - &mesh->vertexBuffer_TEX, - mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_PRE.IsValid() ? &mesh->streamoutBuffer_PRE : &mesh->vertexBuffer_POS), + mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_POS != nullptr ? mesh->streamoutBuffer_POS : mesh->vertexBuffer_POS), + mesh->vertexBuffer_TEX, + mesh->hasDynamicVB() ? dynamicVertexBufferPool : (mesh->streamoutBuffer_PRE != nullptr ? mesh->streamoutBuffer_PRE : mesh->vertexBuffer_POS), dynamicVertexBufferPool, dynamicVertexBufferPool }; @@ -7218,7 +7220,7 @@ void wiRenderer::CreateImpostor(Mesh* mesh) }; GetDevice()->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, offsets, threadID); - GetDevice()->BindIndexBuffer(&mesh->indexBuffer, mesh->GetIndexFormat(), 0, threadID); + GetDevice()->BindIndexBuffer(mesh->indexBuffer, mesh->GetIndexFormat(), 0, threadID); GetDevice()->BindPrimitiveTopology(TRIANGLELIST, threadID); diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index 890895b40..5196197cc 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -292,7 +292,7 @@ protected: UINT mips; VoxelizedSceneData() :enabled(false), res(128), voxelsize(1.0f), center(XMFLOAT3(0, 0, 0)), extents(XMFLOAT3(0, 0, 0)), numCones(8), - rayStepSize(0.5f), secondaryBounceEnabled(true), reflectionsEnabled(false), centerChangedThisFrame(true), mips(8) + rayStepSize(0.5f), secondaryBounceEnabled(true), reflectionsEnabled(false), centerChangedThisFrame(true), mips(7) {} } static voxelSceneData; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 44bb3b69a..45cb84139 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 16; // minor bug fixes, alterations, refactors, updates - const int revision = 31; + const int revision = 39; long GetVersion() diff --git a/models/Sponza/sponza.wimf b/models/Sponza/sponza.wimf index e59aaf0c3..297e795f2 100644 Binary files a/models/Sponza/sponza.wimf and b/models/Sponza/sponza.wimf differ