aboutsummaryrefslogtreecommitdiff
path: root/vrayPlug/plugin/shaveVrayMovingVoxelPrim.cpp
diff options
context:
space:
mode:
authorBen Marsh <[email protected]>2019-10-22 09:07:59 -0400
committerBen Marsh <[email protected]>2019-10-22 09:07:59 -0400
commitbd0027e737c6512397f841c22786274ed74b927f (patch)
treef7ffbdb8f3741bb7f24635616cc189cba5cb865c /vrayPlug/plugin/shaveVrayMovingVoxelPrim.cpp
downloadshave-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.cpp948
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
+