bool Fluids3DWindow::CreateNestedBoxes() { std::string path = mEnvironment.GetPath("VolumeRender.hlsl"); std::shared_ptr<VisualProgram> program = mProgramFactory.CreateFromFiles(path, path, ""); if (!program) { return false; } mPVWMatrixBuffer = std::make_shared<ConstantBuffer>( sizeof(Matrix4x4<float>), true); *mPVWMatrixBuffer->Get<Matrix4x4<float>>() = Matrix4x4<float>::Identity(); mTrilinearClampSampler = std::make_shared<SamplerState>(); mTrilinearClampSampler->filter = SamplerState::MIN_L_MAG_L_MIP_P; mTrilinearClampSampler->mode[0] = SamplerState::CLAMP; mTrilinearClampSampler->mode[1] = SamplerState::CLAMP; mTrilinearClampSampler->mode[2] = SamplerState::CLAMP; program->GetVShader()->Set("PVWMatrix", mPVWMatrixBuffer); program->GetPShader()->Set("volumeTexture", mFluid.GetState()); program->GetPShader()->Set("trilinearClampSampler", mTrilinearClampSampler); std::shared_ptr<VisualEffect> effect = std::make_shared<VisualEffect>(program); struct Vertex { Vector3<float> position, tcoord; }; VertexFormat vformat; vformat.Bind(VA_POSITION, DF_R32G32B32_FLOAT, 0); vformat.Bind(VA_TEXCOORD, DF_R32G32B32_FLOAT, 0); MeshFactory mf; mf.SetVertexFormat(vformat); int const numBoxes = 128; for (int i = 1; i <= numBoxes; ++i) { float extent = 0.5f*i/(numBoxes - 1.0f); std::shared_ptr<Visual> visual(mf.CreateBox(extent, extent, extent)); VertexBuffer* vbuffer = visual->GetVertexBuffer().get(); Vertex* vertex = vbuffer->Get<Vertex>(); for (unsigned int j = 0; j < vbuffer->GetNumElements(); ++j, ++vertex) { Vector3<float>& tcd = vertex->tcoord; Vector3<float> pos = vertex->position; Vector4<float> tmp{ pos[0] + 0.5f, pos[1] + 0.5f, pos[2] + 0.5f, 0.0f }; for (int k = 0; k < 3; ++k) { tcd[k] = 0.5f*(tmp[k] + 1.0f); } } visual->SetEffect(effect); mVisible.push_back(visual); } return true; }
void MinimumVolumeBox3DWindow::CreateScene() { mScene = std::make_shared<Node>(); std::mt19937 mte; std::uniform_real_distribution<float> rnd(-1.0f, 1.0f); Vector3<float> center{ 0.0f, 0.0f, 0.0f }; Vector3<float> extent{ 1.0f, 0.25f, 0.125f }; Vector3<float> axis[3] = { { 1.0f, 1.0f, 0.0f }, { -1.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } }; Normalize(axis[0]); Normalize(axis[1]); Normalize(axis[2]); for (auto& v : mVertices) { float theta = rnd(mte) * (float)GTE_C_TWO_PI; float phi = rnd(mte) * (float)GTE_C_PI; float radius = 0.5f * (rnd(mte) + 1.0f); float x = extent[0] * cos(theta) * sin(phi); float y = extent[1] * sin(theta) * sin(phi); float z = extent[2] * cos(phi); v = center + radius * (x * axis[0] + y * axis[1] + z * axis[2]); } struct Vertex { Vector3<float> position; Vector4<float> color; }; VertexFormat vformat; vformat.Bind(VA_POSITION, DF_R32G32B32_FLOAT, 0); vformat.Bind(VA_COLOR, DF_R32G32B32A32_FLOAT, 0); std::shared_ptr<VertexBuffer> vbuffer(new VertexBuffer(vformat, NUM_POINTS)); Vertex* vertex = vbuffer->Get<Vertex>(); for (int i = 0; i < NUM_POINTS; ++i) { vertex[i].position[0] = (float)mVertices[i][0]; vertex[i].position[1] = (float)mVertices[i][1]; vertex[i].position[2] = (float)mVertices[i][2]; vertex[i].color[0] = 0.5f * (rnd(mte) + 1.0f); vertex[i].color[1] = 0.5f * (rnd(mte) + 1.0f); vertex[i].color[2] = 0.5f * (rnd(mte) + 1.0f); vertex[i].color[3] = 1.0f; } std::shared_ptr<IndexBuffer> ibuffer(new IndexBuffer(IP_POLYPOINT, NUM_POINTS)); std::shared_ptr<VertexColorEffect> effect = std::make_shared<VertexColorEffect>(mProgramFactory); mPoints = std::make_shared<Visual>(vbuffer, ibuffer, effect); mCameraRig.Subscribe(mPoints->worldTransform, effect->GetPVWMatrixConstant()); mScene->AttachChild(mPoints); // Choose the number of threads to use. The default constructor for // MinimumVolumeBox3 uses a default of 1, in which case all computations // are on the main thread. The timings below are for a 64-bit release // build (no debugger attached) on Intel Core i7-3930K CPUs running at // 3.20 GHz. unsigned int numThreads = 1; #if 0 // Compute the convex hull internally using arbitrary precision // arithmetic. This is slower than computing the hull explicitly using // the maximum fixed precision; see the other conditional block of code. Timer timer; typedef BSRational<UIntegerAP32> MVBRational; MinimumVolumeBox3<float, MVBRational> mvb3(numThreads); OrientedBox3<float> minBox = mvb3(NUM_POINTS, &mVertices[0]); std::cout << "mvb3 seconds = " << timer.GetSeconds() << std::endl; // numThreads = 1, seconds = 7.09 // numThreads = 2, seconds = 6.22 #else // If mVertices were to use 'double', you would need the template type // UIntegerFP32<167> to compute the convex hull. Timer timer; typedef BSNumber<UIntegerFP32<27>> CHRational; ConvexHull3<float, CHRational> ch3(numThreads); ch3(NUM_POINTS, &mVertices[0], 0.0f); std::vector<TriangleKey<true>> const& triangles = ch3.GetHullUnordered(); int const numIndices = static_cast<int>(3 * triangles.size()); int const* indices = static_cast<int const*>(&triangles[0].V[0]); typedef BSRational<UIntegerAP32> MVBRational; MinimumVolumeBox3<float, MVBRational> mvb3(numThreads); OrientedBox3<float> minBox = mvb3(NUM_POINTS, &mVertices[0], numIndices, indices); std::cout << "mvb3 seconds = " << timer.GetSeconds() << std::endl; // numThreads = 1, seconds = 2.69 // numThreads = 2, seconds = 2.01 #endif std::vector<int> const& hull = mvb3.GetHull(); ibuffer = std::make_shared<IndexBuffer>(IP_TRIMESH, static_cast<int>(hull.size() / 3), sizeof(int)); Memcpy(ibuffer->GetData(), &hull[0], ibuffer->GetNumBytes()); mPolytope = std::make_shared<Visual>(vbuffer, ibuffer, effect); mScene->AttachChild(mPolytope); MeshFactory mf; mf.SetVertexFormat(vformat); mBoxMesh = mf.CreateBox(1.0f, 1.0f, 1.0f); vbuffer = mBoxMesh->GetVertexBuffer(); vertex = vbuffer->Get<Vertex>(); std::array<Vector3<float>, 8> corner; minBox.GetVertices(corner); for (int i = 0; i < 8; ++i) { vertex[i].position[0] = corner[i][0]; vertex[i].position[1] = corner[i][1]; vertex[i].position[2] = corner[i][2]; vertex[i].color[0] = 0.5f * (rnd(mte) + 1.0f); vertex[i].color[1] = 0.5f * (rnd(mte) + 1.0f); vertex[i].color[2] = 0.5f * (rnd(mte) + 1.0f); vertex[i].color[3] = 1.0f; } mBoxMesh->SetEffect(effect); mScene->AttachChild(mBoxMesh); mTrackball.Attach(mScene); mTrackball.Update(); }