From 16f548f9634a571728c4e2e8d77379e82e24dc62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 6 Jun 2019 20:22:20 +0200 Subject: [PATCH] Add computeNormals --- programs/testSDL.c | 111 +++++++++++++------------------------------ small3dlib.h | 116 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 79 deletions(-) diff --git a/programs/testSDL.c b/programs/testSDL.c index 3366c7a..902f743 100644 --- a/programs/testSDL.c +++ b/programs/testSDL.c @@ -31,6 +31,8 @@ const S3L_Unit ver[] = { S3L_CUBE_VERTICES(S3L_FRACTIONS_PER_UNIT) }; const S3L_Index tri[] = { S3L_CUBE_TRIANGLES }; const S3L_Unit tex_coords[] = { S3L_CUBE_TEXCOORDS(16) }; +S3L_Unit houseNormals[HOUSE_VERTEX_COUNT * 3]; + S3L_Model3D models[2]; S3L_Scene scene; @@ -129,75 +131,8 @@ void houseTex(int32_t u, int32_t v, uint8_t *r, uint8_t *g, uint8_t *b) *b = houseTexture[index + 2]; } -int l0, l1, l2; -int previousTriangle = 255; - void drawPixel(S3L_PixelInfo *p) { - -S3L_Vec4 a,b,c,n,V; - -int tmpI = scene.models[p->modelIndex].triangles[p->triangleIndex * 3] * 3; - -a.x = scene.models[p->modelIndex].vertices[tmpI]; -tmpI++; -a.y = scene.models[p->modelIndex].vertices[tmpI]; -tmpI++; -a.z = scene.models[p->modelIndex].vertices[tmpI]; - -tmpI = scene.models[p->modelIndex].triangles[p->triangleIndex * 3 + 1] * 3; - -b.x = scene.models[p->modelIndex].vertices[tmpI]; -tmpI++; -b.y = scene.models[p->modelIndex].vertices[tmpI]; -tmpI++; -b.z = scene.models[p->modelIndex].vertices[tmpI]; - -tmpI = scene.models[p->modelIndex].triangles[p->triangleIndex * 3 + 2] * 3; - -c.x = scene.models[p->modelIndex].vertices[tmpI]; -tmpI++; -c.y = scene.models[p->modelIndex].vertices[tmpI]; -tmpI++; -c.z = scene.models[p->modelIndex].vertices[tmpI]; - -S3L_triangleNormal(a,b,c,&n); -/* -printf("--------\n"); -S3L_logVec4(a); -S3L_logVec4(b); -S3L_logVec4(c); -S3L_logVec4(n); -*/ -V.x = 10; -V.y = 10; -V.z = 10; - -S3L_normalizeVec3(&V); - -int16_t l = S3L_clamp(S3L_dotProductVec3(V,n) / 2,0,255); - -l &= 192; - -/* -setPixel(p->x,p->y, - S3L_clamp(128 + n.x / 4,0,255), - S3L_clamp(128 + n.y / 4,0,255), - S3L_clamp(128 + n.z / 4,0,255)); -*/ - -setPixel(p->x,p->y,l,l,l); - -return; - - if (p->triangleIndex != previousTriangle) - { - l0 = houseVertexLighting[houseTriangleIndices[p->triangleIndex * 3]]; - l1 = houseVertexLighting[houseTriangleIndices[p->triangleIndex * 3 + 1]]; - l2 = houseVertexLighting[houseTriangleIndices[p->triangleIndex * 3 + 2]]; - previousTriangle = p->triangleIndex; - } - if (p->x < 0 || p ->x >= S3L_RESOLUTION_X || p->y < 0 || p->y >= S3L_RESOLUTION_Y) { offScreenPixels++; @@ -256,23 +191,39 @@ if (p->modelIndex != 0) (v / ((float) S3L_FRACTIONS_PER_UNIT)) * HOUSE_TEXTURE_HEIGHT, &r,&g,&b); - uint8_t l = S3L_interpolateBarycentric(l0,l1,l2, - p->barycentric[0], - p->barycentric[1], - p->barycentric[2]); +S3L_Vec4 n0, n1, n2, n; - l = 255 - l; +n0.x = houseNormals[scene.models[p->modelIndex].triangles[p->triangleIndex * 3] * 3]; +n0.y = houseNormals[scene.models[p->modelIndex].triangles[p->triangleIndex * 3] * 3 + 1]; +n0.z = houseNormals[scene.models[p->modelIndex].triangles[p->triangleIndex * 3] * 3 + 2]; - l /= 2; +n1.x = houseNormals[scene.models[p->modelIndex].triangles[p->triangleIndex * 3 + 1] * 3]; +n1.y = houseNormals[scene.models[p->modelIndex].triangles[p->triangleIndex * 3 + 1] * 3 + 1]; +n1.z = houseNormals[scene.models[p->modelIndex].triangles[p->triangleIndex * 3 + 1] * 3 + 2]; - int16_t clampTmp = r - l; - r = clampTmp >= 0 ? clampTmp : 0; +n2.x = houseNormals[scene.models[p->modelIndex].triangles[p->triangleIndex * 3 + 2] * 3]; +n2.y = houseNormals[scene.models[p->modelIndex].triangles[p->triangleIndex * 3 + 2] * 3 + 1]; +n2.z = houseNormals[scene.models[p->modelIndex].triangles[p->triangleIndex * 3 + 2] * 3 + 2]; - clampTmp = g - l; - g = clampTmp >= 0 ? clampTmp : 0; +n.x = S3L_interpolateBarycentric(n0.x,n1.x,n2.x,p->barycentric[0],p->barycentric[1],p->barycentric[2]); +n.y = S3L_interpolateBarycentric(n0.y,n1.y,n2.y,p->barycentric[0],p->barycentric[1],p->barycentric[2]); +n.z = S3L_interpolateBarycentric(n0.z,n1.z,n2.z,p->barycentric[0],p->barycentric[1],p->barycentric[2]); - clampTmp = b - l; - b = clampTmp >= 0 ? clampTmp : 0; +S3L_Vec4 V; + +V.x = 10; +V.y = 10; +V.z = 10; + +S3L_normalizeVec3(&V); + +int16_t l = 64 + S3L_clamp(S3L_dotProductVec3(n,V),-511,511) / 8; + +//setPixel(p->x,p->y,l,l,l); + +r = S3L_clamp(((int16_t) r) - l,0,255); +g = S3L_clamp(((int16_t) g) - l,0,255); +b = S3L_clamp(((int16_t) b) - l,0,255); setPixel(p->x,p->y,r,g,b); } @@ -360,6 +311,8 @@ void draw() printf("camera: "); S3L_logTransform3D(scene.camera.transform); fps = 0; + + S3L_computeModelNormals(scene.models[1],houseNormals,1); } } diff --git a/small3dlib.h b/small3dlib.h index e5cb308..b7af9fe 100644 --- a/small3dlib.h +++ b/small3dlib.h @@ -460,6 +460,16 @@ S3L_Unit S3L_sqrt(S3L_Unit value); void S3L_triangleNormal(S3L_Vec4 t0, S3L_Vec4 t1, S3L_Vec4 t2, S3L_Vec4 *n); +/** Computes a normalized normal for every vertex of given model (this is + relatively slow and SHOUDN'T be done each frame). The dst array must have a + sufficient size preallocated! The size is: number of model vertices * 3 * + sizeof(S3L_Unit). Note that for advanced allowing sharp edges it is not + sufficient to have per-vertex normals, but must be per-triangle. This + function doesn't support this. */ + +void S3L_computeModelNormals(S3L_Model3D model, S3L_Unit *dst, + int8_t transformNormals); + /** Interpolated between two values, v1 and v2, in the same ratio as t is to tMax. Does NOT prevent zero division. */ static inline S3L_Unit S3L_interpolate( @@ -790,6 +800,112 @@ void S3L_triangleNormal(S3L_Vec4 t0, S3L_Vec4 t1, S3L_Vec4 t2, S3L_normalizeVec3(n); } +void S3L_computeModelNormals(S3L_Model3D model, S3L_Unit *dst, + int8_t transformNormals) +{ + S3L_Index vPos = 0; + + S3L_Vec4 n; + + n.w = 0; + + #define MAX_NORMALS 6 + + S3L_Vec4 ns[MAX_NORMALS]; + S3L_Index normalCount; + + for (S3L_Index i = 0; i < model.vertexCount; ++i) + { + normalCount = 0; + + for (S3L_Index j = 0; j < model.triangleCount * 3; j += 3) + { + if ( + (model.triangles[j] == i) || + (model.triangles[j + 1] == i) || + (model.triangles[j + 2] == i)) + { + S3L_Vec4 t0, t1, t2; + S3L_Index vIndex; + + #define getVertex(n)\ + vIndex = model.triangles[j + n] * 3;\ + t##n.x = model.vertices[vIndex];\ + vIndex++;\ + t##n.y = model.vertices[vIndex];\ + vIndex++;\ + t##n.z = model.vertices[vIndex]; + + getVertex(0) + getVertex(1) + getVertex(2) + + #undef getVertex + + S3L_triangleNormal(t0,t1,t2,&(ns[normalCount])); + + normalCount++; + + if (normalCount >= MAX_NORMALS) + break; + } + } + + n.x = S3L_FRACTIONS_PER_UNIT; + n.y = 0; + n.z = 0; + + if (normalCount != 0) + { + // compute average + + n.x = 0; + + for (uint8_t i = 0; i < MAX_NORMALS; ++i) + { + n.x += ns[i].x; + n.y += ns[i].y; + n.z += ns[i].z; + } + + n.x /= normalCount; + n.y /= normalCount; + n.z /= normalCount; + + S3L_normalizeVec3(&n); + } + + dst[vPos] = n.x; + vPos++; + + dst[vPos] = n.y; + vPos++; + + dst[vPos] = n.z; + vPos++; + } + + #undef MAX_NORMALS + + S3L_Mat4 m; + + S3L_makeWorldMatrix(model.transform,&m); + + if (transformNormals) + for (S3L_Index i = 0; i < model.vertexCount * 3; i += 3) + { + n.x = dst[i]; + n.y = dst[i + 1]; + n.z = dst[i + 2]; + + S3L_vec4Xmat4(&n,&m); + + dst[i] = n.x; + dst[i + 1] = n.y; + dst[i + 2] = n.z; + } +} + void S3L_vec4Xmat4(S3L_Vec4 *v, S3L_Mat4 *m) { S3L_Vec4 vBackup;