Exemplo n.º 1
0
        void CreateDecalForStaticObject(ShapeTriangleID startTriangle, Vec3 pos, Vec3 normal,
                                        MapObject parentMapObject)
        {
            Shape currentShape   = null;
            Mat4  shapeTransform = Mat4.Zero;

            Vec3[] shapeVertices = null;
            int[]  shapeIndices  = null;

            bool existsNormalsMore45Degrees = false;

            //find near triangles
            //Set<ShapeTriangleID> triangleIDs = new Set<ShapeTriangleID>();
            {
                Sphere checkSphere = new Sphere(pos, Type.Size * .5f * 1.41f);                  //Sqrt(2)

                //Set<ShapeTriangleID> checkedTriangles = new Set<ShapeTriangleID>();

                //Stack<ShapeTriangleID> trianglesForCheck = new Stack<ShapeTriangleID>( 16 );
                trianglesForCheck.Push(startTriangle);

                while (trianglesForCheck.Count != 0)
                {
                    ShapeTriangleID triangle = trianglesForCheck.Pop();

                    //add to checked triangles
                    if (!checkedTriangles.AddWithCheckAlreadyContained(triangle))
                    {
                        //ignore already checked triangles
                        continue;
                    }

                    //get triangle points
                    Vec3 p0, p1, p2;
                    {
                        if (currentShape != triangle.shape)
                        {
                            currentShape = triangle.shape;

                            if (currentShape.ShapeType == Shape.Type.Mesh)
                            {
                                ((MeshShape)currentShape).GetData(out shapeVertices, out shapeIndices);
                            }
                            else if (currentShape.ShapeType == Shape.Type.HeightField)
                            {
                                ((HeightFieldShape)currentShape).GetVerticesAndIndices(true,
                                                                                       out shapeVertices, out shapeIndices);
                            }
                            else
                            {
                                Log.Fatal("DecalCreator: Not supported shape type ({0}).",
                                          currentShape.ShapeType.ToString());
                            }

                            shapeTransform = currentShape.Body.GetTransform();
                            if (!currentShape.IsIdentityTransform)
                            {
                                shapeTransform *= currentShape.GetTransform();
                            }
                        }

                        int index = triangle.triangleID * 3;
                        p0 = shapeTransform * shapeVertices[shapeIndices[index + 0]];
                        p1 = shapeTransform * shapeVertices[shapeIndices[index + 1]];
                        p2 = shapeTransform * shapeVertices[shapeIndices[index + 2]];
                    }

                    //cull by checkBounds
                    if (!checkSphere.TriangleIntersection(p0, p1, p2))
                    {
                        continue;
                    }

                    //check normal
                    bool correctNormal = false;

                    if (Type.SpreadType != DecalCreatorType.SpreadTypes.Directional)
                    {
                        Plane plane = Plane.FromPoints(p0, p1, p2);
                        if (plane.GetSide(pos + normal) == Plane.Side.Positive)
                        {
                            Radian angle = MathFunctions.ACos(Vec3.Dot(normal, plane.Normal));

                            if (angle <= new Degree(70.0f).InRadians())
                            {
                                if (!existsNormalsMore45Degrees && angle >= new Degree(45.0f).InRadians())
                                {
                                    existsNormalsMore45Degrees = true;
                                }

                                correctNormal = true;
                            }
                        }
                    }
                    else
                    {
                        correctNormal = true;
                    }

                    if (correctNormal)
                    {
                        //add triangle to result list
                        triangleIDs.Add(triangle);
                    }

                    //add near triangles to check list
                    {
                        //expand vertices
                        const float border = .001f;
                        Vec3        center = (p0 + p1 + p2) * (1.0f / 3.0f);

                        Vec3 diff0 = p0 - center;
                        Vec3 diff1 = p1 - center;
                        Vec3 diff2 = p2 - center;

                        if (diff0 != Vec3.Zero && diff1 != Vec3.Zero && diff2 != Vec3.Zero)
                        {
                            p0 += diff0.GetNormalize() * border;
                            p1 += diff1.GetNormalize() * border;
                            p2 += diff2.GetNormalize() * border;

                            Vec3 p01 = (p0 + p1) * .5f;
                            Vec3 p12 = (p1 + p2) * .5f;
                            Vec3 p20 = (p2 + p0) * .5f;

                            //find triangles
                            for (int n = 0; n < 3; n++)
                            {
                                Vec3 p = Vec3.Zero;
                                switch (n)
                                {
                                case 0: p = p01; break;

                                case 1: p = p12; break;

                                case 2: p = p20; break;
                                }

                                RayCastResult[] piercingResult =
                                    PhysicsWorld.Instance.RayCastPiercing(new Ray(
                                                                              p + normal * .025f, -normal * .05f), (int)ContactGroup.CastOnlyCollision);
                                foreach (RayCastResult result in piercingResult)
                                {
                                    if (result.Shape != null)
                                    {
                                        trianglesForCheck.Push(new ShapeTriangleID(
                                                                   result.Shape, result.TriangleID));
                                    }
                                }
                            }
                        }
                    }
                }

                checkedTriangles.Clear();
            }

            if (triangleIDs.Count == 0)
            {
                return;
            }

            //calculate perpendiculars to normal
            Vec3 side1Normal;
            Vec3 side2Normal;

            {
                if (Math.Abs(normal.X) > .001f || Math.Abs(normal.Y) > .001f)
                {
                    side1Normal = Mat3.FromRotateByZ(MathFunctions.PI / 2) *
                                  new Vec3(normal.X, normal.Y, 0);
                    side1Normal.Normalize();
                }
                else
                {
                    side1Normal = new Vec3(1, 0, 0);
                }

                side2Normal = Vec3.Cross(normal, side1Normal);
            }

            //generate clip planes
            Plane[] clipPlanes = new Plane[6];
            {
                float halfSize = Type.Size * .5f;

                if (existsNormalsMore45Degrees)
                {
                    halfSize *= 1.41f;
                }

                Plane p;
                p             = Plane.FromVectors(normal, -side2Normal, Position);
                clipPlanes[0] = new Plane(p.Normal, p.Distance + halfSize);
                p             = Plane.FromVectors(normal, side2Normal, Position);
                clipPlanes[1] = new Plane(p.Normal, p.Distance + halfSize);
                p             = Plane.FromVectors(normal, -side1Normal, Position);
                clipPlanes[2] = new Plane(p.Normal, p.Distance + halfSize);
                p             = Plane.FromVectors(normal, side1Normal, Position);
                clipPlanes[3] = new Plane(p.Normal, p.Distance + halfSize);
                p             = Plane.FromVectors(side1Normal, side2Normal, Position);
                clipPlanes[4] = new Plane(p.Normal, p.Distance + halfSize);
                //clipPlanes[ 4 ] = new Plane( p.Normal, p.Distance + halfSize * .5f );
                p             = Plane.FromVectors(side1Normal, -side2Normal, Position);
                clipPlanes[5] = new Plane(p.Normal, p.Distance + halfSize);
                //clipPlanes[ 5 ] = new Plane( p.Normal, p.Distance + halfSize * .5f );
            }

            //generate vertices and indices by triangles
            //List<Decal.Vertex> vertices = new List<Decal.Vertex>( triangleIDs.Count * 3 );
            //List<int> indices = new List<int>( triangleIDs.Count * 3 );
            List <Decal.Vertex> vertices = tempVertices;
            List <int>          indices  = tempIndices;

            vertices.Clear();
            indices.Clear();
            {
                foreach (ShapeTriangleID triangle in triangleIDs)
                {
                    Vec3 p0, p1, p2;
                    {
                        if (currentShape != triangle.shape)
                        {
                            currentShape = triangle.shape;

                            if (currentShape.ShapeType == Shape.Type.Mesh)
                            {
                                ((MeshShape)currentShape).GetData(out shapeVertices, out shapeIndices);
                            }
                            else if (currentShape.ShapeType == Shape.Type.HeightField)
                            {
                                ((HeightFieldShape)currentShape).GetVerticesAndIndices(true,
                                                                                       out shapeVertices, out shapeIndices);
                            }
                            else
                            {
                                Log.Fatal("DecalCreator: Not supported shape type ({0}).",
                                          currentShape.ShapeType.ToString());
                            }

                            shapeTransform = currentShape.Body.GetTransform();
                            if (!currentShape.IsIdentityTransform)
                            {
                                shapeTransform *= currentShape.GetTransform();
                            }
                        }

                        int index = triangle.triangleID * 3;
                        p0 = shapeTransform * shapeVertices[shapeIndices[index + 0]];
                        p1 = shapeTransform * shapeVertices[shapeIndices[index + 1]];
                        p2 = shapeTransform * shapeVertices[shapeIndices[index + 2]];
                    }

                    List <Vec3> list = new List <Vec3>();
                    list.Add(p0);
                    list.Add(p1);
                    list.Add(p2);

                    //clip by planes
                    foreach (Plane plane in clipPlanes)
                    {
                        list = CutConvexPlanePolygonByPlane(list, plane);
                        if (list == null)
                        {
                            break;
                        }
                    }

                    //add to vertices and indices lists
                    if (list != null)
                    {
                        int vertexCount = vertices.Count;

                        Vec3 norm = Plane.FromPoints(p0, p1, p2).Normal;
                        foreach (Vec3 p in list)
                        {
                            vertices.Add(new Decal.Vertex(p, norm, Vec2.Zero, Vec3.Zero));
                        }

                        for (int n = 1; n < list.Count - 1; n++)
                        {
                            indices.Add(vertexCount);
                            indices.Add(vertexCount + n);
                            indices.Add(vertexCount + n + 1);
                        }
                    }
                }
            }

            triangleIDs.Clear();

            if (indices.Count == 0)
            {
                return;
            }

            //calculate texCoord and Type.DepthRenderOffset
            {
                Plane planeSide1 = Plane.FromVectors(normal, side1Normal, Position);
                Plane planeSide2 = Plane.FromVectors(normal, side2Normal, Position);
                float invSize    = 1.0f / Type.Size;

                for (int n = 0; n < vertices.Count; n++)
                {
                    Decal.Vertex vertex = vertices[n];

                    //calculate texCoord
                    float distance1 = planeSide1.GetDistance(vertex.position);
                    float distance2 = planeSide2.GetDistance(vertex.position);
                    vertex.texCoord = new Vec2(distance1 * invSize + .5f, distance2 * invSize + .5f);

                    //add Type.DepthRenderOffset
                    vertex.position = vertex.position + normal * Type.DepthRenderOffset;

                    vertices[n] = vertex;
                }
            }

            //calculate tangent vectors
            {
                int triangleCount = indices.Count / 3;
                for (int nTriangle = 0; nTriangle < triangleCount; nTriangle++)
                {
                    int index0 = indices[nTriangle * 3 + 0];
                    int index1 = indices[nTriangle * 3 + 1];
                    int index2 = indices[nTriangle * 3 + 2];

                    Decal.Vertex vertex0 = vertices[index0];
                    Decal.Vertex vertex1 = vertices[index1];
                    Decal.Vertex vertex2 = vertices[index2];

                    Vec3 tangent = MathUtils.CalculateTangentSpaceVector(
                        vertex0.position, vertex0.texCoord,
                        vertex1.position, vertex1.texCoord,
                        vertex2.position, vertex2.texCoord);

                    vertex0.tangent += tangent;
                    vertex1.tangent += tangent;
                    vertex2.tangent += tangent;

                    vertices[index0] = vertex0;
                    vertices[index1] = vertex1;
                    vertices[index2] = vertex2;
                }

                for (int n = 0; n < vertices.Count; n++)
                {
                    Decal.Vertex vertex = vertices[n];
                    if (vertex.tangent != Vec3.Zero)
                    {
                        vertex.tangent.Normalize();
                    }
                    vertices[n] = vertex;
                }
            }

            //subtract decal position (make local vertices coordinates)
            {
                for (int n = 0; n < vertices.Count; n++)
                {
                    Decal.Vertex vertex = vertices[n];
                    vertex.position -= Position;
                    vertices[n]      = vertex;
                }
            }

            //get material
            string materialName = null;
            {
                string physicsMaterialName = startTriangle.shape.MaterialName;
                string defaultMaterialName = "";

                foreach (DecalCreatorType.MaterialItem item in Type.Materials)
                {
                    if (item.PhysicsMaterialName == physicsMaterialName)
                    {
                        materialName = item.MaterialName;
                    }

                    if (string.IsNullOrEmpty(item.PhysicsMaterialName))
                    {
                        defaultMaterialName = item.MaterialName;
                    }
                }

                if (materialName == null)
                {
                    materialName = defaultMaterialName;
                }
            }

            //create Decal
            Decal decal = (Decal)Entities.Instance.Create("Decal", Map.Instance);

            decal.Position = Position;
            decal.Init(this, vertices.ToArray(), indices.ToArray(), materialName, parentMapObject);
            decal.PostCreate();
            Type.AddDecalToCreatedList(decal);
            decals.Add(decal);
        }
