Created
March 31, 2023 20:35
-
-
Save harieamjari/6dfda39ca22852363aae51d5b773e3fd to your computer and use it in GitHub Desktop.
render obj file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import png | |
from ctypes import * | |
""" | |
struct vec3D { | |
double x, y, z; | |
}; | |
/* A triangle is composed of 3D vertices */ | |
struct triangle3D { | |
struct vec3D *vertex[3]; | |
}; | |
/* An object is composed of triangles */ | |
struct object3D { | |
int vertices; | |
struct vec3D **vertex; | |
int faces; | |
struct triangle3D *face; | |
}; | |
""" | |
class vec3D(Structure): | |
_fields_ = [("x", c_double), ("y", c_double), ("z", c_double)] | |
class triangle3D(Structure): | |
_fields_ = [("nda", c_int),("ndb", c_int),("ndz", c_int), ("vertex", POINTER(vec3D)*3)] | |
class object3D(Structure): | |
_fields_ = [("vertices", c_int), | |
("vertex", POINTER(POINTER(vec3D))), | |
("faces", c_int), | |
("face", POINTER(triangle3D))] | |
""" | |
As a C programmer, I feel like I would have saved time writing a whole parser | |
for the obj format in C than trying to demystify Python's syntax. | |
""" | |
def load_obj(obj_name): | |
with open(obj_name, 'r') as file: | |
countv = 0; | |
countf = 0; | |
for line in file: | |
words = [word for word in line.split()] | |
if not words: | |
continue | |
if words[0] == "v": | |
countv+=1 | |
continue | |
if words[0] == "f": | |
countf+=1 | |
continue | |
file.seek(0) | |
#an array of pointer vertex | |
vertex = (POINTER(vec3D)*countv)() | |
#an array of face | |
face = (triangle3D*countf)() | |
vertices = countv; faces = countf; | |
countv = 0; countf = 0; | |
for line in file: | |
words = [word for word in line.split()] | |
if not words: | |
continue | |
if words[0] == "v": | |
x = words[1]; y = words[2]; z = words[3]; | |
vertex[countv] = pointer(vec3D(float(x),float(y),float(z))) | |
#print("x y z ",float(x),float(y),float(z)) | |
countv+=1 | |
continue | |
if words[0] == "f": | |
v1 = words[1].split('/'); v1 = int(v1[0]) | |
v2 = words[2].split('/'); v2 = int(v2[0]) | |
v3 = words[3].split('/'); v3 = int(v3[0]) | |
vert3 = (POINTER(vec3D)*3)() | |
vert3[0].contents = vertex[v1-1].contents | |
vert3[1].contents = vertex[v2-1].contents | |
vert3[2].contents = vertex[v3-1].contents | |
#print("vertices: ", vertex[v1-1].contents, vertex[v2-1].contents, vertex[v3-1].x) | |
face[countf] = triangle3D(v1-1,v2-1,v3-1,vert3); | |
#print(type(vert3), vert3) | |
#face[countf] = triangle3D(pointer(pointer(vertex[v1-1]))) | |
countf+=1 | |
continue | |
print("vertex ", countv) | |
print("faces ", countf) | |
obj_loaded = object3D(vertices, vertex, faces, face) | |
return obj_loaded | |
dll = CDLL("./render.so") | |
print(type(dll)) | |
img_width = 256; img_height = 256; img_channels = 4; #rgba | |
img_buf = create_string_buffer(img_height*img_width * img_channels); | |
dll.render.argtypes = [c_void_p, c_int, c_int, c_int, POINTER(object3D)]; | |
obj_loaded = load_obj("prat.obj") | |
for i in range(256): | |
dll.render(byref(img_buf), img_width, img_height, i, byref(obj_loaded)); | |
f = open("box-"+str(i)+".png", 'wb'); | |
w = png.Writer(width=img_width, height=img_height,greyscale=False, alpha=True, bitdepth=8); | |
w.write_array(f, img_buf); | |
f.close(); | |
print("box-"+str(i)+".png done"); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> // so I wont have to do error handling | |
#include <math.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
//#define DEBUG | |
/* this may be a vertex or a vector */ | |
struct vec3D { | |
double x, y, z; | |
}; | |
/* A triangle is composed of 3D vertices */ | |
struct triangle3D { | |
// struct vec3D vertex[3]; | |
int nda, ndb, ndc; | |
struct vec3D *vertex[3]; | |
}; | |
/* An object is composed of triangles */ | |
struct object3D { | |
int vertices; | |
struct vec3D **vertex; | |
int faces; | |
struct triangle3D *face; | |
}; | |
/* A scene is composed of objects */ | |
struct scene3D { | |
int objects; | |
struct object3D *object; | |
}; | |
static double dot_product(const struct vec3D a, const struct vec3D b) { | |
return a.x * b.x + a.y * b.y + a.z * b.z; | |
} | |
static double magnitude(const struct vec3D a) { | |
return sqrt(dot_product(a, a)); | |
} | |
static struct triangle3D *allocate_triangle(size_t n) { | |
struct triangle3D *ret = malloc(sizeof(struct triangle3D) * n); | |
for (size_t i = 0; i < n; i++) { | |
ret[i].vertex[0] = malloc(sizeof(struct vec3D)); | |
ret[i].vertex[1] = malloc(sizeof(struct vec3D)); | |
ret[i].vertex[2] = malloc(sizeof(struct vec3D)); | |
} | |
return ret; | |
}; | |
static void free_object(struct object3D object) { | |
for (int i = 0; i < object.vertices; i++) { | |
free(object.vertex[i]); | |
} | |
free(object.vertex); | |
free(object.face); | |
} | |
static struct object3D copy_object(struct object3D ctx) { | |
int nb_vertex = ctx.vertices; | |
struct vec3D **vertex = malloc(sizeof(struct vec3D *) * nb_vertex); | |
for (int i = 0; i < nb_vertex; i++) { | |
vertex[i] = malloc(sizeof(struct vec3D)); | |
vertex[i]->x = ctx.vertex[i]->x; | |
vertex[i]->y = ctx.vertex[i]->y; | |
vertex[i]->z = ctx.vertex[i]->z; | |
} | |
int nb_faces = ctx.faces; | |
struct triangle3D *face = malloc(sizeof(struct triangle3D) * nb_faces); | |
for (int i = 0; i < nb_faces; i++) { | |
int nda = ctx.face[i].nda, ndb = ctx.face[i].ndb, ndc = ctx.face[i].ndc; | |
face[i].nda = nda; | |
face[i].ndb = ndb; | |
face[i].ndc = ndc; | |
face[i].vertex[0] = vertex[nda]; | |
face[i].vertex[1] = vertex[ndb]; | |
face[i].vertex[2] = vertex[ndc]; | |
} | |
return (struct object3D){.vertices = ctx.vertices, | |
.vertex = vertex, | |
.faces = ctx.faces, | |
.face = face}; | |
} | |
static struct object3D translate(const struct object3D ctx, const double dx, | |
const double dy, const double dz) { | |
struct vec3D **vertex = ctx.vertex; | |
for (int i = 0; i < ctx.vertices; i++) { | |
vertex[i]->x += dx; | |
vertex[i]->y += dy; | |
vertex[i]->z += dz; | |
} | |
return (struct object3D){.vertices = ctx.vertices, | |
.vertex = ctx.vertex, | |
.faces = ctx.faces, | |
.face = ctx.face}; | |
} | |
static struct object3D dilate(const struct object3D ctx, const double dx, | |
const double dy, const double dz) { | |
for (int i = 0; i < ctx.vertices; i++) { | |
ctx.vertex[i]->x *= dx; | |
ctx.vertex[i]->y *= dy; | |
ctx.vertex[i]->z *= dz; | |
} | |
return (struct object3D){.vertices = ctx.vertices, | |
.vertex = ctx.vertex, | |
.faces = ctx.faces, | |
.face = ctx.face}; | |
} | |
static struct object3D rotate(const struct object3D ctx, const double dx, | |
const double dy, const double dz) { | |
struct vec3D **vertex = ctx.vertex; | |
for (int i = 0; i < ctx.vertices; i++) { | |
double vix, viy, viz; | |
vix = cos(dz) * cos(dy) * vertex[i]->x + | |
(cos(dz) * sin(dy) * sin(dx) - sin(dz) * cos(dx)) * vertex[i]->y + | |
(cos(dz) * sin(dy) * cos(dx) + sin(dz) * sin(dx)) * vertex[i]->z; | |
viy = sin(dz) * cos(dy) * vertex[i]->x + | |
(sin(dz) * sin(dy) * sin(dx) + cos(dz) * cos(dx)) * vertex[i]->y + | |
(sin(dz) * sin(dy) * cos(dx) - cos(dz) * sin(dx)) * vertex[i]->z; | |
viz = -sin(dy) * vertex[i]->x + cos(dy) * sin(dx) * vertex[i]->y + | |
cos(dy) * cos(dx) * vertex[i]->z; | |
vertex[i]->x = vix; | |
vertex[i]->y = viy; | |
vertex[i]->z = viz; | |
} | |
return (struct object3D){.vertices = ctx.vertices, | |
.vertex = ctx.vertex, | |
.faces = ctx.faces, | |
.face = ctx.face}; | |
} | |
static struct vec3D cross_product(const struct vec3D a, const struct vec3D b) { | |
/* designated initializers */ | |
return (struct vec3D){.x = a.y * b.z - a.z * b.y, | |
.y = a.z * b.x - a.x * b.z, | |
.z = a.x * b.y - a.y * b.x}; | |
} | |
static struct vec3D normalize(const struct vec3D ctx) { | |
double mg = magnitude(ctx); | |
return (struct vec3D){.x = ctx.x / mg, .y = ctx.y / mg, .z = ctx.z / mg}; | |
} | |
void render(void *img_buf, int width, int height, int ndx, | |
struct object3D *obj) { | |
double Pz = 150.0; | |
// struct vec3D v1 = {20.0, 50.0, -20.0}; | |
// struct vec3D v2 = {-20.0, 50.0, -20.0}; | |
// struct vec3D v3 = {-20.0, -50.0, -20.0}; | |
// struct vec3D v4 = {20.0, -50.0, -20.0}; | |
// | |
// struct vec3D v5 = {20.0, 50.0, 20.0}; | |
// struct vec3D v6 = {-20.0, 50.0, 20.0}; | |
// struct vec3D v7 = {-20.0, -50.0, 20.0}; | |
// struct vec3D v8 = {20.0, -50.0, 20.0}; | |
// struct vec3D **vertex = malloc(8*sizeof(struct vec3D *)); | |
// vertex[0] = &v1; | |
// vertex[1] = &v2; | |
// vertex[2] = &v3; | |
// vertex[3] = &v4; | |
// vertex[4] = &v5; | |
// vertex[5] = &v6; | |
// vertex[6] = &v7; | |
// vertex[7] = &v8; | |
// | |
// | |
// struct triangle3D face[8] = { | |
// [0].vertex = {[0] = &v3, [1] = &v2, [2] = &v1}, | |
// [1].vertex = {[0] = &v1, [1] = &v4, [2] = &v3}, | |
// [2].vertex = {[0] = &v5, [1] = &v6, [2] = &v7}, | |
// [3].vertex = {[0] = &v7, [1] = &v8, [2] = &v5}, | |
// [4].vertex = {[0] = &v4, [1] = &v1, [2] = &v5}, | |
// [5].vertex = {[0] = &v5, [1] = &v8, [2] = &v4}, | |
// [6].vertex = {[0] = &v7, [1] = &v6, [2] = &v2}, | |
// [7].vertex = {[0] = &v2, [1] = &v3, [2] = &v7}, | |
// }; | |
struct object3D box = copy_object( | |
*obj); // {.vertices=8, .vertex=vertex, .faces = 8, .face = face}; | |
#ifdef DEBUG | |
printf("vertices %d faces %d\n", box.vertices, box.faces); | |
for (int i = 0; i < box.vertices; i++) | |
printf("v%d %f %f %f\n", i, box.vertex[i]->x, box.vertex[i]->y, | |
box.vertex[i]->z); | |
for (int i = 0; i < box.faces; i++) { | |
printf("f%d %f %f %f", i, box.face[i].vertex[0]->x, | |
box.face[i].vertex[0]->y, box.face[i].vertex[0]->z); | |
printf(" %f %f %f", box.face[i].vertex[1]->x, box.face[i].vertex[1]->y, | |
box.face[i].vertex[1]->z); | |
printf(" %f %f %f\n", box.face[i].vertex[2]->x, box.face[i].vertex[2]->y, | |
box.face[i].vertex[2]->z); | |
} | |
printf("b %f %f %f\n", box.vertex[1]->x, box.vertex[1]->y, box.vertex[1]->z); | |
printf("b %f %f %f\n", box.vertex[2]->x, box.vertex[2]->y, box.vertex[2]->z); | |
#endif | |
/* RANDOM SPEED */ | |
// dilate(box, 20, 50, 20); | |
struct object3D rotbox = | |
rotate(box, (double)ndx * 3.0 / 180.0, M_PI * (double)ndx * 4.0 / 180.0, | |
(double)ndx * 7.0 / 180.0); | |
struct object3D trbox = translate(box, 0.0, 0.0, 40.0); | |
// free_object(rotbox); | |
#ifdef DEBUG | |
printf("%f %f %f\n", box.vertex[0]->x, box.vertex[0]->y, box.vertex[0]->z); | |
printf("%f %f %f\n", box.vertex[1]->x, box.vertex[1]->y, box.vertex[1]->z); | |
printf("%f %f %f\n", box.vertex[2]->x, box.vertex[2]->y, box.vertex[2]->z); | |
#endif | |
struct vec3D light_source = { | |
.x = 0.0, .y = 0.0, .z = -1.0}; /* magnitude = 1 */ | |
for (int y = 0; y < height; y++) { | |
uint8_t *line = img_buf + (4 * (width * y)); | |
for (int x = 0; x < width; x++) { | |
double Px = x - (width / 2), Py = (height / 2) - y; | |
struct vec3D ray = {Px, Py, Pz}; | |
double _magnitude = magnitude(ray); | |
struct vec3D normalized_ray = {ray.x / _magnitude, ray.y / _magnitude, | |
ray.z / _magnitude}; | |
struct vec3D BmA; | |
struct vec3D CmA; | |
struct vec3D pvec; | |
double illumination, um, vm; | |
double det, t = INFINITY; /* portable? */ | |
int intersect = 0; | |
/* check if all triangle intersects */ | |
for (int triangle = 0; triangle < trbox.faces; triangle++) { | |
BmA = (struct vec3D){.x = trbox.face[triangle].vertex[1]->x - | |
trbox.face[triangle].vertex[0]->x, | |
.y = trbox.face[triangle].vertex[1]->y - | |
trbox.face[triangle].vertex[0]->y, | |
.z = trbox.face[triangle].vertex[1]->z - | |
trbox.face[triangle].vertex[0]->z}; | |
CmA = (struct vec3D){.x = trbox.face[triangle].vertex[2]->x - | |
trbox.face[triangle].vertex[0]->x, | |
.y = trbox.face[triangle].vertex[2]->y - | |
trbox.face[triangle].vertex[0]->y, | |
.z = trbox.face[triangle].vertex[2]->z - | |
trbox.face[triangle].vertex[0]->z}; | |
pvec = (struct vec3D)cross_product(ray, CmA); | |
double illum = | |
dot_product(normalize(cross_product(BmA, CmA)), light_source); | |
det = dot_product(BmA, pvec); | |
double u = | |
dot_product( | |
pvec, (struct vec3D){.x = -trbox.face[triangle].vertex[0]->x, | |
.y = -trbox.face[triangle].vertex[0]->y, | |
.z = -trbox.face[triangle].vertex[0]->z}) / | |
det; | |
/* return background color */ | |
if (u < 0.0 || u > 1.0) { | |
line[(x * 4) + 0] = 0xA0; | |
line[(x * 4) + 1] = 0xA0; | |
line[(x * 4) + 2] = 0xA0; | |
line[(x * 4) + 3] = 0xFF; | |
continue; | |
} | |
double v = | |
dot_product( | |
cross_product( | |
(struct vec3D){.x = -trbox.face[triangle].vertex[0]->x, | |
.y = -trbox.face[triangle].vertex[0]->y, | |
.z = -trbox.face[triangle].vertex[0]->z}, | |
BmA), | |
ray) / | |
det; | |
if (v < 0.0 || u + v > 1.0) { | |
line[(x * 4) + 0] = 0xA0; | |
line[(x * 4) + 1] = 0xA0; | |
line[(x * 4) + 2] = 0xA0; | |
line[(x * 4) + 3] = 0xFF; | |
continue; | |
} | |
double temp = | |
dot_product(CmA, cross_product( | |
(struct vec3D){ | |
.x = -trbox.face[triangle].vertex[0]->x, | |
.y = -trbox.face[triangle].vertex[0]->y, | |
.z = -trbox.face[triangle].vertex[0]->z}, | |
BmA)) / | |
det; /* | |
double mm = magnitude((struct vec3D){normalized_ray.x*temp, | |
normalized_ray.y*temp, normalized_ray.z*temp});*/ | |
if (t > temp) { | |
illumination = illum; | |
t = temp; | |
intersect = 1; | |
vm = v; | |
um = u; | |
} | |
} | |
// free_object(trbox); | |
if (!intersect) { | |
line[(x * 4) + 0] = 0xA0; | |
line[(x * 4) + 1] = 0xA0; | |
line[(x * 4) + 2] = 0xA0; | |
line[(x * 4) + 3] = 0xFF; | |
continue; | |
} | |
line[(x * 4) + 0] = (unsigned char)(((illumination + 1.0) / 2.0) * 255.0); | |
line[(x * 4) + 1] = (unsigned char)(((illumination + 1.0) / 2.0) * 255.0); | |
line[(x * 4) + 2] = (unsigned char)(((illumination + 1.0) / 2.0) * 255.0); | |
// line[(x * 4) + 0] = (unsigned char)(255.0*powf(um*((illumination | |
// + 1.0) / 2.0), 0.2)); line[(x * 4) + 1] = (unsigned | |
// char)(255.0*powf(vm*((illumination + 1.0) / 2.0), 0.2)); line[(x * | |
// 4) + 2] = (unsigned char)(255.0*powf((1-um-vm) *((illumination | |
// + 1.0) / 2.0), 0.2)); printf("u %f v %f\n", um, vm); | |
line[(x * 4) + 3] = 0xFF; | |
} | |
} | |
free_object(box); | |
// return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment