2016-08-20 3 views
2

문제가 있습니다. 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"

+0

C++에서 작동하고 C++이 더 빠르기 때문에 아마도 C#에서 P/Invoke하는 DLL에 넣어야합니까? 나는 그것을 변환하는 당신의 이유를 모르지만 그게 내가 할 것입니다. –

+0

음 ... 결과로 나온 ppm 파일을 확인 했습니까? 그것은 실제로 무엇을 포함합니까? – Cubic

+1

@VisualVincent 성능과 관련이 없으며 운동으로 변환됩니다. – Cubic

답변

2

당신의 C# 코드가 가지고있는 기본적인 문제와 실행 파일을 만드는 오전 부동 소수점 결과를 원합니다. C++ 코드 에서처럼 원래의 int 값은 나눗셈에서 사용하기 전에 float으로 변환되므로 C# 코드에서도이를 수행해야합니다. 특히, 사용자의 invHeight, invWidthaspectratio 계산 모두는 아닌 정수 연산의 부동 소수점 연산을 사용하여 수행 될 필요 화소 사이

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 + " "); 

당신은 또한 당신이 trace() 방법의 끝에 sphere.emissionColor를 추가하는 데 실패한다는 점에서, 변환에있는 작은 오류가 발생했습니다 :

 return surfaceColor + sphere.emissionColor; 

그 세 가지 변화가 해결됩니다 요 ur 코드를 작성하고 원하는 결과를 생성하십시오.


이제 IMHO는 다른 변경 사항을 고려해 볼 가치가 있습니다. 가장 주목할만한 것은 class 대신 Vec3fCollisionstruct 유형을 사용하는 것입니다. structclass 사이의 유일한 실제 차이점이 C#의 기본 액세스 가능성 인 C++와 달리이 두 가지 유형의 기본 동작은 매우 다릅니다. 이와 같은 프로그램에서 자주 사용되는 값에 대해 class 대신 struct을 사용하면 힙 할당 데이터의 양을 최소화하여 성능을 크게 향상시킬 수 있습니다. 특히 임시로만 존재하며 가비지 수집기에서 수집해야하는 데이터 당신의 프로그램은 다른 일을하려고합니다.

float에서 double으로 데이터 유형을 변경하는 것도 좋습니다. 나는 두 가지 방법으로 코드를 테스트했다. 시각적 출력에는 아무런 차이가 없지만 렌더링은 평균적으로 double에서 2.1 초, 평균으로는 2.8 초 (float)입니다.속도가 25 % 향상되면 아마도 당신이 갖고 싶어 할 것입니다. :)

는 지금까지 structclass 대 질문은 간다, 산술에 대한 빠른 double 유형을 사용하여 내 테스트에서, 나는 (이러한 유형의 class가에서 실행 사용 struct 대신 class를 사용하여 속도가 36 % 향상을 보았다 3.3 초, struct을 사용하는 동안 2.1 초).

동시에 값을 수정할 수있는 struct 유형은 찾기 힘든 버그로 이어질 수 있습니다. A struct은 정말로 변경 불가능해야합니다. 그래서 변경의 일부로 형식을 조정했습니다. Collision 유형의 경우 비교적 간단했지만 Vec3f의 경우 코드에이 값이 수정 된 곳이 있습니다 (normalize()). 변경할 수없는 struct 값을 변경하려면이 값을 모두 변경해야 원래 값 대신 normalize() 메서드의 반환 값이 사용되었습니다. 내가 만든

다른 변경 사항은 다음과 같습니다

  • Vec3f() 생성자를 제거. 어쨌든 struct 유형에는 허용되지 않으며 기본 생성자가 올바른 작업을 수행하므로 필요하지 않습니다.
  • t0 < 0에 대한 충돌 검사를 Collision 유형으로 이동하면 해당 유형의 불변성을 지원합니다.
  • Sphere 반복을 반복하면 원래 C++에서와 같이 정수 인덱스를 사용하여 반복됩니다. foreach 문에는 각 루프에 대한 열거 자 할당이 포함됩니다. 배열을 직접 인덱싱함으로써 이러한 불필요한 할당을 피할 수 있습니다. 즉, 변수 이름이 더 적절하다는 의미입니다 (ij은 일반적으로 인덱스 용으로 예약되어 있으므로 다른 것을 나타내는 이상한 읽기 코드입니다).
  • eta의 초기화와 C++ 코드와 비슷한 코드를 사용하여 코드를 다른 곳의 C++ 코드와 비슷한 것으로 되돌려 줬습니다.
  • 코드를 List<Vec3f>에서 배열을 대신 사용하도록 변경했습니다. 이는보다 효율적이며 정기적으로 목록의 백업 저장소를 재 할당하지 않아도됩니다.

마지막으로 프로그램의 출력을 크게 변경했습니다. 콘솔 창에서 모든 출력물을 인쇄 할 때까지 기다리는 것에 관심이 없었습니다. 또한 텍스트 기반 이미지 출력을 읽고 표시하는 프로그램을 추적하고 설치하는 데 관심이 없었습니다.

대신 텍스트 출력을 메모리 내 문자열에만 기록하도록 변경하고 코드를 추가하여 프로그램이 실제로 열 수있는 실제 PNG 파일을 생성하도록했습니다. 파티 프로그램.

이 모든 밝혔다 및 수행, 이것이 내가 가진 무엇 :

여기

ray-traced balls

코드의 내 최종 버전입니다 :

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); 
    } 
} 

참고 위의 컴파일하려면, ' 프로젝트의 참조를 PresentationCore, WindowsBase 및 System에 추가해야합니다.Xaml 어셈블리. 또한 프로젝트 설정에서 "안전하지 않은 코드 허용"옵션을 선택해야합니다.

+0

대단히 감사합니다! 나는 지금 내 실수를 본다. 프로그래밍에서 떠 다니는 것이 실제 수학 (1/2처럼)과 같다고 생각했습니다. 이제 C++ 코드에서 0.0을 어디서나 사용하는 식으로 생각하는 이유를 알았습니다. 다시 감사합니다. 나는 이것을 내 마음 속에 간직 할 것이다. –

관련 문제