// // returns true if line (L1, L2) intersects with triangle( PV1, PV2, PV3 ) // The point of intersection is returned in HitP // bool CheckLineTri( const CVec3 &L1, const CVec3 &L2, const CVec3 &PV1, const CVec3 &PV2, const CVec3 &PV3, CVec3 &HitP ) { CVec3 VIntersect; // Find Triangle Normal, would be quicker to have these computed already CVec3 VNorm; VNorm = ( PV2 - PV1 ).CrossProduct( PV3 - PV1 ); VNorm.Normalize(); // Find distance from L1 and L2 to the plane defined by the triangle float fDst1 = (L1-PV1).Dot( VNorm ); float fDst2 = (L2-PV1).Dot( VNorm ); if ( (fDst1 * fDst2) >= 0.0f) return false; // line doesn't cross the triangle. if ( fDst1 == fDst2) {return false;} // line and plane are parallel // Find point on the line that intersects with the plane VIntersect = L1 + (L2-L1) * ( -fDst1/(fDst2-fDst1) ); // Find if the interesection point lies inside the triangle by testing it against all edges CVec3 VTest; VTest = VNorm.CrossProduct( PV2-PV1 ); if ( VTest.Dot( VIntersect-PV1 ) < 0.0f ) return false; VTest = VNorm.CrossProduct( PV3-PV2 ); if ( VTest.Dot( VIntersect-PV2 ) < 0.0f ) return false; VTest = VNorm.CrossProduct( PV1-PV3 ); if ( VTest.Dot( VIntersect-PV1 ) < 0.0f ) return false; HitP = VIntersect; return true; }
void UVertMesh::BuildNormals() { // UE1 meshes have no stored normals, should build them // This function is similar to BuildNormals() from SkelMeshInstance.cpp int numVerts = Verts.Num(); int i; Normals.Empty(numVerts); Normals.AddZeroed(numVerts); TArray<CVec3> tmpVerts, tmpNormals; tmpVerts.AddZeroed(numVerts); tmpNormals.AddZeroed(numVerts); // convert verts for (i = 0; i < numVerts; i++) { const FMeshVert &SV = Verts[i]; CVec3 &DV = tmpVerts[i]; DV[0] = SV.X * MeshScale.X; DV[1] = SV.Y * MeshScale.Y; DV[2] = SV.Z * MeshScale.Z; } // iterate faces for (i = 0; i < Faces.Num(); i++) { const FMeshFace &F = Faces[i]; // get vertex indices int i1 = Wedges[F.iWedge[0]].iVertex; int i2 = Wedges[F.iWedge[2]].iVertex; // note: reverse order in comparison with SkeletalMesh int i3 = Wedges[F.iWedge[1]].iVertex; // iterate all frames for (int j = 0; j < FrameCount; j++) { int base = VertexCount * j; // compute edges const CVec3 &V1 = tmpVerts[base + i1]; const CVec3 &V2 = tmpVerts[base + i2]; const CVec3 &V3 = tmpVerts[base + i3]; CVec3 D1, D2, D3; VectorSubtract(V2, V1, D1); VectorSubtract(V3, V2, D2); VectorSubtract(V1, V3, D3); // compute normal CVec3 norm; cross(D2, D1, norm); norm.Normalize(); // compute angles D1.Normalize(); D2.Normalize(); D3.Normalize(); float angle1 = acos(-dot(D1, D3)); float angle2 = acos(-dot(D1, D2)); float angle3 = acos(-dot(D2, D3)); // add normals for triangle verts VectorMA(tmpNormals[base + i1], angle1, norm); VectorMA(tmpNormals[base + i2], angle2, norm); VectorMA(tmpNormals[base + i3], angle3, norm); } } // normalize and convert computed normals for (i = 0; i < numVerts; i++) { CVec3 &SN = tmpNormals[i]; FMeshNorm &DN = Normals[i]; SN.Normalize(); DN.X = appRound(SN[0] * 511 + 512); DN.Y = appRound(SN[1] * 511 + 512); DN.Z = appRound(SN[2] * 511 + 512); } }
static void SV_ClipMoveToEntities(trace_t &trace, const CVec3 &start, const CVec3 &end, const CBox &bounds, edict_t *passedict, int contentmask) { guard(SV_ClipMoveToEntities); if (trace.allsolid) return; int i; CVec3 amins, amaxs; for (i = 0; i < 3; i++) { if (start[i] < end[i]) { amins[i] = bounds.mins[i] + start[i]; amaxs[i] = bounds.maxs[i] + end[i]; } else { amins[i] = bounds.mins[i] + end[i]; amaxs[i] = bounds.maxs[i] + start[i]; } } edict_t *list[MAX_EDICTS]; int num = SV_AreaEdicts(amins, amaxs, ARRAY_ARG(list), AREA_SOLID); if (!num) return; float b1 = dot(bounds.mins, bounds.mins); float b2 = dot(bounds.maxs, bounds.maxs); float t = max(b1, b2); float traceWidth = SQRTFAST(t); CVec3 traceDir; VectorSubtract(end, start, traceDir); float traceLen = traceDir.Normalize() + traceWidth; for (i = 0; i < num; i++) { edict_t *edict = list[i]; entityHull_t &ent = ents[NUM_FOR_EDICT(edict)]; // if (!ent->linked) continue; if (edict->solid == SOLID_NOT || edict == passedict) continue; if (passedict) { if (edict->owner == passedict) continue; // don't clip against own missiles if (passedict->owner == edict) continue; // don't clip against owner } if (!(contentmask & CONTENTS_DEADMONSTER) && (edict->svflags & SVF_DEADMONSTER)) continue; CVec3 eCenter; VectorSubtract(ent.center, start, eCenter); // check position of point projection on line float entPos = dot(eCenter, traceDir); if (entPos < -traceWidth - ent.radius || entPos > traceLen + ent.radius) continue; // too near / too far // check distance between point and line CVec3 tmp; VectorMA(eCenter, -entPos, traceDir, tmp); float dist2 = dot(tmp, tmp); float dist0 = ent.radius + traceWidth; if (dist2 >= dist0 * dist0) continue; trace_t tr; if (ent.model) CM_TransformedBoxTrace(tr, start, end, bounds, ent.model->headnode, contentmask, edict->s.origin, ent.axis); else CM_TransformedBoxTrace(tr, start, end, bounds, CM_HeadnodeForBox(ent.bounds), contentmask, edict->s.origin, nullVec3); if (CM_CombineTrace(trace, tr)) trace.ent = edict; if (trace.allsolid) return; } unguard; }
/////////////////////////////////////////////////////////////////////////////// // _Create_caustic_photonmap // Build the caustic photon map after the creation of global photon map /////////////////////////////////////////////////////////////////////////////// void CMcBspTR::_Create_caustic_photonmap(void) { int i, j; CCol4 cCurrPow; int nStored = 0; TBspRay ray; float fLen; printf("\nBuilding caustic photon map ...\n"); TCausDir *p = m_tCausDir.next; for (i = 0; i < m_nCausDir; i ++) { printf ("."); CCol4 cPow = m_tpLigPatches[p->nLID].cPhotonPow / m_nCauPhoSubd * 5; if (m_bDirectionalLight) { CBspTriangle *tri = &m_pTriangles[m_tpLigPatches[p->nLID].nTID]; fLen = sqrt(tri->Calc_area() / m_tpLigPatches[p->nLID].nPhotonNum); CVec3 vZ = tri->Calc_normal(); CVec3 vY = RANDOM_VEC; CVec3 vX = vY.Cross(vZ); vX.Normalize(); vY = vZ.Cross(vX); vX *= fLen; vY *= fLen; for (j = 0; j < m_nCauPhoSubd; j ++) { ray.vOrg = p->vPos + vX * RANDOM_N1_P1 + vY * RANDOM_N1_P1; ray.vDir = p->vDir; ray.vEnd = ray.vOrg + ray.vDir * m_fSceneSize; _Trace_caustic_photon (ray, cPow, m_tpLigPatches[p->nLID].nTID, nStored); } } else { double fCos = cos(PI/sqrt(m_tpLigPatches[p->nLID].nPhotonNum*4.)); fLen = 2.f * (float) tan( acos(fCos) ); for (j = 0; j < m_nCauPhoSubd; j ++) { ray.vOrg = p->vPos; ray.vDir = p->vDir + (RANDOM_VEC * fLen); ray.vDir.Normalize(); ray.vEnd = ray.vOrg + ray.vDir * m_fSceneSize; _Trace_caustic_photon (ray, cPow, m_tpLigPatches[p->nLID].nTID, nStored); } } m_tCausDir.next = p->next; delete p; p = m_tCausDir.next; } m_tCausDir.next = NULL; // Balance photon map kd-tree printf("\n Balance KD tree"); m_pCausticPhotonMap->balance(); printf("\nFinish building caustic photon map, %d photons stored\n", nStored); }