issue with ray tracer light diffuse - c

I wrote the light diffusing code and it's just not working I dont know why
this is the code I wrote for diffusing
t_vec pi = vec_add(ray.org,vec_times_double(ray.dir, t));
t_vec hp = vec_diff(light.pos, pi);
t_vec normal = get_sphers_normal(sp, pi);
double dot = vec_dot(normalize_vect(normal),normalize_vect(hp));
printf("hitpoint : %lf\n", dot);
put_pixel(mlx.img, x, y, rgb_to_int(sp.color)*double_abs(dot), resolution.width);

In this line:
put_pixel(mlx.img, x, y, rgb_to_int(sp.color)*double_abs(dot), resolution.width);
^-----------------------------------
You seem to be multiplying an integer by a double. I presume that put_pixel expects a 32-bit integer encoding the RGB color, in which case your double gets converted back to int, but in an un-meaningful way, giving those color bands. For example, if sp.color = { 255., 0., 0. } is a red surface, rgb_to_int converts it to 0xff0000, multiplying it by 0.00390625 (dimly lit surface) and converting back to int gives 0x00ff00, which is a bright green rather than a dark red.
You should rather use your vector times scalar function on the argument to rgb_to_int:
rgb_to_int(vec_times_double(sp.color, double_abs(dot)))
I assume here that sp.color is of type t_vec. If it's not then adjust your code accordingly.

Related

weird result when cos is 0

