// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 /********************************************************************** *< FILE: shaveVrayMovingVoxelPrim.cpp -- iplementation file DESCRIPTION: Motion blurred hair voxel primitive CREATED BY: Vladimir Dubovoy HISTORY: created 04-09-2008 *> **********************************************************************/ #include "assert.h" #include "shaveVrayMovingVoxelPrim.h" #include "shaveVraySharedFunctions.h" #if defined(VRAY30) || defined(VRAY40) #include "shaveVrayInstance.h" using namespace VUtils; #endif shaveVrayMovingVoxelPrim::shaveVrayMovingVoxelPrim(IHairVoxel* vox, VR::VRayCore *vray, shaveVrayInstance *inst) :shaveVrayVoxelPrim(vox,vray,inst) #if defined(VRAY30) || defined(VRAY40) , movingHairTree(NULL) #endif { _firstid() = -1; _numblur() = 2; _pts() = NULL; _dpts() = NULL; _uns() = NULL; _duns() = NULL; _vns() = NULL; _dvns() = NULL; _strands() = NULL; #if defined(VRAY30) || defined(VRAY40) minLeaf=0.0f; leafCoeff=1.0f; maxDepth=80; const VRaySequenceData &sdata=vray->getSequenceData(); const VRayFrameData &fdata=vray->getFrameData(); threadman=sdata.threadManager; prog=sdata.progress; #if VRAY_DLL_VERSION < 0x36000 tessParams.setFDataParams(fdata.camToWorld.offs, fdata.fov, fdata.imgWidth); #else tessParams.setFDataParams(fdata.camToWorld.offs, fdata.fov, fdata.imgWidth, fdata.worldToCam, fdata.projType, fdata.zoomFractor, fdata.devAspect); #endif tessParams.setSubdivThresh(inst->plugin->edgeLen); #endif if(voxel()) { VERT pmin; VERT pmax; voxel()->GetBbox(pmin,pmax); _bbox().init();//MovingBox #if defined(VRAY30) _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; _bbox().b[0].pmin -= sceneOffset(); _bbox().b[0].pmax -= sceneOffset(); #else TracePoint tpmin(pmin.x, pmin.y, pmin.z); TracePoint tpmax(pmax.x, pmax.y, pmax.z); tpmin -= sceneOffset(); tpmax -= sceneOffset(); _bbox().b[0].pmin = tpmin.toVector(); _bbox().b[0].pmax = tpmax.toVector(); #endif //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);*/ } _pool_Vector().init(sizeof(VR::Vector)*2*3*numknots(), 1000); } shaveVrayMovingVoxelPrim::~shaveVrayMovingVoxelPrim() { //these should be released in ::collapse() //but we add this code here in any case if(pts()) delete [] pts(); if(dpts()) delete [] dpts(); if(uns()) delete [] uns(); if(duns()) delete [] duns(); if(vns()) delete [] vns(); if(dvns()) delete [] dvns(); #if defined(VRAY30) || defined(VRAY40) delete movingHairTree; #endif } /* | from MovingPrimitive */ void shaveVrayMovingVoxelPrim::getBBox (VR::MovingBox &box) { //DebugPrint("PRIM> shaveVrayMovingVoxelPrim::getBBox "); box = bbox(); } /* | from MovingPrimitive */ bool shaveVrayMovingVoxelPrim::splittable () { //DebugPrint("PRIM> shaveVrayMovingVoxelPrim::splitable\n"); return true; } /* | from MovingPrimitive */ void shaveVrayMovingVoxelPrim::split (int dim, VR::real middle, VR::MovingBox &bLeft, VR::MovingBox &bRight) { //DebugPrint("PRIM> shaveVrayMovingVoxelPrim::split [%i %f]\n",dim,middle); VR::MovingBox bbox; getBBox(bbox); bbox.split(dim, middle, bLeft, bRight); } /* | from MovingPrimitive */ int shaveVrayMovingVoxelPrim::expandable() { return true; } /* | from MovingHairGenerator */ int shaveVrayMovingVoxelPrim::getNumSides() const { return 4; } /* | from MovingHairGenerator */ int shaveVrayMovingVoxelPrim::getNumKnots() { return numknots(); } /* | from MovingHairGenerator */ void shaveVrayMovingVoxelPrim::getSidesUV(float *&uc, float *&vc) { uc = _puc(); vc = _pvc(); } /* | from MovingHairGenerator */ void shaveVrayMovingVoxelPrim::getSidesUV(const float *&uc, const float *&vc) const { uc = puc(); vc = pvc(); } /* | from MovingHairGenerator */ int shaveVrayMovingVoxelPrim::getFlatNormal() const { return true; } /* | from MovingHairGenerator */ float shaveVrayMovingVoxelPrim::getRadius() { return 1.0f; //not sure } /* | from MovingHairGenerator */ float shaveVrayMovingVoxelPrim::getLength() { return 100.f; //not sure } /* | from MovingHairGenerator */ float shaveVrayMovingVoxelPrim::getTaper() { return 0.0f; //not sure } /* | from MovingHairGenerator */ VR::Vector shaveVrayMovingVoxelPrim::getGravity() { return VR::Vector(0.0f, 0.0f, 0.0f); //not sure } /* | from MovingHairGenerator */ float shaveVrayMovingVoxelPrim::getLengthRand() { return 0.0f; } /* | from MovingHairGenerator */ float shaveVrayMovingVoxelPrim::getRadiusRand() { return 0.0f; } /* | from MovingHairGenerator */ float shaveVrayMovingVoxelPrim::getGravityRand() { return 0.0f; } /* | from MovingHairGenerator */ float shaveVrayMovingVoxelPrim::getDirRand() { return 0.0f; } /* | from MovingHairGenerator */ float shaveVrayMovingVoxelPrim::getBend() { return 0.0f; } int shaveVrayMovingVoxelPrim::generateStrand(int faceIndex, int strandIndex, const VR::Vector *pv, const VR::Vector *nv, VR::Vector *pts, VR::Vector *un, VR::Vector *vn) { assert(false); //maybe we do not need to change array elementws as far as we passed initalized strands return true; } /* | from MovingHairGenerator */ VR::Vector shaveVrayMovingVoxelPrim::getStrandBaryCoords(int faceIndex, int strandIndex) const { return VR::Vector(1.0f, 0.0f, 0.f); } /* | from MovingHairGenerator */ VR::Vector* shaveVrayMovingVoxelPrim::newVectors(int threadIndex) { return (VR::Vector*) _pool_Vector().newElement(); } /* | from MovingHairGenerator */ void shaveVrayMovingVoxelPrim::deleteVectors(VR::Vector *x, int threadIndex) { _pool_Vector().releaseElement(x); } /* | from GeometryGenerator */ #if defined(VRAY30) VR::Vector shaveVrayMovingVoxelPrim::getGNormal(VR::RSRay &rsray) { return rsray.is.primitive->getGNormal(rsray); } VR::Vector shaveVrayMovingVoxelPrim::getNormal(VR::RSRay &rsray) { return rsray.is.primitive->getNormal(rsray); } #elif defined(VRAY40) VR::ShadeVec shaveVrayMovingVoxelPrim::getGNormal(VR::RSRay &rsray) { return rsray.is.primitive->getGNormal(rsray); } VR::ShadeVec shaveVrayMovingVoxelPrim::getNormal(VR::RSRay &rsray) { return rsray.is.primitive->getNormal(rsray); } #endif /* | from MovingPrimitive */ #if defined(VRAY30) || defined(VRAY40) /* * ########################################### * Implementation for V-Ray 3.0+ * ########################################### */ int shaveVrayMovingVoxelPrim::initHairData() { const HairType &hair=voxel()->GetHair(); int numHairs=hair.GetNumStrands(); //assume all hairs have the same number of segments _numknots()=hair.face_end[0]-hair.face_start[0]; for (int i=0; i<2; ++i) { hairData[i].vertices=VR::VectorRefList(numHairs*_numknots()); hairData[i].time=float(i); } hairData[0].numVertices=VR::IntRefList(numHairs); hairData[0].widths=VR::FloatRefList(numHairs*_numknots()); hairData[0].colors=VR::ColorRefList(numHairs*_numknots()); // share some arrays as they are the same hairData[1].numVertices=hairData[0].numVertices; hairData[1].widths=hairData[0].widths; hairData[1].colors=hairData[0].colors; VR::Vector scnoffs=VR::toVector(sceneOffset()); for (int g=0; gplugin->dynHairTessel) { tesselateHairData(tmHairData[0], &tessHairData[0], &tmHairData[1], &tessHairData[1], tessParams); } return numHairs; } #if defined(VRAY30) void shaveVrayMovingVoxelPrim::storeInGlobalTree(VR::RayServerInterface2 *rayserver) #elif defined(VRAY40) void shaveVrayMovingVoxelPrim::storeInGlobalTree(VR::RayServerInterface *rayserver) #endif { if (!movingHairTree) { int num_hairs=initHairData(); if(firstid()==-1) _firstid()=rayserver->getNewRenderIDArray(num_hairs+1); movingHairTree=new MovingHairTreePrimitive(firstid(), &tmHairData[0], &tmHairData[1], 0); } rayserver->storeMovingHairData(movingHairTree, this, firstid(), tmHairData[0], tmHairData[1]); } int shaveVrayMovingVoxelPrim::expand(VR::DynamicRaycaster *raycaster, int threadIndex) { int num_hairs=initHairData(); if(firstid()==-1) _firstid()=raycaster->getNewRenderIDArray(num_hairs+1); #if VRAY_DLL_VERSION < 0x31000 movingHairTree=new MovingHairTreePrimitive(firstid()+1, &tmHairData[0], &tmHairData[1], true); #else #if VRAY_DLL_VERSION >= 0x40000 RayServerInterface* rayserver = vrayCore->getSequenceData().rayserver; #else RayServerInterface2* rayserver = vrayCore->getSequenceData().rayserver; #endif VoxelTree * tree = rayserver->newMovingVoxelTree(&tmHairData[0], tmHairData[0].time, tmHairData[1].time, voxelTreeType_hairTree); movingHairTree=new MovingHairTreePrimitive(firstid()+1, &tmHairData[0], &tmHairData[1], tree); #endif movingHairTree->build(prog, threadman, maxDepth, minLeaf, leafCoeff); raycaster->insertPrimitive(threadIndex, movingHairTree, this, firstid()); int totalVertices=num_hairs*numknots(); uint64 memUsage=movingHairTree->getMemUsage(); return memUsage+3*2*sizeof(Vector)*totalVertices; } int shaveVrayMovingVoxelPrim::collapse(VR::DynamicRaycaster *raycaster, int threadIndex) { raycaster->removePrimitive(threadIndex, movingHairTree); uint64 memUsage=movingHairTree->getMemUsage(); delete movingHairTree; movingHairTree=NULL; memUsage+=3*2*sizeof(Vector)*tmHairData[1].hairData->vertices.size(); for (int i=0; i<2; ++i) { tmHairData[i].freeMem(); hairData[i].freeMem(); tessHairData[i].freeMem(); } return memUsage; } void shaveVrayMovingVoxelPrim::getMovingIntersectionData(int strandIdx, int segmentIdx, float time, Vector *p, Vector *dirs) { int startIdx = tmHairData[0].hairData->vertexOffsets[strandIdx] + segmentIdx; const Vector *p0 = &tmHairData[0].worldSpaceVertices[startIdx]; const Vector *dirs0 = &tmHairData[0].dirs[startIdx]; const Vector *p1 = &tmHairData[1].worldSpaceVertices[startIdx]; const Vector *dirs1 = &tmHairData[1].dirs[startIdx]; float time0=0.0f;//tmHairData[0].time; float time1=1.0f;//tmHairData[1].time; float k=(time-time0)/(time1-time0); p[0] = p0[0]+(p1[0]-p0[0])*k; p[1] = p0[1]+(p1[1]-p0[1])*k; dirs[0] = dirs0[0]+(dirs1[0]-dirs0[0])*k; dirs[1] = dirs0[1]+(dirs1[1]-dirs0[1])*k; } #if defined(VRAY30) void shaveVrayMovingVoxelPrim::setCommonIntersectionData(VR::RSRay &rsray, void *isd, int strandIdx, int segmentIdx, float wParam, const Vector &gNormal, const Vector &normal) #elif defined(VRAY40) void shaveVrayMovingVoxelPrim::setCommonIntersectionData(VR::RSRay &rsray, void *isd, int strandIdx, int segmentIdx, float wParam, const ShadeVec &gNormal, const ShadeVec &normal) #endif { IntersectionData &isData=*((IntersectionData*) isd); RSIntersection &is=rsray.is; isData.primitive=rsray.is.primitive; isData.skipTag=is.skipTag; isData.sb=getShadeable(); isData.sd=getExtTexMapping(); isData.si=getExtShadeData(); isData.surfaceProps=NULL; isData.volume=NULL; isData.wpointCoeff=is.t; #if defined(VRAY30) isData.wpoint=rsray.p+TracePoint(rsray.dir)*is.t; #elif defined(VRAY40) isData.wpoint=rsray.p+rsray.dir*is.t; #endif isData.gnormal=gNormal; isData.normal=normal; // These will be used to get per-vertex attributes like color, transparency, etc. isData.extra_int[1]=strandIdx; // the hair strand index isData.faceIndex=segmentIdx; // the segment index within a hair strand #if defined(VRAY30) isData.bary = Vector(wParam, 0.0f, 0.0f); // the length along the segment isData.faceBase = Vector(0.0f, 0.0f, 0.0f); isData.faceEdge0 = Vector(0.0f, 0.0f, 0.0f); isData.faceEdge1 = Vector(0.0f, 0.0f, 0.0f); #elif defined(VRAY40) isData.bary = ShadeVec(wParam, 0.0f, 0.0f); // the length along the segment isData.faceBase = ShadeVec(0.0f, 0.0f, 0.0f); isData.faceEdge0 = ShadeVec(0.0f, 0.0f, 0.0f); isData.faceEdge1 = ShadeVec(0.0f, 0.0f, 0.0f); #endif } #if defined(VRAY30) void shaveVrayMovingVoxelPrim::setCommonIntersectionData(const VR::RayBunchParams& params, VR::PrimitiveIntersections& result, const RAY_IDX idx, int strandIdx, int segmentIdx, float wParam, const VUtils::Vector &gNormal, const VUtils::Vector &normal) { VR::Ireal t = result.rayDistances()[ idx ]; for(int d=0; d<3; d++) result.isectPoints(d)[idx] = params.origins(d)[idx] + params.dirs(d)[idx] * t; for(int d=0; d<3; d++) result.geomNormals(d)[idx] = gNormal[d]; for(int d=0; d<3; d++) result.smoothNormals(d)[idx] = normal[d]; // These will be used to get per-vertex attributes like color, transparency, etc. result.extraInts(1)[idx] = strandIdx; // the hair strand index result.faceIndices()[idx] = segmentIdx; // the segment index within a hair strand VR::Vector bary = VR::Vector(wParam, 0.0f, 0.0f); // the length along the segment for(int d=0; d<3; d++) result.baryCoords(d)[idx] = bary[d]; for(int d=0; d<3; d++) result.facesBase(d)[idx] = 0.0f; for(int d=0; d<3; d++) result.facesEdge0(d)[idx] = 0.0f; for(int d=0; d<3; d++) result.facesEdge1(d)[idx] = 0.0f; } #endif void shaveVrayMovingVoxelPrim::setIntersectionData(VR::RSRay &rsray, void *isd) { MovingHairTreePrimitive *treePrim=static_cast(rsray.is.primitive); int strandIdx=treePrim->getStrandIndex(rsray); int segmentIdx=treePrim->getSegmentIndex(rsray); Vector p[2], dirs[2]; getMovingIntersectionData(strandIdx, segmentIdx, rsray.time, p, dirs); setCommonIntersectionData(rsray, isd, strandIdx, segmentIdx, treePrim->getWparam(rsray, p), treePrim->getGNormal(rsray, p), treePrim->getNormal(rsray, p, dirs, getFlatNormal())); } #if defined(VRAY30) void shaveVrayMovingVoxelPrim::setIntersectionData(const VR::RayBunchParams& params, VR::PrimitiveIntersections& result, const RAY_IDX* idxs, size_t count) { // Iterate over the active rays for( size_t i = 0; i < count; i++ ) { const RAY_IDX idx = idxs[ i ]; MovingHairTreePrimitive *treePrim=static_cast(result.primitives()[idx]); int strandIdx=treePrim->getStrandIndex(params, result, idx); int segmentIdx=treePrim->getSegmentIndex(params, result, idx); Vector p[2], dirs[2]; getMovingIntersectionData(strandIdx, segmentIdx, params.times()[idx], p, dirs); setCommonIntersectionData(params, result, idx, strandIdx, segmentIdx, treePrim->getWparam(params, result, idx, p), treePrim->getGNormal(params, result, idx, p), treePrim->getNormal(params, result, idx, p, dirs, getFlatNormal())); } } #endif VR::ShadeVec shaveVrayMovingVoxelPrim::getHairDir(const VR::VRayContext &rc) const { const VR::Vector *vertices0 = tmHairData[0].worldSpaceVertices.get(); const VR::Vector *vertices1 = tmHairData[1].worldSpaceVertices.get(); VR::ShadeVec v0, v1, v2; int strandIdx, segmentIdx; shaveVrayGetHairParams(rc, strandIdx, segmentIdx); int pos=hairData[0].vertexOffsets[strandIdx]+segmentIdx; float blend=rc.rayresult.bary[0]; VR::ShadeVec result(0.0f, 0.0f, 0.0f); float k=(rc.rayparams.rayTime-tmHairData[0].time)/(tmHairData[1].time-tmHairData[0].time); if (segmentIdx==0) { VR::ShadeVec vertex0=VR::toShadeVec(vertices0[pos]); VR::ShadeVec vertex1=VR::toShadeVec(vertices1[pos]); VR::ShadeVec vertex0_next=VR::toShadeVec(vertices0[pos+1]); VR::ShadeVec vertex1_next=VR::toShadeVec(vertices1[pos+1]); v1=vertex0+(vertex1-vertex0)*k; v2=vertex0_next+(vertex1_next-vertex0_next)*k; result=normalize0(v2-v1); } else { VR::ShadeVec vertex0_prev=VR::toShadeVec(vertices0[pos-1]); VR::ShadeVec vertex1_prev=VR::toShadeVec(vertices1[pos-1]); VR::ShadeVec vertex0=VR::toShadeVec(vertices0[pos]); VR::ShadeVec vertex1=VR::toShadeVec(vertices1[pos]); VR::ShadeVec vertex0_next=VR::toShadeVec(vertices0[pos+1]); VR::ShadeVec vertex1_next=VR::toShadeVec(vertices1[pos+1]); v0=vertex0_prev+(vertex1_prev-vertex0_prev)*k; v1=vertex0+(vertex1-vertex0)*k; v2=vertex0_next+(vertex1_next-vertex0_next)*k; VR::ShadeVec prev_dir=normalize0(v1-v0); VR::ShadeVec curr_dir=normalize0(v2-v1); result=normalize0(prev_dir + (curr_dir - prev_dir)*blend); } return result; } #else //VRAY30 not defined below this line /* * ########################################### * Implementation for V-Ray <= 2.99 * ########################################### */ int shaveVrayMovingVoxelPrim::expand (VR::DynamicRaycaster< VR::MovingBox > *raycaster, int threadIndex) { const HairType& hair = voxel()->GetHair(); int numHairs = hair.GetNumStrands(); if(numHairs == 0) return 0; int numblur_prims = numblur() - 1; if(firstid() == -1) _firstid() = raycaster->getNewRenderIDArray(numHairs*numblur_prims); //assume all hairs have the same number of segments _numknots() = hair.face_end[0] - hair.face_start[0]; int nalloc = numknots()*numHairs*numblur(); int nalloc2= numknots()*numHairs*numblur_prims; _pts() = new VR::Vector[nalloc]; _dpts()= new VR::Vector[nalloc2]; _uns() = new VR::Vector[nalloc]; _duns()= new VR::Vector[nalloc2]; _vns() = new VR::Vector[nalloc]; _dvns()= new VR::Vector[nalloc2]; float step = 1.0f/(float)numblur_prims; //calc point and vectors for(int i = 0; i < numHairs; i++) { int strand_offset = i*numknots()*numblur(); float root_radius = hair.radiusroot[i]; float delta_radius = hair.radiustip[i] - root_radius; //calc stuff for moving strands for(int oo = 0; oo < numblur(); oo++) { float T = step*(float)oo; int pts_offset = strand_offset + oo*numknots(); VR::Vector initialNormal; VR::Vector sv0, sv1; hair.GetVert(0, sv0.x, sv0.y, sv0.z); hair.GetVert(1, sv1.x, sv1.y, sv1.z); initialNormal=VR::normalize0(sv1-sv0); // Compute the initial tangent vectors - these are later on propagated along the // strand length to avoids issues with flipped tangent vectors. VR::Vector u,v; VR::computeTangentVectors(initialNormal, u, v); VR::Vector v0; for(int j = 0; j < numknots(); j++) { int vert_idx = hair.face_start[i] + j; int pt_idx = pts_offset + j; VR::Vector v1; VR::Vector s(0.0f,0.0f,0.0f); //not moved vert hair.GetVert(vert_idx,v1.x,v1.y,v1.z); //vertex velosity hair.GetVelocity(vert_idx,s.x,s.y,s.z); //calc moved vert locations //v1 += (T + 0.5f)*s; v1 += T*s; _pt(pt_idx) = v1; _pt(pt_idx) -= sceneOffset(); //calc un and vn if(j == 0) { float radius = root_radius; if (radius<0.001f) radius=0.001f; // For the first point, just use the tangent vectors directly _un(pt_idx) = u*radius; _vn(pt_idx) = v*radius; } else { float t = (float)j/(float)(numknots()-1); float radius = root_radius + t*delta_radius; VR::Vector d=v1-v0; float dlenSqr=d.lengthSqr(); if (dlenSqr>1e-12f) { VR::Vector nu=u-d*((u*d)/sqrtf(dlenSqr)); // Project the previous u vector on the current cross plane float nuLenSqr=lengthSqr(nu); if (nuLenSqr>1e-12f) { u=nu/sqrtf(nuLenSqr); v=normalize(d^nu); } } _un(pt_idx) = u*radius; _vn(pt_idx) = v*radius; } v0 = v1; } } } //calc differences for(int i = 0; i < numHairs; i++) { int strand_offset = i*numknots()*numblur(); int strand_offset2 = i*numknots()*numblur_prims; for(int oo = 0; oo < numblur_prims; oo++) { int pts_offset0 = strand_offset + oo*numknots(); int pts_offset1 = pts_offset0 + numknots(); int pts_offset2 = strand_offset2+ oo*numknots(); for(int j = 0; j < numknots(); j++) { int pt_offset0 = pts_offset0 + j; int pt_offset1 = pts_offset1 + j; int pt_offset2 = pts_offset2 + j; _dpt(pt_offset2) = pt(pt_offset1) - pt(pt_offset0); _dun(pt_offset2) = un(pt_offset1) - un(pt_offset0); _dvn(pt_offset2) = vn(pt_offset1) - vn(pt_offset0); } } } //alloc and place strands int k = 0; _strands() = new VR::MovingHairStrand[numHairs*numblur_prims]; for(int i = 0; i < numHairs; i++) { int strand_offset = i*numknots()*numblur(); int strand_offset2 = i*numknots()*numblur_prims; for(int oo = 0; oo < numblur_prims; oo++) { float t0 = step*(float)oo; float t1 = t0 + step; int pts_offset0 = strand_offset + oo*numknots(); int pts_offset2 = strand_offset2 + oo*numknots(); _strand(i).init(static_cast(this), t0, pts(pts_offset0), uns(pts_offset0), vns(pts_offset0), t1, dpts(pts_offset2),duns(pts_offset2), dvns(pts_offset2)); raycaster->insertPrimitive(threadIndex, &_strand(i), static_cast(this), k + firstid()); k++; } } return numHairs*numblur_prims*sizeof(VR::MovingHairStrand) + nalloc*3*sizeof(VR::Vector)+ nalloc2*3*sizeof(VR::Vector); } /* | from MovingPrimitive */ int shaveVrayMovingVoxelPrim::collapse (VR::DynamicRaycaster< VR::MovingBox > *raycaster, int threadIndex) { // DebugPrint("PRIM> shaveVrayMovingVoxelPrim::collapse\n"); const HairType& hair = voxel()->GetHair(); int numHairs = hair.GetNumStrands(); if(numHairs == 0) return 0; if(strands()) { int n = numHairs*(numblur()-1); for (int i=0; i < n; i++) raycaster->removePrimitive(threadIndex, &_strand(i)); delete[] strands(); _strands() = NULL; } if(pts()) { delete [] pts(); _pts() = NULL; } if(dpts()) { delete [] dpts(); _dpts() = NULL; } if(uns()) { delete [] uns(); _uns() = NULL; } if(duns()) { delete [] duns(); _duns() = NULL; } if(dvns()) { delete [] dvns(); _dvns() = NULL; } _pool_Vector().freeMem(); return numHairs*(numblur()-1)*sizeof(VR::MovingHairStrand) + numHairs*(numblur()-1)*3*sizeof(VR::Vector) + numHairs*numblur()*3*sizeof(VR::Vector); } /* | from GeometryGenerator */ void shaveVrayMovingVoxelPrim::setIntersectionData(VR::RSRay &rsray, void *isd) { VR::IntersectionData &isData=*((VR::IntersectionData*) isd); VR::RSIntersection &is=rsray.is; //assert(PRIM_TYPE_STATIC_HAIR_SEGMENT_LINE == is.primitive->type()); VR::MovingHairStrand *s=(VR::MovingHairStrand*) (is.primitive->owner); isData.primitive=is.primitive; isData.skipTag =is.skipTag; isData.faceIndex= (s->ownerIndex - firstid())/(numblur()-1); if(ownbsdf()) isData.sb = shade(); else isData.sb = shdata(); isData.sd = shdata(); isData.si = /*NULL;*/ shinst(); isData.volume=NULL; isData.bary= VR::Vector(0.5f, 0.5f, 0.5f); isData.wpointCoeff=is.t; isData.gnormal=getGNormal(rsray); isData.normal =getNormal(rsray); isData.wpoint=rsray.p + VR::TracePoint(rsray.dir)*is.t; //isData.wpoint= (rsray.p + VR::TracePoint(rsray.dir)*is.t) - sceneOffset(); isData.extraf=(float) s->getSegmentIndex((VR::MovingHairSegmentLine*) is.primitive); isData.bary[2]=((VR::MovingHairSegmentLine*) is.primitive)->getWparam(rsray); // Vector *verts=fface->getVerts(); // isData.faceBase=verts[0]; // isData.faceEdge0=verts[1]-verts[0]; // isData.faceEdge1=verts[2]-verts[0]; // We don't have any meaningful data here isData.surfaceProps = NULL; // sfprops(); } void shaveVrayMovingVoxelPrim::setIntersectionData(const VR::RayBunchParams& params, VR::PrimitiveIntersections& result, const RAY_IDX* idxs, size_t count) { for(size_t ii=0; ii(result.primitives()[idx]); VR::MovingHairStrand *strand=static_cast(segment->owner); float t=result.rayDistances()[idx]; for(int d=0; d<3; d++) result.isectPoints(d)[idx]=params.origins(d)[idx]+double(params.dirs(d)[idx])*t; VR::Vector gnormal = segment->getGNormal(params, result, idx); for(int d=0; d<3; d++) result.geomNormals(d)[idx]=gnormal[d]; VR::Vector normal = segment->getNormal(params, result, idx); for(int d=0; d<3; d++) result.smoothNormals(d)[idx]=normal[d]; // These will be used to get per-vertex attributes like color, transparency, etc. result.faceIndices()[idx]=strand->ownerIndex - firstid(); result.extraFloats(6)[idx]=(float)strand->getSegmentIndex(segment); // the segment index within a hair strand VR::Vector bary(0.5f, 0.5f, segment->getWparam(params, result, idx)); // the length along the segment for(int d=0; d<3; d++) result.baryCoords(d)[idx]=bary[d]; for(int d=0; d<3; d++) result.facesBase(d)[idx]=0.0f; for(int d=0; d<3; d++) result.facesEdge0(d)[idx]=0.0f; for(int d=0; d<3; d++) result.facesEdge1(d)[idx]=0.0f; } } #endif //VRAY30