예제 #1
0
    public void CalculateMirrorPlanes()
    {
        // clear old contents
        planeCenters.Clear();
        planeNormals.Clear();
        // determine triangle centers and normals in world coordinates
        Mesh room_mesh = GetComponent <MeshFilter>().mesh;

        Vector3[] room_n        = room_mesh.normals;
        Vector3[] room_vertices = room_mesh.vertices;
        int[]     room_tri      = room_mesh.triangles;
        Matrix4x4 M_scene       = transform.localToWorldMatrix;
        Matrix4x4 N_scene       = Matrix4x4.Transpose(Matrix4x4.Inverse(M_scene));

        for (var i_tri = 0; i_tri < room_tri.Length; i_tri += 3)
        {
            Vector3 new_center = (Vector3)(M_scene * ((room_vertices[room_tri[i_tri]]
                                                       + room_vertices[room_tri[i_tri + 1]]
                                                       + room_vertices[room_tri[i_tri + 2]]) / 3))
                                 + transform.position;
            Vector3 new_normal = ((Vector3)(N_scene * ((room_n[room_tri[i_tri]]
                                                        + room_n[room_tri[i_tri + 1]]
                                                        + room_n[room_tri[i_tri + 2]]) / 3))).normalized;
            // check for duplicate planes
            bool new_plane = true;
            for (var i_plane = 0; i_plane < planeCenters.Count; ++i_plane)
            {
                if (ISMMath.PlaneEQ(planeCenters[i_plane], planeNormals[i_plane], new_center, new_normal))
                {
                    new_plane = false;
                    break;
                }
            }
            if (new_plane)
            {
                // Add plane if not a duplicate
                planeCenters.Add(new_center);
                planeNormals.Add(new_normal);
            }
        }
    }