hello i am writing basic calculator. everytime i use 90 degrees on cos function it gives -0 as result
int deg;
float rad,result;
printf("\ndegree\n");
scanf("%d",&deg);
rad = deg * (M_PI/180);
result=cos(rad);
printf("\nresult= %f",result);
result
i dont even know what to try.
i just googled it and did not see any similar results.
M_PI is defined as 3.141593... which is slightly over PI, consequently, the cos(90.xxx) is lesser than 0.
If you try with 3.1415926, you will get positive result:
https://onlinegdb.com/7MWNEkkqI
None of those two values match the real PI value, and they might even be defined differently on different compilers. The point is that having one above the real PI and the other below the real PI make them to fall in different quadrants, and a different sign on the result.
The float being represented by 32bit, it is not possible to represent exactly most of the real numbers (except those few ~2^32 values). And going to double will not solve this.
At the end, it is the function converting the number to a string for representation on the screen who can detect that "-0" and write "0" instead. That is why if you open most applications, you don't get "-0" very often.
The solution is to have the "print" (note, that this is not necessarily the official printf ) which is aware of the number of relevant bits, and can convert this -0.0000000x to 0; 0.9999999x to 1, etc.. Modern "print" functions will provide a mechanism to set the precision (for example std::setprecision in C++).
Note: rounding the value will not work with very big or small numbers.
Other answers have suggested changing the value of pi slightly.
Other answers have suggested changing type float to type double.
Both of these suggestions move the problem around slightly, perhaps changing the objectionable displayed value of -0 to plain 0.
(And switching from float to double is almost always a good idea, no matter what.)
But none of these suggestions actually "solve" this particular "problem", because fundamentally there is no actual problem here.
The real issue, as I said in a comment, is that it is just not possible to compute the cosine of 90.0000000000 degrees, at all, because you are never going to be able to represent the value π/2 perfectly accurately in radians. You're inevitably always going to be working with the equivalent of 89.9999999999 degrees, or 90.0000000001 degrees, so to speak. That is, the problem isn't that cos() is computing the wrong value; the problem is that you're not even passing it the "right" value to begin with! And when π/2 comes out a little bit over, meaning that cos() ends up computing a value like -0.0000000001, a high-quality version of printf is going to round and display it as -0, because -0 is a thing in computer floating point.
If you have a "fixed" version of the original program that no longer displays cos(90) as -0, I suggest trying it with cos(-90), or cos(270) — I bet one or the other of those will display -0, so you're right back out of the frying pan and into the fire again.
If you have a requirement that says you must never display "-0", I believe you would want to pursue a completely different approach, perhaps something along the lines of
char tmp[50];
snprintf(tmp, sizeof(tmp), "%f", result);
if(*tmp == '-' && atof(tmp) == 0) result = -result;
printf("result = %f\n", result);
It may seem strange to be tinkering around with the string representation like this, but it actually makes sense, because it's only after converting (and perhaps rounding) to a string representation that we can be sure we've got the "-0.000000" case that needs special attention.
If you use %g instead of %f, you would see that the result is not exactly 0, but a very small, negative value. Hence the minus sign with %f.
Now, for a more accurate result, you should use the type double instead of float for the variables rad and result (cos already takes a double and returns a double). The sign will be positive, but the result will still not be 0 exactly. As π/2 is irrational, there is no way to get an exact 0 with the cos function (unless its implementation is buggy).
The next C standard (C23) will include a cospi function (as recommended by the IEEE 754 standard), which could solve your issue as it is defined as cospi(x) = cos(πx). So, for 90 degrees, you would call cospi with the argument 0.5, which is exactly representable.
EDIT: Some implementations may be tempted to hide the issue by guessing what the result should be, such as assuming that if the cos argument is very close to π/2, then it is regarded as π/2 exactly, so that an exact 0 is returned. This is a bad idea (in particular for generic libraries like the C library), which could yield surprising results. Even user code should be careful. See this video to see possible consequences of such hacks on a Casio calculator.
cos(90) is exactly 0. Purely mathematically, 0 is equal to -0. I assume that the problem is the minus sign?
M_PI is of type double, with the value 3.14159265358979323846, which is slightly less than true pi.
Converting it to a float makes it 3.1415927410125732421875, which is slightly more than true pi. The calculations could be done in type double, and converted to float afterwards? That code would of course be slightly less efficient, but depending on the use case, it would probably not matter, and the risk for any similar errors would be minimized.
EDIT: I just realized M_PI exists as a float too, depending on the library, as previous answer states. Both ways should solve the problem.
everytime i use 90 degrees on cos function it gives -0 as result
Rounded text
The result is not -0 but a value between 0.0 and -0.0000005 that when printed using "%f" (in the form d.dddddd) OP saw a rounded value as "-0.000000".
To see a more informative output, use "%g".
printf("\nresult= %g",result);
// result= -4.37114e-08
Related graphic
Why -4.37114e-08?
rad = deg * (M_PI/180); attempts to convert degrees to radians using an approximation to π. π is irrational. All finite floating point values are rational and so M_PI is never exactly π, regardless how precise the floating point type. Thus rad = deg * (M_PI/180); introduces small errors that are magnified in cos(rad) when it performs it argument range reduction.
There is an alternative. Perform the argument range reduction in degrees, which can be exact, scale and then call cos().
#include <math.h>
#include <stdio.h>
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif
static double d2r(double d) {
return (d / 180.0) * ((double) M_PI);
}
double cosd(double x) {
if (!isfinite(x)) {
return cos(x);
}
int quo;
double d_45 = remquo(fabs(x), 90.0, &quo);
// d_45 is in the range [-45...45]
double r_pidiv4 = d2r(d_45);
switch (quo % 4) {
case 0:
return cos(r_pidiv4);
case 1:
// Add 0.0 to avoid -0.0
return 0.0 - sin(r_pidiv4);
case 2:
return -cos(r_pidiv4);
case 3:
return sin(r_pidiv4);
}
return 0.0;
}
Test
int main(void) {
int prec = DBL_DECIMAL_DIG - 1;
for (int d = -360; d <= 360; d += 15) {
double r = d2r(d);
printf("cos (%6.1f degrees) = % .*e\n", 1.0 * d, prec, cos(r));
printf("cosd(%6.1f degrees) = % .*e\n", 1.0 * d, prec, cosd(d));
}
return 0;
}
Ouput
cos (-360.0 degrees) = 1.0000000000000000e+00
cosd(-360.0 degrees) = 1.0000000000000000e+00
...
cos (-270.0 degrees) = -1.8369701987210297e-16
cosd(-270.0 degrees) = 0.0000000000000000e+00 // Exactly zero
...
cos ( 0.0 degrees) = 1.0000000000000000e+00
cosd( 0.0 degrees) = 1.0000000000000000e+00
...
cos ( 60.0 degrees) = 5.0000000000000011e-01 // Not 0.5
cosd( 60.0 degrees) = 4.9999999999999994e-01 // Not 0.5, yet closer
...
cos ( 90.0 degrees) = 6.1232339957367660e-17
cosd( 90.0 degrees) = 0.0000000000000000e+00 // Exactly zero, OP's goal
...
cos ( 270.0 degrees) = -1.8369701987210297e-16
cosd( 270.0 degrees) = 0.0000000000000000e+00 // Exactly zero
...
cos ( 360.0 degrees) = 1.0000000000000000e+00
cosd( 360.0 degrees) = 1.0000000000000000e+00

