/// <summary> /// Method for checking if element can be assigned as flat - checking surface area ratio /// </summary> /// <param name="element"></param> /// <returns></returns> private bool CheckIfElementIsFlat(GameObject element) { Vector3 size = GetSizeOfGameObject(element); ModelSurface mainSurface = GetMainSurfaceOfGameObject(element); float mainSurfaceArea = 0.0f; float auxSurfaceArea0 = 0.0f; float auxSurfaceArea1 = 0.0f; if (mainSurface == ModelSurface.XY) { mainSurfaceArea = Math.Abs(size.x * size.y); auxSurfaceArea0 = Math.Abs(size.z * size.y); auxSurfaceArea1 = Math.Abs(size.z * size.x); } else if (mainSurface == ModelSurface.XZ) { mainSurfaceArea = Math.Abs(size.x * size.z); auxSurfaceArea0 = Math.Abs(size.y * size.z); auxSurfaceArea1 = Math.Abs(size.y * size.x); } else if (mainSurface == ModelSurface.YZ) { mainSurfaceArea = Math.Abs(size.y * size.z); auxSurfaceArea0 = Math.Abs(size.x * size.y); auxSurfaceArea1 = Math.Abs(size.x * size.z); } else { return(false); } //If main surface area is 0 return false; if (mainSurfaceArea == 0) { return(false); } //Checking first aux surface area if (auxSurfaceArea0 / mainSurfaceArea > MinFlatSurfaceRatio) { return(false); } //Checking second aux surface area if (auxSurfaceArea1 / mainSurfaceArea > MinFlatSurfaceRatio) { return(false); } //Main surface is big enough - element is flat return(true); }
// used for initial loads, reloadModel, and reloading the data of purged models Upon exit, the model will absolutely be valid, but possibly as a default model public override void LoadModel() { int version, i, num; Lexer parser = new(LEXFL.ALLOWPATHNAMES | LEXFL.NOSTRINGESCAPECHARS); if (!purged) { PurgeModel(); } purged = false; if (!parser.LoadFile(name)) { MakeDefaultModel(); return; } parser.ExpectTokenString(ModelX.MD5_VERSION_STRING); version = parser.ParseInt(); if (version != ModelX.MD5_VERSION) { parser.Error($"Invalid version {version}. Should be version {ModelX.MD5_VERSION}\n"); } // skip commandline parser.ExpectTokenString("commandline"); parser.ReadToken(out var token); // parse num joints parser.ExpectTokenString("numJoints"); num = parser.ParseInt(); joints = new MD5Joint[num]; defaultPose = new JointQuat[num]; var poseMat3 = stackalloc JointMat[num + JointMat.ALLOC16]; poseMat3 = _alloca16T(poseMat3); // parse num meshes parser.ExpectTokenString("numMeshes"); num = parser.ParseInt(); if (num < 0) { parser.Error($"Invalid size: {num}"); } meshes = new MD5Mesh[num]; // parse joints parser.ExpectTokenString("joints"); parser.ExpectTokenString("{"); for (i = 0; i < joints.Length; i++) { var pose = defaultPose[i]; var joint = joints[i]; ParseJoint(parser, joint, pose); poseMat3[i].SetRotation(pose.q.ToMat3()); poseMat3[i].SetTranslation(pose.t); if (joint.parent != null) { var parentNum = joint.parent - joints; pose.q = (poseMat3[i].ToMat3() * poseMat3[parentNum].ToMat3().Transpose()).ToQuat(); pose.t = (poseMat3[i].ToVec3() - poseMat3[parentNum].ToVec3()) * poseMat3[parentNum].ToMat3().Transpose(); } } parser.ExpectTokenString("}"); //----------------------------------------- // create the inverse of the base pose joints to support tech6 style deformation of base pose vertexes, normals, and tangents. // // vertex * joints * inverseJoints == vertex when joints is the base pose When the joints are in another pose, it gives the animated vertex position //----------------------------------------- invertedDefaultPose = new JointMat[RenderWorldX.SIMD_ROUND_JOINTS(joints.Length)]; for (i = 0; i < joints.Length; i++) { invertedDefaultPose[i] = poseMat3[i]; invertedDefaultPose[i].Invert(); } RenderWorldX.SIMD_INIT_LAST_JOINT(invertedDefaultPose, joints.Length); for (i = 0; i < meshes.Length; i++) { var isPDAmesh = false; parser.ExpectTokenString("mesh"); meshes[i].ParseMesh(parser, defaultPose.Length, poseMat3); // Koz begin: Remove hands from weapon & pda viewmodels if desired. var materialName = meshes[i].shader.Name; if (string.IsNullOrEmpty(materialName)) { meshes[i].shader = null; } // change material to _pdaImage instead of deault this allows rendering the PDA & swf menus to the model ingame. if we find this gui, we also need to add a surface to the model, so flag. else if (materialName == "textures/common/pda_gui" || materialName == "_pdaImage" || materialName == "_pdaimage") { meshes[i].shader = declManager.FindMaterial("_pdaImage"); isPDAmesh = true; } if (isPDAmesh) { common.Printf("Load pda model\n"); for (var ti = 0; ti < meshes[i].NumVerts; ti++) { common.Printf($"Numverts {meshes[i].NumVerts} Vert {ti} {meshes[i].deformInfo.verts[ti].xyz.x} {meshes[i].deformInfo.verts[ti].xyz.y} {meshes[i].deformInfo.verts[ti].xyz.z} : {meshes[i].deformInfo.verts[ti].TexCoordS} {meshes[i].deformInfo.verts[ti].TexCoordT} {meshes[i].deformInfo.verts[ti].st[0]} {meshes[i].deformInfo.verts[ti].st[1]}\n"); } common.Printf("PDA gui found, creating gui surface for hitscan.\n"); var pdasurface = new ModelSurface { id = 0, shader = declManager.FindMaterial("_pdaImage") }; var pdageometry = AllocSurfaceTriangles(meshes[i].NumVerts, meshes[i].deformInfo.numIndexes); Debug.Assert(pdageometry != null); // infinite bounds pdageometry.bounds[0].x = pdageometry.bounds[0].y = pdageometry.bounds[0].z = -99999; pdageometry.bounds[1].x = pdageometry.bounds[1].y = pdageometry.bounds[1].z = 99999; pdageometry.numVerts = meshes[i].NumVerts; pdageometry.numIndexes = meshes[i].deformInfo.numIndexes; for (var zz = 0; zz < pdageometry.numIndexes; zz++) { pdageometry.indexes[zz] = meshes[i].deformInfo.indexes[zz]; } for (var zz = 0; zz < pdageometry.numVerts; zz++) { pdageometry.verts[zz].xyz = meshes[i].deformInfo.verts[zz].xyz; //pdageometry.verts[zz].SetTexCoord( meshes[i].deformInfo.verts[zz].GetTexCoord() ); pdageometry.verts[zz].st = meshes[i].deformInfo.verts[zz].st; } common.Printf("verify pda model\n"); for (var ti = 0; ti < pdageometry.numVerts; ti++) { common.Printf($"Numverts {pdageometry.numVerts} Vert {ti} {pdageometry.verts[ti].xyz.x} {pdageometry.verts[ti].xyz.y} {pdageometry.verts[ti].xyz.z} : {pdageometry.verts[ti].TexCoordS} {pdageometry.verts[ti].TexCoordT} {pdageometry.verts[ti].st[0]} {pdageometry.verts[ti].st[1]}\n"); } pdasurface.geometry = pdageometry; AddSurface(pdasurface); } } // calculate the bounds of the model CalculateBounds(poseMat3); // set the timestamp for reloadmodels fileSystem.ReadFile(name, out var timeStamp); }
public void UpdateSurface(RenderEntity ent, JointMat[] joints, ModelSurface surf) { int i; tr.pc.c_deformedSurfaces++; tr.pc.c_deformedVerts += deformInfo.numOutputVerts; tr.pc.c_deformedIndexes += deformInfo.numIndexes; surf.shader = shader; if (surf.geometry != null) { // if the number of verts and indexes are the same we can re-use the triangle surface the number of indexes must be the same to assure the correct amount of memory is allocated for the facePlanes if (surf.geometry.numVerts == deformInfo.numOutputVerts && surf.geometry.numIndexes == deformInfo.numIndexes) { R_FreeStaticTriSurfVertexCaches(surf.geometry); } else { R_FreeStaticTriSurf(surf.geometry); surf.geometry = R_AllocStaticTriSurf(); } } else { surf.geometry = R_AllocStaticTriSurf(); } var tri = surf.geometry; // note that some of the data is references, and should not be freed tri.deformedSurface = true; tri.tangentsCalculated = false; tri.facePlanesCalculated = false; tri.numIndexes = deformInfo.numIndexes; tri.indexes = deformInfo.indexes; tri.silIndexes = deformInfo.silIndexes; tri.numMirroredVerts = deformInfo.numMirroredVerts; tri.mirroredVerts = deformInfo.mirroredVerts; tri.numDupVerts = deformInfo.numDupVerts; tri.dupVerts = deformInfo.dupVerts; tri.numSilEdges = deformInfo.numSilEdges; tri.silEdges = deformInfo.silEdges; tri.dominantTris = deformInfo.dominantTris; tri.numVerts = deformInfo.numOutputVerts; if (tri.verts == null) { R_AllocStaticTriSurfVerts(tri, tri.numVerts); for (i = 0; i < deformInfo.numSourceVerts; i++) { tri.verts[i].Clear(); tri.verts[i].st = texCoords[i]; } } fixed(JointMat *jointsJ = joints) if (ent.shaderParms[IRenderWorld.SHADERPARM_MD5_SKINSCALE] != 0f) { TransformScaledVerts(tri.verts, jointsJ, ent.shaderParms[IRenderWorld.SHADERPARM_MD5_SKINSCALE]); } else { TransformVerts(tri.verts, jointsJ); } // replicate the mirror seam vertexes var base_ = deformInfo.numOutputVerts - deformInfo.numMirroredVerts; for (i = 0; i < deformInfo.numMirroredVerts; i++) { tri.verts[base_ + i] = tri.verts[deformInfo.mirroredVerts[i]]; } R_BoundTriSurf(tri); // If a surface is going to be have a lighting interaction generated, it will also have to call R_DeriveTangents() to get normals, tangents, and face planes. If it only // needs shadows generated, it will only have to generate face planes. If it only has ambient drawing, or is culled, no additional work will be necessary if (!r_useDeferredTangents.Bool) { R_DeriveTangents(tri); // set face planes, vertex normals, tangents } }
/// <summary> /// Method for checking raycast from main surface of element and center point - in order to check whether element is inside switchboard or not /// </summary> /// <param name="element"> /// Element to check /// </param> /// <returns> /// Array of raycast results - if one of them is false than element is outside the switchboard /// </returns> private bool[] CheckElementsRaycast(GameObject element) { ModelSurface mainSurface = GetMainSurfaceOfGameObject(element); Vector3 elementCenterPoint = GetCenterPointOfGameObject(element); Vector3 elementSize = GetSizeOfGameObject(element); //Two points of raycasting - raycast should be performed from center point, moved to the external surface of element //For every direction there is different external surface Vector3 raycastPoint0 = new Vector3(0, 0, 0); Vector3 raycastPoint1 = new Vector3(0, 0, 0); //Two directions of raycasting Vector3 raycastDirection0 = new Vector3(0, 0, 1); Vector3 raycastDirection1 = new Vector3(0, 0, -1); switch (mainSurface) { case ModelSurface.XY: { raycastDirection0 = new Vector3(0, 0, 1); raycastDirection1 = new Vector3(0, 0, -1); raycastPoint0 = elementCenterPoint + new Vector3(0, 0, elementSize.z / 2); raycastPoint1 = elementCenterPoint + new Vector3(0, 0, -elementSize.z / 2); break; } case ModelSurface.XZ: { raycastDirection0 = new Vector3(0, 1, 0); raycastDirection1 = new Vector3(0, -1, 0); raycastPoint0 = elementCenterPoint + new Vector3(0, elementSize.y / 2, 0); raycastPoint1 = elementCenterPoint + new Vector3(0, -elementSize.y / 2, 0); break; } case ModelSurface.YZ: { raycastDirection0 = new Vector3(1, 0, 0); raycastDirection1 = new Vector3(-1, 0, 0); raycastPoint0 = elementCenterPoint + new Vector3(elementSize.x / 2, 0, 0); raycastPoint1 = elementCenterPoint + new Vector3(-elementSize.x / 2, 0, 0); break; } } //Raycasting depening on raycast length set var raycast0Result = false; var raycast1Result = false; if (MaxRaycastDistance < 0) { raycast0Result = Physics.Raycast(raycastPoint0, raycastDirection0); raycast1Result = Physics.Raycast(raycastPoint1, raycastDirection1); } else { raycast0Result = Physics.Raycast(raycastPoint0, raycastDirection0, MaxRaycastDistance); raycast1Result = Physics.Raycast(raycastPoint1, raycastDirection1, MaxRaycastDistance); } return(new bool[] { raycast0Result, raycast1Result }); }