Color GetLightPathColor(Vector3 pos, Vector3 dir, float length)
 {
     RayTrace.Ray ray = new RayTrace.Ray(pos, dir, length);
     RayTrace.Intersect(ref ray);
     if (ray.geomID == RayTrace.Invalid)
     {
         return(Color.white);
     }
     else
     {
         SimpleModel model    = scene.models[(int)ray.geomID];
         SimpleMesh  mesh     = model.mesh;
         int         t0       = mesh.triangles[ray.primID * 3 + 0];
         int         t1       = mesh.triangles[ray.primID * 3 + 1];
         int         t2       = mesh.triangles[ray.primID * 3 + 2];
         Vector2     uv       = RayTraceTool.Lerp(mesh.uv[t0], mesh.uv[t1], mesh.uv[t2], ray.u, ray.v);
         Vector3     hitPos   = ray.pos + ray.dir * ray.length;
         Color       texColor = model.material.PointSample(uv);
         if (texColor.a < 0.99f)
         {
             Color aheadColor = GetLightPathColor(hitPos, dir * 0.01f, length - ray.length);
             Color blendColor = (aheadColor * (1 - texColor.a)) + (texColor * texColor.a);
             return(blendColor);
         }
     }
     return(Color.black);
 }
    public void Render()
    {
        //RayTraceTool.GetRandomDirs_BlinnPhong_Importance2(Vector3.up, new Vector3(1, 0.1f, 0).normalized, 0.7f, 1000);
        //return;

        updateProgress(0);
        Camera cam = GetComponent <Camera>();

        if (cam)
        {
            Vector3       left          = Vector3.Cross(cam.transform.forward, cam.transform.up);
            Vector3       up            = Vector3.Cross(left, cam.transform.forward);
            float         lengthY       = Mathf.Tan(Mathf.Deg2Rad * cam.fieldOfView / 2) * 2;
            float         lengthX       = lengthY * width / height;
            int           waitNum       = width * height;
            int           curIndex      = 0;
            SimpleTexture targetTexture = new SimpleTexture(width, height);

            float startTime = Time.realtimeSinceStartup;
            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    int x = i - width / 2;
                    int y = height / 2 - j;

                    Color color      = Color.black;
                    int   splitPixel = antiAliasing ? 3 : 1;
                    for (int ax = 0; ax < splitPixel; ax++)
                    {
                        for (int ay = 0; ay < splitPixel; ay++)
                        {
                            float   fx           = (lengthX * (x + ax / (float)splitPixel)) / width;
                            float   fy           = (lengthY * (y + ay / (float)splitPixel)) / height;
                            Vector3 temp         = cam.transform.position + cam.transform.forward + left * fx + up * fy;
                            Vector3 tempDir      = Vector3.Normalize(temp - cam.transform.position);
                            int     subSampleNum = sampleNum / (splitPixel * splitPixel);
                            color += TraceColor(cam.transform.position, tempDir, subSampleNum, 3);
                        }
                    }
                    color  /= splitPixel * splitPixel;
                    color.a = 1;
                    targetTexture.SetColor(width - i - 1, height - j - 1, RayTraceTool.LinearToGammaSpace(color));

                    curIndex += 1;
                }
                if (updateProgress(curIndex / (float)waitNum))
                {
                    break;
                }
            }
            //TaskPipeLine.Flush();
            Debug.Log("render time : " + (Time.realtimeSinceStartup - startTime));
            texture.SetPixels(targetTexture.colors);
            texture.Apply(true);
        }
    }
    public SimpleMaterial(Material mat)
    {
        unityTexture = mat.mainTexture as Texture2D;

        if (mat.mainTexture != null)
        {
            Int64 key = mat.mainTexture.GetNativeTexturePtr().ToInt64();
            if (!textures.TryGetValue(key, out texture))
            {
                texture       = new SimpleTexture(mat.mainTexture as Texture2D);
                textures[key] = texture;
            }
        }
        else
        {
            texture = new SimpleTexture(null);
        }
        if (mat.HasProperty("_Color"))
        {
            this.color = RayTraceTool.GammaToLinearSpace(mat.color);
        }
        if (mat.HasProperty("_Glossiness"))
        {
            glossiness = mat.GetFloat("_Glossiness");
        }
        if (mat.HasProperty("_Metallic"))
        {
            metallic = mat.GetFloat("_Metallic");
        }
        if (mat.HasProperty("_Cutoff"))
        {
            renderMode = RenderMode.Alphablend;
        }
        else if (mat.shader.name.ToLower().Contains("standard"))
        {
            if (mat.HasProperty("_Mode"))
            {
                if (mat.GetInt("_Mode") == 0)
                {
                    renderMode = RenderMode.Opaque;
                }
            }
        }
        else if (mat.shader.name.ToLower().Contains("multiply"))
        {
            renderMode = RenderMode.Multiply;
        }
        else if (mat.shader.name.ToLower().Contains("transparent"))
        {
            renderMode = RenderMode.Alphablend;
        }
    }
    public override Color LinearSample(Vector2 uv)
    {
        Color rlt = Color.black;

        for (int i = 0; i < alphamapLayers; i++)
        {
            float alpha = RayTraceTool.BilinearInterpolation(alphamaps[i], alphamapWidth, alphamapHeight, new Vector2(uv.y, uv.x));
            if (alpha > 0.004f)
            {
                rlt += RayTraceTool.LinearSample(textures[i].colors, textures[i].width, textures[i].height, Vector2.Scale(uv, textures[i].scale)) * alpha;
            }
        }
        return(rlt);
    }
    public SimpleTexture(Texture2D texture)
    {
        if (texture != null)
        {
            string assetPath = UnityEditor.AssetDatabase.GetAssetPath(texture);
            var    tImporter = UnityEditor.AssetImporter.GetAtPath(assetPath) as UnityEditor.TextureImporter;
            if (tImporter == null || !tImporter.isReadable)
            {
                RenderTexture rt = new RenderTexture(texture.width, texture.height, 0);
                RenderTexture.active = rt;
                Graphics.Blit(texture, rt);
                texture = new Texture2D(texture.width, texture.height);
                texture.ReadPixels(new Rect(0, 0, texture.width, texture.height), 0, 0);
                texture.Apply();
                RenderTexture.active = null;

                if (bFirst)
                {
                    bFirst = false;
                    RayTraceRenderer.Instance.previewTexture = texture;
                }
            }
        }
        if (texture)
        {
            width  = texture.width;
            height = texture.height;
            colors = texture.GetPixels();
            for (int i = 0; i < colors.Length; i++)
            {
                colors[i] = RayTraceTool.GammaToLinearSpace(colors[i]);
            }
        }

        if (colors == null || colors.Length == 0)
        {
            width     = 1;
            height    = 1;
            colors    = new Color[1];
            colors[0] = Color.white;
        }
    }
    Color TraceColor(Vector3 startPos, Vector3 rayDir, int sample, int depth)
    {
        if (depth <= 0)
        {
            return(Color.black);
        }
        RayTrace.Ray ray = new RayTrace.Ray(startPos, rayDir, 1000);
        RayTrace.Intersect(ref ray);
        if (ray.geomID == RayTrace.Invalid)
        {
            return(skyColor);
        }
        else
        {
            SimpleModel model    = scene.models[(int)ray.geomID];
            SimpleMesh  mesh     = model.mesh;
            int         t0       = mesh.triangles[ray.primID * 3 + 0];
            int         t1       = mesh.triangles[ray.primID * 3 + 1];
            int         t2       = mesh.triangles[ray.primID * 3 + 2];
            Vector2     uv       = RayTraceTool.Lerp(mesh.uv[t0], mesh.uv[t1], mesh.uv[t2], ray.u, ray.v);
            Color       texColor = model.material.LinearSample(uv);

            if (!ignoreMaterialColor)
            {
                texColor *= model.material.GetColor();
            }

            if (model.material.GetRenderMode() == SimpleMaterial.RenderMode.Opaque)
            {
                texColor.a = 1;
            }

            Vector3 hitPos    = ray.pos + ray.dir * ray.length;
            Vector3 hitNormal = RayTraceTool.Lerp(mesh.normals[t0], mesh.normals[t1], mesh.normals[t2], ray.u, ray.v);
            hitNormal = (model.rst.rot * hitNormal);


            float transFactor   = 1 - texColor.a;
            float glossiness    = model.material.glossiness;
            float reflectFactor = Mathf.Lerp(0.2f * glossiness, 1f, model.material.metallic);
            if (reflectFactor > 0.01f)
            {
                reflectFactor = Fresnel_Schlick(Vector3.Dot(-rayDir, hitNormal), reflectFactor);
            }
            float grayscale     = texColor.grayscale;
            float diffuseFactor = Mathf.Clamp01(1 - transFactor - reflectFactor);

            int transSample   = (int)(sample * grayscale * transFactor);
            int reflectSample = (int)(sample * reflectFactor);
            int diffuseSample = (int)(sample * grayscale * diffuseFactor);


            Color finaleColor = Color.black;

            Color reflectColor = Color.black;
            {
                Color finalLightColor = Color.black;// GetAllLightsColor(model, hitPos, hitNormal) * (reflectFactor + scene.lights.Length);//光源直接贡献
                if (reflectSample > 0)
                {
                    Vector3   reflectDir = Vector3.Reflect(rayDir, hitNormal);
                    Vector3[] dirs       = RayTraceTool.GetRandomDirs_BlinnPhong_Importance2(hitNormal, reflectDir, glossiness, reflectSample);
                    for (int i = 0; i < reflectSample; i++)
                    {
                        finalLightColor += TraceColor(hitPos + hitNormal * 0.01f, dirs[i], 1, depth - 1);//间接光贡献
                    }
                    finalLightColor /= (reflectSample);
                }
                reflectColor = Color.Lerp(Color.white, texColor, model.material.metallic) * finalLightColor;
            }

            Color diffuseColor = Color.black;
            {
                Color finalLightColor = GetAllLightsColor(model, hitPos, hitNormal) * (diffuseSample + scene.lights.Length);//光源直接贡献
                if (diffuseSample > 0)
                {
                    Vector3   reflectDir = Vector3.Reflect(rayDir, hitNormal);
                    Vector3[] dirs       = RayTraceTool.GetRandomDirs_RoundProj(hitNormal, diffuseSample);
                    for (int i = 0; i < diffuseSample; i++)
                    {
                        finalLightColor += TraceColor(hitPos + hitNormal * 0.01f, dirs[i], 1, depth - 1);//间接光贡献
                    }
                }
                finalLightColor /= (diffuseSample + scene.lights.Length);
                diffuseColor     = texColor * finalLightColor;
            }

            //Color reflectColor = Color.black;
            //if(reflectFactor > 0.01f){
            //    Vector3 refDir = Vector3.Reflect(rayDir,hitNormal);
            //    Color finalLightColor = TraceColor(hitPos + refDir * 0.01f, refDir,reflectSample ,depth - 1);
            //    reflectColor = finalLightColor;
            //}

            finaleColor = reflectColor * reflectFactor + diffuseColor * diffuseFactor;

            if (texColor.a < 0.99f)
            {
                Color transColor = TraceColor(hitPos + rayDir * 0.01f, rayDir, transSample, depth);
                if (model.material.GetRenderMode() == SimpleMaterial.RenderMode.Alphablend)
                {
                    finaleColor = finaleColor * texColor.a + transColor * (1 - texColor.a);
                }
                else if (model.material.GetRenderMode() == SimpleMaterial.RenderMode.Multiply)
                {
                    finaleColor = finaleColor * transColor;
                }
                else if (model.material.GetRenderMode() == SimpleMaterial.RenderMode.Additive)
                {
                    finaleColor = finaleColor + transColor;
                }
            }

            return(finaleColor);
        }
    }
    public void Init()
    {
        Instance = this;
        updateProgress(0);
        HaltonTool.InitHaltonSequence();

        Debug.Log("Start Time : " + Time.realtimeSinceStartup);

        scene = new SimpleScene();

        RayTrace.Init();
        SimpleMaterial.textures.Clear();

        scene.lights = GameObject.FindObjectsOfType <Light>();

        Camera cam = GetComponent <Camera>();

        if (cam)
        {
            MeshRenderer[] renderers = GameObject.FindObjectsOfType <MeshRenderer>();
            foreach (MeshRenderer r in renderers)
            {
                bool isLayerVisible = ((1 << r.gameObject.layer) & cam.cullingMask) != 0;
                if (r.isVisible && isLayerVisible)
                {
                    MeshFilter filter = r.gameObject.GetComponent <MeshFilter>();
                    if (filter && filter.sharedMesh)
                    {
                        for (int i = 0; i < filter.sharedMesh.subMeshCount; i++)
                        {
                            Mesh  mesh      = filter.sharedMesh;
                            int[] triangles = filter.sharedMesh.GetTriangles(i);
                            RayTrace.AddMesh(filter.gameObject.transform, mesh.vertexCount, triangles.Length, mesh.vertices, triangles, 1);
                            SimpleModel model = new SimpleModel(r.gameObject.transform, filter.sharedMesh, i, r.sharedMaterials[i]);
                            model.lights = RayTraceTool.GetActivityLights(r, scene);
                            scene.models.Add(model);
                        }
                    }
                }
            }
            Terrain[] terrains = GameObject.FindObjectsOfType <Terrain>();
            foreach (Terrain terrain in terrains)
            {
                bool isLayerVisible = ((1 << terrain.gameObject.layer) & cam.cullingMask) != 0;
                if (terrain.gameObject.activeInHierarchy && isLayerVisible)
                {
                    int   w          = terrain.terrainData.heightmapWidth;
                    int   h          = terrain.terrainData.heightmapHeight;
                    float realWidth  = terrain.terrainData.size.x * (1 + 1f / w);
                    float realHeight = terrain.terrainData.size.z * (1 + 1f / h);
                    float[,] heights = terrain.terrainData.GetHeights(0, 0, w, h);
                    Vector3[] vertices  = new Vector3[w * h];
                    Vector2[] uvs       = new Vector2[vertices.Length];
                    Vector3[] normals   = new Vector3[vertices.Length];
                    int[]     triangles = new int[(w - 1) * (h - 1) * 2 * 3];
                    for (int i = 0; i < w; i++)
                    {
                        for (int j = 0; j < h; j++)
                        {
                            Vector3 pos = new Vector3(i * realWidth / w, heights[j, i] * terrain.terrainData.size.y, j * realHeight / h);
                            vertices[j * w + i] = pos;
                            uvs[j * w + i]      = new Vector2(i / (float)w, j / (float)h);
                            normals[j * w + i]  = terrain.terrainData.GetInterpolatedNormal(i / (float)w, j / (float)h);
                        }
                    }

                    for (int i = 0; i < w - 1; i++)
                    {
                        for (int j = 0; j < h - 1; j++)
                        {
                            int index = (j * (w - 1) + i) * 6;
                            triangles[index + 0] = (i + 0) + (j + 0) * w;
                            triangles[index + 1] = (i + 1) + (j + 1) * w;
                            triangles[index + 2] = (i + 1) + (j + 0) * w;
                            triangles[index + 3] = (i + 0) + (j + 0) * w;
                            triangles[index + 4] = (i + 0) + (j + 1) * w;
                            triangles[index + 5] = (i + 1) + (j + 1) * w;
                        }
                    }

                    RayTrace.AddMesh(terrain.transform, vertices.Length, triangles.Length, vertices, triangles, 1);
                    SimpleModel model = new SimpleModel();
                    model.mesh     = new SimpleMesh(triangles, uvs, vertices, normals);
                    model.material = new SimpleTerrainMaterial(terrain.terrainData);
                    model.rst      = new RayTrace.RST(terrain.transform.rotation, terrain.transform.lossyScale, terrain.transform.position);
                    model.lights.AddRange(scene.lights);
                    scene.models.Add(model);
                }
            }
        }

        RayTrace.Commit();

        texture = new Texture2D(width, height, TextureFormat.ARGB32, true);
        //viewResult.sharedMaterial.mainTexture = texture;
    }
 public override Color LinearSample(Vector2 uv)
 {
     return(RayTraceTool.LinearSample(texture.colors, texture.width, texture.height, uv));
 }