Bicubic Interpolation in CUDA and C / How is bicubic interpolation applied to an entire image?

I am currently writing a MEX file for Matlab in C to first rotate an image and then interpolate it bicubically. While researching I found a partial implementation of bicubic interpolation in C++ on https://www.paulinternet.nl/?page=bicubic. However, the code there only interpolates a 4 by 4 area and returns only a single interpolated value instead of enough values to fill the initial area.
Can anybody tell me how bicubic interpolation is applied to an entire image? Is the image divided into 4x4 chunks that are then interpolated? How do I get values for the entire area of the image?
Also, what exactly are "x" and "y" in the function "bicubicInterpolate"?
double cubicInterpolate (double p[4], double x) {
return p[1] + 0.5 * x*(p[2] - p[0] + x*(2.0*p[0] - 5.0*p[1] + 4.0*p[2] - p[3] + x*(3.0*(p[1] - p[2]) + p[3] - p[0])));
}
double bicubicInterpolate (double p[4][4], double x, double y) {
double arr[4];
arr[0] = cubicInterpolate(p[0], y);
arr[1] = cubicInterpolate(p[1], y);
arr[2] = cubicInterpolate(p[2], y);
arr[3] = cubicInterpolate(p[3], y);
return cubicInterpolate(arr, x);
}
I tried to discern that from the code from this post "https://stackoverflow.com/questions/20923956/bicubic-interpolation", but I do not understand how the fraction is calculated.
Thank you for your help.
Okay, I think I found a solution. During rotation, the original coordinates of a pixel are stored as floating-point numbers. These coordinates are then given to the bicubic interpolation algorithm. The algorithm samples the surrounding 4x4 square to calculate the colour or value of the pixel. This value is then returned to the rotation algorithm and stored at the new coordinates of the pixel. The Fraction or in this case "x" is the floored value of either the origin row or column.

Effect of adjusting Y component in YUV?

