문제가 있습니다. raytracing 용 C++ 코드 article on scratchapixel을 읽었습니다. C++은 괜찮습니다. 파이썬으로 변환하려고 시도했지만, 17 배 느린 결과와 4 배 축소 된 해상도로 작동했습니다. C#으로 변환하려고했지만 코드가 작동하지 않습니다. 내가 볼 수있는 것은 공백의 흰색 800x600 이미지뿐입니다. C++ 코드에 대해서는 이전에 링크 된 기사를 참조하십시오.Raytracer가 예상 출력을 생성하지 않습니다.
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);
}
}
}
누구나 무엇이 잘못 참조 :
이 C# 코드로 그것의 나의 해석은 무엇입니까?
편집 프로그램은 콘솔 화면에 추적 색상을 쓰고 있습니다. 그런 다음 Windows 배치 파일을 사용하여 ppm 파일에 쓸 수 있습니다. 나는 int
값 어디를 사용에는 Csc.exe 를 사용하여 "에는 Csc.exe의 raytracer.cs" 실행 프로그램 "raytracer.exe> out.ppm"
C++에서 작동하고 C++이 더 빠르기 때문에 아마도 C#에서 P/Invoke하는 DLL에 넣어야합니까? 나는 그것을 변환하는 당신의 이유를 모르지만 그게 내가 할 것입니다. –
음 ... 결과로 나온 ppm 파일을 확인 했습니까? 그것은 실제로 무엇을 포함합니까? – Cubic
@VisualVincent 성능과 관련이 없으며 운동으로 변환됩니다. – Cubic