TRS CLevelEntity::CalculateGlobalTRS(CLevelEntity* pThis) { TRS trsLocal; tstring sLocalOrigin = pThis->GetParameterValue("Origin"); if (sLocalOrigin.length() && CanUnserializeString_TVector(sLocalOrigin)) trsLocal.m_vecTranslation = UnserializeString_TVector(sLocalOrigin); tstring sLocalAngles = pThis->GetParameterValue("Angles"); if (sLocalAngles.length() && CanUnserializeString_EAngle(sLocalAngles)) trsLocal.m_angRotation = UnserializeString_EAngle(sLocalAngles); tstring sScale = pThis->GetParameterValue("Scale"); if (sScale.length() && CanUnserializeString_TVector(sScale)) trsLocal.m_vecScaling = UnserializeString_TVector(sScale); tstring sAABB = pThis->GetParameterValue("BoundingBox"); if (CanUnserializeString_AABB(sAABB)) { AABB aabbBounds = UnserializeString_AABB(sAABB, pThis->GetName(), pThis->m_sClass, "BoundingBox"); // Center the entity around this bounding box. trsLocal.m_vecTranslation += aabbBounds.Center(); } return trsLocal; }
Matrix4x4 CLevelEntity::CalculateGlobalTransform(CLevelEntity* pThis) { Matrix4x4 mLocal; tstring sLocalOrigin = pThis->GetParameterValue("Origin"); if (sLocalOrigin.length() && CanUnserializeString_TVector(sLocalOrigin)) mLocal.SetTranslation(UnserializeString_TVector(sLocalOrigin)); tstring sLocalAngles = pThis->GetParameterValue("Angles"); if (sLocalAngles.length() && CanUnserializeString_EAngle(sLocalAngles)) mLocal.SetAngles(UnserializeString_EAngle(sLocalAngles)); tstring sAABB = pThis->GetParameterValue("BoundingBox"); if (CanUnserializeString_AABB(sAABB)) { AABB aabbBounds = UnserializeString_AABB(sAABB, pThis->GetName(), pThis->m_sClass, "BoundingBox"); // Center the entity around this bounding box. Vector vecGlobalOrigin = aabbBounds.Center(); mLocal.SetTranslation(mLocal.GetTranslation() + vecGlobalOrigin); Vector vecNewOrigin = mLocal.GetTranslation(); pThis->SetParameterValue("Origin", pretty_float(vecNewOrigin.x) + " " + pretty_float(vecNewOrigin.y) + " " + pretty_float(vecNewOrigin.z)); aabbBounds.m_vecMins -= vecGlobalOrigin; aabbBounds.m_vecMaxs -= vecGlobalOrigin; pThis->SetParameterValue("BoundingBox", pretty_float(aabbBounds.m_vecMins.x) + " " + pretty_float(aabbBounds.m_vecMins.y) + " " + pretty_float(aabbBounds.m_vecMins.z) + " " + pretty_float(aabbBounds.m_vecMaxs.x) + " " + pretty_float(aabbBounds.m_vecMaxs.y) + " " + pretty_float(aabbBounds.m_vecMaxs.z)); } return mLocal; }
Vector CToy::GetPhysicsBoxHalfSize(size_t iBox) { TRS& trs = GetPhysicsBox(iBox); TAssert(trs.m_angRotation.p == 0); TAssert(trs.m_angRotation.y == 0); TAssert(trs.m_angRotation.r == 0); Matrix4x4 mTRS = trs.GetMatrix4x4(); AABB aabbBox = s_aabbBoxDimensions; aabbBox.m_vecMins = mTRS*aabbBox.m_vecMins; aabbBox.m_vecMaxs = mTRS*aabbBox.m_vecMaxs; return aabbBox.m_vecMaxs - aabbBox.Center(); }
AABB CLevelEntity::CalculateBoundingBox(CLevelEntity* pThis) { size_t iModel = pThis->GetModelID(); CModel* pModel = CModelLibrary::GetModel(iModel); if (pModel) return pModel->m_aabbVisBoundingBox; tstring sAABB = pThis->GetParameterValue("BoundingBox"); AABB aabbBounds = AABB(Vector(-0.5f, -0.5f, -0.5f), Vector(0.5f, 0.5f, 0.5f)); if (CanUnserializeString_AABB(sAABB)) { aabbBounds = UnserializeString_AABB(sAABB, pThis->GetName(), pThis->m_sClass, "BoundingBox"); // Center the entity around this bounding box. Vector vecGlobalOrigin = aabbBounds.Center(); aabbBounds.m_vecMins -= vecGlobalOrigin; aabbBounds.m_vecMaxs -= vecGlobalOrigin; } else { CSaveData* pSaveData = CBaseEntity::FindSaveDataByHandle(tstring("C"+pThis->m_sClass).c_str(), "BoundingBox"); if (pSaveData && pSaveData->m_bDefault) memcpy(&aabbBounds, &pSaveData->m_oDefault, sizeof(aabbBounds)); } if (pThis->m_hMaterialModel.IsValid() && pThis->m_hMaterialModel->m_ahTextures.size()) { CTextureHandle hBaseTexture = pThis->m_hMaterialModel->m_ahTextures[0]; if (hBaseTexture.IsValid()) { aabbBounds.m_vecMaxs.y *= (float)hBaseTexture->m_iHeight/pThis->m_hMaterialModel->m_iTexelsPerMeter; aabbBounds.m_vecMins.y *= (float)hBaseTexture->m_iHeight/pThis->m_hMaterialModel->m_iTexelsPerMeter; aabbBounds.m_vecMaxs.z *= (float)hBaseTexture->m_iWidth/pThis->m_hMaterialModel->m_iTexelsPerMeter; aabbBounds.m_vecMins.z *= (float)hBaseTexture->m_iWidth/pThis->m_hMaterialModel->m_iTexelsPerMeter; } } aabbBounds.m_vecMins = aabbBounds.m_vecMins * pThis->GetScale(); aabbBounds.m_vecMaxs = aabbBounds.m_vecMaxs * pThis->GetScale(); return aabbBounds; }
bool ConvexHullIntersectsAABB(const AABB& box, const tvector<vec3>& avecPoints, const tvector<size_t>& aiTriangles) { TAssert(aiTriangles.size() % 3 == 0); vec3 vecCenter = box.Center(); vec3 n; for (size_t i = 0; i < aiTriangles.size(); i += 3) { const vec3& v1 = avecPoints[aiTriangles[i]]; const vec3& v2 = avecPoints[aiTriangles[i+1]]; const vec3& v3 = avecPoints[aiTriangles[i+2]]; n = (v2-v1).Cross(v3-v1).Normalized(); if (n.Dot(vecCenter-v1) < 0) continue; if (!TriangleIntersectsAABB(box, v1, v2, v3)) return false; } return true; }
bool RayIntersectsAABB(const ray& r, const AABB& b, vec3& vecIntersection) { float tmin = 0; float tmax = b.Size().LengthSqr(); // It's a ray so make tmax effectively infinite. if (tmax < 1) tmax = 100; float flDistTbox = (r.m_pos - b.Center()).LengthSqr(); if (flDistTbox < 1) flDistTbox = 100; tmax *= flDistTbox * 100; if (!ClipRay(b.m_mins.x, b.m_maxs.x, r.m_pos.x, r.m_dir.x, tmin, tmax)) return false; if (!ClipRay(b.m_mins.y, b.m_maxs.y, r.m_pos.y, r.m_dir.y, tmin, tmax)) return false; if (!ClipRay(b.m_mins.z, b.m_maxs.z, r.m_pos.z, r.m_dir.z, tmin, tmax)) return false; vecIntersection = r.m_pos + r.m_dir * tmin; return true; }
void CAOGenerator::GenerateShadowMaps() { double flProcessSceneRead = 0; double flProgress = 0; size_t iShadowMapSize = 1024; // A frame buffer for holding the depth buffer shadow render CFrameBuffer oDepthFB = SMAKRenderer()->CreateFrameBuffer(iShadowMapSize, iShadowMapSize, (fb_options_e)(FB_DEPTH_TEXTURE|FB_RENDERBUFFER)); // RB unused // A frame buffer for holding the UV layout once it is rendered flat with the shadow CFrameBuffer oUVFB = SMAKRenderer()->CreateFrameBuffer(m_iWidth, m_iHeight, (fb_options_e)(FB_TEXTURE|FB_LINEAR|FB_DEPTH)); // Depth unused // A frame buffer for holding the completed AO map m_oAOFB = SMAKRenderer()->CreateFrameBuffer(m_iWidth, m_iHeight, (fb_options_e)(FB_TEXTURE|FB_TEXTURE_HALF_FLOAT|FB_LINEAR|FB_DEPTH)); // Depth unused CRenderingContext c(SMAKRenderer()); c.UseFrameBuffer(&m_oAOFB); c.ClearColor(Color(0, 0, 0, 0)); c.SetDepthFunction(DF_LEQUAL); c.SetDepthTest(true); c.SetBackCulling(false); Matrix4x4 mBias( 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f); // Bias from [-1, 1] to [0, 1] AABB oBox = m_pScene->m_oExtends; Vector vecCenter = oBox.Center(); float flSize = oBox.Size().Length(); // Length of the box's diagonal Matrix4x4 mLightProjection = Matrix4x4::ProjectOrthographic(-flSize/2, flSize/2, -flSize/2, flSize/2, 1, flSize*2); size_t iSamples = (size_t)sqrt((float)m_iSamples); m_pWorkListener->SetAction("Taking exposures", m_iSamples); for (size_t x = 0; x <= iSamples; x++) { float flPitch = -asin(RemapVal((float)x, 0, (float)iSamples, -1, 1)) * 90 / (M_PI/2); for (size_t y = 0; y < iSamples; y++) { if (x == 0 || x == iSamples) { // Don't do a bunch of samples from the same spot on the poles. if (y != 0) continue; } float flYaw = RemapVal((float)y, 0, (float)iSamples, -180, 180); // Randomize the direction a tad to help fight moire Vector vecDir = AngleVector(EAngle(flPitch+RandomFloat(-1, 1)/2, flYaw+RandomFloat(-1, 1)/2, 0)); Vector vecLightPosition = vecDir*flSize + vecCenter; // Puts us twice as far from the closest vertex if (ao_debug.GetInt() > 1) SMAKWindow()->AddDebugLine(vecLightPosition, vecLightPosition-vecDir); Matrix4x4 mLightView = Matrix4x4::ConstructCameraView(vecLightPosition, (vecCenter-vecLightPosition).Normalized(), Vector(0, 1, 0)); c.SetProjection(mLightProjection); c.SetView(mLightView); // If we're looking from below and ground occlusion is on, don't bother with this render. if (!(flPitch < -10 && m_bGroundOcclusion)) { c.UseProgram("model"); c.UseFrameBuffer(&oDepthFB); c.SetViewport(Rect(0, 0, iShadowMapSize, iShadowMapSize)); c.SetBackCulling(false); c.ClearDepth(); c.BeginRenderVertexArray(m_iSceneDepth); c.SetPositionBuffer((size_t)0, 8*sizeof(float)); c.SetNormalsBuffer((size_t)3*sizeof(float), 8*sizeof(float)); c.SetTexCoordBuffer((size_t)6*sizeof(float), 8*sizeof(float)); c.EndRenderVertexArray(m_iSceneDepthVerts); c.UseFrameBuffer(nullptr); if (ao_debug.GetBool()) { CRenderingContext c(SMAKRenderer()); c.SetViewport(Rect(0, 0, iShadowMapSize/2, iShadowMapSize/2)); DrawTexture(oDepthFB.m_iDepthTexture, 1, c); } } Matrix4x4 mTextureMatrix = mBias*mLightProjection*mLightView; { CRenderingContext c(SMAKRenderer(), true); c.UseFrameBuffer(&oUVFB); c.SetViewport(Rect(0, 0, m_iWidth, m_iHeight)); c.ClearColor(Color(0, 0, 0, 0)); c.ClearDepth(); c.UseProgram("flat_shadow"); c.SetUniform("mBiasedLightMatrix", mTextureMatrix); c.SetUniform("iShadowMap", 0); c.SetUniform("vecLightNormal", -vecDir); c.SetUniform("bOccludeAll", (flPitch < -10 && m_bGroundOcclusion)); c.SetUniform("flTime", (float)Application()->GetTime()); c.BindTexture(oDepthFB.m_iDepthTexture); c.BeginRenderVertexArray(m_iScene); c.SetPositionBuffer((size_t)0, 8*sizeof(float)); c.SetNormalsBuffer((size_t)3*sizeof(float), 8*sizeof(float)); c.SetTexCoordBuffer((size_t)6*sizeof(float), 8*sizeof(float)); c.EndRenderVertexArray(m_iSceneVerts); } if (ao_debug.GetBool()) { CRenderingContext c(SMAKRenderer()); c.SetViewport(Rect(iShadowMapSize/2, 0, m_iWidth, m_iHeight)); DrawTexture(oUVFB.m_iMap, 1, c); } double flTimeBefore = SMAKWindow()->GetTime(); c.SetViewport(Rect(0, 0, m_iWidth, m_iHeight)); c.UseFrameBuffer(&m_oAOFB); AccumulateTexture(oUVFB.m_iMap); c.UseFrameBuffer(nullptr); if (ao_debug.GetBool()) { CRenderingContext c(SMAKRenderer()); c.UseProgram("ao"); c.SetViewport(Rect(iShadowMapSize/2+m_iWidth, 0, m_iWidth, m_iHeight)); c.SetUniform("iAOMap", 0); c.SetBlend(BLEND_ALPHA); DrawTexture(m_oAOFB.m_iMap, 1, c); } flProcessSceneRead += (SMAKWindow()->GetTime() - flTimeBefore); flTimeBefore = SMAKWindow()->GetTime(); m_pWorkListener->WorkProgress(x*iSamples + y); flProgress += (SMAKWindow()->GetTime() - flTimeBefore); if (m_bStopGenerating) break; } if (m_bStopGenerating) break; } c.UseFrameBuffer(&m_oAOFB); c.ReadPixels(0, 0, m_iWidth, m_iHeight, m_pvecPixels); c.UseFrameBuffer(nullptr); if (!m_bStopGenerating) { size_t iBufferSize = m_iWidth*m_iHeight; m_pWorkListener->SetAction("Reading pixels", iBufferSize); for (size_t p = 0; p < iBufferSize; p++) { Vector4D& vecPixel = m_pvecPixels[p]; if (vecPixel.w == 0.0f) continue; m_avecShadowValues[p].x = vecPixel.x; m_aiShadowReads[p] = (size_t)vecPixel.w; m_bPixelMask[p] = true; m_pWorkListener->WorkProgress(p); } } oDepthFB.Destroy(); oUVFB.Destroy(); // Don't destroy m_oAOFB yet, we need it in a bit. It gets destroyed later. }