// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 /********************************************************************** *< FILE: shaveVrayStaticTriVoxelPrim.cpp -- iplementation file DESCRIPTION: Static (non motion blurred) instanced hair voxel primitive CREATED BY: Vladimir Dubovoy HISTORY: created 12-05-2010 *> **********************************************************************/ #include "assert.h" #include "shaveVrayStaticTriVoxelPrim.h" #include "shaveVrayInstanceI.h" #include "misc_ray.h" shaveVrayStaticTriVoxelPrim::shaveVrayStaticTriVoxelPrim( IHairVoxel* vox, VR::VRayCore *vray, shaveVrayInstanceI *inst): shaveVrayTriVoxelPrim(vox,vray,inst) { _firstid() = -1; _tris() = NULL; //if(shdata()) //{ // ((shaveVrayTriShadeData*)shdata())->init(inst->GetItm0()); //} } shaveVrayStaticTriVoxelPrim::~shaveVrayStaticTriVoxelPrim() { } /* | from StaticPrimitive */ void shaveVrayStaticTriVoxelPrim::getBBox (VR::StaticBox &bbox) { //DebugPrint("PRIM> shaveVrayStaticTriVoxelPrim::getBBox "); if(voxel()) { VERT pmin; VERT pmax; voxel()->GetBbox(pmin,pmax); bbox.pmin.x = pmin.x; bbox.pmin.y = pmin.y; bbox.pmin.z = pmin.z; bbox.pmax.x = pmax.x; bbox.pmax.y = pmax.y; bbox.pmax.z = pmax.z; /*DebugPrint("[%f %f %f][%f %f %f]\n", bbox.pmin.x, bbox.pmin.y, bbox.pmin.z, bbox.pmax.x, bbox.pmax.y, bbox.pmax.z);*/ VR::Vector scnoffs = VR::toVector(sceneOffset()); bbox.pmin -= scnoffs; bbox.pmax -= scnoffs; } } /* | from StaticPrimitive */ bool shaveVrayStaticTriVoxelPrim::splittable () { //DebugPrint("PRIM> shaveVrayStaticTriVoxelPrim::splitable\n"); return true; } /* | from StaticPrimitive */ void shaveVrayStaticTriVoxelPrim::split (int dim, VR::real middle, VR::StaticBox &bLeft, VR::StaticBox &bRight) { //DebugPrint("PRIM> shaveVrayStaticTriVoxelPrim::split [%i %f]\n",dim,middle); VR::StaticBox bbox; getBBox(bbox); bbox.split(dim, middle, bLeft, bRight); } /* | from StaticPrimitive */ int shaveVrayStaticTriVoxelPrim::expandable() { return true; } /* | from StaticPrimitive */ int shaveVrayStaticTriVoxelPrim::expand (VR::DynamicRaycaster< VR::StaticBox > *raycaster, int threadIndex) { const HairType& hair = voxel()->GetHair(); int numFaces = hair.GetNumFaces(); int numVerts = hair.GetNumVerts(); if(numFaces == 0) return 0; if(firstid() == -1) _firstid() = raycaster->getNewRenderIDArray(numFaces); _normals().resize(numVerts); for(int i = 0; i < numVerts; i++) { _normal(i) = VR::Vector(0.0f,0.0f,0.0f); } VR::Vector scnoffs = VR::toVector(sceneOffset()); _tris() = new VR::StaticTriangle[numFaces]; for(int i = 0; i < numFaces; i++) { int fs; int fe; int k = 0; //int k = 2; hair.GetFace(i,fs,fe); int df = fe - fs; //we expect triangular mesh if(df != 3) { LOGMSGI("PRIM", "triangular face is expected, vertex count:",df); continue; } for(int j = fs; j < fe; j++) { int vert_idx = hair.GetFaceVert(j); hair.GetVert(vert_idx,_tri(i).p[k].x,_tri(i).p[k].y,_tri(i).p[k].z); _tri(i).p[k] -= scnoffs; k++; //k--; } raycaster->insertPrimitive(threadIndex, &_tri(i), static_cast(this), i + firstid()); // pre-compute normals int i0 = hair.GetFaceVert(fs); int i1 = hair.GetFaceVert(fs+1); int i2 = hair.GetFaceVert(fs+2); VR::Vector v0; VR::Vector v1; VR::Vector v2; hair.GetVert(i0,v0.x,v0.y,v0.z); hair.GetVert(i1,v1.x,v1.y,v1.z); hair.GetVert(i2,v2.x,v2.y,v2.z); VR::Vector e0 = v1-v0; VR::Vector e1 = v2-v0; VR::Vector fn = -normalize(e0^e1); _normal(i0) += fn; _normal(i1) += fn; _normal(i2) += fn; } for(int i = 0; i < numVerts; i++) { _normal(i) = normalize(normal(i)); } #ifdef _DEBUG #ifdef WIN32 assert(_CrtCheckMemory()); #endif #endif return numFaces*sizeof(VR::StaticTriangle); } /* | from StaticPrimitive */ int shaveVrayStaticTriVoxelPrim::collapse (VR::DynamicRaycaster< VR::StaticBox > *raycaster, int threadIndex) { // printf("PRIM> shaveVrayStaticVoxelPrim::collapse\n");fflush(stdout); const HairType& hair = voxel()->GetHair(); int numFaces = hair.GetNumFaces(); if(numFaces == 0) return 0; if(tris()) { for (int i=0; i < numFaces; i++) raycaster->removePrimitive(threadIndex, &_tri(i)); delete[] tris(); _tris() = NULL; } return numFaces*sizeof(VR::StaticTriangle); } /* | from GeometryGenerator */ //VR::Vector shaveVrayStaticTriVoxelPrim::getGNormal(VR::RSRay &rsray) //{ // return rsray.is.primitive->getGNormal(rsray); //} /* | from GeometryGenerator */ //VR::Vector shaveVrayStaticTriVoxelPrim::getNormal(VR::RSRay &rsray) //{ // return rsray.is.primitive->getNormal(rsray); //} /* | from GeometryGenerator */ void shaveVrayStaticTriVoxelPrim::setIntersectionData(VR::RSRay &rsray, void *isd) { VR::IntersectionData &isData=*((VR::IntersectionData*) isd); VR::RSIntersection &is=rsray.is; assert(PRIM_TYPE_STATIC_TRIANGLE == is.primitive->type()); shaveVrayStaticTriVoxelPrim* owner =(shaveVrayStaticTriVoxelPrim*) (is.primitive->owner); assert(owner == this); VR::StaticTriangle* T = (VR::StaticTriangle*)is.primitive; const HairType& hair = voxel()->GetHair(); isData.primitive=is.primitive; isData.skipTag =is.skipTag; isData.faceIndex= T->ownerIndex - firstid(); #ifdef OWN_SHADEABLE_FOR_TRI isData.sb = shade(); #else isData.sb = shdata(); #endif isData.sd = shdata(); isData.si = NULL; //shinst(); isData.volume=NULL; isData.bary=VR::toShadeVec(is.bary); isData.wpointCoeff=is.t; isData.faceBase=VR::toShadeVec(T->p[0]); isData.faceEdge0=VR::toShadeVec(T->p[1]); isData.faceEdge1=VR::toShadeVec(T->p[2]); isData.faceEdge0-=isData.faceBase; isData.faceEdge1-=isData.faceBase; isData.gnormal= -normalize(isData.faceEdge0^isData.faceEdge1); //VR::Vector(); #if 0 isData.normal = isData.gnormal;//T->getNormal(rsray); #else int fs; int fe; hair.GetFace(isData.faceIndex,fs,fe); int v0 = hair.GetFaceVert(fs); int v1 = hair.GetFaceVert(fs+1); int v2 = hair.GetFaceVert(fs+2); VR::ShadeVec n0 = VR::toShadeVec(normal(v0)); VR::ShadeVec n1 = VR::toShadeVec(normal(v1)); VR::ShadeVec n2 = VR::toShadeVec(normal(v2)); VR::ShadeVec N = is.bary.x*n0 + is.bary.y*n1 + is.bary.z*n2; isData.normal = normalize(N); #endif isData.wpoint=VR::toShadeVec(rsray.p) + VR::toShadeVec(rsray.dir)*is.t; // We don't have any meaningful data here isData.surfaceProps = NULL; // sfprops(); } #if defined(VRAY30) void shaveVrayStaticTriVoxelPrim::setIntersectionData(const VR::RayBunchParams& params, VR::PrimitiveIntersections& result, const RAY_IDX* idxs, size_t count) { for(size_t ii=0; ii(result.primitives()[idx]->owner); assert(owner == this); const HairType& hair = voxel()->GetHair(); // These will be used to get per-vertex attributes like color, transparency, etc. int fs = T->ownerIndex - firstid(); result.faceIndices()[idx] = fs; result.skipTags()[idx] = params.parentSkipTags()[idx]; //VR::Vector bary(0.5f, 0.5f, segment->getWparam(params, result, idx)); // the length along the segment double dist = result.rayDistances()[ idx ]; double isectPtX = params.origins(0)[ idx ] + params.dirs(0)[ idx ] * dist; double isectPtY = params.origins(1)[ idx ] + params.dirs(1)[ idx ] * dist; double isectPtZ = params.origins(2)[ idx ] + params.dirs(2)[ idx ] * dist; result.isectPoints(0)[idx] = isectPtX; result.isectPoints(1)[idx] = isectPtY; result.isectPoints(2)[idx] = isectPtZ; VR::Vector gn = T->getGNormal(params, result, idx); if (VR::dotf(dir, gn) < 0) gn = -gn; result.geomNormals(0)[idx] = gn[0]; result.geomNormals(1)[idx] = gn[1]; result.geomNormals(2)[idx] = gn[2]; int v0 = hair.GetFaceVert(fs); int v1 = hair.GetFaceVert(fs+1); int v2 = hair.GetFaceVert(fs+2); VR::Vector sn = normalize0( result.baryCoords(0)[idx] * normal(v0) + result.baryCoords(1)[idx] * normal(v1) + result.baryCoords(2)[idx] * normal(v2)); if (VR::dotf(dir, sn) < 0) sn = -sn; result.smoothNormals(0)[idx] = sn[0]; result.smoothNormals(1)[idx] = sn[1]; result.smoothNormals(2)[idx] = sn[2]; for(int d=0; d<3; d++) result.facesBase(d)[idx]=T->p[0][d]; for(int d=0; d<3; d++) result.facesEdge0(d)[idx]=T->p[1][d]-T->p[0][d]; for(int d=0; d<3; d++) result.facesEdge1(d)[idx]=T->p[2][d]-T->p[0][d]; } } #endif // VRAY30