예제 #2
0
    /// <summary>
    /// Apply Image Source Method (ISM) to calculate specular reflections
    /// </summary>
    void ISMUpdate()
    {
        // Clear old data
        hitPaths.Clear();
        System.Array.Clear(ir, 0, ir.Length);
        // Check if the image source positions must be updated
        if (SourceHasMoved() || renderSettings.IRUpdateRequested)
        {
            // Clear old image sources
            imageSources.Clear();
            // === E1: Add direct sound ===
            // Add the original source to the image sources list
            // (E1) YOUR CODE HERE
            ImageSource OriginalSource = new ImageSource(transform.position);
            imageSources.Add(OriginalSource);


            // For each order of reflection
            int i_end = 0;
            for (var i_refl = 0;
                 i_refl < renderSettings.NumberOfISMReflections;
                 ++i_refl)
            {
                // === E4: Higher order reflections ===
                // (E4) YOUR CODE HERE: Update parent interval
                int i_begin = 0;
                i_end = imageSources.Count;
                // i_end = ... Mathf.Min(1, imageSources.Count
                // For each parent to reflect  = i_begin; i_parent < i_end;
                /* <-- (E4) YOUR CODE HERE: use i_begin and i_end to go through the parent image sources */
                for (var i_parent = i_begin; i_parent < i_end; ++i_parent)

                {
                    // === E2: Calculate image source positions ===
                    // Parent source on this iteration
                    ImageSource parentSource = imageSources[i_parent];
                    // For each mirroring plane
                    for (var i_child = 0;
                         i_child < renderSettings.PlaneCenters.Length;
                         ++i_child)
                    {
                        // Get the current mirroring plane
                        Vector3 p_plane = renderSettings.PlaneCenters[i_child];
                        Vector3 n_plane = renderSettings.PlaneNormals[i_child];
                        // (E2) YOUR CODE HERE: calculate the distance from the plane to the source


                        Plane wall_plane = new Plane();
                        wall_plane.SetNormalAndPosition(n_plane, p_plane);

                        //Debug.Log(wall_plane.GetDistanceToPoint(transform.position));
                        float sourcePlaneDistance = wall_plane.GetDistanceToPoint(imageSources[i_parent].pos);


                        // Is the parent source in front of the plane?
                        if (sourcePlaneDistance > 0) /* <-- (E2) YOUR CODE HERE */
                        {
                            // Parent source is in front of the plane,
                            // calculate mirrored position
                            Vector3 mirroredPosition = imageSources[i_parent].pos + 2 * sourcePlaneDistance * (-n_plane);

                            // Add the image source
                            // (E2) YOUR CODE HERE
                            ImageSource IMGSource = new ImageSource(mirroredPosition, p_plane, n_plane, i_parent);
                            imageSources.Add(IMGSource);
                        }
                    }
                }
            }
        }
        // === E3: Cast rays ===
        // A mask for game objects using ISMCollider (You define this "User Layer")
        int ism_colliders_only = LayerMask.GetMask("ISM colliders");

        // For each image source
        for (var i = 0; i < imageSources.Count; ++i)
        {
            // Calculate path length
            float pathLength = Vector3.Distance(imageSources[i].pos, ListenerPosition);/* <-- (E3) YOUR CODE HERE */
            // Check that the path can contribute to the impulse response
            if (pathLength < renderSettings.MaximumRayLength)
            {
                // Create a container for this path
                RaycastHitPath path = new RaycastHitPath(pathLength);
                // (E3) YOUR CODE HERE: Set the listener as the starting point for
                // the ray
                Vector3 origin = ListenerPosition;
                //Debug.Log(ListenerPosition.x);
                Vector3 originNormal = imageSources[i].pos - origin;
                int     i_next       = i;
                bool    isValidPath  = true;
                // Loop until we have either processed the original source or
                // found the path invalid
                while (i_next != -1 && isValidPath)
                {
                    // Get the current source
                    ImageSource imageSource = imageSources[i_next];
                    // (E3) YOUR CODE HERE: Determine ray direction and length
                    Vector3 dir        = originNormal;
                    float   max_length = Vector3.Distance(origin, imageSource.pos); //I OR I NEXT?
                    //Debug.Log(max_length);
                    // Trace the ray
                    RaycastHit hit;
                    //Physics.Raycast(origin, dir, out hit, max_length, ism_colliders_only);
                    Physics.Raycast(origin, dir, out hit, max_length);

                    //Debug.Log(hit.point);
                    //Debug.Log(hit.distance);
                    //Debug.Log(hit.collider);

                    if (imageSource.i_parent == -1)
                    {
                        // Handle the real source
                        // (E3) YOUR CODE HERE: check that the path is not obstructed
                        //if (Mathf.Abs(max_length - hit.distance) < 0.2)
                        if (Mathf.Abs(max_length - hit.distance) < 0.2)
                        {
                            isValidPath = true; //Physics.Raycast(origin, dir);
                            Debug.Log("path is not obstructed");
                        }
                        else
                        {
                            isValidPath = false;
                            Debug.Log("path is invalid");
                        }
                    }
                    else
                    {
                        // Handle image sources
                        // (E3) YOUR CODE HERE: check that the ray hits a wall on mirroring plane
                        isValidPath = ISMMath.PlaneEQ(hit, imageSource);
                    }
                    // (E3) Are there more checks needed? This depends on your previous implementation.

                    // Add the traced path if it is still valid
                    if (isValidPath)
                    {
                        // Path is valid, add the hit point to the ray path
                        // (E3) YOUR CODE HERE
                        path.points.Add(hit.point);
                        Debug.Log("path is valid, add hit point");
                        // Prepare to send the ray towards the next image source // it that okay?
                        origin = hit.point;
                        i_next = imageSource.i_parent;
                        //originNormal =  imageSources[i_next].pos - origin;
                        if (i_next != -1)
                        {
                            originNormal = imageSources[i_next].pos - origin;
                        }
                    }
                }

                // Add the traced path if it is still valid
                if (isValidPath)
                {
                    // (E3) YOUR CODE HERE
                    Debug.Log("path added");
                    hitPaths.Add(path);
                }
            }
        }
        // === E5: create image source impulse response ===
        foreach (var path in hitPaths)
        {
            // Calculate the sample that the ray path contributes to
            int i_path = Mathf.RoundToInt(
                AudioSettings.outputSampleRate * path.totalPathLength / ISMRenderSettings.speedOfSound);  // <-- (E5) YOUR CODE HERE
            if (i_path < ir.Length)
            {
                float abs  = renderSettings.Absorption;
                float diff = renderSettings.DiffuseProportion;
                float num  = path.points.Count;
                float eps  = Mathf.Pow(10, -6);

                float p_ray = (Mathf.Pow((1 - abs) * (1 - diff), num / 2) / (path.totalPathLength + eps));


                // (E5) YOUR CODE HERE: Determine the signal magnitude  w.r.t.
                // the amount of wall hits in the path
                ir[i_path] += p_ray;
            }
        }
    }