I've been reverse engineering a program and recently came across a function that is intended to create a sort of translucent-looking color to be used for text selections. It does this by converting RGB to YUV, alters the Y (luma?) component, then converts back to RGB.
uint32_t CalcSelectionColor(uint32_t bgr)
{
double r,g,b;
double y,u,v;
r = (bgr >> 0) & 0xFF;
g = (bgr >> 8) & 0xFF;
b = (bgr >> 16) & 0xFF;
/* RGB to YUV */
y = 0.299*r + 0.587*g + 0.114*b;
u = (b-y) * 0.565 * 0.5;
v = (r-y) * 0.713 * 0.5;
/* lower brightness? */
y = 255.0 - y;
/* YUV to RGB */
r = y + 1.403*v;
g = y - 0.344*u - 0.714*v;
b = y + 1.77*u;
return ((uint8_t)(b) << 16) | ((uint8_t)(g) << 8) | ((uint8_t)(r));
}
As someone with very limited knowledge of computer graphics, I'd just like a bit more detail of what it does between the conversions, and the actually intended effect in a broader sense. Is this a common approach of adjusting brightness of a color or something? If I pass in 0x00FF00, the result I get is 0x1E9D1E
The formulas used in this code are similar to Julien transformation from RGB to YUV and back:
Transformation from RGB to YUV:
Y = 0.299R + 0.587G + 0.114B
U'= (B-Y)*0.565
V'= (R-Y)*0.713
Transformation from YUV to RGB:
R = Y + 1.403V'
G = Y - 0.344U' - 0.714V'
B = Y + 1.770U'
However, the formulas in your code are a bit different. While the back transformation is the same, the forward transform has an additional multiplier 0.5 for both U and V components. There is also a trivial manipulation with the brightness component
y = 255.0 - y
which simply inverses the brightness. So, what happens here?
If you use normal Julien RGB->YUV transform, you get a representation for your color as a combination of brightness Y and two color tone components U and V, which define the color as shown on this picture:
However, in your code you also multiply both U and V components by 0.5. This means, that on this UV plane you move from any given color two times closer to the point of origin (0, 0). For example, if the initial color was A with UV coordinates (-0.4, 0.3), then you'll get a new color B with UV coordinates (-0.2, 0.15). Similarly, the color C (0.2, -0.3) becomes color D (0.1, -0.15):
After that you inverse the brightness of the color, making dark colors bright and bright colors dark. This is the effect of your code.
It's not terribly common, but it's a very good approach. Commonly used models like HSL/HSV don't represent intensity correctly and have some weird piecewise-linear stuff with hue/color going on. YUV is a really good colorspace, representing intensity along one axis and chroma (hue/color) in a perpendicular plane.
Normally modifying Y without also adjusting (at least clamping) U and V is somewhat dubious, because near the extremes (Y=0 black, Y=full white) U and V have limited range (no range at all at the endpoints). Otherwise applying them will take you outside of the RGB cube and result in bogus clipped results when you go back to RGB. But here the trick is very clever. The code is inverting Y while keeping chroma fixed, so the incoming range limits on U and V near black will automatically ensure they're roughly correct in the output, and vice versa.
As Alex noted, the code here is also halving the chroma values, reducing color saturation. This was probably to avoid the above mentioned clipping issue, but it's not needed. But maybe it's part of the intended visual effect too.
So, TL;DR: the effect is inverting intensity/luma and halving saturation.

Angle to Quaternion - Making an object facing another object

i have two Objects in a 3D World and want to make the one object facing the other object. I already calculated all the angles and stuff (pitch angle and yaw angle).
The problem is i have no functions to set the yaw or pitch individually which means that i have to do it by a quaternion. As the only function i have is: SetEnetyQuaternion(float x, float y, float z, float w). This is my pseudocode i have yet:
float px, py, pz;
float tx, ty, tz;
float distance;
GetEnetyCoordinates(ObjectMe, &px, &py, &pz);
GetEnetyCoordinates(TargetObject, &tx, &ty, &tz);
float yaw, pitch;
float deltaX, deltaY, deltaZ;
deltaX = tx - px;
deltaY = ty - py;
deltaZ = tz - pz;
float hyp = SQRT((deltaX*deltaX) + (deltaY*deltaY) + (deltaZ*deltaZ));
yaw = (ATAN2(deltaY, deltaX));
if(yaw < 0) { yaw += 360; }
pitch = ATAN2(-deltaZ, hyp);
if (pitch < 0) { pitch += 360; }
//here is the part where i need to do a calculation to convert the angles
SetEnetyQuaternion(ObjectMe, pitch, 0, yaw, 0);
What i tried yet was calculating the sinus from those angles devided with 2 but this didnt work - i think this is for euler angles or something like that but didnt help me. The roll(y axis) and the w argument can be left out i think as i dont want my object to have a roll. Thats why i put 0 in.
If anyone has any idea i would really appreciate help.
Thank you in advance :)
Let's suppose that the quaternion you want describes the attitude of the player relative to some reference attitude. It is then essential to know what the reference attitude is.
Moreover, you need to understand that an object's attitude comprises more than just its facing -- it also comprises the object's orientation around that facing. For example, imagine the player facing directly in the positive x direction of the position coordinate system. This affords many different attitudes, from the one where the player is standing straight up to ones where he is horizontal on either his left or right side, to one where he is standing on his head, and all those in between.
Let's suppose that the appropriate reference attitude is the one facing parallel to the positive x direction, and with "up" parallel to the positive z direction (we'll call this "vertical"). Let's also suppose that among the attitudes in which the player is facing the target, you want the one having "up" most nearly vertical. We can imagine the wanted attitude change being performed in two steps: a rotation about the coordinate y axis followed by a rotation about the coordinate z axis. We can write a unit quaternion for each of these, and the desired quaternion for the overall rotation is the Hamilton product of these quaternions.
The quaternion for a rotation of angle θ around the unit vector described by coordinates (x, y, z) is (cos θ/2, x sin θ/2, y sin θ/2, z sin θ/2). Consider then, the first quaternion you want, corresponding to the pitch. You have
double semiRadius = sqrt(deltaX * deltaX + deltaY * deltaY);
double cosPitch = semiRadius / hyp;
double sinPitch = deltaZ / hyp; // but note that we don't actually need this
. But you need the sine and cosine of half that angle. The half-angle formulae come in handy here:
double sinHalfPitch = sqrt((1 - cosPitch) / 2) * ((deltaZ < 0) ? -1 : 1);
double cosHalfPitch = sqrt((1 + cosPitch) / 2);
The cosine will always be nonnegative because the pitch angle must be in the first or fourth quadrant; the sine will be positive if the object is above the player, or negative if it is below. With all that being done, the first quaternion is
(cosHalfPitch, 0, sinHalfPitch, 0)
Similar analysis applies to the second quaternion. The cosine and sine of the full rotation angle are
double cosYaw = deltaX / semiRadius;
double sinYaw = deltaY / semiRadius; // again, we don't actually need this
We can again apply the half-angle formulae, but now we need to account for the full angle to be in any quadrant. The half angle, however, can be only in quadrant 1 or 2, so its sine is necessarily non-negative:
double sinHalfYaw = sqrt((1 - cosYaw) / 2);
double cosHalfYaw = sqrt((1 + cosYaw) / 2) * ((deltaY < 0) ? -1 : 1);
That gives us an overall second quaternion of
(cosHalfYaw, 0, 0, sinHalfYaw)
The quaternion you want is the Hamilton product of these two, and you must take care to compute it with the correct operand order (qYaw * qPitch), because the Hamilton product is not commutative. All the zeroes in the two factors make the overall expression much simpler than it otherwise would be, however:
(cosHalfYaw * cosHalfPitch,
-sinHalfYaw * sinHalfPitch,
cosHalfYaw * sinHalfPitch,
sinHalfYaw * cosHalfPitch)
At this point I remind you that we started with an assumption about the reference attitude for the quaternion system, and the this result depends on that choice. I also remind you that I made an assumption about the wanted attitude, and that also affects this result.
Finally, I observe that this approach breaks down where the target object is very nearly directly above or directly below the player (corresponding to semiRadius taking a value very near zero) and where the player is very nearly on top of the target (corresponding to hyp taking a value very near zero). There is a non-zero chance of causing a division by zero if you use these formulae exactly as given, so you'll want to think about how to deal with that.)

What is the correct way to perform alpha blending? (C)

