Add more functions, add example, fix ray collision detection
All checks were successful
CI / build-and-analyze (push) Successful in 41s
All checks were successful
CI / build-and-analyze (push) Successful in 41s
This commit is contained in:
33
CgeMath.h
33
CgeMath.h
@@ -126,6 +126,12 @@ int CgeRay2fIntersectBox2f(const float aStart[2], const float aDirection[2],
|
|||||||
int CgeSegment2fIntersectBox2f(const float aStart[2], const float aEnd[2],
|
int CgeSegment2fIntersectBox2f(const float aStart[2], const float aEnd[2],
|
||||||
const float bMin[2], const float bMax[2],
|
const float bMin[2], const float bMax[2],
|
||||||
float *t, float out[2]);
|
float *t, float out[2]);
|
||||||
|
int CgeRay2fIntersectCircle(const float start[2], const float direction[2],
|
||||||
|
const float center[2], float radius, float *t,
|
||||||
|
float out[2]);
|
||||||
|
int CgeSegment2fIntersectCircle(const float start[2], const float end[2],
|
||||||
|
const float center[2], float radius, float *t,
|
||||||
|
float out[2]);
|
||||||
|
|
||||||
int CgeRay3fIntersectPlane(const float start[3], const float direction[3],
|
int CgeRay3fIntersectPlane(const float start[3], const float direction[3],
|
||||||
const float plane[4], float *t, float out[3]);
|
const float plane[4], float *t, float out[3]);
|
||||||
@@ -143,6 +149,12 @@ int CgeRay3fIntersectBox3f(const float aStart[3], const float aDirection[3],
|
|||||||
int CgeSegment3fIntersectBox3f(const float aStart[3], const float aEnd[3],
|
int CgeSegment3fIntersectBox3f(const float aStart[3], const float aEnd[3],
|
||||||
const float bMin[3], const float bMax[3],
|
const float bMin[3], const float bMax[3],
|
||||||
float *t, float out[3]);
|
float *t, float out[3]);
|
||||||
|
int CgeRay3fIntersectSphere(const float start[3], const float direction[3],
|
||||||
|
const float center[3], float radius, float *t,
|
||||||
|
float out[3]);
|
||||||
|
int CgeSegment3fIntersectSphere(const float start[3], const float end[3],
|
||||||
|
const float center[3], float radius, float *t,
|
||||||
|
float out[3]);
|
||||||
|
|
||||||
void CgeVec2fAdd(const float a[2], const float b[2], float out[2]);
|
void CgeVec2fAdd(const float a[2], const float b[2], float out[2]);
|
||||||
void CgeVec2fSub(const float a[2], const float b[2], float out[2]);
|
void CgeVec2fSub(const float a[2], const float b[2], float out[2]);
|
||||||
@@ -162,6 +174,12 @@ void CgeVec2fLerp(const float a[2], const float b[2], float t, float out[2]);
|
|||||||
void CgeVec2fProject(const float a[2], const float b[2], float out[2]);
|
void CgeVec2fProject(const float a[2], const float b[2], float out[2]);
|
||||||
void CgeVec2fBarycentric(const float a[2], const float b[2], const float c[2],
|
void CgeVec2fBarycentric(const float a[2], const float b[2], const float c[2],
|
||||||
float v, float w, float out[2]);
|
float v, float w, float out[2]);
|
||||||
|
float CgeVec2fDistance(const float a[2], const float b[2]);
|
||||||
|
void CgeVec2fReflect(const float in[2], const float norm[2], float out[2]);
|
||||||
|
void CgeVec2fRefract(const float in[2], const float norm[2], float eta,
|
||||||
|
float out[2]);
|
||||||
|
void CgeVec2fClamp(const float in[2], float minVal, float maxVal, float out[2]);
|
||||||
|
void CgeVec2fAbs(const float in[2], float out[2]);
|
||||||
|
|
||||||
void CgeVec2iAdd(const int a[2], const int b[2], int out[2]);
|
void CgeVec2iAdd(const int a[2], const int b[2], int out[2]);
|
||||||
void CgeVec2iSub(const int a[2], const int b[2], int out[2]);
|
void CgeVec2iSub(const int a[2], const int b[2], int out[2]);
|
||||||
@@ -171,6 +189,8 @@ void CgeVec2iMulAdd(const int a[2], const int b[2], const int c[2], int out[2]);
|
|||||||
void CgeVec2iNegate(const int in[2], int out[2]);
|
void CgeVec2iNegate(const int in[2], int out[2]);
|
||||||
void CgeVec2iMin(const int a[2], const int b[2], int out[2]);
|
void CgeVec2iMin(const int a[2], const int b[2], int out[2]);
|
||||||
void CgeVec2iMax(const int a[2], const int b[2], int out[2]);
|
void CgeVec2iMax(const int a[2], const int b[2], int out[2]);
|
||||||
|
void CgeVec2iClamp(const int in[2], int minVal, int maxVal, int out[2]);
|
||||||
|
void CgeVec2iAbs(const int in[2], int out[2]);
|
||||||
|
|
||||||
void CgeVec3fAdd(const float a[3], const float b[3], float out[3]);
|
void CgeVec3fAdd(const float a[3], const float b[3], float out[3]);
|
||||||
void CgeVec3fSub(const float a[3], const float b[3], float out[3]);
|
void CgeVec3fSub(const float a[3], const float b[3], float out[3]);
|
||||||
@@ -190,6 +210,12 @@ void CgeVec3fLerp(const float a[3], const float b[3], float t, float out[3]);
|
|||||||
void CgeVec3fProject(const float a[3], const float b[3], float out[3]);
|
void CgeVec3fProject(const float a[3], const float b[3], float out[3]);
|
||||||
void CgeVec3fBarycentric(const float a[3], const float b[3], const float c[3],
|
void CgeVec3fBarycentric(const float a[3], const float b[3], const float c[3],
|
||||||
float v, float w, float out[3]);
|
float v, float w, float out[3]);
|
||||||
|
float CgeVec3fDistance(const float a[3], const float b[3]);
|
||||||
|
void CgeVec3fReflect(const float in[3], const float norm[3], float out[3]);
|
||||||
|
void CgeVec3fRefract(const float in[3], const float norm[3], float eta,
|
||||||
|
float out[3]);
|
||||||
|
void CgeVec3fClamp(const float in[3], float minVal, float maxVal, float out[3]);
|
||||||
|
void CgeVec3fAbs(const float in[3], float out[3]);
|
||||||
|
|
||||||
void CgeVec3iAdd(const int a[3], const int b[3], int out[3]);
|
void CgeVec3iAdd(const int a[3], const int b[3], int out[3]);
|
||||||
void CgeVec3iSub(const int a[3], const int b[3], int out[3]);
|
void CgeVec3iSub(const int a[3], const int b[3], int out[3]);
|
||||||
@@ -199,6 +225,8 @@ void CgeVec3iMulAdd(const int a[3], const int b[3], const int c[3], int out[3]);
|
|||||||
void CgeVec3iNegate(const int in[3], int out[3]);
|
void CgeVec3iNegate(const int in[3], int out[3]);
|
||||||
void CgeVec3iMin(const int a[3], const int b[3], int out[3]);
|
void CgeVec3iMin(const int a[3], const int b[3], int out[3]);
|
||||||
void CgeVec3iMax(const int a[3], const int b[3], int out[3]);
|
void CgeVec3iMax(const int a[3], const int b[3], int out[3]);
|
||||||
|
void CgeVec3iClamp(const int in[3], int minVal, int maxVal, int out[3]);
|
||||||
|
void CgeVec3iAbs(const int in[3], int out[3]);
|
||||||
|
|
||||||
void CgeVec4fAdd(const float a[4], const float b[4], float out[4]);
|
void CgeVec4fAdd(const float a[4], const float b[4], float out[4]);
|
||||||
void CgeVec4fSub(const float a[4], const float b[4], float out[4]);
|
void CgeVec4fSub(const float a[4], const float b[4], float out[4]);
|
||||||
@@ -217,6 +245,9 @@ void CgeVec4fLerp(const float a[4], const float b[4], float t, float out[4]);
|
|||||||
void CgeVec4fProject(const float a[4], const float b[4], float out[4]);
|
void CgeVec4fProject(const float a[4], const float b[4], float out[4]);
|
||||||
void CgeVec4fBarycentric(const float a[4], const float b[4], const float c[4],
|
void CgeVec4fBarycentric(const float a[4], const float b[4], const float c[4],
|
||||||
float v, float w, float out[4]);
|
float v, float w, float out[4]);
|
||||||
|
float CgeVec4fDistance(const float a[4], const float b[4]);
|
||||||
|
void CgeVec4fClamp(const float in[4], float minVal, float maxVal, float out[4]);
|
||||||
|
void CgeVec4fAbs(const float in[4], float out[4]);
|
||||||
|
|
||||||
void CgeVec4iAdd(const int a[4], const int b[4], int out[4]);
|
void CgeVec4iAdd(const int a[4], const int b[4], int out[4]);
|
||||||
void CgeVec4iSub(const int a[4], const int b[4], int out[4]);
|
void CgeVec4iSub(const int a[4], const int b[4], int out[4]);
|
||||||
@@ -226,5 +257,7 @@ void CgeVec4iMulAdd(const int a[4], const int b[4], const int c[4], int out[4]);
|
|||||||
void CgeVec4iNegate(const int in[4], int out[4]);
|
void CgeVec4iNegate(const int in[4], int out[4]);
|
||||||
void CgeVec4iMin(const int a[4], const int b[4], int out[4]);
|
void CgeVec4iMin(const int a[4], const int b[4], int out[4]);
|
||||||
void CgeVec4iMax(const int a[4], const int b[4], int out[4]);
|
void CgeVec4iMax(const int a[4], const int b[4], int out[4]);
|
||||||
|
void CgeVec4iClamp(const int in[4], int minVal, int maxVal, int out[4]);
|
||||||
|
void CgeVec4iAbs(const int in[4], int out[4]);
|
||||||
|
|
||||||
#endif /* CGE_MATH_H */
|
#endif /* CGE_MATH_H */
|
||||||
|
|||||||
@@ -51,6 +51,13 @@ int main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Checkout the `examples` folder to look at an example of the raytracer using
|
||||||
|
this library.
|
||||||
|
|
||||||
|
Here is an example of its output:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Portability
|
## Portability
|
||||||
|
|
||||||
- Written in C89 + stdint.h
|
- Written in C89 + stdint.h
|
||||||
|
|||||||
62
Ray2f.c
62
Ray2f.c
@@ -134,13 +134,6 @@ int CgeRay2fIntersectBox2f(const float aStart[2], const float aDirection[2],
|
|||||||
timeNear = -1.0f / 0.0f;
|
timeNear = -1.0f / 0.0f;
|
||||||
timeFar = 1.0f / 0.0f;
|
timeFar = 1.0f / 0.0f;
|
||||||
|
|
||||||
/* Check if origin inside box */
|
|
||||||
if (CgeBox2fContains(bMin, bMax, aStart)) {
|
|
||||||
memcpy(out, aStart, sizeof(float) * 2);
|
|
||||||
*t = 0.0f;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check each axis for the minimal and maximum intersection time */
|
/* Check each axis for the minimal and maximum intersection time */
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
if (fabsf(aDirection[i]) < EPSILON) {
|
if (fabsf(aDirection[i]) < EPSILON) {
|
||||||
@@ -191,3 +184,58 @@ int CgeSegment2fIntersectBox2f(const float aStart[2], const float aEnd[2],
|
|||||||
*t = time;
|
*t = time;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CgeRay2fIntersectCircle(const float start[2], const float direction[2],
|
||||||
|
const float center[2], float radius, float *t,
|
||||||
|
float out[2])
|
||||||
|
{
|
||||||
|
float v[2], tmp[2];
|
||||||
|
float tCa, d2, th, t1, t2;
|
||||||
|
|
||||||
|
CgeVec2fSub(center, start, v);
|
||||||
|
tCa = CgeVec2fDot(v, direction);
|
||||||
|
d2 = CgeVec2fDot(v, v) - tCa * tCa;
|
||||||
|
|
||||||
|
if (d2 > radius * radius)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
th = (float)sqrt(radius * radius - d2);
|
||||||
|
t1 = tCa - th;
|
||||||
|
t2 = tCa + th;
|
||||||
|
|
||||||
|
if (t2 < EPSILON) return 0;
|
||||||
|
|
||||||
|
*t = (t1 > EPSILON) ? t1 : t2;
|
||||||
|
CgeVec2fScale(direction, *t, tmp);
|
||||||
|
CgeVec2fAdd(start, tmp, out);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CgeSegment2fIntersectCircle(const float start[2], const float end[2],
|
||||||
|
const float center[2], float radius, float *t,
|
||||||
|
float out[2]) {
|
||||||
|
float dir[2], lenSq, len;
|
||||||
|
float norm[2];
|
||||||
|
|
||||||
|
CgeVec2fSub(end, start, dir);
|
||||||
|
lenSq = CgeVec2fDot(dir, dir);
|
||||||
|
|
||||||
|
if (lenSq == 0.0f)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len = (float)sqrt(lenSq);
|
||||||
|
CgeVec2fScale(dir, 1.0f / len, norm);
|
||||||
|
|
||||||
|
if (!CgeRay2fIntersectCircle(start, norm, center, radius, t, out)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*t = *t / len;
|
||||||
|
if (*t > len)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
CgeVec2fScale(dir, *t, out);
|
||||||
|
CgeVec2fAdd(start, out, out);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|||||||
62
Ray3f.c
62
Ray3f.c
@@ -135,13 +135,6 @@ int CgeRay3fIntersectBox3f(const float aStart[3], const float aDirection[3],
|
|||||||
timeNear = -1.0f / 0.0f;
|
timeNear = -1.0f / 0.0f;
|
||||||
timeFar = 1.0f / 0.0f;
|
timeFar = 1.0f / 0.0f;
|
||||||
|
|
||||||
/* Check if origin inside box */
|
|
||||||
if (CgeBox3fContains(bMin, bMax, aStart)) {
|
|
||||||
memcpy(out, aStart, sizeof(float) * 3);
|
|
||||||
*t = 0.0f;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check each axis for the minimal and maximum intersection time */
|
/* Check each axis for the minimal and maximum intersection time */
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
if (fabsf(aDirection[i]) < EPSILON) {
|
if (fabsf(aDirection[i]) < EPSILON) {
|
||||||
@@ -193,3 +186,58 @@ int CgeSegment3fIntersectBox3f(const float aStart[3], const float aEnd[3],
|
|||||||
*t = time;
|
*t = time;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CgeRay3fIntersectSphere(const float start[3], const float direction[3],
|
||||||
|
const float center[3], float radius, float *t,
|
||||||
|
float out[3])
|
||||||
|
{
|
||||||
|
float v[3], tmp[3];
|
||||||
|
float tCa, d2, th, t1, t2;
|
||||||
|
|
||||||
|
CgeVec3fSub(center, start, v);
|
||||||
|
tCa = CgeVec3fDot(v, direction);
|
||||||
|
d2 = CgeVec3fDot(v, v) - tCa * tCa;
|
||||||
|
|
||||||
|
if (d2 > radius * radius)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
th = (float)sqrt(radius * radius - d2);
|
||||||
|
t1 = tCa - th;
|
||||||
|
t2 = tCa + th;
|
||||||
|
|
||||||
|
if (t2 < EPSILON) return 0;
|
||||||
|
|
||||||
|
*t = (t1 > EPSILON) ? t1 : t2;
|
||||||
|
CgeVec3fScale(direction, *t, tmp);
|
||||||
|
CgeVec3fAdd(start, tmp, out);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CgeSegment3fIntersectSphere(const float start[3], const float end[3],
|
||||||
|
const float center[3], float radius, float *t,
|
||||||
|
float out[3]) {
|
||||||
|
float dir[3], lenSq, len;
|
||||||
|
float norm[3];
|
||||||
|
|
||||||
|
CgeVec3fSub(end, start, dir);
|
||||||
|
lenSq = CgeVec3fDot(dir, dir);
|
||||||
|
|
||||||
|
if (lenSq == 0.0f)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len = (float)sqrt(lenSq);
|
||||||
|
CgeVec3fScale(dir, 1.0f / len, norm);
|
||||||
|
|
||||||
|
if (!CgeRay3fIntersectSphere(start, norm, center, radius, t, out)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*t = *t / len;
|
||||||
|
if (*t > len)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
CgeVec3fScale(dir, *t, out);
|
||||||
|
CgeVec3fAdd(start, out, out);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|||||||
43
Vec2f.c
43
Vec2f.c
@@ -93,3 +93,46 @@ void CgeVec2fBarycentric(const float a[2], const float b[2], const float c[2],
|
|||||||
SET_ROW(tmp1, v); CgeVec2fMulAdd(b, tmp1, tmp2, tmp2);
|
SET_ROW(tmp1, v); CgeVec2fMulAdd(b, tmp1, tmp2, tmp2);
|
||||||
SET_ROW(tmp1, w); CgeVec2fMulAdd(c, tmp1, tmp2, out);
|
SET_ROW(tmp1, w); CgeVec2fMulAdd(c, tmp1, tmp2, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float CgeVec2fDistance(const float a[2], const float b[2]) {
|
||||||
|
float tmp[2];
|
||||||
|
|
||||||
|
CgeVec2fSub(a, b, tmp);
|
||||||
|
return CgeVec2fLength(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec2fReflect(const float in[2], const float norm[2], float out[2]) {
|
||||||
|
float tmp[2];
|
||||||
|
float dot;
|
||||||
|
|
||||||
|
dot = CgeVec2fDot(in, norm);
|
||||||
|
CgeVec2fScale(norm, 2.0f * dot, tmp);
|
||||||
|
CgeVec2fSub(in, tmp, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec2fRefract(const float in[2], const float norm[2], float eta,
|
||||||
|
float out[2]) {
|
||||||
|
float tmp1[2], tmp2[2];
|
||||||
|
float nDotI, k;
|
||||||
|
|
||||||
|
nDotI = CgeVec2fDot(norm, in);
|
||||||
|
k = 1.0f - eta * eta * (1.0f - nDotI * nDotI);
|
||||||
|
if (k < 0.0f) {
|
||||||
|
out[0] = out[1] = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CgeVec2fScale(norm, eta * nDotI + (float)sqrt(k), tmp1);
|
||||||
|
CgeVec2fScale(in, eta, tmp2);
|
||||||
|
CgeVec2fSub(tmp2, tmp1, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec2fClamp(const float in[2], float minVal, float maxVal, float out[2]) {
|
||||||
|
out[0] = in[0] < minVal ? minVal : (in[0] > maxVal ? maxVal : in[0]);
|
||||||
|
out[1] = in[1] < minVal ? minVal : (in[1] > maxVal ? maxVal : in[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec2fAbs(const float in[2], float out[2]) {
|
||||||
|
out[0] = in[0] < 0 ? -in[0] : in[0];
|
||||||
|
out[1] = in[1] < 0 ? -in[1] : in[1];
|
||||||
|
}
|
||||||
|
|||||||
10
Vec2i.c
10
Vec2i.c
@@ -40,3 +40,13 @@ void CgeVec2iMax(const int a[2], const int b[2], int out[2]) {
|
|||||||
if (a[0] > b[0]) out[0] = a[0]; else out[0] = b[0];
|
if (a[0] > b[0]) out[0] = a[0]; else out[0] = b[0];
|
||||||
if (a[1] > b[1]) out[1] = a[1]; else out[1] = b[1];
|
if (a[1] > b[1]) out[1] = a[1]; else out[1] = b[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CgeVec2iClamp(const int in[2], int minVal, int maxVal, int out[2]) {
|
||||||
|
out[0] = in[0] < minVal ? minVal : (in[0] > maxVal ? maxVal : in[0]);
|
||||||
|
out[1] = in[1] < minVal ? minVal : (in[1] > maxVal ? maxVal : in[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec2iAbs(const int in[2], int out[2]) {
|
||||||
|
out[0] = in[0] < 0 ? -in[0] : in[0];
|
||||||
|
out[1] = in[1] < 0 ? -in[1] : in[1];
|
||||||
|
}
|
||||||
|
|||||||
45
Vec3f.c
45
Vec3f.c
@@ -107,3 +107,48 @@ void CgeVec3fBarycentric(const float a[3], const float b[3], const float c[3],
|
|||||||
SET_ROW(tmp1, v); CgeVec3fMulAdd(b, tmp1, tmp2, tmp2);
|
SET_ROW(tmp1, v); CgeVec3fMulAdd(b, tmp1, tmp2, tmp2);
|
||||||
SET_ROW(tmp1, w); CgeVec3fMulAdd(c, tmp1, tmp2, out);
|
SET_ROW(tmp1, w); CgeVec3fMulAdd(c, tmp1, tmp2, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float CgeVec3fDistance(const float a[3], const float b[3]) {
|
||||||
|
float tmp[3];
|
||||||
|
|
||||||
|
CgeVec3fSub(a, b, tmp);
|
||||||
|
return CgeVec3fLength(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec3fReflect(const float in[3], const float norm[3], float out[3]) {
|
||||||
|
float tmp[3];
|
||||||
|
float dot;
|
||||||
|
|
||||||
|
dot = CgeVec3fDot(in, norm);
|
||||||
|
CgeVec3fScale(norm, 2.0f * dot, tmp);
|
||||||
|
CgeVec3fSub(in, tmp, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec3fRefract(const float in[3], const float norm[3], float eta,
|
||||||
|
float out[3]) {
|
||||||
|
float tmp1[3], tmp2[3];
|
||||||
|
float nDotI, k;
|
||||||
|
|
||||||
|
nDotI = CgeVec3fDot(norm, in);
|
||||||
|
k = 1.0f - eta * eta * (1.0f - nDotI * nDotI);
|
||||||
|
if (k < 0.0f) {
|
||||||
|
out[0] = out[1] = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CgeVec3fScale(norm, eta * nDotI + (float)sqrt(k), tmp1);
|
||||||
|
CgeVec3fScale(in, eta, tmp2);
|
||||||
|
CgeVec3fSub(tmp2, tmp1, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec3fClamp(const float in[3], float minVal, float maxVal, float out[3]) {
|
||||||
|
out[0] = in[0] < minVal ? minVal : (in[0] > maxVal ? maxVal : in[0]);
|
||||||
|
out[1] = in[1] < minVal ? minVal : (in[1] > maxVal ? maxVal : in[1]);
|
||||||
|
out[2] = in[2] < minVal ? minVal : (in[2] > maxVal ? maxVal : in[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec3fAbs(const float in[3], float out[3]) {
|
||||||
|
out[0] = in[0] < 0 ? -in[0] : in[0];
|
||||||
|
out[1] = in[1] < 0 ? -in[1] : in[1];
|
||||||
|
out[2] = in[2] < 0 ? -in[2] : in[2];
|
||||||
|
}
|
||||||
|
|||||||
12
Vec3i.c
12
Vec3i.c
@@ -48,3 +48,15 @@ void CgeVec3iMax(const int a[3], const int b[3], int out[3]) {
|
|||||||
if (a[1] > b[1]) out[1] = a[1]; else out[1] = b[1];
|
if (a[1] > b[1]) out[1] = a[1]; else out[1] = b[1];
|
||||||
if (a[2] > b[2]) out[2] = a[2]; else out[2] = b[2];
|
if (a[2] > b[2]) out[2] = a[2]; else out[2] = b[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CgeVec3iClamp(const int in[3], int minVal, int maxVal, int out[3]) {
|
||||||
|
out[0] = in[0] < minVal ? minVal : (in[0] > maxVal ? maxVal : in[0]);
|
||||||
|
out[1] = in[1] < minVal ? minVal : (in[1] > maxVal ? maxVal : in[1]);
|
||||||
|
out[2] = in[2] < minVal ? minVal : (in[2] > maxVal ? maxVal : in[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec3iAbs(const int in[3], int out[3]) {
|
||||||
|
out[0] = in[0] < 0 ? -in[0] : in[0];
|
||||||
|
out[1] = in[1] < 0 ? -in[1] : in[1];
|
||||||
|
out[2] = in[2] < 0 ? -in[2] : in[2];
|
||||||
|
}
|
||||||
|
|||||||
21
Vec4f.c
21
Vec4f.c
@@ -106,3 +106,24 @@ void CgeVec4fBarycentric(const float a[4], const float b[4], const float c[4],
|
|||||||
SET_ROW(tmp1, v); CgeVec4fMulAdd(b, tmp1, tmp2, tmp2);
|
SET_ROW(tmp1, v); CgeVec4fMulAdd(b, tmp1, tmp2, tmp2);
|
||||||
SET_ROW(tmp1, w); CgeVec4fMulAdd(c, tmp1, tmp2, out);
|
SET_ROW(tmp1, w); CgeVec4fMulAdd(c, tmp1, tmp2, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float CgeVec4fDistance(const float a[4], const float b[4]) {
|
||||||
|
float tmp[4];
|
||||||
|
|
||||||
|
CgeVec4fSub(a, b, tmp);
|
||||||
|
return CgeVec4fLength(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec4fClamp(const float in[4], float minVal, float maxVal, float out[4]) {
|
||||||
|
out[0] = in[0] < minVal ? minVal : (in[0] > maxVal ? maxVal : in[0]);
|
||||||
|
out[1] = in[1] < minVal ? minVal : (in[1] > maxVal ? maxVal : in[1]);
|
||||||
|
out[2] = in[2] < minVal ? minVal : (in[2] > maxVal ? maxVal : in[2]);
|
||||||
|
out[3] = in[3] < minVal ? minVal : (in[3] > maxVal ? maxVal : in[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec4fAbs(const float in[4], float out[4]) {
|
||||||
|
out[0] = in[0] < 0 ? -in[0] : in[0];
|
||||||
|
out[1] = in[1] < 0 ? -in[1] : in[1];
|
||||||
|
out[2] = in[2] < 0 ? -in[2] : in[2];
|
||||||
|
out[3] = in[3] < 0 ? -in[3] : in[3];
|
||||||
|
}
|
||||||
|
|||||||
14
Vec4i.c
14
Vec4i.c
@@ -56,3 +56,17 @@ void CgeVec4iMax(const int a[4], const int b[4], int out[4]) {
|
|||||||
if (a[2] > b[2]) out[2] = a[2]; else out[2] = b[2];
|
if (a[2] > b[2]) out[2] = a[2]; else out[2] = b[2];
|
||||||
if (a[3] > b[3]) out[3] = a[3]; else out[3] = b[3];
|
if (a[3] > b[3]) out[3] = a[3]; else out[3] = b[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CgeVec4iClamp(const int in[4], int minVal, int maxVal, int out[4]) {
|
||||||
|
out[0] = in[0] < minVal ? minVal : (in[0] > maxVal ? maxVal : in[0]);
|
||||||
|
out[1] = in[1] < minVal ? minVal : (in[1] > maxVal ? maxVal : in[1]);
|
||||||
|
out[2] = in[2] < minVal ? minVal : (in[2] > maxVal ? maxVal : in[2]);
|
||||||
|
out[3] = in[3] < minVal ? minVal : (in[3] > maxVal ? maxVal : in[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CgeVec4iAbs(const int in[4], int out[4]) {
|
||||||
|
out[0] = in[0] < 0 ? -in[0] : in[0];
|
||||||
|
out[1] = in[1] < 0 ? -in[1] : in[1];
|
||||||
|
out[2] = in[2] < 0 ? -in[2] : in[2];
|
||||||
|
out[3] = in[3] < 0 ? -in[3] : in[3];
|
||||||
|
}
|
||||||
|
|||||||
205
examples/demo.c
Normal file
205
examples/demo.c
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "CgeMath.h"
|
||||||
|
|
||||||
|
#define WIDTH 640
|
||||||
|
#define HEIGHT 480
|
||||||
|
#define BG_R 0.05f
|
||||||
|
#define BG_G 0.05f
|
||||||
|
#define BG_B 0.1f
|
||||||
|
#define MAX_BOUNCES 7
|
||||||
|
|
||||||
|
static int toInt(float x) {
|
||||||
|
return (int)(x * 255.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float center[3];
|
||||||
|
float radius;
|
||||||
|
const float *color;
|
||||||
|
float reflectivity;
|
||||||
|
float shininess;
|
||||||
|
float specular;
|
||||||
|
} Sphere;
|
||||||
|
|
||||||
|
static const float gRed[3] = {1.0f, 0.0f, 0.0f};
|
||||||
|
static const float gGreen[3] = {0.0f, 1.0f, 0.0f};
|
||||||
|
static const float gBlue[3] = {0.0f, 0.0f, 1.0f};
|
||||||
|
|
||||||
|
static const Sphere gSpheres[] = {
|
||||||
|
{{-2.0f, 0.0f, -5.0f}, 1.0f, gRed, 0.1f, 20.0f, 0.5f},
|
||||||
|
{{ 0.0f, 2.0f, -4.0f}, 1.0f, gGreen, 0.5f, 50.0f, 0.8f},
|
||||||
|
{{ 2.0f, 0.0f, -5.0f}, 1.0f, gBlue, 0.95f, 100.0f, 1.0f}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int gNumSpheres = 3;
|
||||||
|
static const float gLightPos[3] = {0.0f, 3.0f, -2.0f};
|
||||||
|
static const float gAmbient = 0.2f;
|
||||||
|
static const float gOrigin[3] = {0.0f, 0.5f, 0.0f};
|
||||||
|
|
||||||
|
int traceRay(const float origin[3], const float direction[3], float *t,
|
||||||
|
int *hitIndex, float hitPoint[3], float normal[3]) {
|
||||||
|
float t0, closest;
|
||||||
|
float p[3];
|
||||||
|
int i, hit;
|
||||||
|
|
||||||
|
closest = 1e10f;
|
||||||
|
hit = -1;
|
||||||
|
|
||||||
|
for (i = 0; i < gNumSpheres; i++) {
|
||||||
|
if (CgeRay3fIntersectSphere(origin, direction, gSpheres[i].center, gSpheres[i].radius, &t0, p) == 1) {
|
||||||
|
if (t0 > 0.001f && t0 < closest) {
|
||||||
|
closest = t0;
|
||||||
|
hit = i;
|
||||||
|
CgeVec3fSub(p, gSpheres[i].center, normal);
|
||||||
|
CgeVec3fNormal(normal, normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (direction[1] != 0.0f) {
|
||||||
|
float t_plane;
|
||||||
|
t_plane = (-1.0f - origin[1]) / direction[1];
|
||||||
|
if (t_plane > 0.001f && t_plane < closest) {
|
||||||
|
closest = t_plane;
|
||||||
|
hit = -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closest == 1e10f) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*t = closest;
|
||||||
|
*hitIndex = hit;
|
||||||
|
|
||||||
|
hitPoint[0] = origin[0] + closest * direction[0];
|
||||||
|
hitPoint[1] = origin[1] + closest * direction[1];
|
||||||
|
hitPoint[2] = origin[2] + closest * direction[2];
|
||||||
|
|
||||||
|
if (hit >= 0) {
|
||||||
|
CgeVec3fSub(hitPoint, gSpheres[hit].center, normal);
|
||||||
|
CgeVec3fNormal(normal, normal);
|
||||||
|
} else if (hit == -2) {
|
||||||
|
normal[0] = 0.0f; normal[1] = 1.0f; normal[2] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void traceColor(const float origin[3], const float direction[3], float color[3],
|
||||||
|
int depth) {
|
||||||
|
float viewDir[3], halfVec[3], reflectDir[3], offset[3], reflectOrigin[3];
|
||||||
|
float hitPoint[3], normal[3], localColor[3], reflectColor[3];
|
||||||
|
float toLight[3], lightDir[3], dummyPoint[3], dummyNormal[3];
|
||||||
|
float t, NdotL, diffuse, specular, brightness, tile, NdotH, reflectivity;
|
||||||
|
float shadow, tShadow;
|
||||||
|
const float *surf;
|
||||||
|
int hitIndex, dummyIdx, ix, iz;
|
||||||
|
|
||||||
|
if (depth >= MAX_BOUNCES) {
|
||||||
|
color[0] = color[1] = color[2] = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (traceRay(origin, direction, &t, &hitIndex, hitPoint, normal) >= 0) {
|
||||||
|
CgeVec3fSub(gLightPos, hitPoint, toLight);
|
||||||
|
CgeVec3fNormal(toLight, lightDir);
|
||||||
|
|
||||||
|
shadow = 1.0f;
|
||||||
|
if (traceRay(hitPoint, lightDir, &tShadow, &dummyIdx, dummyPoint, dummyNormal) >= 0) {
|
||||||
|
float lightDist = CgeVec3fDistance(gLightPos, hitPoint);
|
||||||
|
if (tShadow < lightDist) {
|
||||||
|
shadow = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NdotL = CgeVec3fDot(normal, lightDir);
|
||||||
|
diffuse = (NdotL > 0.0f) ? NdotL : 0.0f;
|
||||||
|
|
||||||
|
specular = 0.0f;
|
||||||
|
if (hitIndex >= 0 && NdotL > 0.0f) {
|
||||||
|
CgeVec3fSub(gOrigin, hitPoint, viewDir);
|
||||||
|
CgeVec3fNormal(viewDir, viewDir);
|
||||||
|
|
||||||
|
CgeVec3fAdd(viewDir, lightDir, halfVec);
|
||||||
|
CgeVec3fNormal(halfVec, halfVec);
|
||||||
|
|
||||||
|
NdotH = CgeVec3fDot(normal, halfVec);
|
||||||
|
if (NdotH > 0.0f) {
|
||||||
|
specular = powf(NdotH, gSpheres[hitIndex].shininess) * gSpheres[hitIndex].specular;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
brightness = gAmbient + diffuse * shadow + specular * shadow;
|
||||||
|
|
||||||
|
if (hitIndex == -2) {
|
||||||
|
ix = (int)floorf(hitPoint[0]);
|
||||||
|
iz = (int)floorf(hitPoint[2]);
|
||||||
|
tile = ((ix + iz) % 2 == 0) ? 1.0f : 0.3f;
|
||||||
|
localColor[0] = localColor[1] = localColor[2] = tile * brightness;
|
||||||
|
} else {
|
||||||
|
surf = gSpheres[hitIndex].color;
|
||||||
|
localColor[0] = surf[0] * brightness;
|
||||||
|
localColor[1] = surf[1] * brightness;
|
||||||
|
localColor[2] = surf[2] * brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
reflectivity = (hitIndex >= 0) ? gSpheres[hitIndex].reflectivity : 0.0f;
|
||||||
|
if (reflectivity > 0.0f) {
|
||||||
|
CgeVec3fReflect(direction, normal, reflectDir);
|
||||||
|
CgeVec3fScale(reflectDir, 0.001f, offset);
|
||||||
|
CgeVec3fAdd(hitPoint, offset, reflectOrigin);
|
||||||
|
|
||||||
|
traceColor(reflectOrigin, reflectDir, reflectColor, depth + 1);
|
||||||
|
|
||||||
|
localColor[0] = localColor[0] * (1.0f - reflectivity) + reflectColor[0] * reflectivity;
|
||||||
|
localColor[1] = localColor[1] * (1.0f - reflectivity) + reflectColor[1] * reflectivity;
|
||||||
|
localColor[2] = localColor[2] * (1.0f - reflectivity) + reflectColor[2] * reflectivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
color[0] = localColor[0];
|
||||||
|
color[1] = localColor[1];
|
||||||
|
color[2] = localColor[2];
|
||||||
|
} else {
|
||||||
|
color[0] = BG_R;
|
||||||
|
color[1] = BG_G;
|
||||||
|
color[2] = BG_B;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int x, y;
|
||||||
|
float u, v, aspect, fov;
|
||||||
|
float direction[3], color[3];
|
||||||
|
|
||||||
|
printf("P3\n%d %d\n255\n", WIDTH, HEIGHT);
|
||||||
|
|
||||||
|
aspect = (float)WIDTH / (float)HEIGHT;
|
||||||
|
fov = 1.0f;
|
||||||
|
|
||||||
|
for (y = 0; y < HEIGHT; y++) {
|
||||||
|
for (x = 0; x < WIDTH; x++) {
|
||||||
|
u = (2.0f * (x + 0.5f) / (float)WIDTH - 1.0f) * aspect;
|
||||||
|
v = (2.0f * (HEIGHT - y - 0.5f) / (float)HEIGHT - 1.0f);
|
||||||
|
|
||||||
|
direction[0] = u;
|
||||||
|
direction[1] = v;
|
||||||
|
direction[2] = -fov;
|
||||||
|
CgeVec3fNormal(direction, direction);
|
||||||
|
traceColor(gOrigin, direction, color, 0);
|
||||||
|
|
||||||
|
if (color[0] < 0.0f) color[0] = 0.0f; else if (color[0] > 1.0f) color[0] = 1.0f;
|
||||||
|
if (color[1] < 0.0f) color[1] = 0.0f; else if (color[1] > 1.0f) color[1] = 1.0f;
|
||||||
|
if (color[2] < 0.0f) color[2] = 0.0f; else if (color[2] > 1.0f) color[2] = 1.0f;
|
||||||
|
|
||||||
|
color[0] = powf(color[0], 1.0f / 2.2f);
|
||||||
|
color[1] = powf(color[1], 1.0f / 2.2f);
|
||||||
|
color[2] = powf(color[2], 1.0f / 2.2f);
|
||||||
|
|
||||||
|
printf("%d %d %d\n", toInt(color[0]), toInt(color[1]), toInt(color[2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
examples/demo.png
Normal file
BIN
examples/demo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
Reference in New Issue
Block a user