Exemplo n.º 2
0
        void CreateDirectionalDecal(Shape shape, Vec3 pos, Vec3 normal, int triangleID)
        {
            bool smallDecal = Type.Size < .3f;

            Body body = shape.Body;

            //static objects
            if (shape.ContactGroup == (int)ContactGroup.Collision)
            {
                ShapeTriangleID triangle = new ShapeTriangleID(shape, triangleID);

                //StaticMesh
                {
                    StaticMesh staticMesh = StaticMesh.GetStaticMeshByBody(body);
                    if (staticMesh != null)
                    {
                        if (staticMesh.AllowDecals == StaticMesh.DecalTypes.OnlySmall && smallDecal ||
                            staticMesh.AllowDecals == StaticMesh.DecalTypes.All)
                        {
                            CreateDecalForStaticObject(triangle, pos, normal, null);
                            return;
                        }
                    }
                }

                //HeightmapTerrain
                if (HeightmapTerrain.GetTerrainByBody(body) != null)
                {
                    CreateDecalForStaticObject(triangle, pos, normal, null);
                    return;
                }

                if (Type.ApplyToMapObjects)
                {
                    //MapObject: Attached mesh
                    MapObject mapObject = MapSystemWorld.GetMapObjectByBody(body);
                    if (mapObject != null)
                    {
                        bool isCollision = false;

                        foreach (MapObjectAttachedObject attachedObject in mapObject.AttachedObjects)
                        {
                            MapObjectAttachedMesh attachedMesh = attachedObject as MapObjectAttachedMesh;
                            if (attachedMesh != null && attachedMesh.CollisionBody == body)
                            {
                                isCollision = true;
                                break;
                            }
                        }

                        if (isCollision)
                        {
                            CreateDecalForStaticObject(triangle, pos, normal, mapObject);
                            return;
                        }
                    }
                }
            }

            //dynamic objects
            {
                //not implemented
            }
        }