I'm writing a very simple graphics library, and I'm trying to figure out how to do alpha blending. I tried it a few times, but my results were less than satisfactory. According to Wikipedia, I should do:
Value = (1-alpha)Value0 + alphavalue1
This, however is not working at all. Maybe I'm doing something wrong?
The code I've included draws a colorful picture (that's the 'proximity' function), then attempts to draw a partially transparent box at (100,100). However, instead of a white translucent box, I get a weird-looking distortion to the image (I'll try to have them at the bottom of my post). Any suggestions? Here is my code:
#include "hgl.h"
void proximity()
{
int x = 0, y = 0, d1, d2, d3, dcenter;
while(x < WIDTH){
while(y < HEIGHT){
d1 = distance(x, y, (WIDTH/2) - 200, (HEIGHT/2) + 200);
d2 = distance(x, y, (WIDTH/2) + 200, (HEIGHT/2) + 200);
d3 = distance(x, y, (WIDTH/2), (HEIGHT/2) - 150);
dcenter = distance(x, y, WIDTH/2, HEIGHT/2);
putpixel(x, y, d1, d2, d3);
y++;
}
y = 0;
x++;
}
}
int alpha_transparency(float alpha, float value1, float value2)
{
return (1-alpha) * value1 + alpha * value2;
}
void transparent_box(int pos_x, int pos_y, int width, int height, float alpha, char r, char g, char b)
{
int x = 0, y = 0;
while(x < width)
{
while(y < height)
{
int rr, rg, rb;
rr = alpha_transparency(alpha, p.bitmap[x+pos_x][y+pos_y].r, r);
rg = alpha_transparency(alpha, p.bitmap[x+pos_x][y+pos_y].g, g);
rb = alpha_transparency(alpha, p.bitmap[x+pos_x][y+pos_y].b, b);
putpixel(pos_x + x, pos_y + y, rr, rg, rb);
y++;
}
x++;
y = 0;
}
}
int main()
{
fp = fopen("out.bmp","wb");
set_dimensions(1440, 900);
insert_header();
white_screen();
proximity();
transparent_box(100, 100, 500, 500, .9, 255, 255, 255);
insert_image();
fclose(fp);
return 0;
}
Sorry, I couldn't include the output because I'm a new user. However, here are the links:
Original Picture
Picture with "transparent" box
Your alpha blend function is correct; another way to think of alpha blending is that it interpolates between two color values based on alpha, so it should be a value in [0, 1].
However, you shouldn't be passing the color components as char, which is signed by default. You should pass them either as unsigned char or as a wider integer type. What is happening is that instead of passing in 255 as you expect, you are passing in -1.
In other words, store your color components as unsigned chars to ensure you don't have signedness shenanigans (see EDIT2).
EDIT: Note that if your alpha is in [0, 255], you should normalize it to [0, 1] to perform the alpha blending operation.
EDIT2: Also, if you are storing your pixels as char instead of unsigned char, this would explain the odd clamping I saw:
alpha_transparency(0.9, (char)255, (char)255)
== alpha_transparency(0.9f, -1.0f, -1.0f)
== -1.0f
== 0xff (cast to char)
alpha_transparency(0.9, (char)128, (char)255)
== alpha_transparency(0.9f, -128.0f, -1.0f)
== -13.7f
== 0xf3
alpha_transparency(0.9, (char)127, (char)255)
== alpha_transparency(0.9f, 127.0f, -1.0f)
== -11.80f
== 0x0b
alpha_transparency(0.9, (char)0, (char)255)
== alpha_transparency(0.9f, 0.0f, -1.0f)
== -0.9f
== 0x00
The issue I think is in the way you're dealing with colors. The method used in Wikipedia assumes that 0 is black and 1 is white, with 0.5 being in the middle. However your code is using ints, so I assume that you're defining 0 as black and 255 as white.
So the correct code is:
return (255-alpha)*value1+alpha*value2;
You may be also suffering from the compiler rounding where you don't think it would. I would change the code in your function to this:
float result = (255.0f-alpha)*value1+alpha*value2;
return (int) result;
In general it's very common to work with images using floats instead of ints. Many programs today convert the entire image to floats, process it then convert it back. You can avoid several bugs this way.
It is probably best to stick with a single datatype: either all floats, or all integers; this reduces the potential for confusion, and avoids a class of performance pitfalls.
For all ints, you need to remember to re-scale the integer so the result fits back into the original range:
int alpha_transparency(int alpha, int value1, int value2) {
int unscaled= (255-alpha)*value1 + alpha*value2;
return unscaled / 255; /* integer division */
}
For all-floats, you need to remember to normalize integer inputs from a raw value in [0..255] (or whatever) to a float in [0.0 .. 1.0], do all the processing, then convert back to integer only at the end.
float input_raw_value(unsigned char value) { return value/255.0; }
...
float alpha_transparency(float alpha, float value1, float value2) {
return (1.0-alpha)*value1 + alpha*value2;
}
...
unsigned char output_raw_value(float value) { return value*255.0; }
Note that I have ignored rounding issues in each method; once you've got the basic math up and running, you should pay some attention to that. Also, there are various tricks to replace the divisions (which can be relatively slow) by multiplication or bit-fiddling.

Resources