void rtBIHNode::calcBox() { if (hasLeaves()) { UINT leavesCount = getLeavesCount(); if (leavesCount > 0) { m_BoundingBox = m_pLeaves[0]->box; for (UINT i = 1; i<leavesCount; i++) { m_BoundingBox.Min = XMVectorMin(m_BoundingBox.Min, m_pLeaves[i]->box.Min); m_BoundingBox.Max = XMVectorMax(m_BoundingBox.Max, m_pLeaves[i]->box.Max); } } else { m_BoundingBox.Min = g_XMZero; m_BoundingBox.Max = g_XMZero; } } else { m_pChild[0].calcBox(); m_pChild[1].calcBox(); m_BoundingBox.Min = XMVectorMin(m_pChild[0].m_BoundingBox.Min, m_pChild[1].m_BoundingBox.Min); m_BoundingBox.Max = XMVectorMax(m_pChild[0].m_BoundingBox.Max, m_pChild[1].m_BoundingBox.Max); } }
VOID Bound::Merge( const Bound& Other ) { Sphere OtherSphere; OtherSphere.Center = Other.GetCenter(); OtherSphere.Radius = Other.GetMaxRadius(); if( m_Type == Bound::No_Bound ) { SetSphere( OtherSphere ); return; } Sphere ThisSphere; if( m_Type != Bound::Sphere_Bound ) { // convert this bound into a sphere ThisSphere.Center = GetCenter(); ThisSphere.Radius = GetMaxRadius(); } else { ThisSphere = GetSphere(); } XMVECTOR vThisCenter = XMLoadFloat3( &ThisSphere.Center ); XMVECTOR vOtherCenter = XMLoadFloat3( &OtherSphere.Center ); XMVECTOR vThisToOther = XMVectorSubtract( vOtherCenter, vThisCenter ); XMVECTOR vDistance = XMVector3LengthEst( vThisToOther ); FLOAT fCombinedDiameter = XMVectorGetX( vDistance ) + ThisSphere.Radius + OtherSphere.Radius; if( fCombinedDiameter <= ( ThisSphere.Radius * 2 ) ) { SetSphere( ThisSphere ); return; } if( fCombinedDiameter <= ( OtherSphere.Radius * 2 ) ) { SetSphere( OtherSphere ); return; } XMVECTOR vDirectionNorm = XMVector3Normalize( vThisToOther ); XMVECTOR vRadius = XMVectorSet( ThisSphere.Radius, OtherSphere.Radius, 0, 0 ); XMVECTOR vThisRadius = XMVectorSplatX( vRadius ); XMVECTOR vOtherRadius = XMVectorSplatY( vRadius ); XMVECTOR vCombinedDiameter = vThisRadius + vDistance + vOtherRadius; XMVECTOR vMaxDiameter = XMVectorMax( vCombinedDiameter, vThisRadius * 2 ); vMaxDiameter = XMVectorMax( vMaxDiameter, vOtherRadius * 2 ); XMVECTOR vMaxRadius = vMaxDiameter * 0.5f; ThisSphere.Radius = XMVectorGetX( vMaxRadius ); vMaxRadius -= vThisRadius; XMVECTOR vCombinedCenter = vThisCenter + vMaxRadius * vDirectionNorm; XMStoreFloat3( &ThisSphere.Center, vCombinedCenter ); SetSphere( ThisSphere ); }
//! Returns the bounding box in world space. [NOTE] Does not work [TODO]. AxisAlignedBox AnimatedObject::GetBoundingBox() { //AxisAlignedBox aabb = mSkinnedModel->GetBoundingBox(); // [WIP] The precalculated AABB for the model. SkinnedMeshList* meshList = mSkinnedModel->GetMeshList(); XNA::AxisAlignedBox aabb = meshList->operator[](0)->GetPrimitive()->GetBoundingBox(); XMFLOAT3 min = aabb.Center - aabb.Extents; XMFLOAT3 max = aabb.Center + aabb.Extents; for(int i = 1; i < meshList->size(); i++) { AxisAlignedBox meshAABB = (*meshList)[i]->GetPrimitive()->GetBoundingBox(); XMFLOAT3 meshMin = meshAABB.Center - meshAABB.Extents; XMFLOAT3 meshMax = meshAABB.Center + meshAABB.Extents; XMStoreFloat3(&min, XMVectorMin(XMLoadFloat3(&meshMin), XMLoadFloat3(&min))); XMStoreFloat3(&max, XMVectorMax(XMLoadFloat3(&meshMax), XMLoadFloat3(&max))); } aabb.Center = (min + max) * 0.5f; aabb.Extents = (max - min) * 0.5f; // Break up the world matrix into it's components. XMVECTOR scale, rotation, translation; XMMatrixDecompose(&scale, &rotation, &translation, GetWorldMatrix()); // Transform the AABB with the components. TransformAxisAlignedBoxCustom(&aabb, &aabb, scale, rotation, translation); aabb.Center = GetPosition(); // [NOTE] Not like this in StaticObject. return aabb; }
void Entity::LoadVertData(std::vector<Vertex::Basic32>& verts, UINT& k) { XMFLOAT3 vMinf3(+MathHelper::Infinity, +MathHelper::Infinity, +MathHelper::Infinity); XMFLOAT3 vMaxf3(-MathHelper::Infinity, -MathHelper::Infinity, -MathHelper::Infinity); XMVECTOR vMin = XMLoadFloat3(&vMinf3); XMVECTOR vMax = XMLoadFloat3(&vMaxf3); for (size_t i = 0; i < mGrid.Vertices.size(); ++i, ++k) { verts[k].Pos = mGrid.Vertices[i].Position; verts[k].Normal = mGrid.Vertices[i].Normal; verts[k].Tex = mGrid.Vertices[i].TexC; //Copy Into The Buttons Messh For Future Collision Check mMeshVertices[i].Pos = mGrid.Vertices[i].Position; mMeshVertices[i].Normal = mGrid.Vertices[i].Normal; XMVECTOR P = XMLoadFloat3(&mMeshVertices[i].Pos); vMin = XMVectorMin(vMin, P); vMax = XMVectorMax(vMax, P); } XMStoreFloat3(&mMeshBox.Center, 0.5f*(vMin + vMax)); XMStoreFloat3(&mMeshBox.Extents, 0.5f*(vMax - vMin)); }
bool D3D11RendererMesh::BuildBuffers(const GeoGen::MeshData& mesh) { D3D11_BUFFER_DESC desc = { 0 }; desc.ByteWidth = sizeof(VertexPositionNormalTexture) * mesh.vertices.size(); desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; desc.Usage = D3D11_USAGE_DEFAULT; m_nVBSize = mesh.vertices.size(); m_nIBSize = mesh.indices.size(); vertices.resize(mesh.vertices.size()); float Infinity = FLT_MAX; XMFLOAT3 vMinf3(+Infinity, +Infinity, +Infinity); XMFLOAT3 vMaxf3(-Infinity, -Infinity, -Infinity); vMin = XMLoadFloat3(&vMinf3); vMax = XMLoadFloat3(&vMaxf3); for (UINT i = 0; i < mesh.vertices.size(); ++i) { vertices[i].position = mesh.vertices[i].pos; vertices[i].normal = mesh.vertices[i].normal; vertices[i].textureCoordinate = mesh.vertices[i].tex; XMVECTOR P = XMLoadFloat3(&vertices[i].position); vMin = XMVectorMin(vMin, P); vMax = XMVectorMax(vMax, P); } D3D11_SUBRESOURCE_DATA vData; vData.pSysMem = &vertices[0]; vData.SysMemPitch = 0; vData.SysMemSlicePitch = 0; if (FAILED(m_d3dDevice->CreateBuffer(&desc, &vData, &m_VB))) { MessageBox(NULL, L"Create Vertex Buffer failed!", L"Error", MB_OK); return false; } D3D11_BUFFER_DESC iDesc = { 0 }; iDesc.ByteWidth = sizeof(UINT) * mesh.indices.size(); iDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; iDesc.Usage = D3D11_USAGE_DEFAULT; indices.resize(mesh.indices.size()); for (UINT i = 0; i < mesh.indices.size(); ++i) { indices[i] = mesh.indices[i]; } D3D11_SUBRESOURCE_DATA iData; iData.pSysMem = &indices[0]; iData.SysMemPitch = 0; iData.SysMemSlicePitch = 0; if (FAILED(m_d3dDevice->CreateBuffer(&iDesc, &iData, &m_IB))) { MessageBox(NULL, L"Create Index Buffer failed!", L"Error", MB_OK); return false; } return true; }
/** * Component wise set to maximum of this and other. */ CFVec4& CFVec4::MaximizeWith( CFVec4Arg fv4Other ) { XMVECTOR& v4V = *reinterpret_cast<XMVECTOR*>( this ); const XMVECTOR& v4V2 = *reinterpret_cast<const XMVECTOR*>( &fv4Other ); v4V = XMVectorMax( v4V, v4V2 ); return *this; }
CFVec4 CFVec4::GetMax( CFVec4Arg fv4Other ) const { CFVec4 v4Return; const XMVECTOR& v4V = *reinterpret_cast<const XMVECTOR*>( this ); const XMVECTOR& v4V2 = *reinterpret_cast<const XMVECTOR*>( &fv4Other ); XMVECTOR& v4Result = *reinterpret_cast<XMVECTOR*>( &v4Return ); v4Result = XMVectorMax( v4V, v4V2 ); return v4Return; }
void Entity::UpdateAAB() { XMFLOAT3 vMinf3(+MathHelper::Infinity, +MathHelper::Infinity, +MathHelper::Infinity); XMFLOAT3 vMaxf3(-MathHelper::Infinity, -MathHelper::Infinity, -MathHelper::Infinity); XMVECTOR vMin = XMLoadFloat3(&vMinf3); XMVECTOR vMax = XMLoadFloat3(&vMaxf3); for (size_t i = 0; i < mGrid.Vertices.size(); ++i) { XMVECTOR P = XMLoadFloat3(&mMeshVertices[i].Pos); P = XMVector3TransformCoord(P, XMLoadFloat4x4(&mWorld)); vMin = XMVectorMin(vMin, P); vMax = XMVectorMax(vMax, P); } XMStoreFloat3(&mMeshBox.Center, 0.5f*(vMin + vMax)); XMStoreFloat3(&mMeshBox.Extents, 0.5f*(vMax - vMin)); }
//----------------------------------------------------------------------------- // Transform an axis aligned box by an angle preserving transform. //----------------------------------------------------------------------------- VOID TransformAxisAlignedBoxCustom(XNA::AxisAlignedBox* pOut, const XNA::AxisAlignedBox* pIn, FXMVECTOR Scale, FXMVECTOR Rotation, FXMVECTOR Translation ) { XMASSERT( pOut ); XMASSERT( pIn ); static XMVECTOR Offset[8] = { { -1.0f, -1.0f, -1.0f, 0.0f }, { -1.0f, -1.0f, 1.0f, 0.0f }, { -1.0f, 1.0f, -1.0f, 0.0f }, { -1.0f, 1.0f, 1.0f, 0.0f }, { 1.0f, -1.0f, -1.0f, 0.0f }, { 1.0f, -1.0f, 1.0f, 0.0f }, { 1.0f, 1.0f, -1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 0.0f } }; // Load center and extents. XMVECTOR Center = XMLoadFloat3( &pIn->Center ); XMVECTOR Extents = XMLoadFloat3( &pIn->Extents ); XMVECTOR VectorScale = Scale;//XMVectorReplicate( Scale ); // Compute and transform the corners and find new min/max bounds. XMVECTOR Corner = Center + Extents * Offset[0]; Corner = XMVector3Rotate( Corner * VectorScale, Rotation ) + Translation; XMVECTOR Min, Max; Min = Max = Corner; for( INT i = 1; i < 8; i++ ) { Corner = Center + Extents * Offset[i]; Corner = XMVector3Rotate( Corner * VectorScale, Rotation ) + Translation; Min = XMVectorMin( Min, Corner ); Max = XMVectorMax( Max, Corner ); } // Store center and extents. XMStoreFloat3( &pOut->Center, ( Min + Max ) * 0.5f ); XMStoreFloat3( &pOut->Extents, ( Max - Min ) * 0.5f ); return; }
XMVECTOR LimitAngle(const XMVECTOR& quat, const XMVECTOR& rotmin, const XMVECTOR& rotmax) { XMVECTOR rot_xyz = GetAngle(quat); /* XMMATRIX mtx = XMMatrixRotationQuaternion(quat); //ZYX Y=-90〜90°Y軸=ねじり方向 float rx = -atan2f(XMVectorGetY(mtx.r[2]),XMVectorGetZ(mtx.r[2])); float ry = asinf(XMVectorGetX(mtx.r[2])); float rz = -atan2f(XMVectorGetX(mtx.r[1]),XMVectorGetX(mtx.r[0])); XMVECTOR rot_xyz = {rx,ry,rz,0}; *rotang_before = rot_xyz; */ rot_xyz = XMVectorMax(rot_xyz, rotmin); rot_xyz = XMVectorMin(rot_xyz, rotmax); XMMATRIX mtx = XMMatrixRotationZ(XMVectorGetZ(rot_xyz)); mtx = XMMatrixMultiply(mtx, XMMatrixRotationY(XMVectorGetY(rot_xyz))); mtx = XMMatrixMultiply(mtx, XMMatrixRotationX(XMVectorGetX(rot_xyz))); return XMQuaternionRotationMatrix(mtx); }
void SkinnedModel::CalculateAABB() { XMFLOAT3 min = XMFLOAT3(numeric_limits<float>::infinity(), numeric_limits<float>::infinity(), numeric_limits<float>::infinity()); XMFLOAT3 max = XMFLOAT3(-numeric_limits<float>::infinity(), -numeric_limits<float>::infinity(), -numeric_limits<float>::infinity()); for(int i = 0; i < 1; i++) { vector<XMFLOAT4X4> transforms = mAnimator->GetTransforms(1.0f); for(int j = 0; j < mMeshList.size(); j++) { XNA::AxisAlignedBox aabb = mMeshList[j]->CalculateAABB(transforms); XMFLOAT3 meshMin = aabb.Center - aabb.Extents; XMFLOAT3 meshMax = aabb.Center + aabb.Extents; XMStoreFloat3(&min, XMVectorMin(XMLoadFloat3(&meshMin), XMLoadFloat3(&min))); XMStoreFloat3(&max, XMVectorMax(XMLoadFloat3(&meshMax), XMLoadFloat3(&max))); } } mAABB.Center = (min + max) * 0.5f; mAABB.Extents = (max - min) * 0.5f; }
Vector3 Vector3::maximise(const Vector3& a, const Vector3& b) { return Vector3(XMVectorMax(a, b)); }
void InstancingAndCullingApp::BuildSkullGeometryBuffers() { std::ifstream fin("Models/skull.txt"); if(!fin) { MessageBox(0, L"Models/skull.txt not found.", 0, 0); return; } UINT vcount = 0; UINT tcount = 0; std::string ignore; fin >> ignore >> vcount; fin >> ignore >> tcount; fin >> ignore >> ignore >> ignore >> ignore; XMFLOAT3 vMinf3(+MathHelper::Infinity, +MathHelper::Infinity, +MathHelper::Infinity); XMFLOAT3 vMaxf3(-MathHelper::Infinity, -MathHelper::Infinity, -MathHelper::Infinity); XMVECTOR vMin = XMLoadFloat3(&vMinf3); XMVECTOR vMax = XMLoadFloat3(&vMaxf3); std::vector<Vertex::Basic32> vertices(vcount); for(UINT i = 0; i < vcount; ++i) { fin >> vertices[i].Pos.x >> vertices[i].Pos.y >> vertices[i].Pos.z; fin >> vertices[i].Normal.x >> vertices[i].Normal.y >> vertices[i].Normal.z; XMVECTOR P = XMLoadFloat3(&vertices[i].Pos); vMin = XMVectorMin(vMin, P); vMax = XMVectorMax(vMax, P); } XMStoreFloat3(&mSkullBox.Center, 0.5f*(vMin+vMax)); XMStoreFloat3(&mSkullBox.Extents, 0.5f*(vMax-vMin)); fin >> ignore; fin >> ignore; fin >> ignore; mSkullIndexCount = 3*tcount; std::vector<UINT> indices(mSkullIndexCount); for(UINT i = 0; i < tcount; ++i) { fin >> indices[i*3+0] >> indices[i*3+1] >> indices[i*3+2]; } fin.close(); D3D11_BUFFER_DESC vbd; vbd.Usage = D3D11_USAGE_IMMUTABLE; vbd.ByteWidth = sizeof(Vertex::Basic32) * vcount; vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER; vbd.CPUAccessFlags = 0; vbd.MiscFlags = 0; D3D11_SUBRESOURCE_DATA vinitData; vinitData.pSysMem = &vertices[0]; HR(md3dDevice->CreateBuffer(&vbd, &vinitData, &mSkullVB)); // // Pack the indices of all the meshes into one index buffer. // D3D11_BUFFER_DESC ibd; ibd.Usage = D3D11_USAGE_IMMUTABLE; ibd.ByteWidth = sizeof(UINT) * mSkullIndexCount; ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; ibd.CPUAccessFlags = 0; ibd.MiscFlags = 0; D3D11_SUBRESOURCE_DATA iinitData; iinitData.pSysMem = &indices[0]; HR(md3dDevice->CreateBuffer(&ibd, &iinitData, &mSkullIB)); }
void rtBIHNode::buildSubNodes(rtNodeBuildDesc* pDesc, UINT* pCounter) { size_t dataSize = sizeof(rtBIHLeaf*) * pDesc->leavesCount; if (pDesc->leavesCount < 3) { m_pLeaves = (rtBIHLeaf**)pDesc->pLeavesMemPool->alloc(dataSize); memcpy_4(m_pLeaves, pDesc->pSrcLeaves, dataSize); m_Flags = BIH_LEAF | (pDesc->leavesCount << 2); return; } LARGE_INTEGER start, stop; // sort leaves for (UINT i = 0; i<3; i++) { if (i != pDesc->sortedBy) { memcpy_4(pDesc->pSortedLeaves[i], pDesc->pSrcLeaves, dataSize); if (pDesc->leavesCount > INSERT_SORT_TRESHOLD+1) quickSortObjectsByAxis(pDesc->pSortedLeaves[i], 0, pDesc->leavesCount-1, i); else insertSortObjectsByAxis(pDesc->pSortedLeaves[i], 0, pDesc->leavesCount-1, i); } } if (pDesc->sortedBy < 3) memcpy_4(pDesc->pSortedLeaves[pDesc->sortedBy], pDesc->pSrcLeaves, dataSize); XMVECTOR leftCost, rightCost, totalCost; XMVECTOR bestCost = XMVectorReplicate(1.0e+30f); UINT bestAxis = 3; UINT bestSplitPos = 0; int i; QueryPerformanceCounter(&start); for (UINT axis = 0; axis<3; axis++) { //calculate possible left node aabbs pDesc->LeftAABBs[0] = pDesc->pSortedLeaves[axis][0]->box; XMVECTOR prevMin = pDesc->LeftAABBs[0].Min; XMVECTOR prevMax = pDesc->LeftAABBs[0].Max; for (i = 1; i<pDesc->leavesCount; i++) { prevMin = XMVectorMin(prevMin, pDesc->pSortedLeaves[axis][i]->box.Min); prevMax = XMVectorMax(prevMax, pDesc->pSortedLeaves[axis][i]->box.Max); pDesc->LeftAABBs[i].Min = prevMin; pDesc->LeftAABBs[i].Max = prevMax; } //calculate possible right node aabbs pDesc->RightAABBs[pDesc->leavesCount-1] = pDesc->pSortedLeaves[axis][pDesc->leavesCount-1]->box; prevMin = pDesc->RightAABBs[pDesc->leavesCount-1].Min; prevMax = pDesc->RightAABBs[pDesc->leavesCount-1].Max; for (i = pDesc->leavesCount-2; i>=0; i--) { prevMin = XMVectorMin(prevMin, pDesc->pSortedLeaves[axis][i]->box.Min); prevMax = XMVectorMax(prevMax, pDesc->pSortedLeaves[axis][i]->box.Max); pDesc->RightAABBs[i].Min = prevMin; pDesc->RightAABBs[i].Max = prevMax; } UINT splitpos; UINT max_splitpos = pDesc->leavesCount-1; XMVECTOR leftCount, rightcount; switch (pDesc->heuristics) { case SURFACE_AREA: for (splitpos = 2; splitpos<max_splitpos; splitpos++) { leftCost = pDesc->LeftAABBs[splitpos].getSurfaceArea(); rightCost = pDesc->RightAABBs[splitpos+1].getSurfaceArea(); leftCount = XMConvertVectorUIntToFloat(XMVectorReplicateInt(splitpos + 1), 0); rightcount = XMConvertVectorUIntToFloat(XMVectorReplicateInt(max_splitpos - splitpos), 0); totalCost = leftCost*leftCount + rightCost*rightcount; if (XMVector3Greater(bestCost, totalCost)) { bestAxis = axis; bestSplitPos = splitpos; bestCost = totalCost; } } break; case VOLUME: for (splitpos = 2; splitpos<max_splitpos; splitpos++) { leftCost = pDesc->LeftAABBs[splitpos].getVolume(); rightCost = pDesc->RightAABBs[splitpos+1].getVolume(); leftCount = XMVectorReplicate((float)(splitpos + 1)); rightcount = XMVectorReplicate((float)(max_splitpos - splitpos)); totalCost = leftCost*leftCount + rightCost*rightcount; if (XMVector3Greater(bestCost, totalCost)) { bestAxis = axis; bestSplitPos = splitpos; bestCost = totalCost; } } break; } } QueryPerformanceCounter(&stop); g_sortingTime.QuadPart += stop.QuadPart - start.QuadPart; if (bestAxis >= 3) { bestSplitPos = 1; bestAxis = 0; /* m_pLeaves = (rtBIHLeaf**)pDesc->pLeavesMemPool->alloc(dataSize); memcpy_4(m_pLeaves, pDesc->pSrcLeaves, dataSize); m_Flags = BIH_LEAF | (pDesc->leavesCount << 2); return; */ } // m_pChild = (rtBIHNode*)pDesc->pNodesMemPool->alloc(sizeof(rtBIHNode)*2); UINT childLeavesCount; rtNodeBuildDesc desc; desc.heuristics = pDesc->heuristics; desc.pLeavesMemPool = pDesc->pLeavesMemPool; desc.pNodesMemPool = pDesc->pNodesMemPool; desc.LeftAABBs = pDesc->LeftAABBs; desc.RightAABBs = pDesc->RightAABBs; desc.pSortedLeaves[0] = pDesc->pSortedLeaves[0]; desc.pSortedLeaves[1] = pDesc->pSortedLeaves[1]; desc.pSortedLeaves[2] = pDesc->pSortedLeaves[2]; desc.sortedBy = bestAxis; //construct left node m_pChild[0] = rtBIHNode(); m_pChild[0].m_ID = *pCounter; m_pChild[0].m_pParent = this; desc.leavesCount = bestSplitPos+1; desc.pSrcLeaves = pDesc->pSortedLeaves[bestAxis]; (*pCounter)++; m_pChild[0].buildSubNodes(&desc, pCounter); //construct right node m_pChild[1] = rtBIHNode(); m_pChild[1].m_ID = *pCounter; m_pChild[1].m_pParent = this; desc.leavesCount = pDesc->leavesCount - (bestSplitPos+1); desc.pSrcLeaves = &(pDesc->pSortedLeaves[bestAxis][bestSplitPos+1]); (*pCounter)++; m_pChild[1].buildSubNodes(&desc, pCounter); m_Flags = bestAxis; }
// Renders meshes using cascaded shadow mapping void MeshRenderer::RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera) { PIXEvent event(L"Sun Shadow Map Rendering"); const float MinDistance = reductionDepth.x; const float MaxDistance = reductionDepth.y; // Compute the split distances based on the partitioning mode float CascadeSplits[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; { float lambda = 1.0f; float nearClip = camera.NearClip(); float farClip = camera.FarClip(); float clipRange = farClip - nearClip; float minZ = nearClip + MinDistance * clipRange; float maxZ = nearClip + MaxDistance * clipRange; float range = maxZ - minZ; float ratio = maxZ / minZ; for(uint32 i = 0; i < NumCascades; ++i) { float p = (i + 1) / static_cast<float>(NumCascades); float log = minZ * std::pow(ratio, p); float uniform = minZ + range * p; float d = lambda * (log - uniform) + uniform; CascadeSplits[i] = (d - nearClip) / clipRange; } } Float3 c0Extents; Float4x4 c0Matrix; const Float3 lightDir = AppSettings::SunDirection; // Render the meshes to each cascade for(uint32 cascadeIdx = 0; cascadeIdx < NumCascades; ++cascadeIdx) { PIXEvent cascadeEvent((L"Rendering Shadow Map Cascade " + ToString(cascadeIdx)).c_str()); // Set the viewport SetViewport(context, ShadowMapSize, ShadowMapSize); // Set the shadow map as the depth target ID3D11DepthStencilView* dsv = sunShadowDepthMap.DSView; ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { NULL }; context->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, nullRenderTargets, dsv); context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); // Get the 8 points of the view frustum in world space XMVECTOR frustumCornersWS[8] = { XMVectorSet(-1.0f, 1.0f, 0.0f, 1.0f), XMVectorSet( 1.0f, 1.0f, 0.0f, 1.0f), XMVectorSet( 1.0f, -1.0f, 0.0f, 1.0f), XMVectorSet(-1.0f, -1.0f, 0.0f, 1.0f), XMVectorSet(-1.0f, 1.0f, 1.0f, 1.0f), XMVectorSet( 1.0f, 1.0f, 1.0f, 1.0f), XMVectorSet( 1.0f, -1.0f, 1.0f, 1.0f), XMVectorSet(-1.0f, -1.0f, 1.0f, 1.0f), }; float prevSplitDist = cascadeIdx == 0 ? MinDistance : CascadeSplits[cascadeIdx - 1]; float splitDist = CascadeSplits[cascadeIdx]; XMVECTOR det; XMMATRIX invViewProj = XMMatrixInverse(&det, camera.ViewProjectionMatrix().ToSIMD()); for(uint32 i = 0; i < 8; ++i) frustumCornersWS[i] = XMVector3TransformCoord(frustumCornersWS[i], invViewProj); // Get the corners of the current cascade slice of the view frustum for(uint32 i = 0; i < 4; ++i) { XMVECTOR cornerRay = XMVectorSubtract(frustumCornersWS[i + 4], frustumCornersWS[i]); XMVECTOR nearCornerRay = XMVectorScale(cornerRay, prevSplitDist); XMVECTOR farCornerRay = XMVectorScale(cornerRay, splitDist); frustumCornersWS[i + 4] = XMVectorAdd(frustumCornersWS[i], farCornerRay); frustumCornersWS[i] = XMVectorAdd(frustumCornersWS[i], nearCornerRay); } // Calculate the centroid of the view frustum slice XMVECTOR frustumCenterVec = XMVectorZero(); for(uint32 i = 0; i < 8; ++i) frustumCenterVec = XMVectorAdd(frustumCenterVec, frustumCornersWS[i]); frustumCenterVec = XMVectorScale(frustumCenterVec, 1.0f / 8.0f); Float3 frustumCenter = frustumCenterVec; // Pick the up vector to use for the light camera Float3 upDir = camera.Right(); Float3 minExtents; Float3 maxExtents; { // Create a temporary view matrix for the light Float3 lightCameraPos = frustumCenter; Float3 lookAt = frustumCenter - lightDir; XMMATRIX lightView = XMMatrixLookAtLH(lightCameraPos.ToSIMD(), lookAt.ToSIMD(), upDir.ToSIMD()); // Calculate an AABB around the frustum corners XMVECTOR mins = XMVectorSet(REAL_MAX, REAL_MAX, REAL_MAX, REAL_MAX); XMVECTOR maxes = XMVectorSet(-REAL_MAX, -REAL_MAX, -REAL_MAX, -REAL_MAX); for(uint32 i = 0; i < 8; ++i) { XMVECTOR corner = XMVector3TransformCoord(frustumCornersWS[i], lightView); mins = XMVectorMin(mins, corner); maxes = XMVectorMax(maxes, corner); } minExtents = mins; maxExtents = maxes; } // Adjust the min/max to accommodate the filtering size float scale = (ShadowMapSize + FilterSize) / static_cast<float>(ShadowMapSize); minExtents.x *= scale; minExtents.y *= scale; maxExtents.x *= scale; maxExtents.x *= scale; Float3 cascadeExtents = maxExtents - minExtents; // Get position of the shadow camera Float3 shadowCameraPos = frustumCenter + lightDir * -minExtents.z; // Come up with a new orthographic camera for the shadow caster OrthographicCamera shadowCamera(minExtents.x, minExtents.y, maxExtents.x, maxExtents.y, 0.0f, cascadeExtents.z); shadowCamera.SetLookAt(shadowCameraPos, frustumCenter, upDir); // Draw the mesh with depth only, using the new shadow camera RenderDepth(context, shadowCamera, true, false); // Apply the scale/offset matrix, which transforms from [-1,1] // post-projection space to [0,1] UV space XMMATRIX texScaleBias; texScaleBias.r[0] = XMVectorSet(0.5f, 0.0f, 0.0f, 0.0f); texScaleBias.r[1] = XMVectorSet(0.0f, -0.5f, 0.0f, 0.0f); texScaleBias.r[2] = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); texScaleBias.r[3] = XMVectorSet(0.5f, 0.5f, 0.0f, 1.0f); XMMATRIX shadowMatrix = shadowCamera.ViewProjectionMatrix().ToSIMD(); shadowMatrix = XMMatrixMultiply(shadowMatrix, texScaleBias); // Store the split distance in terms of view space depth const float clipDist = camera.FarClip() - camera.NearClip(); shadowConstants.Data.CascadeSplits[cascadeIdx] = camera.NearClip() + splitDist * clipDist; if(cascadeIdx == 0) { c0Extents = cascadeExtents; c0Matrix = shadowMatrix; shadowConstants.Data.ShadowMatrix = XMMatrixTranspose(shadowMatrix); shadowConstants.Data.CascadeOffsets[0] = Float4(0.0f, 0.0f, 0.0f, 0.0f); shadowConstants.Data.CascadeScales[0] = Float4(1.0f, 1.0f, 1.0f, 1.0f); } else { // Calculate the position of the lower corner of the cascade partition, in the UV space // of the first cascade partition Float4x4 invCascadeMat = Float4x4::Invert(shadowMatrix); Float3 cascadeCorner = Float3::Transform(Float3(0.0f, 0.0f, 0.0f), invCascadeMat); cascadeCorner = Float3::Transform(cascadeCorner, c0Matrix); // Do the same for the upper corner Float3 otherCorner = Float3::Transform(Float3(1.0f, 1.0f, 1.0f), invCascadeMat); otherCorner = Float3::Transform(otherCorner, c0Matrix); // Calculate the scale and offset Float3 cascadeScale = Float3(1.0f, 1.0f, 1.f) / (otherCorner - cascadeCorner); shadowConstants.Data.CascadeOffsets[cascadeIdx] = Float4(-cascadeCorner, 0.0f); shadowConstants.Data.CascadeScales[cascadeIdx] = Float4(cascadeScale, 1.0f); } ConvertToEVSM(context, cascadeIdx, shadowConstants.Data.CascadeScales[cascadeIdx].To3D()); } }
//----------------------------------------------------------------------------- // Compute the intersection of a ray (Origin, Direction) with an axis aligned // box using the slabs method. //----------------------------------------------------------------------------- BOOL GLibIntersectRayAxisAlignedBox( FXMVECTOR Origin, FXMVECTOR Direction, const XNA::AxisAlignedBox* pVolume, FLOAT* pDist ) { XMASSERT( pVolume ); XMASSERT( pDist ); //XMASSERT( XMVector3IsUnit( Direction ) ); static const XMVECTOR Epsilon = { 1e-20f, 1e-20f, 1e-20f, 1e-20f }; static const XMVECTOR FltMin = { -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX }; static const XMVECTOR FltMax = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; // Load the box. XMVECTOR Center = XMLoadFloat3( &pVolume->Center ); XMVECTOR Extents = XMLoadFloat3( &pVolume->Extents ); // Adjust ray origin to be relative to center of the box. XMVECTOR TOrigin = Center - Origin; // Compute the dot product againt each axis of the box. // Since the axii are (1,0,0), (0,1,0), (0,0,1) no computation is necessary. XMVECTOR AxisDotOrigin = TOrigin; XMVECTOR AxisDotDirection = Direction; // if (fabs(AxisDotDirection) <= Epsilon) the ray is nearly parallel to the slab. XMVECTOR IsParallel = XMVectorLessOrEqual( XMVectorAbs( AxisDotDirection ), Epsilon ); // Test against all three axii simultaneously. XMVECTOR InverseAxisDotDirection = XMVectorReciprocal( AxisDotDirection ); XMVECTOR t1 = ( AxisDotOrigin - Extents ) * InverseAxisDotDirection; XMVECTOR t2 = ( AxisDotOrigin + Extents ) * InverseAxisDotDirection; // Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't // use the results from any directions parallel to the slab. XMVECTOR t_min = XMVectorSelect( XMVectorMin( t1, t2 ), FltMin, IsParallel ); XMVECTOR t_max = XMVectorSelect( XMVectorMax( t1, t2 ), FltMax, IsParallel ); // t_min.x = maximum( t_min.x, t_min.y, t_min.z ); // t_max.x = minimum( t_max.x, t_max.y, t_max.z ); t_min = XMVectorMax( t_min, XMVectorSplatY( t_min ) ); // x = max(x,y) t_min = XMVectorMax( t_min, XMVectorSplatZ( t_min ) ); // x = max(max(x,y),z) t_max = XMVectorMin( t_max, XMVectorSplatY( t_max ) ); // x = min(x,y) t_max = XMVectorMin( t_max, XMVectorSplatZ( t_max ) ); // x = min(min(x,y),z) // if ( t_min > t_max ) return FALSE; XMVECTOR NoIntersection = XMVectorGreater( XMVectorSplatX( t_min ), XMVectorSplatX( t_max ) ); // if ( t_max < 0.0f ) return FALSE; NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( XMVectorSplatX( t_max ), XMVectorZero() ) ); // if (IsParallel && (-Extents > AxisDotOrigin || Extents < AxisDotOrigin)) return FALSE; XMVECTOR ParallelOverlap = XMVectorInBounds( AxisDotOrigin, Extents ); NoIntersection = XMVectorOrInt( NoIntersection, XMVectorAndCInt( IsParallel, ParallelOverlap ) ); if(!GLibXMVector3AnyTrue( NoIntersection ) ) { // Store the x-component to *pDist XMStoreFloat( pDist, t_min ); return TRUE; } return FALSE; }