그래서 모든 벡터 수학 및 교차 계산에 익숙해 지도록 작은 경로 추적기를 작성하고 싶습니다. 그래서 C#에서 Windows Forms 응용 프로그램을 만들고 PictureBox를 사용하여 비트 맵을 표시합니다.Pathtracing 코드가 작동하지 않습니다. 내가 올바르게했을 것 같아요.
내 클래스는 "renderScene"입니다. 비트 맵을 생성하고 모든 픽셀을 반복하며 픽셀에 따라 광선을 계산합니다. 광선을 만든 후에는 반복적으로 세계를 추적하고 마지막으로 픽셀의 색상을 반환합니다.
public Color Trace(Ray ray, int depth, BaseObject missObject = null)
{
float distance = 5000.0f;
BaseObject lastHitObject = null;
Vector3D HitPoint = null;
foreach (BaseObject obj in this.scene.Objects)
{
if (obj == missObject)
continue;
float currentDistance = obj.Intersect(ray);
if (currentDistance < distance && currentDistance > 0)
{
distance = currentDistance;
lastHitObject = obj;
}
}
if (distance == 5000.0f) //Kein Objekt wurde getroffen
return Color.Black;
if (lastHitObject.isEmitter) //Eine Lichtquelle wurde getroffen
return lastHitObject.surfaceColor;
if (depth == MAX_DEPTH)
return Color.Black;
HitPoint = ray.origin.add(ray.direction.multiply(distance));
Vector3D normal = lastHitObject.Normal(HitPoint);
Ray reflectionRay = null;
if (lastHitObject.mat == Material.Diffuse)
{
Vector3D randomVector = Vector3D.getRandomVectorInHemisphere();
if (randomVector.Dotproduct(normal) < 0.0)
randomVector = randomVector.negate();
reflectionRay = new Ray(HitPoint, randomVector.normalize());
}
Color returnColor = Trace(reflectionRay, depth + 1, lastHitObject);
float r = lastHitObject.surfaceColor.R * returnColor.R;
float g = lastHitObject.surfaceColor.G * returnColor.G;
float b = lastHitObject.surfaceColor.B * returnColor.B;
r /= 255.0f;
g /= 255.0f;
b /= 255.0f;
return Color.FromArgb(255, (int)r, (int)g, (int)b);
}
내가 그래서 마지막을 확인하지 않는 일부 부동 소수점 수학 부정확성을 방지하기 위해 "missObject"매개 변수를 사용
public void renderScene()
{
Bitmap drawArea = new Bitmap(pB_Result.Size.Width, pB_Result.Size.Height);
pB_Result.Image = drawArea;
int height = pB_Result.Size.Height;
int width = pB_Result.Size.Width;
float fov = 160 * (float)Math.PI/180;
float zdir = 1.0f/(float)Math.Tan(fov);
float aspect = (float)height/(float)width;
//BWorker.RunWorkerAsync(new Tuple<int, int, Bitmap, float, float, float>(height, width, drawArea, fov, zdir, aspect));
for (int y = 0; y < pB_Result.Height; y++)
{
for (int x = 0; x < pB_Result.Width; x++)
{
float xdir = (x/(float)width) * 2.0f - 1.0f;
float ydir = ((y/(float)height) * 2.0f - 1.0f) * aspect;
Ray ray = new Ray(Camera, new Vector3D(xdir, ydir, zdir).normalize());
float r = 0, g = 0, b = 0;
System.Threading.Tasks.Parallel.For(0, RAYS_PER_PIXEL, i =>
{
Color c = Trace(ray, 0);
r += c.R;
g += c.G;
b += c.B;
});
//for (int i = 0; i < RAYS_PER_PIXEL; i++)
//{
// Color c = Trace(ray, 0);
// r += c.R;
// g += c.G;
// b += c.B;
//}
drawArea.SetPixel(x, y, Color.FromArgb(255, (int)r/RAYS_PER_PIXEL, (int)g/RAYS_PER_PIXEL, (int)b/RAYS_PER_PIXEL));
}
}
pB_Result.Image = drawArea;
}
그리고 여기에 재귀 장면 광선을 교차 내 추적 기능입니다 다시 개체를 누르십시오.
그리고 여기 3D 공간에서 포인트를 나타내는 내 Vector3D 클래스가 있습니다.
이public class Vector3D
{
public float x { get; set; }
public float y { get; set; }
public float z { get; set; }
public Vector3D()
{
}
public Vector3D(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public float Dotproduct(Vector3D Dotvector)
{
return (Dotvector.x * this.x + Dotvector.y * this.y + Dotvector.z * this.z);
}
public float Length()
{
return (float)Math.Sqrt(x*x + y*y + z*z);
}
public Vector3D subtract(Vector3D subVec)
{
return new Vector3D(this.x - subVec.x, this.y - subVec.y, this.z - subVec.z);
}
public Vector3D add(Vector3D addVec)
{
return new Vector3D(this.x + addVec.x, this.y + addVec.y, this.z + addVec.z);
}
public Vector3D add(float value)
{
return add(new Vector3D(value, value, value));
}
public Vector3D multiply(Vector3D multVec)
{
return new Vector3D(this.x * multVec.x, this.y * multVec.y, this.z * multVec.z);
}
public Vector3D multiply(float value)
{
return multiply(new Vector3D(value, value, value));
}
public Vector3D divide(Vector3D divVec)
{
return new Vector3D(this.x/divVec.x, this.y/divVec.y, this.z/divVec.z);
}
public Vector3D divide(float value)
{
return divide(new Vector3D(value, value, value));
}
public Vector3D CrossProduct(Vector3D crossVec)
{
return new Vector3D
{
x = this.y * crossVec.z - this.z * crossVec.y,
y = this.z * crossVec.x - this.x * crossVec.z,
z = this.x * crossVec.y - this.y * crossVec.x
};
}
public Vector3D negate()
{
return new Vector3D
{
x = -x,
y = -y,
z = -z
};
}
public Vector3D normalize()
{
float f = (float)(1.0f/Math.Sqrt(this.Dotproduct(this)));
x *= f;
y *= f;
z *= f;
return new Vector3D(x, y, z);
}
public static Vector3D getRandomVectorInHemisphere()
{
Random rnd = new Random(DateTime.Now.Millisecond);
Vector3D v = new Vector3D
{
x = (float)rnd.NextDouble() * 2.0f - 1.0f,
y = (float)rnd.NextDouble() * 2.0f - 1.0f,
z = (float)rnd.NextDouble() * 2.0f - 1.0f
};
v = v.normalize();
return v;
}
}
이 도움이 될 수 있습니다 : http://ericlippert.com/2014/03/05/how-to-debug-small-programs/를 당신은 당신의 질문은 코드의 최소한의 금액이 포함되어 있는지 확인해야합니다 – Samuel
문제를 재현하는 데 필요한 - 빈 생성자 거의 귀하의 문제와 관련이없는 것을 보장합니다. 그렇게 말하면서, 당신은 실제로 문제가 정확히 무엇인지 말하지 않았습니까? 현재하고있는 프로그램이 예상하지 못한 것은 무엇입니까? – Sayse
정확히 무엇이 잘못되었는지 나는 모르겠다. 나는 모든 것을 올렸다. 5 개의 구체 (1 이미 터)가있는 간단한 장면을 렌더링하면 다음 결과가 나타납니다. http://img5.fotos-hochladen.net/uploads/studioray4imagwzndt723ql.png – binaryBigInt