void renProjectTriangle(S_Renderer *pRenderer, S_Model *pModel, int i) { S_Coords aa, bb, cc; /* souradnice vrcholu po transformaci */ S_Coords naa, nbb, ncc; /* normaly ve vrcholech po transformaci */ S_Coords nn; /* normala trojuhelniku po transformaci */ int u1, v1, u2, v2, u3, v3; /* souradnice vrcholu po projekci do roviny obrazovky */ S_Triangle * triangle; IZG_ASSERT(pRenderer && pModel && i >= 0 && i < trivecSize(pModel->triangles)); /* z modelu si vytahneme trojuhelnik */ triangle = trivecGetPtr(pModel->triangles, i); /* transformace vrcholu matici model */ trTransformVertex(&aa, cvecGetPtr(pModel->vertices, triangle->v[0])); trTransformVertex(&bb, cvecGetPtr(pModel->vertices, triangle->v[1])); trTransformVertex(&cc, cvecGetPtr(pModel->vertices, triangle->v[2])); /* promitneme vrcholy trojuhelniku na obrazovku */ trProjectVertex(&u1, &v1, &aa); trProjectVertex(&u2, &v2, &bb); trProjectVertex(&u3, &v3, &cc); /* pro osvetlovaci model transformujeme take normaly ve vrcholech */ trTransformVector(&naa, cvecGetPtr(pModel->normals, triangle->v[0])); trTransformVector(&nbb, cvecGetPtr(pModel->normals, triangle->v[1])); trTransformVector(&ncc, cvecGetPtr(pModel->normals, triangle->v[2])); /* normalizace normal */ coordsNormalize(&naa); coordsNormalize(&nbb); coordsNormalize(&ncc); /* transformace normaly trojuhelniku matici model */ trTransformVector(&nn, cvecGetPtr(pModel->trinormals, triangle->n)); /* normalizace normaly */ coordsNormalize(&nn); /* je troj. privraceny ke kamere, tudiz viditelny? */ if( !renCalcVisibility(pRenderer, &aa, &nn) ) { /* odvracene troj. vubec nekreslime */ return; } /* rasterizace trojuhelniku */ renDrawTriangle(pRenderer, &aa, &bb, &cc, &naa, &nbb, &ncc, u1, v1, u2, v2, u3, v3 ); }
int renCalcVisibility(S_Renderer *pRenderer, const S_Coords *point, const S_Coords *normal) { S_Coords cvec; IZG_ASSERT(pRenderer && point && normal); /* vektor od kamery k plosce, pozice kamery je (0, 0, -camera_dist) */ cvec = makeCoords(point->x, point->y, point->z + pRenderer->camera_dist); coordsNormalize(&cvec); /* test zda je normala privracena * skalarni soucin vektoru od kamery a normaly */ return (normal->x * cvec.x + normal->y * cvec.y + normal->z * cvec.z > 0) ? 0 : 1; }
S_RGBA renLambertianReflectance(S_Renderer *pRenderer, const S_Coords *point, const S_Coords *normal) { S_Coords lvec; double diffuse, r, g, b; S_RGBA color; IZG_ASSERT(pRenderer && point && normal); /* vektor ke zdroji svetla */ lvec = makeCoords(pRenderer->light_position.x - point->x, pRenderer->light_position.y - point->y, pRenderer->light_position.z - point->z); coordsNormalize(&lvec); /* ambientni cast */ r = pRenderer->light_ambient.red * pRenderer->mat_ambient.red; g = pRenderer->light_ambient.green * pRenderer->mat_ambient.green; b = pRenderer->light_ambient.blue * pRenderer->mat_ambient.blue; /* difuzni cast */ diffuse = lvec.x * normal->x + lvec.y * normal->y + lvec.z * normal->z; if( diffuse > 0 ) { r += diffuse * pRenderer->light_diffuse.red * pRenderer->mat_diffuse.red; g += diffuse * pRenderer->light_diffuse.green * pRenderer->mat_diffuse.green; b += diffuse * pRenderer->light_diffuse.blue * pRenderer->mat_diffuse.blue; } /* saturace osvetleni*/ r = MIN(1, r); g = MIN(1, g); b = MIN(1, b); /* kreslici barva */ color.red = ROUND2BYTE(255 * r); color.green = ROUND2BYTE(255 * g); color.blue = ROUND2BYTE(255 * b); return color; }
void studrenProjectTriangle(S_Renderer *pRenderer, S_Model *pModel, int i, float n) { S_Coords aa, bb, cc; /* souradnice vrcholu po transformaci */ S_Coords naa, nbb, ncc; /* normaly ve vrcholech po transformaci */ S_Coords nn; /* normala trojuhelniku po transformaci */ int u1, v1, u2, v2, u3, v3; /* souradnice vrcholu po projekci do roviny obrazovky */ S_Triangle * triangle; int vertexOffset, normalOffset; /* offset pro vrcholy a normalove vektory trojuhelniku */ int i0, i1, i2, in; /* indexy vrcholu a normaly pro i-ty trojuhelnik n-teho snimku */ S_Coords aa1, bb1, cc1; /* souradnice vrcholu po transformaci */ S_Coords naa1, nbb1, ncc1; /* normaly ve vrcholech po transformaci */ S_Coords nn1; /* normala trojuhelniku po transformaci */ int vertexOffset1, normalOffset1; int i01, i11, i21, in1; /* indexy vrcholu a normaly pro i-ty trojuhelnik (n+1)-teho snimku */ IZG_ASSERT(pRenderer && pModel && i >= 0 && i < trivecSize(pModel->triangles) && n >= 0 ); int N = (int) floor(n); float xN = n - floor(n); /* z modelu si vytahneme i-ty trojuhelnik */ triangle = trivecGetPtr(pModel->triangles, i); /* ziskame offset pro vrcholy n-teho snimku */ vertexOffset = (N % pModel->frames) * pModel->verticesPerFrame; vertexOffset1 = ((N + 1) % pModel->frames) * pModel->verticesPerFrame; /* ziskame offset pro normaly trojuhelniku n-teho snimku */ normalOffset = (N % pModel->frames) * pModel->triangles->size; normalOffset1 = ((N + 1) % pModel->frames) * pModel->triangles->size; /* indexy vrcholu pro i-ty trojuhelnik n-teho snimku - pricteni offsetu */ i0 = triangle->v[ 0 ] + vertexOffset; i1 = triangle->v[ 1 ] + vertexOffset; i2 = triangle->v[ 2 ] + vertexOffset; i01 = triangle->v[ 0 ] + vertexOffset1; i11 = triangle->v[ 1 ] + vertexOffset1; i21 = triangle->v[ 2 ] + vertexOffset1; /* index normaloveho vektoru pro i-ty trojuhelnik n-teho snimku - pricteni offsetu */ in = triangle->n + normalOffset; in1 = triangle->n + normalOffset1; /* transformace vrcholu matici model */ trTransformVertex(&aa, cvecGetPtr(pModel->vertices, i0)); trTransformVertex(&bb, cvecGetPtr(pModel->vertices, i1)); trTransformVertex(&cc, cvecGetPtr(pModel->vertices, i2)); trTransformVertex(&aa1, cvecGetPtr(pModel->vertices, i01)); trTransformVertex(&bb1, cvecGetPtr(pModel->vertices, i11)); trTransformVertex(&cc1, cvecGetPtr(pModel->vertices, i21)); /* Interpolace vrcholu*/ aa.x = (1 - xN) * aa.x + xN * aa1.x; aa.y = (1 - xN) * aa.y + xN * aa1.y; aa.z = (1 - xN) * aa.z + xN * aa1.z; bb.x = (1 - xN) * bb.x + xN * bb1.x; bb.y = (1 - xN) * bb.y + xN * bb1.y; bb.z = (1 - xN) * bb.z + xN * bb1.z; cc.x = (1 - xN) * cc.x + xN * cc1.x; cc.y = (1 - xN) * cc.y + xN * cc1.y; cc.z = (1 - xN) * cc.z + xN * cc1.z; /* promitneme vrcholy trojuhelniku na obrazovku */ double h0 = trProjectVertex(&u1, &v1, &aa); double h1 = trProjectVertex(&u2, &v2, &bb); double h2 = trProjectVertex(&u3, &v3, &cc); /* pro osvetlovaci model transformujeme take normaly ve vrcholech */ trTransformVector(&naa, cvecGetPtr(pModel->normals, i0)); trTransformVector(&nbb, cvecGetPtr(pModel->normals, i1)); trTransformVector(&ncc, cvecGetPtr(pModel->normals, i2)); trTransformVector(&naa1, cvecGetPtr(pModel->normals, i01)); trTransformVector(&nbb1, cvecGetPtr(pModel->normals, i11)); trTransformVector(&ncc1, cvecGetPtr(pModel->normals, i21)); /* Interpolace normal */ naa.x = (1 - xN) * naa.x + xN * naa1.x; naa.y = (1 - xN) * naa.y + xN * naa1.y; naa.z = (1 - xN) * naa.z + xN * naa1.z; nbb.x = (1 - xN) * nbb.x + xN * nbb1.x; nbb.y = (1 - xN) * nbb.y + xN * nbb1.y; nbb.z = (1 - xN) * nbb.z + xN * nbb1.z; ncc.x = (1 - xN) * ncc.x + xN * ncc1.x; ncc.y = (1 - xN) * ncc.y + xN * ncc1.y; ncc.z = (1 - xN) * ncc.z + xN * ncc1.z; /* normalizace normal */ coordsNormalize(&naa); coordsNormalize(&nbb); coordsNormalize(&ncc); /* transformace normaly trojuhelniku matici model */ trTransformVector(&nn, cvecGetPtr(pModel->trinormals, in)); trTransformVector(&nn1, cvecGetPtr(pModel->trinormals, in1)); /* Interpolace normaly */ nn.x = (1 - xN) * nn.x + xN * nn1.x; nn.y = (1 - xN) * nn.y + xN * nn1.y; nn.z = (1 - xN) * nn.z + xN * nn1.z; /* normalizace normaly */ coordsNormalize(&nn); /* je troj. privraceny ke kamere, tudiz viditelny? */ if( !renCalcVisibility(pRenderer, &aa, &nn) ) { /* odvracene troj. vubec nekreslime */ return; } S_Triangle *texture = trivecGetPtr(pModel->triangles, i); /* rasterizace trojuhelniku */ studrenDrawTriangle(pRenderer, &aa, &bb, &cc, &naa, &nbb, &ncc, &triangle->t[0], &triangle->t[1], &triangle->t[2], u1, v1, u2, v2, u3, v3, h0, h1, h2 ); }
S_RGBA studrenPhongReflectance(S_Renderer *pRenderer, const S_Coords *point, const S_Coords *normal) { S_Coords lvec, eyevec, reflect; double diffuse, specular, reflect_scalar; double r, g, b; /* If = Ia + Id + Is */ S_RGBA color; IZG_ASSERT(pRenderer && point && normal); /* vektor ke zdroji svetla */ lvec = makeCoords(pRenderer->light_position.x - point->x, pRenderer->light_position.y - point->y, pRenderer->light_position.z - point->z); coordsNormalize(&lvec); /* vektor ke kamere */ eyevec = makeCoords(-point->x, -point->y, -pRenderer->camera_dist - point->z); coordsNormalize(&eyevec); /* ambientni cast -- Ia = (Al * Am) + (As * Am) */ /* As je barva sceny, muzeme zanedbat */ r = pRenderer->light_ambient.red * pRenderer->mat_ambient.red; g = pRenderer->light_ambient.green * pRenderer->mat_ambient.green; b = pRenderer->light_ambient.blue * pRenderer->mat_ambient.blue; /* difuzni cast -- Id = Dl * Dm * LambertTerm */ /* LambertTerm = dot(N, L) */ diffuse = lvec.x * normal->x + lvec.y * normal->y + lvec.z * normal->z; if( diffuse > 0 ) { r += diffuse * pRenderer->light_diffuse.red * pRenderer->mat_diffuse.red; g += diffuse * pRenderer->light_diffuse.green * pRenderer->mat_diffuse.green; b += diffuse * pRenderer->light_diffuse.blue * pRenderer->mat_diffuse.blue; } /* odraziva cast -- Is = Sm * Sl * pow( max( dot(R, E), 0.0), f ) */ /* R = reflect(-L, N) = 2 * dot(N, L) * N - L */ reflect_scalar = 2 * (normal->x * lvec.x + normal->y * lvec.y + normal->z * lvec.z); reflect.x = reflect_scalar * normal->x - lvec.x; reflect.y = reflect_scalar * normal->y - lvec.y; reflect.z = reflect_scalar * normal->z - lvec.z; specular = pow( MAX(reflect.x * eyevec.x + reflect.y * eyevec.y + reflect.z * eyevec.z, 0.0f), ((S_StudentRenderer*)pRenderer)->mat_shininess); r += specular * pRenderer->light_specular.red * pRenderer->mat_specular.red; g += specular * pRenderer->light_specular.green * pRenderer->mat_specular.green; b += specular * pRenderer->light_specular.blue * pRenderer->mat_specular.blue; /* saturace osvetleni*/ r = MIN(1, r); g = MIN(1, g); b = MIN(1, b); /* kreslici barva */ color.red = ROUND2BYTE(255 * r); color.green = ROUND2BYTE(255 * g); color.blue = ROUND2BYTE(255 * b); return color; }
void studrenDrawTriangle(S_Renderer *pRenderer, S_Coords *v1, S_Coords *v2, S_Coords *v3, S_Coords *n1, S_Coords *n2, S_Coords *n3, int x1, int y1, int x2, int y2, int x3, int y3 ) { // oblast trojuhelniku int min[2] = { MIN(x1, MIN(x2, x3)), MIN(y1, MIN(y2, y3)) }; int max[2] = { MAX(x1, MAX(x2, x3)), MAX(y1, MAX(y2, y3)) }; // oriznuti rozmerem okna min[0] = MAX(min[0], 0); min[1] = MAX(min[1], 0); max[0] = MIN(max[0], pRenderer->frame_w - 1); max[1] = MIN(max[1], pRenderer->frame_h - 1); // pro urceni hranic trojuhelnika pouzijeme pineduv algoritmus // hranova funkce je rovnice Ax + By + C = 0 // A,B je normalovy vektor primky, tzn. (-dy, dx) // C vyjadrime jako x1y2 - x2y1 int A[3] = { { y1 - y2 }, { y2 - y3 }, { y3 - y1 } }; int B[3] = { { x2 - x1 }, { x3 - x2 }, { x1 - x3 } }; int C[3] = { { x1 * y2 - x2 * y1 }, { x2 * y3 - x3 * y2 }, { x3 * y1 - x1 * y3 } }; // do hranove funkce dosadime protejsi vrcholy // provedeme normalizaci, aby kladna strana byla uvnitr oblasti int s0 = A[0] * x3 + B[0] * y3 + C[0]; int s1 = A[1] * x1 + B[1] * y1 + C[1]; int s2 = A[2] * x2 + B[2] * y2 + C[2]; if (s0 < 0) { A[0] *= -1; B[0] *= -1; C[0] *= -1; s0 *= -1; } if (s1 < 0) { A[1] *= -1; B[1] *= -1; C[1] *= -1; s1 *= -1; } if (s2 < 0) { A[2] *= -1; B[2] *= -1; C[2] *= -1; s2 *= -1; } double _s0 = 1.0f / (double)s0; double _s1 = 1.0f / (double)s1; double _s2 = 1.0f / (double)s2; /* gourandovo stinovani */ //S_RGBA color, b1, b2, b3; //b1 = pRenderer->calcReflectanceFunc(pRenderer, v1, n1); //b2 = pRenderer->calcReflectanceFunc(pRenderer, v2, n2); //b3 = pRenderer->calcReflectanceFunc(pRenderer, v3, n3); // vyplnovani pinedovim algoritmem for (int y = min[1]; y <= max[1]; ++y) { int e[3] = { A[0] * min[0] + B[0] * y + C[0], A[1] * min[0] + B[1] * y + C[1], A[2] * min[0] + B[2] * y + C[2] }; for (int x = min[0]; x <= max[0]; ++x) { // uvnitr trojuhelniku jsou cisla kladna if (e[0] >= 0 && e[1] >= 0 && e[2] >= 0) { // spocitame barycentricke koeficienty u,v,w double u = e[1] * _s1; double v = e[2] * _s2; double w = e[0] * _s0; // nemelo by nastat, protoze jsme uvnitr trojuhelniku //if (u < 0.0f || u > 1.0f) continue; //if (v < 0.0f || v > 1.0f) continue; //if (w < 0.0f || w > 1.0f) continue; // bod v trojuhelniku pred projekci ve 3D S_Coords pt = makeCoords( u * v1->x + v * v2->x + w * v3->x, u * v1->y + v * v2->y + w * v3->y, u * v1->z + v * v2->z + w * v3->z); /* gourandovo stinovani */ //double r = u * b1.red + v * b2.red + w * b3.red; //double g = u * b1.green + v * b2.green + w * b3.green; //double b = u * b1.blue + v * b2.blue + w * b3.blue; //double a = u * b1.alpha + v * b2.alpha + w * b3.alpha; //r = MIN(255.0f, MAX(r, 0.0f)); //g = MIN(255.0f, MAX(g, 0.0f)); //b = MIN(255.0f, MAX(b, 0.0f)); //a = MIN(255.0f, MAX(a, 0.0f)); //color.red = ROUND2BYTE(r); //color.green = ROUND2BYTE(g); //color.blue = ROUND2BYTE(b); //color.alpha = ROUND2BYTE(a); // vektor smerujici od bodu ke kamere S_Coords P_Cam = makeCoords( -pt.x, -pt.y, -pRenderer->camera_dist - pt.z); // vykreslime jen blizsi body double depth = sqrt(P_Cam.x * P_Cam.x + P_Cam.y * P_Cam.y + P_Cam.z * P_Cam.z); if (depth <= DEPTH(pRenderer, x, y)) { // normala bodu S_Coords n = makeCoords( u * n1->x + v * n2->x + w * n3->x, u * n1->y + v * n2->y + w * n3->y, u * n1->z + v * n2->z + w * n3->z); coordsNormalize(&n); S_RGBA color; color = pRenderer->calcReflectanceFunc(pRenderer, &pt, &n); /* vybarvi objekt normalou */ //color.red = ROUND2BYTE(255.0f * (n.x / 2.0f + 0.5f)); //color.green = ROUND2BYTE(255.0f * (n.y / 2.0f + 0.5f)); //color.blue = ROUND2BYTE(255.0f * (-n.z / 2.0f + 0.5f)); //color.alpha = 255; DEPTH(pRenderer, x, y) = depth; PIXEL(pRenderer, x, y) = color; } } // Ei(x+1,y) = Ei(x,y) + dy e[0] += A[0]; e[1] += A[1]; e[2] += A[2]; } } }