예제 #3
0
    /// <summary>
    /// Apply Image Source Method (ISM) to calculate specular reflections
    /// </summary>
    void ISMUpdate()
    {
        // Clear old data
        hitPaths.Clear();
        System.Array.Clear(ir, 0, ir.Length);
        // Check if the image source positions must be updated
        if (SourceHasMoved() || renderSettings.IRUpdateRequested)
        {
            // Clear old image sources
            imageSources.Clear();
            // === E1: Add direct sound ===
            // (E1) YOUR CODE HERE
            // Add the original source to the image sources list
            imageSources.Add(new ImageSource(SourcePosition));

            // For each order of reflection
            int i_begin;
            int i_end = 0;

            for (var i_refl = 0; i_refl < renderSettings.NumberOfISMReflections; ++i_refl)
            {
                // === E4: Higher order reflections ===
                // (E4) YOUR CODE HERE: Update parent interval
                i_begin = i_end;
                i_end   = imageSources.Count;
                // For each parent to reflect
                for (var i_parent = i_begin; i_parent < i_end; ++i_parent) // <-- (E4) YOUR CODE HERE
                {
                    // === E2: Calculate image source positions ===
                    // Parent source on this iteration
                    ImageSource parentSource = imageSources[i_parent];
                    // For each mirroring plane
                    for (var i_child = 0;
                         i_child < renderSettings.PlaneCenters.Length;
                         ++i_child)
                    {
                        // Get the current mirroring plane
                        Vector3 p_plane = renderSettings.PlaneCenters[i_child];
                        Vector3 n_plane = renderSettings.PlaneNormals[i_child];
                        // (E2) YOUR CODE HERE: calculate the distance from the plane to the source
                        float sourcePlaneDistance = Vector3.Dot(parentSource.pos - p_plane, n_plane);

                        // Is the parent source in front of the plane?
                        if (sourcePlaneDistance > 0.0)
                        {
                            // Parent source is in front of the plane, calculate mirrored position
                            Vector3 N = transform.TransformDirection(n_plane);
                            Vector3 mirroredPosition = parentSource.pos - 2 * n_plane * sourcePlaneDistance;
                            // (E2) YOUR CODE HERE
                            // Add the image source
                            imageSources.Add(new ImageSource(mirroredPosition, p_plane, n_plane, i_parent));
                        }
                    }
                }
            }
        }

        // === E3: Cast rays ===
        // A mask for game objects using ISMCollider
        int ism_colliders_only = LayerMask.GetMask("ISM colliders");

        // For each image source
        for (var i = 0; i < imageSources.Count; ++i)
        {
            // Calculate path length
            float pathLength = Vector3.Distance(imageSources[i].pos, ListenerPosition);

            // Check that the path can contribute to the impulse response
            if (pathLength < renderSettings.MaximumRayLength)
            {
                // Create a container for this path
                RaycastHitPath path = new RaycastHitPath(pathLength);
                // (E3) YOUR CODE HERE: Set the listener as the starting point for
                // the ray
                Vector3 origin       = ListenerPosition;
                Vector3 originNormal = imageSources[i].pos - origin;
                int     i_next       = i;
                bool    isValidPath  = true;

                // Loop until we have either processed the original source or
                // found the path invalid
                while (i_next != -1 && isValidPath)
                {
                    // Get the current source
                    ImageSource imageSource = imageSources[i_next];
                    // (E3) YOUR CODE HERE: Determine ray direction and length
                    Vector3 dir        = originNormal;
                    float   max_length = Vector3.Distance(origin, imageSource.pos);
                    // Trace the ray
                    RaycastHit hit;
                    // First, check that the outgoing ray is reflected from the wall
                    if (!Physics.Raycast(origin, dir, out hit, max_length, ism_colliders_only))
                    {
                        // The ray is sent in the wall, so the path is invalid
                        isValidPath = false;
                    }
                    else if (imageSource.i_parent == -1)
                    {
                        // (E3) YOUR CODE HERE
                        // Handle the real source: check that the path is not obstructed
                        if (Mathf.Abs(max_length - hit.distance) < 0.2)
                        {
                            isValidPath = true;
                        }
                        else
                        {
                            isValidPath = false;
                        }
                    }
                    else
                    {
                        // Handle image sources
                        // (E3) YOUR CODE HERE: check that the ray hits a wall on mirroring plane
                        isValidPath = ISMMath.PlaneEQ(hit, imageSource);
                    }
                    // Add the traced path if it is still valid
                    if (isValidPath)
                    {
                        // Path is valid, add the hit point to the ray path
                        // (E3) YOUR CODE HERE
                        path.points.Add(hit.point);
                        // Prepare to send the ray towards the next image source
                        i_next = imageSource.i_parent;
                        origin = hit.point;
                        if (i_next != -1)
                        {
                            originNormal = imageSources[i_next].pos - origin;
                        }
                    }
                }
                // Add the traced path if it is still valid
                if (isValidPath)
                {
                    // (E3) YOUR CODE HERE
                    hitPaths.Add(path);
                }
            }
        }
        // === E5: create image source impulse response ===
        foreach (var path in hitPaths)
        {
            // Calculate the sample that the ray path contributes to
            int i_path = Mathf.RoundToInt( // <-- (E5) YOUR CODE HERE
                AudioSettings.outputSampleRate * path.totalPathLength / ISMRenderSettings.speedOfSound
                );
            if (i_path < ir.Length)
            {
                // (E5) YOUR CODE HERE: Determine the signal magnitude  w.r.t.
                // the amount of wall hits in the path
                ir[i_path] += Mathf.Pow(
                    (1 - renderSettings.Absorption) * (1 - renderSettings.DiffuseProportion),
                    path.points.Count / 2
                    ) / (path.totalPathLength + float.Epsilon);
            }
        }
    }