光线跟踪器未产生预期输出 我有个问题:我用C++代码读取了一个光线跟踪的代码。C++是可以的。我试着把它转换成Python,它成功了(结果慢了17倍,分辨率降低了4倍)。我试图将其转换为C#,但我的代码无法工作。我唯一能看到的是一张空白的白色800x600图像。有关C++代码,请参阅先前链接的文章。

光线跟踪器未产生预期输出 我有个问题:我用C++代码读取了一个光线跟踪的代码。C++是可以的。我试着把它转换成Python,它成功了(结果慢了17倍,分辨率降低了4倍)。我试图将其转换为C#,但我的代码无法工作。我唯一能看到的是一张空白的白色800x600图像。有关C++代码,请参阅先前链接的文章。,c#,graphics,raytracing,C#,Graphics,Raytracing,这是我对C代码的解释: 使用系统; 使用System.Collections.Generic; 名称空间光线跟踪器 { 班级计划 { const int MAX_RAY_DEPTH=8; 常量浮点远=100000000; 公共静态void Main(字符串[]args) { 球体[]球体=新球体[7]; 球体[0]=新球体(新Vec3f(0.0f,-10004,-20),10000,新Vec3f(0.20f,0.20f,0.20f),0,0.0f); 球体[1]=新球体(新Vec3f(0.0f,

这是我对C代码的解释:

