// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 /********************************************************************** *< FILE: shaveVrayMovingTriVoxelPrim.cpp -- iplementation file DESCRIPTION: Static (non motion blurred) instanced hair voxel primitive CREATED BY: Vladimir Dubovoy HISTORY: created 20-05-2010 *> **********************************************************************/ #include "assert.h" #include "shaveVrayMovingTriVoxelPrim.h" #include "shaveVrayInstanceI.h" #include "misc_ray.h" #include "vray3_compat.h" shaveVrayMovingTriVoxelPrim::shaveVrayMovingTriVoxelPrim( IHairVoxel* vox, VR::VRayCore *vray, shaveVrayInstanceI *inst): shaveVrayTriVoxelPrim(vox,vray,inst) { _firstid() = -1; _tris() = NULL; //_numblur() = 2; if(voxel()) { VERT pmin; VERT pmax; voxel()->GetBbox(pmin,pmax); _bbox().init();//MovingBox _bbox().b[0].pmin.x = pmin.x; _bbox().b[0].pmin.y = pmin.y; _bbox().b[0].pmin.z = pmin.z; _bbox().b[0].pmax.x = pmax.x; _bbox().b[0].pmax.y = pmax.y; _bbox().b[0].pmax.z = pmax.z; VR::Vector scnoffs = VR::toVector(sceneOffset()); _bbox().b[0].pmin -= scnoffs; _bbox().b[0].pmax -= scnoffs; //calc speed box const HairType& hair = voxel()->GetHair(); int nv = hair.GetNumVerts(); for(int i = 0; i < nv; i++) { float x, y, z; hair.GetVelocity(i,x,y,z); _bbox().b[1].pmin.x = bbox().b[1].pmin.x > x ? x : bbox().b[1].pmin.x; _bbox().b[1].pmin.y = bbox().b[1].pmin.y > y ? y : bbox().b[1].pmin.y; _bbox().b[1].pmin.z = bbox().b[1].pmin.z > z ? z : bbox().b[1].pmin.z; _bbox().b[1].pmax.x = bbox().b[1].pmax.x < x ? x : bbox().b[1].pmax.x; _bbox().b[1].pmax.y = bbox().b[1].pmax.y < y ? y : bbox().b[1].pmax.y; _bbox().b[1].pmax.z = bbox().b[1].pmax.z < z ? z : bbox().b[1].pmax.z; } _bbox().t[0] = 0.0f; _bbox().t[1] = 1.0f; /*DebugPrint("[%f %f %f][%f %f %f]\n", pmin.x, pmin.y, pmin.z, pmax.x, pmax.y, pmax.z);*/ } } shaveVrayMovingTriVoxelPrim::~shaveVrayMovingTriVoxelPrim() { } /* | from MovingPrimitive */ void shaveVrayMovingTriVoxelPrim::getBBox (VR::MovingBox &box) { //DebugPrint("PRIM> shaveVrayMovingTriVoxelPrim::getBBox "); box = bbox(); } /* | from StaticPrimitive */ bool shaveVrayMovingTriVoxelPrim::splittable () { //DebugPrint("PRIM> shaveVrayMovingTriVoxelPrim::splitable\n"); return true; } /* | from StaticPrimitive */ void shaveVrayMovingTriVoxelPrim::split (int dim, VR::real middle, VR::MovingBox &bLeft, VR::MovingBox &bRight) { //DebugPrint("PRIM> shaveVrayMovingTriVoxelPrim::split [%i %f]\n",dim,middle); VR::MovingBox bbox; getBBox(bbox); bbox.split(dim, middle, bLeft, bRight); } /* | from StaticPrimitive */ int shaveVrayMovingTriVoxelPrim::expandable() { return true; } /* | from StaticPrimitive */ int shaveVrayMovingTriVoxelPrim::expand (VR::DynamicRaycaster< VR::MovingBox > *raycaster, int threadIndex) { const HairType& hair = voxel()->GetHair(); int numFaces = hair.GetNumFaces(); int numVerts = hair.GetNumVerts(); if(numFaces == 0) return 0; //int numblur_prims = numblur() - 1; //float step = 1.0f/(float)numblur_prims; if(firstid() == -1) _firstid() = raycaster->getNewRenderIDArray(numFaces/**numblur_prims*/); _normals().resize(numVerts); for(int i = 0; i < numVerts; i++) { _normal(i) = VR::Vector(0.0f,0.0f,0.0f); } VR::Vector p0[3]; VR::Vector p1[3]; VR::Vector v[3]; float t0 = 0.0f; float t1 = 0.99f; float dt = t1 - t0; _tris() = new VR::MovingTriangle[numFaces]; VR::Vector scnoffs=VR::toVector(sceneOffset()); 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); //hair.GetVelocity(vert_idx,_tri(i).d[k].x,_tri(i).d[k].y,_tri(i).d[k].z); //_tri(i).d[k] = VR::Vector(); //_tri(i).p[k] -= sceneOffset(); hair.GetVert (vert_idx, p0[k].x, p0[k].y, p0[k].z); hair.GetVelocity(vert_idx, v[k].x, v[k].y, v[k].z); p0[k] -= scnoffs; p1[k] = p0[k] + v[k]*dt; k++; } //_tri(i).t[0] = 0.0f; //_tri(i).t[1] = 1.0f; _tri(i).init(p0,p1 /*v*/ /*p0*/,t0,t1); 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::MovingTriangle); } /* | from StaticPrimitive */ int shaveVrayMovingTriVoxelPrim::collapse (VR::DynamicRaycaster< VR::MovingBox > *raycaster, int threadIndex) { 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; } _normals().clear(); return numFaces*sizeof(VR::MovingTriangle); } /* | from GeometryGenerator */ void shaveVrayMovingTriVoxelPrim::setIntersectionData(VR::RSRay &rsray, void *isd) { VR::IntersectionData &isData=*((VR::IntersectionData*) isd); VR::RSIntersection &is=rsray.is; assert(PRIM_TYPE_MOVING_TRIANGLE == is.primitive->type()); shaveVrayMovingTriVoxelPrim* owner =(shaveVrayMovingTriVoxelPrim*) (is.primitive->owner); assert(owner == this); VR::MovingTriangle* T = (VR::MovingTriangle*)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 shaveVrayMovingTriVoxelPrim::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. result.faceIndices()[idx] = T->ownerIndex - firstid(); 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); result.geomNormals(0)[idx] = gn[0]; result.geomNormals(1)[idx] = gn[1]; result.geomNormals(2)[idx] = gn[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