public void UpdateAmbientOcclusionOld(Model model, Group occluders)
        {
            string       mapName = "point_normals_for_ambient_occlusion";
            GeometryMesh mesh    = model.Batch.MeshSource as GeometryMesh;

            if (mesh == null)
            {
                return;
            }
            Matrix4  pointFrame = new Matrix4();
            Geometry geometry   = mesh.Geometry;

            var pointLocations   = geometry.PointAttributes.Find <Vector3>("point_locations");
            var polygonCentroids = geometry.PolygonAttributes.Find <Vector3>("polygon_centroids");
            var pointNormals     = geometry.PointAttributes.Find <Vector3>(mapName);
            var cornerNormals    = geometry.CornerAttributes.Contains <Vector3>("corner_normals") ? geometry.CornerAttributes.Find <Vector3>("corner_normals") : null;
            var cornerColors     = geometry.CornerAttributes.FindOrCreate <Vector4>("corner_colors");

            cornerColors.Clear();
            float[] colorBuffer = new float[mesh.GetMesh.VertexBufferRange.Count * 4];
            foreach (Polygon polygon in geometry.Polygons)
            {
                foreach (Corner corner in polygon.Corners)
                {
                    Point   point = corner.Point;
                    Vector3 eye   = Vector3.Mix(pointLocations[point], polygonCentroids[polygon], 0.01f);
                    Vector3 normal;

                    if (
                        (cornerNormals != null) &&
                        (cornerNormals.ContainsKey(corner) == true)
                        )
                    {
                        normal = cornerNormals[corner];
                    }
                    else
                    {
                        normal = pointNormals[point];
                    }
                    eye    = model.Frame.LocalToWorld.Matrix.TransformPoint(eye);
                    normal = model.Frame.LocalToWorld.Matrix.TransformDirection(normal);
                    eye   += normal * 0.01f;

                    //aoEye = eye;
                    //aoBack = normal;
                    Matrix4.CreateLookAt(eye, eye + normal, normal.MinAxis, out pointFrame);
                    Vector3 positionInWorld = pointFrame.TransformPoint(new Vector3(0.0f, 0.0f, 0.0f));
                    aoHemicubeRenderer.Render(pointFrame, occluders);
                    float occlusion = aoHemicubeRenderer.Average;
                    cornerColors[corner] = new Vector4(occlusion, occlusion, occlusion, 1.0f);
                }
            }
            mesh.BuildMeshFromGeometry(BufferUsageHint.StaticDraw, NormalStyle.CornerNormals);

            model.Name = "AmbientOcclusion(" + model.Name + ")";
        }
        //int sampleCount = 50;
        //float distance = 4.0f;
        public void UpdateAmbientOcclusion(Model model, Group occluders, string mapName)
        {
#if false // \todo fix
            GeometryMesh mesh = model.Batch.MeshSource as GeometryMesh;
            if (mesh == null)
            {
                return;
            }
            Geometry geometry = mesh.Geometry;

            model.UpdateOctree();
            var shape = new TriangleMeshShape(model.Octree);
            shape.SphericalExpansion = 0.0f;

#if VISUALIZE_RAYS
            sceneManager.DebugLineRenderer.Begin();
#endif

            var pointLocations   = geometry.PointAttributes.Find <Vector3>("point_locations");
            var polygonCentroids = geometry.PolygonAttributes.Find <Vector3>("polygon_centroids");
            var pointNormals     = geometry.PointAttributes.Find <Vector3>(mapName);
            var cornerNormals    = geometry.CornerAttributes.Contains <Vector3>("corner_normals") ? geometry.CornerAttributes.Find <Vector3>("corner_normals") : null;
            var cornerColors     = geometry.CornerAttributes.FindOrCreate <Vector4>("corner_colors");
            cornerColors.Clear();
            int badCount = 0;
            foreach (Polygon polygon in geometry.Polygons)
            {
                foreach (Corner corner in polygon.Corners)
                {
                    Point point = corner.Point;

                    //  Start from corner position slightly moved towards polygon center
                    Vector3 initialEye = Vector3.Mix(pointLocations[point], polygonCentroids[polygon], 0.001f);
                    Vector3 normal;

                    if (
                        (cornerNormals != null) &&
                        (cornerNormals.ContainsKey(corner) == true)
                        )
                    {
                        normal = cornerNormals[corner];
                    }
                    else
                    {
                        normal = pointNormals[point];
                    }

                    JMatrix orientation    = JMatrix.Identity;
                    JMatrix invOrientation = JMatrix.Identity;
                    Vector3 modelPosition  = Vector3.Zero;

                    //  Slightly up from surface
                    initialEye += normal * 0.01f;

                    int visibility = sampleCount;

                    JVector position = Conversions.JVector(modelPosition);
                    JVector direction;
                    JVector jnormal;

                    Vector3 eye    = initialEye;
                    JVector origin = Conversions.JVector(eye);

                    //  Sample a few directions
                    for (int c = 0; c < sampleCount; ++c)
                    {
                        //  Get a random direction until it points up from the surface
                        Vector3 sampleDirection;
                        float   dot;
                        do
                        {
                            sampleDirection = Random();
                            dot             = Vector3.Dot(normal, sampleDirection);
                        }while(dot < 0.25f);

                        //  Scale
                        direction = Conversions.JVector(sampleDirection * distance);

                        bool hit = false;
                        {
                            float tempFraction;

                            if (shape is Multishape)
                            {
                                Multishape ms = (shape as Multishape).RequestWorkingClone();
                                JVector    tempNormal;
                                int        msLength = ms.Prepare(ref origin, ref direction);

                                for (int i = 0; i < msLength; i++)
                                {
                                    ms.SetCurrentShape(i);

                                    if (
                                        GJKCollide.Raycast(
                                            ms, ref orientation, ref invOrientation, ref position,
                                            ref origin, ref direction, out tempFraction, out tempNormal
                                            )
                                        )
                                    {
                                        hit = true;
                                        break;
                                    }
                                }

                                ms.ReturnWorkingClone();
                            }
                            else
                            {
                                hit = GJKCollide.Raycast(
                                    shape, ref orientation, ref invOrientation, ref position,
                                    ref origin, ref direction, out tempFraction, out jnormal
                                    );
                            }
                        }


                        if (hit)
                        {
                            visibility -= 1;
                        }

                        Vector3 root = new Vector3(origin.X, origin.Y, origin.Z);
                        Vector3 tip  = root + 0.02f * new Vector3(direction.X, direction.Y, direction.Z);
#if VISUALIZE_RAYS
                        sceneManager.DebugLineRenderer.Line(
                            root,
                            Vector4.Zero,
                            tip,
                            (hit ? Vector4.UnitX : Vector4.UnitY)
                            );
#endif
                    }
                    float visibilityFloat = (float)(visibility) / (float)(sampleCount);
                    cornerColors[corner] = new Vector4(visibilityFloat, visibilityFloat, visibilityFloat, 1.0f);
                }
            }
            mesh.Geometry.ComputePolygonCentroids();
            mesh.Geometry.ComputePolygonNormals();
            mesh.Geometry.SmoothNormalize("corner_normals", "polygon_normals", (2.0f * (float)Math.PI));
            mesh.Geometry.SmoothAverage("corner_colors", mapName);
            mesh.BuildMeshFromGeometry(BufferUsageHint.StaticDraw, NormalStyle.CornerNormals);
            //UpdateMeshCornerColors(mesh);
            Debug.WriteLine("bad count = " + badCount.ToString());

#if VISUALIZE_RAYS
            sceneManager.DebugLineRenderer.End();
            sceneManager.DebugFrame = model.Frame;
#endif

            //model.Name = "AmbientOcclusion(" + model.Name + ")";
#endif
        }