Simplify code of the raytracer demo
All checks were successful
CI / build-and-analyze (push) Successful in 40s

This commit is contained in:
2026-07-04 18:10:01 +03:00
parent ba1ef9a88e
commit 57a1be7924

View File

@@ -1,12 +1,10 @@
#include <stdio.h>
#include <math.h> #include <math.h>
#include <stdio.h>
#include <string.h>
#include "CgeMath.h" #include "CgeMath.h"
#define WIDTH 640 #define WIDTH 640
#define HEIGHT 480 #define HEIGHT 480
#define BG_R 0.05f
#define BG_G 0.05f
#define BG_B 0.1f
#define MAX_BOUNCES 7 #define MAX_BOUNCES 7
static int toInt(float x) { static int toInt(float x) {
@@ -22,6 +20,7 @@ typedef struct {
float specular; float specular;
} Sphere; } Sphere;
static const float bg[3] = {0.05f, 0.05f, 0.1f};
static const float red[3] = {1.0f, 0.0f, 0.0f}; static const float red[3] = {1.0f, 0.0f, 0.0f};
static const float green[3] = {0.0f, 1.0f, 0.0f}; static const float green[3] = {0.0f, 1.0f, 0.0f};
static const float blue[3] = {0.0f, 0.0f, 1.0f}; static const float blue[3] = {0.0f, 0.0f, 1.0f};
@@ -41,75 +40,63 @@ int traceRay(const float origin[3], const float direction[3], float *t,
int *hitIndex, float hitPoint[3], float normal[3]) { int *hitIndex, float hitPoint[3], float normal[3]) {
float t0, closest; float t0, closest;
float p[3]; float p[3];
int i, hit; int i;
closest = 1e10f;
hit = -1;
closest = 1.0 / 0.0;
*hitIndex = -1;
for (i = 0; i < numSpheres; i++) { for (i = 0; i < numSpheres; i++) {
if (CgeRay3fIntersectSphere(origin, direction, spheres[i].center, spheres[i].radius, &t0, p) == 1) { if (CgeRay3fIntersectSphere(origin, direction, spheres[i].center, spheres[i].radius, &t0, p)) {
if (t0 > 0.001f && t0 < closest) { if (t0 > 0.001f && t0 < closest) {
closest = t0; closest = t0;
hit = i; *t = t0;
CgeVec3fSub(p, spheres[i].center, normal); *hitIndex = i;
memcpy(hitPoint, p, sizeof(p));
CgeVec3fSub(hitPoint, spheres[i].center, normal);
CgeVec3fNormal(normal, normal); CgeVec3fNormal(normal, normal);
} }
} }
} }
if (direction[1] != 0.0f) { t0 = (-1.0f - origin[1]) / direction[1];
float tPlane; if (t0 > 0.001f && t0 < closest) {
tPlane = (-1.0f - origin[1]) / direction[1]; closest = t0;
if (tPlane > 0.001f && tPlane < closest) { *t = t0;
closest = tPlane; *hitIndex = -2;
hit = -2;
}
}
if (closest == 1e10f) { CgeVec3fScale(direction, closest, hitPoint);
return -1; CgeVec3fAdd(origin, hitPoint, hitPoint);
}
*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, spheres[hit].center, normal);
CgeVec3fNormal(normal, normal);
} else if (hit == -2) {
normal[0] = 0.0f; normal[1] = 1.0f; normal[2] = 0.0f; normal[0] = 0.0f; normal[1] = 1.0f; normal[2] = 0.0f;
} }
return 1; return *hitIndex != -1;
} }
void traceColor(const float origin[3], const float direction[3], float color[3], void traceColor(const float origin[3], const float direction[3], float color[3],
int depth) { int depth) {
float viewDir[3], halfVec[3], reflectDir[3], offset[3], reflectOrigin[3]; float normal[3], hitPoint[3];
float hitPoint[3], normal[3], localColor[3], reflectColor[3]; float t;
float toLight[3], lightDir[3], dummyPoint[3], dummyNormal[3]; int hitIndex;
float t, NdotL, diffuse, specular, brightness, tile, NdotH, reflectivity;
float shadow, tShadow;
const float *surf;
int hitIndex, dummyIdx, ix, iz;
if (depth >= MAX_BOUNCES) { if (depth >= MAX_BOUNCES) {
color[0] = color[1] = color[2] = 0.0f; color[0] = color[1] = color[2] = 0.0f;
return; return;
} }
if (traceRay(origin, direction, &t, &hitIndex, hitPoint, normal) >= 0) { if (traceRay(origin, direction, &t, &hitIndex, hitPoint, normal)) {
float localColor[3], toLight[3], lightDir[3];
float dummyPoint[3], dummyNormal[3];
float NdotL, diffuse, specular, brightness, reflectivity;
float shadow;
int dummyIdx;
CgeVec3fSub(lightPos, hitPoint, toLight); CgeVec3fSub(lightPos, hitPoint, toLight);
CgeVec3fNormal(toLight, lightDir); CgeVec3fNormal(toLight, lightDir);
shadow = 1.0f; shadow = 1.0f;
if (traceRay(hitPoint, lightDir, &tShadow, &dummyIdx, dummyPoint, dummyNormal) >= 0) { if (traceRay(hitPoint, lightDir, &t, &dummyIdx, dummyPoint, dummyNormal)) {
float lightDist = CgeVec3fDistance(lightPos, hitPoint); float lightDist = CgeVec3fDistance(lightPos, hitPoint);
if (tShadow < lightDist) { if (t < lightDist) {
shadow = 0.0f; shadow = 0.0f;
} }
} }
@@ -119,6 +106,9 @@ void traceColor(const float origin[3], const float direction[3], float color[3],
specular = 0.0f; specular = 0.0f;
if (hitIndex >= 0 && NdotL > 0.0f) { if (hitIndex >= 0 && NdotL > 0.0f) {
float viewDir[3], halfVec[3];
float NdotH;
CgeVec3fSub(origin, hitPoint, viewDir); CgeVec3fSub(origin, hitPoint, viewDir);
CgeVec3fNormal(viewDir, viewDir); CgeVec3fNormal(viewDir, viewDir);
@@ -126,72 +116,62 @@ void traceColor(const float origin[3], const float direction[3], float color[3],
CgeVec3fNormal(halfVec, halfVec); CgeVec3fNormal(halfVec, halfVec);
NdotH = CgeVec3fDot(normal, halfVec); NdotH = CgeVec3fDot(normal, halfVec);
if (NdotH > 0.0f) { if (NdotH > 0.0f)
specular = powf(NdotH, spheres[hitIndex].shininess) * spheres[hitIndex].specular; specular = powf(NdotH, spheres[hitIndex].shininess) * spheres[hitIndex].specular;
} }
}
brightness = ambient + diffuse * shadow + specular * shadow; brightness = ambient + diffuse * shadow + specular * shadow;
if (hitIndex == -2) { if (hitIndex == -2) {
float tile;
int ix, iz;
ix = (int)floorf(hitPoint[0]); ix = (int)floorf(hitPoint[0]);
iz = (int)floorf(hitPoint[2]); iz = (int)floorf(hitPoint[2]);
tile = ((ix + iz) % 2 == 0) ? 1.0f : 0.3f; tile = ((ix + iz) % 2 == 0) ? 1.0f : 0.3f;
localColor[0] = localColor[1] = localColor[2] = tile * brightness; localColor[0] = localColor[1] = localColor[2] = tile * brightness;
} else { } else {
surf = spheres[hitIndex].color; CgeVec3fScale(spheres[hitIndex].color, brightness, localColor);
localColor[0] = surf[0] * brightness;
localColor[1] = surf[1] * brightness;
localColor[2] = surf[2] * brightness;
} }
reflectivity = (hitIndex >= 0) ? spheres[hitIndex].reflectivity : 0.0f; reflectivity = (hitIndex >= 0) ? spheres[hitIndex].reflectivity : 0.0f;
if (reflectivity > 0.0f) { if (reflectivity > 0.0f) {
float reflectDir[3], offset[3], reflectOrigin[3], reflectColor[3];
CgeVec3fReflect(direction, normal, reflectDir); CgeVec3fReflect(direction, normal, reflectDir);
CgeVec3fScale(reflectDir, 0.001f, offset); CgeVec3fScale(reflectDir, 0.001f, offset);
CgeVec3fAdd(hitPoint, offset, reflectOrigin); CgeVec3fAdd(hitPoint, offset, reflectOrigin);
traceColor(reflectOrigin, reflectDir, reflectColor, depth + 1); traceColor(reflectOrigin, reflectDir, reflectColor, depth + 1);
localColor[0] = localColor[0] * (1.0f - reflectivity) + reflectColor[0] * reflectivity; CgeVec3fScale(localColor, (1.0f - reflectivity), localColor);
localColor[1] = localColor[1] * (1.0f - reflectivity) + reflectColor[1] * reflectivity; CgeVec3fScale(reflectColor, reflectivity, reflectColor);
localColor[2] = localColor[2] * (1.0f - reflectivity) + reflectColor[2] * reflectivity; CgeVec3fAdd(localColor, reflectColor, localColor);
} }
color[0] = localColor[0]; memcpy(color, localColor, sizeof(localColor));
color[1] = localColor[1];
color[2] = localColor[2];
} else { } else {
color[0] = BG_R; memcpy(color, bg, sizeof(bg));
color[1] = BG_G;
color[2] = BG_B;
} }
} }
int main() { int main() {
int x, y; int x, y;
float u, v, aspect, fov; float aspect;
float direction[3], color[3]; float direction[3], color[3];
printf("P3\n%d %d\n255\n", WIDTH, HEIGHT); printf("P3\n%d %d\n255\n", WIDTH, HEIGHT);
aspect = (float)WIDTH / (float)HEIGHT; aspect = (float)WIDTH / (float)HEIGHT;
fov = 1.0f;
for (y = 0; y < HEIGHT; y++) { for (y = 0; y < HEIGHT; y++) {
for (x = 0; x < WIDTH; x++) { for (x = 0; x < WIDTH; x++) {
u = (2.0f * (x + 0.5f) / (float)WIDTH - 1.0f) * aspect; direction[0] = (2.0f * (x + 0.5f) / (float)WIDTH - 1.0f) * aspect;
v = (2.0f * (HEIGHT - y - 0.5f) / (float)HEIGHT - 1.0f); direction[1] = (2.0f * (HEIGHT - y - 0.5f) / (float)HEIGHT - 1.0f);
direction[2] = -1.0;
direction[0] = u;
direction[1] = v;
direction[2] = -fov;
CgeVec3fNormal(direction, direction); CgeVec3fNormal(direction, direction);
traceColor(origin, direction, color, 0); traceColor(origin, direction, color, 0);
CgeVec3fClamp(color, 0.0f, 1.0f, color);
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[0] = powf(color[0], 1.0f / 2.2f);
color[1] = powf(color[1], 1.0f / 2.2f); color[1] = powf(color[1], 1.0f / 2.2f);