diff options
| author | Ben Marsh <[email protected]> | 2019-10-22 09:07:59 -0400 |
|---|---|---|
| committer | Ben Marsh <[email protected]> | 2019-10-22 09:07:59 -0400 |
| commit | bd0027e737c6512397f841c22786274ed74b927f (patch) | |
| tree | f7ffbdb8f3741bb7f24635616cc189cba5cb865c /vrayPlug/plugin/shaveVrayMovingVoxelPrim.cpp | |
| download | shave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.tar.xz shave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.zip | |
Adding Shave-and-a-Haircut 9.6
Diffstat (limited to 'vrayPlug/plugin/shaveVrayMovingVoxelPrim.cpp')
| -rw-r--r-- | vrayPlug/plugin/shaveVrayMovingVoxelPrim.cpp | 948 |
1 files changed, 948 insertions, 0 deletions
diff --git a/vrayPlug/plugin/shaveVrayMovingVoxelPrim.cpp b/vrayPlug/plugin/shaveVrayMovingVoxelPrim.cpp new file mode 100644 index 0000000..35e528d --- /dev/null +++ b/vrayPlug/plugin/shaveVrayMovingVoxelPrim.cpp @@ -0,0 +1,948 @@ +// 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 <[email protected]> + + 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; g<numHairs; ++g) { + float root_radius=hair.radiusroot[g]; + float delta_radius=hair.radiustip[g]-root_radius; + for (int k=0; k<numknots(); ++k) { + int knot_idx=hair.face_start[g]+k; + Vector p, v; + hair.GetVert(knot_idx, p.x, p.y, p.z); + p-=scnoffs; + hair.GetVelocity(knot_idx, v.x, v.y, v.z); + + int hd_idx=numknots()*g+k; + hairData[0].vertices[hd_idx]=p; + hairData[1].vertices[hd_idx]=p+v; + + float t=float(k)/float(numknots()-1); + float w=VR::Max(0.0001f, root_radius+t*delta_radius); + hairData[0].widths[hd_idx]=w; + + VR::Color knot_color; + hair.GetVertColor(g, k, knot_color.r, knot_color.g, knot_color.b); + hairData[0].colors[hd_idx]=knot_color; + } + hairData[0].numVertices[g]=_numknots(); + } + + hairData[0].initVertexOffsets(); + hairData[1].vertexOffsets=hairData[0].vertexOffsets; + + for (int i=0; i<2; ++i) { + tmHairData[i].hairData=&hairData[i]; + tmHairData[i].worldSpaceVertices=hairData[i].vertices; + tmHairData[i].initDirs(); + tmHairData[i].time=float(i); + } + + if (hinst()->plugin->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<VR::MovingBox> *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<VR::MovingBox> *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<MovingHairTreePrimitive*>(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<MovingHairTreePrimitive*>(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<MovingHairGenerator*>(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<GeometryGenerator*>(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<count; ++ii) { + const RAY_IDX idx=idxs[ii]; + + VR::MovingHairSegmentLine *segment=static_cast<VR::MovingHairSegmentLine*>(result.primitives()[idx]); + VR::MovingHairStrand *strand=static_cast<VR::MovingHairStrand*>(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 + |