TEXTURE *material_map(const Vector3d& EPoint, const TEXTURE *Texture) { int reg_number = -1; int Material_Number; DBL xcoor = 0.0, ycoor = 0.0; RGBFTColour colour; /* * Now we have transformed x, y, z we use image mapping routine to determine * texture index. */ if(map_pos(EPoint, Texture->pattern.get(), &xcoor, &ycoor)) Material_Number = 0; else { if (const ImagePatternImpl *pattern = dynamic_cast<ImagePatternImpl*>(Texture->pattern.get())) image_colour_at(pattern->pImage, xcoor, ycoor, colour, ®_number); // TODO ALPHA - we should decide whether we prefer premultiplied or non-premultiplied alpha else POV_PATTERN_ASSERT(false); if(reg_number == -1) Material_Number = (int)(colour.red() * 255.0); else Material_Number = reg_number; } if(Material_Number > Texture->Materials.size()) Material_Number %= Texture->Materials.size(); return Texture->Materials[Material_Number % Texture->Materials.size()]; }
bool image_map(const Vector3d& EPoint, const PIGMENT *Pigment, TransColour& colour) { // TODO ALPHA - the caller does expect non-premultiplied data, but maybe he could profit from premultiplied data? int reg_number; DBL xcoor = 0.0, ycoor = 0.0; // If outside map coverage area, return clear if(map_pos(EPoint, Pigment->pattern.get(), &xcoor, &ycoor)) { colour = ToTransColour(RGBFTColour(1.0, 1.0, 1.0, 0.0, 1.0)); return false; } else { RGBFTColour rgbft; if (const ImagePatternImpl *pattern = dynamic_cast<ImagePatternImpl*>(Pigment->pattern.get())) image_colour_at(pattern->pImage, xcoor, ycoor, rgbft, ®_number, false); else POV_PATTERN_ASSERT(false); colour = ToTransColour(rgbft); return true; } }
static void quilted (const Vector3d& EPoint, const TNORMAL *Tnormal, Vector3d& normal) { Vector3d value; DBL t; value[X] = EPoint[X]-FLOOR(EPoint[X])-0.5; value[Y] = EPoint[Y]-FLOOR(EPoint[Y])-0.5; value[Z] = EPoint[Z]-FLOOR(EPoint[Z])-0.5; t = value.length(); const QuiltedPattern *pattern = dynamic_cast<QuiltedPattern*>(Tnormal->pattern.get()); POV_PATTERN_ASSERT(pattern); t = quilt_cubic(t, pattern->Control0, pattern->Control1); value *= t; normal += (DBL)Tnormal->Amount * value; }
static void facets (const Vector3d& EPoint, const TNORMAL *Tnormal, Vector3d& normal, TraceThreadData *Thread) { int i; int thisseed; DBL sum, minsum; Vector3d sv, tv, dv, t1, add, newnormal, pert; DBL scale; int UseSquare; int UseUnity; DBL Metric; const FacetsPattern *pattern = dynamic_cast<FacetsPattern*>(Tnormal->pattern.get()); POV_PATTERN_ASSERT(pattern); Vector3d *cv = Thread->Facets_Cube; Metric = pattern->facetsMetric; UseSquare = (Metric == 2 ); UseUnity = (Metric == 1 ); normal.normalize(); if (pattern->facetsCoords) { tv = EPoint; } else { tv = normal; } if (pattern->facetsSize < 1e-6) { scale = 1e6; } else { scale = 1. / pattern->facetsSize; } tv *= scale; /* * Check to see if the input point is in the same unit cube as the last * call to this function, to use cache of cubelets for speed. */ thisseed = PickInCube(tv, t1); if (thisseed != Thread->Facets_Last_Seed) { /* * No, not same unit cube. Calculate the random points for this new * cube and its 80 neighbours which differ in any axis by 1 or 2. * Why distance of 2? If there is 1 point in each cube, located * randomly, it is possible for the closest random point to be in the * cube 2 over, or the one two over and one up. It is NOT possible * for it to be two over and two up. Picture a 3x3x3 cube with 9 more * cubes glued onto each face. */ /* Now store a points for this cube and each of the 80 neighbour cubes. */ int cvc = 0; for (add[X] = -2.0; add[X] < 2.5; add[X] +=1.0) { for (add[Y] = -2.0; add[Y] < 2.5; add[Y] += 1.0) { for (add[Z] = -2.0; add[Z] < 2.5; add[Z] += 1.0) { /* For each cubelet in a 5x5 cube. */ if ((fabs(add[X])>1.5)+(fabs(add[Y])>1.5)+(fabs(add[Z])>1.5) <= 1.0) { /* Yes, it's within a 3d knight move away. */ sv = tv + add; PickInCube(sv, t1); cv[cvc] = t1; cvc++; } } } } Thread->Facets_Last_Seed = thisseed; Thread->Facets_CVC = cvc; } /* * Find the point with the shortest distance from the input point. */ dv = cv[0] - tv; if ( UseSquare ) { minsum = dv.lengthSqr(); } else if ( UseUnity ) { minsum = dv[X]+dv[Y]+dv[Z]; } else { minsum = pow(fabs(dv[X]), Metric)+ pow(fabs(dv[Y]), Metric)+ pow(fabs(dv[Z]), Metric); } newnormal = cv[0]; /* Loop for the 81 cubelets to find closest. */ for (i = 1; i < Thread->Facets_CVC; i++) { dv = cv[i] - tv; if ( UseSquare ) { sum = dv.lengthSqr(); } else { if ( UseUnity ) { sum = dv[X]+dv[Y]+dv[Z]; } else { sum = pow(fabs(dv[X]), Metric)+ pow(fabs(dv[Y]), Metric)+ pow(fabs(dv[Z]), Metric); } } if (sum < minsum) { minsum = sum; newnormal = cv[i]; } } if (pattern->facetsCoords) { DNoise( pert, newnormal ); sum = dot(pert, normal); newnormal = normal * sum; pert -= newnormal; normal += pattern->facetsCoords * pert; } else { normal = newnormal; } }
bool Compute_Pigment (TransColour& colour, const PIGMENT *Pigment, const Vector3d& EPoint, const Intersection *Intersect, const Ray *ray, TraceThreadData *Thread) { bool Colour_Found; Vector3d TPoint; DBL value; if (Thread->qualityFlags.quickColour && Pigment->Quick_Colour.IsValid()) { colour = Pigment->Quick_Colour; return (true); } if (Pigment->Type <= LAST_SPECIAL_PATTERN) { Colour_Found = true; switch (Pigment->Type) { case NO_PATTERN: POV_PATTERN_ASSERT(false); // should have been forced to PLAIN_PATTERN in Post_Pigment colour.Clear(); break; case PLAIN_PATTERN: colour = Pigment->colour; break; case AVERAGE_PATTERN: Warp_EPoint (TPoint, EPoint, Pigment); Do_Average_Pigments(colour, Pigment, TPoint, Intersect, ray, Thread); break; case UV_MAP_PATTERN: if(Intersect == NULL) throw POV_EXCEPTION_STRING("The 'uv_mapping' pattern cannot be used as part of a pigment function!"); Colour_Found = Pigment->Blend_Map->ComputeUVMapped(colour, Intersect, ray, Thread); break; case BITMAP_PATTERN: Warp_EPoint (TPoint, EPoint, Pigment); colour.Clear(); Colour_Found = image_map (TPoint, Pigment, colour); break; default: throw POV_EXCEPTION_STRING("Pigment type not yet implemented."); } return(Colour_Found); } /* NK 19 Nov 1999 added Warp_EPoint */ Warp_EPoint (TPoint, EPoint, Pigment); value = Evaluate_TPat (Pigment, TPoint, Intersect, ray, Thread); return Pigment->Blend_Map->Compute (colour, value, TPoint, Intersect, ray, Thread); }
void Post_Pigment(PIGMENT *Pigment, bool* pHasFilter) { bool hasFilter; if (Pigment == NULL) { throw POV_EXCEPTION_STRING("Missing pigment"); } if (Pigment->Flags & POST_DONE) { if ((pHasFilter != NULL) && (Pigment->Flags & HAS_FILTER)) *pHasFilter = true; return; } if (Pigment->Type == NO_PATTERN) { Pigment->Type = PLAIN_PATTERN; Pigment->colour.Clear(); ;// TODO MESSAGE Warning(150, "No pigment type given."); } Pigment->Flags |= POST_DONE; switch (Pigment->Type) { case NO_PATTERN: POV_PATTERN_ASSERT(false); // should have been forced to PLAIN_PATTERN by now break; case PLAIN_PATTERN: case BITMAP_PATTERN: break; default: if (Pigment->Blend_Map == NULL) { switch (Pigment->Type) { // NB: The const default blend maps are marked so that they will not be modified nor destroyed later. case AVERAGE_PATTERN: // TODO MESSAGE Error("Missing pigment_map in average pigment"); break; default: Pigment->Blend_Map = std::tr1::static_pointer_cast<GenericPigmentBlendMap, ColourBlendMap>( std::tr1::const_pointer_cast<ColourBlendMap, const ColourBlendMap>( Pigment->pattern->GetDefaultBlendMap())); break; } } break; } /* Now we test wether this pigment is opaque or not. [DB 8/94] */ hasFilter = false; if (!Pigment->colour.TransmittedColour().IsNearZero(EPSILON)) { hasFilter = true; } if ((Pigment->Type == BITMAP_PATTERN) && (dynamic_cast<ImagePattern*>(Pigment->pattern.get())->pImage != NULL)) { // bitmaps are transparent if they are used only once, or the image is not opaque if ((dynamic_cast<ImagePattern*>(Pigment->pattern.get())->pImage->Once_Flag) || !is_image_opaque(dynamic_cast<ImagePattern*>(Pigment->pattern.get())->pImage)) hasFilter = true; } GenericPigmentBlendMap* Map = Pigment->Blend_Map.get(); if (Map != NULL) { Map->Post(hasFilter); } if (hasFilter) { Pigment->Flags |= HAS_FILTER; if (pHasFilter != NULL) *pHasFilter = true; } }
void bump_map(const Vector3d& EPoint, const TNORMAL *Tnormal, Vector3d& normal) { DBL xcoor = 0.0, ycoor = 0.0; int index = -1, index2 = -1, index3 = -1; RGBFTColour colour1, colour2, colour3; Vector3d p1, p2, p3; Vector3d bump_normal; Vector3d xprime, yprime, zprime; DBL Length; DBL Amount = Tnormal->Amount; const ImageData *image; if (const ImagePatternImpl *pattern = dynamic_cast<ImagePatternImpl*>(Tnormal->pattern.get())) image = pattern->pImage; else POV_PATTERN_ASSERT(false); // going to have to change this // need to know if bump point is off of image for all 3 points if(map_pos(EPoint, Tnormal->pattern.get(), &xcoor, &ycoor)) return; else image_colour_at(image, xcoor, ycoor, colour1, &index); // TODO ALPHA - we should decide whether we prefer premultiplied or non-premultiplied alpha xcoor--; ycoor++; if(xcoor < 0.0) xcoor += (DBL)image->iwidth; else if(xcoor >= image->iwidth) xcoor -= (DBL)image->iwidth; if(ycoor < 0.0) ycoor += (DBL)image->iheight; else if(ycoor >= (DBL)image->iheight) ycoor -= (DBL)image->iheight; image_colour_at(image, xcoor, ycoor, colour2, &index2); // TODO ALPHA - we should decide whether we prefer premultiplied or non-premultiplied alpha xcoor += 2.0; if(xcoor < 0.0) xcoor += (DBL)image->iwidth; else if(xcoor >= image->iwidth) xcoor -= (DBL)image->iwidth; image_colour_at(image, xcoor, ycoor, colour3, &index3); // TODO ALPHA - we should decide whether we prefer premultiplied or non-premultiplied alpha if(image->Use || (index == -1) || (index2 == -1) || (index3 == -1)) { p1[X] = 0; p1[Y] = Amount * colour1.Greyscale(); p1[Z] = 0; p2[X] = -1; p2[Y] = Amount * colour2.Greyscale(); p2[Z] = 1; p3[X] = 1; p3[Y] = Amount * colour3.Greyscale(); p3[Z] = 1; } else { p1[X] = 0; p1[Y] = Amount * index; p1[Z] = 0; p2[X] = -1; p2[Y] = Amount * index2; p2[Z] = 1; p3[X] = 1; p3[Y] = Amount * index3; p3[Z] = 1; } // we have points 1,2,3 for a triangle now we need the surface normal for it xprime = p1 - p2; yprime = p3 - p2; bump_normal = cross(yprime, xprime).normalized(); yprime = normal; xprime = cross(yprime, Vector3d(0.0, 1.0, 0.0)); Length = xprime.length(); if(Length < EPSILON) { if(fabs(normal[Y] - 1.0) < EPSILON) { yprime = Vector3d(0.0, 1.0, 0.0); xprime = Vector3d(1.0, 0.0, 0.0); Length = 1.0; } else { yprime = Vector3d(0.0,-1.0, 0.0); xprime = Vector3d(1.0, 0.0, 0.0); Length = 1.0; } } xprime /= Length; zprime = cross(xprime, yprime).normalized(); xprime *= bump_normal[X]; yprime *= bump_normal[Y]; zprime *= bump_normal[Z]; normal = xprime + yprime - zprime; }