Reputation: 69
I am getting strange rings of black on my spheres when I render with lighting. I just added lighting and I cannot figure out why the black rings are being created.
Here is my code for my tracer.
public class Tracer {
public Camera Cam;
public int Width, Height;
public BufferedImage Image;
public Color BackGroundColor;
public int StartX, StartY, EndX, EndY,RowCount,ColCount;
public ArrayList<GeometricObject> GeoObjects;
public ArrayList<LightObject> LightObjects;
public boolean Tracing;
public double AmbientLight;
public Tracer(Camera cam, int width, int height, BufferedImage image, Color backGroundColor, int startX, int startY, int endX, int endY, int rowCount, int colCount, ArrayList<GeometricObject> Geoobjects,ArrayList<LightObject> Lightobjects,double ambientLight) {
super();
Cam = cam;
Width = width;
Height = height;
Image = image;
BackGroundColor = backGroundColor;
StartX = startX;
StartY = startY;
EndX = endX;
EndY = endY;
RowCount = rowCount;
ColCount = colCount;
GeoObjects = Geoobjects;
LightObjects = Lightobjects;
if(ambientLight > 1){
AmbientLight = 1;
}else if(ambientLight < 0){
AmbientLight = 0;
}else{
AmbientLight = ambientLight;
}
}
public void TracePixelFast(int x, int y) {
Color color = new Color(BackGroundColor.r,BackGroundColor.g,BackGroundColor.b);
for(int o = 0;o < GeoObjects.size();o++){
GeometricObject GO = GeoObjects.get(o);
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, 1, 1, RowCount, ColCount), Cam.GetRayDir(Width, Height, x, y, 1,1, RowCount, ColCount));
double hit = GO.hit(r);
if (hit != 0.0) {
color = Cal_Pixel(x,y);
Image.setRGB(x, y, color.toInt());
break;
}
}
}
public void TracePixelSmooth(int x, int y) {
Image.setRGB(x, y,Cal_Pixel(x,y).toInt());
}
public Color Cal_Pixel(int x,int y){
Color color = new Color(BackGroundColor);
Color colorh = new Color(BackGroundColor);
Color bgc = new Color(BackGroundColor);
int HIT = 0;
int MISS = 0;
for (int row = 0; row < RowCount; row++) {
for (int col = 0; col < ColCount; col++) {
double min = Double.MAX_VALUE;
for (int o = 0; o < GeoObjects.size(); o++) {
GeometricObject GO = GeoObjects.get(o);
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, row, col, RowCount, ColCount),Cam.GetRayDir(Width, Height, x, y, row, col, RowCount, ColCount));
double hit = GO.hit(r);
if (hit != 0.0 && hit < min) {
min = hit;
colorh = ShadePixel(GO, r, hit);
HIT++;
} else {
double min2 = Double.MAX_VALUE;
for (int o2 = 0; o2 < GeoObjects.size(); o2++) {
if(o!=o2){
GeometricObject GO2 = GeoObjects.get(o2);
double hit2 = GO2.hit(r);
if (hit2 != 0.0 && hit2 < min2) {
min2 = hit2;
bgc = ShadePixel(GO2, r, hit2);
}
}
}
MISS++;
}
}
}
}
for(int h = 0;h < HIT;h++){
color.Add(colorh);
}
for(int m = 0;m < MISS;m++){
color.Add(bgc);
}
color.Divide(RowCount * ColCount);
return color;
}
public Color ShadePixel(GeometricObject GO,Ray ray,double t){
ArrayList<Color> PixelShade = new ArrayList<Color>();
Normal normal = GO.Cal_Normal(ray, t);
for(int l = 0;l < LightObjects.size();l++){
LightObject light = LightObjects.get(l);
Vector3D r_Dir = light.Pos.Sub(normal.Origin);
r_Dir.normalize();
Ray raytolight = new Ray(normal.Origin,r_Dir);
int WAS_HIT = 0;
for(int o = 0;o < GeoObjects.size();o++){
GeometricObject NGO = GeoObjects.get(o);
double hit = NGO.hit(raytolight);
if (hit != 0.0) {
WAS_HIT = 1;
}
}
if(WAS_HIT == 0){
double Dot = normal.Direction.Dot(r_Dir);
if(Dot < 0){
Dot = 0;
}
double Diffuse = 1 - AmbientLight;
Color color = new Color(GO.Color);
double Shade = AmbientLight + Diffuse*Dot;
color.Mul(Shade);
PixelShade.add(color);
}else{
Color color = new Color(GO.Color);
double Shade = AmbientLight;
color.Mul(Shade);
PixelShade.add(color);
}
}
Color Final = new Color();
for(int s = 0;s < PixelShade.size();s++){
Final.Add(PixelShade.get(s));
}
Final.Divide(PixelShade.size());
return Final;
}
public void TraceArea(boolean SmoothTracing) {
Tracing = true;
if(SmoothTracing){
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelSmooth(x,y);
}
}
}else{
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelFast(x,y);
}
}
}
}
}
And here is the code for the sphere.
public class Sphere extends GeometricObject{
public Vector3D Center;
public double Radius;
public Sphere(Vector3D Center,double Radius,Color Color){
this.Center = Center;
this.Radius = Radius;
this.Color = Color;
}
public double hit(Ray ray) {
double a = ray.Direction.Dot(ray.Direction);
double b = 2 * ray.Origin.Sub(Center).Dot(ray.Direction);
double c = ray.Origin.Sub(Center).Dot(ray.Origin.Sub(Center))-Radius*Radius;
double discreminant = b*b-4*a*c;
if(discreminant < 0.0f){
return 0.0;
}else{
double t = (-b - Math.sqrt(discreminant))/(2*a);
if(t > 10E-9){
return t;
}else{
return 0.0;
}
}
}
public Normal Cal_Normal(Ray ray,double t) {
Vector3D NPos = new Vector3D(ray.Origin.x + ray.Direction.x*t,ray.Origin.y + ray.Direction.y*t,ray.Origin.z + ray.Direction.z*t);
Vector3D NDir = NPos.Sub(Center).Div(Radius);
return new Normal(NPos,NDir);
}
}
I am sure the problem is in shadepixel()
but I could be wrong.
I just found out that the more objects that I add the more rings there are:
1 object no rings.
2 objects 1 ring.
3 objects 2 rings.
If you need me to post more of my code.Just ask and I will.
When I get back from school I will post my color class and fix the color problem. I still do not understand why the more objects (spheres) I add, the more rings there are. Can anyone explain to me why this is happening?
Here is my Color code.
public class Color {
public float r,g,b;
public Color(){
r = 0.0f;
g = 0.0f;
b = 0.0f;
}
public Color(float fr,float fg,float fb){
r = fr;
g = fg;
b = fb;
}
public Color(Color color){
r = color.r;
g = color.g;
b = color.b;
}
public void Add(Color color){
r += color.r;
g += color.g;
b += color.b;
}
public void Divide(int scalar){
r /= scalar;
g /= scalar;
b /= scalar;
}
public void Mul(double mul){
r *= mul;
g *= mul;
b *= mul;
}
public int toInt(){
return (int) (r*255)<<16 | (int) (g*255)<<8 | (int) (b*255);
}
Upvotes: 3
Views: 253
Reputation: 54781
Think about how you can visually debug this scene.
First are the normals correct? Display them as the colour to see.
Taking the range for each component [-1..1]
to the range [0..255]
:
r = 255*(n.x + 1)/2;
g = 255*(n.y + 1)/2;
b = 255*(n.z + 1)/2;
Once you think they look correct move on to the next stage and build it up stage by stage.
e.g. you might look at if your dot product is as expected (again [-1..1]
because the vectors are supposedly normalised):
r = 255*(dot + 1)/2;
g = 255*(dot + 1)/2;
b = 255*(dot + 1)/2;
Upvotes: 0
Reputation: 1323
There are multiple issues with this code, but the direct reason for the rings is that color component values are overflowing 0-255 range. This in turn is caused by incorrect calculations in what I take to be an attempt at antialiasing in Cal_Pixel()
, as well as by no control whatsoever of numeric range in ShadePixel()
.
Upvotes: 2