使用系统;
使用System.Collections.Generic;
名称空间光线跟踪器
{
班级计划
{
const int MAX_RAY_DEPTH=8;
常量浮点远=100000000;
公共静态void Main(字符串[]args)
{
球体[]球体=新球体[7];
球体[0]=新球体(新Vec3f(0.0f,-10004,-20),10000,新Vec3f(0.20f,0.20f,0.20f),0,0.0f);
球体[1]=新球体(新Vec3f(0.0f,0,-20),4,新Vec3f(1.00f,0.32f,0.36f),1,0.5f);
球体[2]=新球体(新Vec3f(5.0f,-1,-15),2,新Vec3f(0.90f,0.76f,0.46f),1,0.0f);
球体[3]=新球体(新Vec3f(5.0f,0,-25),3,新Vec3f(0.65f,0.77f,0.97f),1,0.0f);
球体[4]=新球体(新Vec3f(-5.5f,0,-15),3,新Vec3f(0.90f,0.90f,0.90f),1,0.0f);
球体[5]=新球体(新Vec3f(2f,2,-30),4,新Vec3f(0.53f,0.38f,0.91f),1,0.7f);
球体[6]=新球体(新Vec3f(0,20,-25),3,新Vec3f(0.00f,0.00f,0.00f),0,0.0f,新Vec3f(3));
渲染(球体);
}
公共类冲突
{
公众浮标t0、t1;
公共利益冲突;
公共冲突(布尔列,浮点tt0=0,浮点tt1=0)
{
t0=tt0;
t1=tt1;
碰撞=col;
}
}
公共类Vec3f
{
公共浮动x,y,z;
公共向量3f(){x=y=z=0;}
公共向量3f(float v){x=y=z=v;}
公共向量3f(浮点xx,浮点yy,浮点zz){x=xx;y=yy;z=zz;}
公共Vec3f规范化()
{
浮动nor2=长度2();
如果(nor2>0)
{
浮点invNor=1/(浮点)数学Sqrt(nor2);
x*=invNor;y*=invNor;z*=invNor;
}
归还这个;
}
公共静态Vec3f运算符*(Vec3f l,Vec3f r)
{
返回新的Vec3f(l.x*r.x,l.y*r.y,l.z*r.z);
}
公共静态Vec3f运算符*(Vec3f l,float r)
{
返回新的Vec3f(长x*r、长y*r、长z*r);
}
公共浮点数(Vec3f v)
{
返回x*v.x+y*v.y+z*v.z;
}
公共静态Vec3f运算符-(Vec3f l,Vec3f r)
{
返回新的Vec3f(l.x-r.x,l.y-r.y,l.z-r.z);
}
公共静态Vec3f运算符+(Vec3f l,Vec3f r)
{
返回新的Vec3f(l.x+r.x,l.y+r.y,l.z+r.z);
}
公共静态Vec3f运算符-(Vec3f v)
{
返回新的Vec3f(-v.x,-v.y,-v.z);
}
公众浮标长度2()
{
返回x*x+y*y+z*z;
}
公共浮动长度()
{
return(float)Math.Sqrt(length2());
}
}
公共阶级领域
{
公共Vec3f中心、表面颜色、发射颜色;
公共浮动半径,半径2;
公开透明、反思;
公共球体(Vec3f c,float r,Vec3f sc,float refl=0,float transp=0,Vec3f ec=null)
{
中心=c;半径=r;半径2=r*r;
surfaceColor=sc;emissionColor=(ec==null)?新Vec3f(0):ec;
透明度=传输;反射=反射;
}
公共碰撞相交(Vec3f rayorig、Vec3f raydir)
{
Vec3f l=中心-雷奥里格;
浮点数tca=l.dot(raydir);
如果(tca<0){返回新的冲突(false);}
浮点数d2=l.dot(l)-tca*tca;
如果(d2>radius2){返回新的冲突(false);}
Collision coll=新的碰撞(true);
float thc=(float)Math.Sqrt(radius2-d2);
coll.t0=tca-thc;
coll.t1=tca+thc;
返回coll;
}
}
公共静态浮动组合(浮动a、浮动b、浮动组合)
{
返回b*混合+a*(1-混合);
}
公共静态Vec3f跟踪(Vec3f rayorig,Vec3f raydir,Sphere[]spheres,int depth)
{
浮动时间=远;
球体=空;
foreach(球体中的球体i)
{
浮点数t0=FAR,t1=FAR;
碰撞coll=i.intersect(rayorig,raydir);
if(coll.collide)
{
如果(coll.t0<0){coll.t0=coll.t1;}
如果(coll.t00{nhit=-nhit;inside=true;}
if((sphere.transparency>0 | | sphere.reflection>0)&&depth0)
{
浮动ior=1.1f;浮动eta=0;
如果(内部){eta=ior;}否则{eta=1/ior;}
float cosi=-nhit.dot(raydir);
浮点数k=1-埃塔*埃塔*(1-余弦*余弦);
Vec3f refrdir=raydir*eta+nhit*(eta*cosi-(fl
using System;
using System.Collections.Generic;

namespace raytracer
{
class Program
{
    const int MAX_RAY_DEPTH = 8;
    const float FAR = 100000000;

    public static void Main(string[] args)
    {
        Sphere[] spheres = new Sphere[7];
        spheres[0] = new Sphere(new Vec3f( 0.0f, -10004, -20), 10000, new Vec3f(0.20f, 0.20f, 0.20f), 0, 0.0f);
        spheres[1] = new Sphere(new Vec3f( 0.0f,      0, -20),     4, new Vec3f(1.00f, 0.32f, 0.36f), 1, 0.5f);
        spheres[2] = new Sphere(new Vec3f( 5.0f,     -1, -15),     2, new Vec3f(0.90f, 0.76f, 0.46f), 1, 0.0f);
        spheres[3] = new Sphere(new Vec3f( 5.0f,      0, -25),     3, new Vec3f(0.65f, 0.77f, 0.97f), 1, 0.0f);
        spheres[4] = new Sphere(new Vec3f(-5.5f,      0, -15),     3, new Vec3f(0.90f, 0.90f, 0.90f), 1, 0.0f);
        spheres[5] = new Sphere(new Vec3f(   2f,      2, -30),     4, new Vec3f(0.53f, 0.38f, 0.91f), 1, 0.7f);
        spheres[6] = new Sphere(new Vec3f(    0,     20, -25),     3, new Vec3f(0.00f, 0.00f, 0.00f), 0, 0.0f, new Vec3f(3));
        Render(spheres);
    }

    public class Collision
    {
        public float t0, t1;
        public bool collide;
        public Collision(bool col, float tt0 = 0, float tt1 = 0)
        {
            t0 = tt0;
            t1 = tt1;
            collide = col;
        }
    }

    public class Vec3f
    {
        public float x, y, z;
        public Vec3f(){ x = y = z = 0; }
        public Vec3f(float v){ x = y = z = v; }
        public Vec3f(float xx, float yy, float zz){ x = xx; y = yy; z = zz; }

        public Vec3f normalize()
        {
            float nor2 = length2();
            if (nor2 > 0)
            {
                float invNor = 1 / (float)Math.Sqrt(nor2);
                x *= invNor; y *= invNor; z *= invNor;
            }
            return this;
        }
        public static Vec3f operator *(Vec3f l, Vec3f r)
        {
            return new Vec3f(l.x * r.x, l.y * r.y, l.z * r.z);
        }
        public static Vec3f operator *(Vec3f l, float r)
        {
            return new Vec3f(l.x * r, l.y * r, l.z * r);
        }
        public float dot(Vec3f v)
        {
            return x * v.x + y * v.y + z * v.z;
        }
        public static Vec3f operator -(Vec3f l, Vec3f r)
        {
            return new Vec3f(l.x - r.x, l.y - r.y, l.z - r.z);
        }
        public static Vec3f operator +(Vec3f l, Vec3f r)
        {
            return new Vec3f(l.x + r.x, l.y + r.y, l.z + r.z);
        }
        public static Vec3f operator -(Vec3f v)
        {
            return new Vec3f(-v.x, -v.y, -v.z);
        }
        public float length2()
        {
            return x * x + y * y + z * z;
        }
        public float length()
        {
            return (float)Math.Sqrt(length2());
        }
    }

    public class Sphere
    {
        public Vec3f center, surfaceColor, emissionColor;
        public float radius, radius2;
        public float transparency, reflection;
        public Sphere(Vec3f c, float r, Vec3f sc, float refl = 0, float transp = 0, Vec3f ec = null)
        {
            center = c; radius = r; radius2 = r * r;
            surfaceColor = sc; emissionColor = (ec == null) ? new Vec3f(0) : ec;
            transparency = transp; reflection = refl;
        }

        public Collision intersect(Vec3f rayorig, Vec3f raydir)
        {
            Vec3f l = center - rayorig;
            float tca = l.dot(raydir);
            if (tca < 0){ return new Collision(false); }
            float d2 = l.dot(l) - tca * tca;
            if (d2 > radius2){ return new Collision(false); }
            Collision coll = new Collision(true);
            float thc = (float)Math.Sqrt(radius2 - d2);
            coll.t0 = tca - thc;
            coll.t1 = tca + thc;
            return coll;
        }
    }

    public static float mix(float a, float b, float mix)
    {
        return b * mix + a * (1 - mix);
    }

    public static Vec3f trace(Vec3f rayorig, Vec3f raydir, Sphere[] spheres, int depth)
    {
        float tnear = FAR;
        Sphere sphere = null;
        foreach(Sphere i in spheres)
        {
            float t0 = FAR, t1 = FAR;
            Collision coll = i.intersect(rayorig, raydir);
            if (coll.collide)
            {
                if (coll.t0 < 0) { coll.t0 = coll.t1; }
                if (coll.t0 < tnear) { tnear = coll.t0; sphere = i; }
            }
        }
        if (sphere == null){ return new Vec3f(2); }
        Vec3f surfaceColor = new Vec3f(0);
        Vec3f phit = rayorig + raydir * tnear;
        Vec3f nhit = phit - sphere.center;
        nhit.normalize();
        float bias = 1e-4f;
        bool inside = false;
        if (raydir.dot(nhit) > 0){ nhit = -nhit; inside = true; }
        if ((sphere.transparency > 0 || sphere.reflection > 0) && depth < MAX_RAY_DEPTH)
        {
            float facingratio = -raydir.dot(nhit);
            float fresneleffect = mix((float)Math.Pow(1 - facingratio, 3), 1, 0.1f);
            Vec3f refldir = raydir - nhit * 2 * raydir.dot(nhit);
            refldir.normalize();
            Vec3f reflection = trace(phit + nhit * bias, refldir, spheres, depth + 1);
            Vec3f refraction = new Vec3f(0);
            if (sphere.transparency > 0)
            {
                float ior = 1.1f; float eta = 0;
                if (inside){ eta = ior; } else { eta = 1 / ior; }
                float cosi = -nhit.dot(raydir);
                float k = 1 - eta * eta * (1 - cosi * cosi);
                Vec3f refrdir = raydir * eta + nhit * (eta * cosi - (float)Math.Sqrt(k));
                refrdir.normalize();
                refraction = trace(phit - nhit * bias, refrdir, spheres, depth + 1);
            }
            surfaceColor = 
            (
                reflection * fresneleffect + refraction * 
                (1 - fresneleffect) * sphere.transparency) * sphere.surfaceColor;
        }
        else
        {
            foreach(Sphere i in spheres)
            {
                if (i.emissionColor.x > 0)
                {
                    Vec3f transmission = new Vec3f(1);
                    Vec3f lightDirection = i.center - phit;
                    lightDirection.normalize();
                    foreach(Sphere j in spheres)
                    {
                        if (i != j)
                        {
                            Collision jcoll = j.intersect(phit + nhit * bias, lightDirection);
                            if (jcoll.collide)
                            {
                                transmission = new Vec3f(0);
                                break;
                            }
                        }
                    }
                    surfaceColor += sphere.surfaceColor * transmission * Math.Max(0, nhit.dot(lightDirection)) * i.emissionColor;

                }
            }
        }
        return surfaceColor;
    }

    public static void Render(Sphere[] spheres)
    {
        int width = 800, height = 600;
        List<Vec3f> image = new List<Vec3f>();
        float invWidth = 1 / width, invHeight = 1 / height;
        float fov = 30, aspectratio = width / height;
        float angle = (float)Math.Tan(Math.PI * 0.5 * fov / 180);
        for (int y = 0; y < height; y++)
        {
            for(int x = 0; x < width; x++)
            {
                float xx = (2 * ((x + 0.5f) * invWidth) - 1) * angle * aspectratio;
                float yy = (1 - 2 * ((y + 0.5f) * invHeight)) * angle;
                Vec3f raydir = new Vec3f(xx, yy, -1);
                raydir.normalize();
                image.Add(trace(new Vec3f(0), raydir, spheres, 0));
            }
        }
        Console.Write("P3 800 600 255\r\n");
        int line = 150;
        for(int i = 0; i < width * height; ++i)
        {
            if(line <= 0) {line = 150; Console.Write("\r\n");}
            line--;
            Vec3f pixel = GetColor(image[i]);
            Console.Write(pixel.x + " " + pixel.y + " " + pixel.z);
        }
    }

    public static Vec3f GetColor(Vec3f col)
    {
        return new Vec3f(Math.Min(1, col.x)* 255, Math.Min(1, col.y)* 255, Math.Min(1, col.z)* 255);
    }
}
}
    float invWidth = 1f / width, invHeight = 1f / height;
    float fov = 30, aspectratio = (float)width / height;
    for(int i = 0; i < width * height; ++i)
    {
        if(line <= 0) {line = 150; Console.Write("\r\n");}
        else if (line < 150) Console.Write(" ");
        line--;
        Vec3f pixel = GetColor(image[i]);
        Console.Write(pixel.x + " " + pixel.y + " " + pixel.z);
    }
        Console.Write(pixel.x + " " + pixel.y + " " + pixel.z + " ");
        return surfaceColor + sphere.emissionColor;
class Program
{
    const int MAX_RAY_DEPTH = 8;
    const float FAR = 100000000;

    public static void Main(string[] args)
    {
        Sphere[] spheres = new Sphere[7];
        spheres[0] = new Sphere(new Vec3f( 0.0f, -10004, -20), 10000, new Vec3f(0.20f, 0.20f, 0.20f), 0, 0.0f);
        spheres[1] = new Sphere(new Vec3f( 0.0f,      0, -20),     4, new Vec3f(1.00f, 0.32f, 0.36f), 1, 0.5f);
        spheres[2] = new Sphere(new Vec3f( 5.0f,     -1, -15),     2, new Vec3f(0.90f, 0.76f, 0.46f), 1, 0.0f);
        spheres[3] = new Sphere(new Vec3f( 5.0f,      0, -25),     3, new Vec3f(0.65f, 0.77f, 0.97f), 1, 0.0f);
        spheres[4] = new Sphere(new Vec3f(-5.5f,      0, -15),     3, new Vec3f(0.90f, 0.90f, 0.90f), 1, 0.0f);
        spheres[5] = new Sphere(new Vec3f(   2f,      2, -30),     4, new Vec3f(0.53f, 0.38f, 0.91f), 1, 0.7f);
        spheres[6] = new Sphere(new Vec3f(    0,     20, -30),     3, new Vec3f(0.00f, 0.00f, 0.00f), 0, 0.0f, new Vec3f(3));
        Render(spheres);
    }

    public struct Collision
    {
        public readonly float t0, t1;
        public readonly bool collide;

        public Collision(bool col, float tt0, float tt1)
        {
            t0 = tt0 < 0 ? tt1 : tt0;
            t1 = tt1;
            collide = col;
        }
    }

    public struct Vec3f
    {
        public readonly float x, y, z;
        public Vec3f(float v) { x = y = z = v; }
        public Vec3f(float xx, float yy, float zz) { x = xx; y = yy; z = zz; }

        public Vec3f normalize()
        {
            float nor2 = length2();
            if (nor2 > 0)
            {
                float invNor = 1 / (float)Math.Sqrt(nor2);

                return new Vec3f(x * invNor, y * invNor, z * invNor);
            }

            return this;
        }
        public static Vec3f operator *(Vec3f l, Vec3f r)
        {
            return new Vec3f(l.x * r.x, l.y * r.y, l.z * r.z);
        }
        public static Vec3f operator *(Vec3f l, float r)
        {
            return new Vec3f(l.x * r, l.y * r, l.z * r);
        }
        public float dot(Vec3f v)
        {
            return x * v.x + y * v.y + z * v.z;
        }
        public static Vec3f operator -(Vec3f l, Vec3f r)
        {
            return new Vec3f(l.x - r.x, l.y - r.y, l.z - r.z);
        }
        public static Vec3f operator +(Vec3f l, Vec3f r)
        {
            return new Vec3f(l.x + r.x, l.y + r.y, l.z + r.z);
        }
        public static Vec3f operator -(Vec3f v)
        {
            return new Vec3f(-v.x, -v.y, -v.z);
        }
        public float length2()
        {
            return x * x + y * y + z * z;
        }
        public float length()
        {
            return (float)Math.Sqrt(length2());
        }
    }

    public class Sphere
    {
        public readonly Vec3f center, surfaceColor, emissionColor;
        public readonly float radius, radius2;
        public readonly float transparency, reflection;
        public Sphere(Vec3f c, float r, Vec3f sc, float refl = 0, float transp = 0, Vec3f? ec = null)
        {
            center = c; radius = r; radius2 = r * r;
            surfaceColor = sc; emissionColor = (ec == null) ? new Vec3f() : ec.Value;
            transparency = transp; reflection = refl;
        }

        public Collision intersect(Vec3f rayorig, Vec3f raydir)
        {
            Vec3f l = center - rayorig;
            float tca = l.dot(raydir);
            if (tca < 0) { return new Collision(); }
            float d2 = l.dot(l) - tca * tca;
            if (d2 > radius2) { return new Collision(); }
            float thc = (float)Math.Sqrt(radius2 - d2);
            return new Collision(true, tca - thc, tca + thc);
        }
    }

    public static float mix(float a, float b, float mix)
    {
        return b * mix + a * (1 - mix);
    }

    public static Vec3f trace(Vec3f rayorig, Vec3f raydir, Sphere[] spheres, int depth)
    {
        float tnear = FAR;
        Sphere sphere = null;
        for (int i = 0; i < spheres.Length; i++)
        {
            Collision coll = spheres[i].intersect(rayorig, raydir);
            if (coll.collide && coll.t0 < tnear)
            {
                tnear = coll.t0;
                sphere = spheres[i];
            }
        }
        if (sphere == null) { return new Vec3f(2); }
        Vec3f surfaceColor = new Vec3f();
        Vec3f phit = rayorig + raydir * tnear;
        Vec3f nhit = (phit - sphere.center).normalize();
        float bias = 1e-4f;
        bool inside = false;
        if (raydir.dot(nhit) > 0) { nhit = -nhit; inside = true; }
        if ((sphere.transparency > 0 || sphere.reflection > 0) && depth < MAX_RAY_DEPTH)
        {
            float facingratio = -raydir.dot(nhit);
            float fresneleffect = mix((float)Math.Pow(1 - facingratio, 3), 1, 0.1f);
            Vec3f refldir = (raydir - nhit * 2 * raydir.dot(nhit)).normalize();
            Vec3f reflection = trace(phit + nhit * bias, refldir, spheres, depth + 1);
            Vec3f refraction = new Vec3f();
            if (sphere.transparency > 0)
            {
                float ior = 1.1f; float eta = inside ? ior : 1 / ior;
                float cosi = -nhit.dot(raydir);
                float k = 1 - eta * eta * (1 - cosi * cosi);
                Vec3f refrdir = (raydir * eta + nhit * (eta * cosi - (float)Math.Sqrt(k))).normalize();
                refraction = trace(phit - nhit * bias, refrdir, spheres, depth + 1);
            }
            surfaceColor = (
                reflection * fresneleffect + 
                refraction * (1 - fresneleffect) * sphere.transparency) * sphere.surfaceColor;
        }
        else
        {
            for (int i = 0; i < spheres.Length; i++)
            {
                if (spheres[i].emissionColor.x > 0)
                {
                    Vec3f transmission = new Vec3f(1);
                    Vec3f lightDirection = (spheres[i].center - phit).normalize();
                    for (int j = 0; j < spheres.Length; j++)
                    {
                        if (i != j)
                        {
                            Collision jcoll = spheres[j].intersect(phit + nhit * bias, lightDirection);
                            if (jcoll.collide)
                            {
                                transmission = new Vec3f();
                                break;
                            }
                        }
                    }
                    surfaceColor += sphere.surfaceColor * transmission *
                        Math.Max(0, nhit.dot(lightDirection)) * spheres[i].emissionColor;

                }
            }
        }

        return surfaceColor + sphere.emissionColor;
    }

    public static void Render(Sphere[] spheres)
    {
        int width = 800, height = 600;
        Vec3f[] image = new Vec3f[width * height];
        int pixelIndex = 0;
        float invWidth = 1f / width, invHeight = 1f / height;
        float fov = 30, aspectratio = (float)width / height;
        float angle = (float)Math.Tan(Math.PI * 0.5 * fov / 180);
        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++, pixelIndex++)
            {
                float xx = (2 * ((x + 0.5f) * invWidth) - 1) * angle * aspectratio;
                float yy = (1 - 2 * ((y + 0.5f) * invHeight)) * angle;
                Vec3f raydir = new Vec3f(xx, yy, -1).normalize();

                image[pixelIndex] = trace(new Vec3f(), raydir, spheres, 0);
            }
        }

        StringWriter writer = new StringWriter();
        WriteableBitmap bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Rgb24, null);

        bitmap.Lock();

        unsafe
        {
            byte* buffer = (byte*)bitmap.BackBuffer;

            {
                writer.Write("P3 800 600 255\r\n");
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; ++x)
                    {
                        if (x > 0) { writer.Write(" "); }
                        Vec3f pixel = GetColor(image[y * width + x]);
                        writer.Write(pixel.x + " " + pixel.y + " " + pixel.z);

                        int bufferOffset = y * bitmap.BackBufferStride + x * 3;
                        buffer[bufferOffset] = (byte)pixel.x;
                        buffer[bufferOffset + 1] = (byte)pixel.y;
                        buffer[bufferOffset + 2] = (byte)pixel.z;
                    }

                    writer.WriteLine();
                }
            }
        }

        bitmap.Unlock();


        var encoder = new PngBitmapEncoder();

        using (Stream stream = File.OpenWrite("temp.png"))
        {
            encoder.Frames.Add(BitmapFrame.Create(bitmap));
            encoder.Save(stream);
        }

        string result = writer.ToString();
    }

    public static Vec3f GetColor(Vec3f col)
    {
        return new Vec3f(Math.Min(1, col.x) * 255, Math.Min(1, col.y) * 255, Math.Min(1, col.z) * 255);
    }
}