aboutsummaryrefslogtreecommitdiff
path: root/vrayPlug/plugin/shaveVrayStaticVoxelPrim.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/shaveVrayStaticVoxelPrim.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/shaveVrayStaticVoxelPrim.cpp')
-rw-r--r--vrayPlug/plugin/shaveVrayStaticVoxelPrim.cpp790
1 files changed, 790 insertions, 0 deletions
diff --git a/vrayPlug/plugin/shaveVrayStaticVoxelPrim.cpp b/vrayPlug/plugin/shaveVrayStaticVoxelPrim.cpp
new file mode 100644
index 0000000..b116873
--- /dev/null
+++ b/vrayPlug/plugin/shaveVrayStaticVoxelPrim.cpp
@@ -0,0 +1,790 @@
+// Shave and a Haircut
+// (c) 2019 Epic Games
+// US Patent 6720962
+
+/**********************************************************************
+ *<
+ FILE: shaveVrayStaticVoxelPrim.cpp -- iplementation file
+
+ DESCRIPTION: Static (non motion blurred) hair primitive
+
+ CREATED BY: Vladimir Dubovoy <[email protected]>
+
+ HISTORY: created 20-08-2008 ( as part of 3ds Max + VRay hair shaders)
+ merged 31-03-2010
+
+ *>
+ **********************************************************************/
+
+#include "assert.h"
+#include "shaveVrayStaticVoxelPrim.h"
+#include "shaveVrayInstance.h"
+//#include "HairVrPrimsSharedFunctions.h"
+#include "misc_ray.h"
+
+#if defined(VRAY30) || defined(VRAY40)
+using namespace VUtils;
+#endif
+
+shaveVrayStaticVoxelPrim::shaveVrayStaticVoxelPrim(IHairVoxel* voxel,VR::VRayCore *vray, shaveVrayInstance *inst)
+ :shaveVrayVoxelPrim(voxel,vray,inst)
+#if defined(VRAY30) || defined(VRAY40)
+ ,staticHairTree(NULL)
+#endif
+
+{
+ _firstid() = -1;
+ _pts() = NULL;
+ _uns() = NULL;
+ _vns() = 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);
+#else
+ _pool_Vector().init(sizeof(VR::Vector)*3*numknots(), 1000);
+#endif
+}
+
+shaveVrayStaticVoxelPrim::~shaveVrayStaticVoxelPrim()
+{
+ //these should be released in ::collapse()
+ //but we add this code here in any case
+ if(pts())
+ delete [] pts();
+
+ if(uns())
+ delete [] uns();
+
+ if(vns())
+ delete [] vns();
+#if defined(VRAY30) || defined(VRAY40)
+ if(staticHairTree)
+ delete staticHairTree;
+#endif
+}
+
+/*
+| from StaticPrimitive
+*/
+void shaveVrayStaticVoxelPrim::getBBox (VR::StaticBox &bbox)
+{
+ //DebugPrint("PRIM> shaveVrayStaticVoxelPrim::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 shaveVrayStaticVoxelPrim::splittable ()
+{
+ //DebugPrint("PRIM> shaveVrayStaticVoxelPrim::splitable\n");
+
+ return true;
+}
+
+/*
+| from StaticPrimitive
+*/
+void shaveVrayStaticVoxelPrim::split (int dim, VR::real middle, VR::StaticBox &bLeft, VR::StaticBox &bRight)
+{
+ //DebugPrint("PRIM> shaveVrayStaticVoxelPrim::split [%i %f]\n",dim,middle);
+
+ VR::StaticBox bbox;
+ getBBox(bbox);
+ bbox.split(dim, middle, bLeft, bRight);
+}
+/*
+| from StaticPrimitive
+*/
+int shaveVrayStaticVoxelPrim::expandable()
+{
+ return true;
+}
+
+
+/*
+| from StaticHairGenerator
+*/
+int shaveVrayStaticVoxelPrim::getNumSides() const
+{
+ return 4;
+}
+
+/*
+| from StaticHairGenerator
+*/
+int shaveVrayStaticVoxelPrim::getNumKnots()
+{
+ return numknots();
+}
+/*
+| from StaticHairGenerator
+*/
+void shaveVrayStaticVoxelPrim::getSidesUV(float *&uc, float *&vc)
+{
+ uc = _puc();
+ vc = _pvc();
+}
+/*
+| from StaticHairGenerator
+*/
+void shaveVrayStaticVoxelPrim::getSidesUV(const float *&uc, const float *&vc) const
+{
+ uc = puc();
+ vc = pvc();
+ //int size = eNumSides*sizeof(float);
+ //memcpy((void*)uc,puc(),size);
+ //memcpy((void*)vc,pvc(),size);
+}
+/*
+| from StaticHairGenerator
+*/
+int shaveVrayStaticVoxelPrim::getFlatNormal() const
+{
+ return true;
+}
+/*
+| from StaticHairGenerator
+*/
+float shaveVrayStaticVoxelPrim::getRadius()
+{
+ return 1.0f; //not sure
+}
+/*
+| from StaticHairGenerator
+*/
+float shaveVrayStaticVoxelPrim::getLength()
+{
+ return 100.f; //not sure
+}
+/*
+| from StaticHairGenerator
+*/
+float shaveVrayStaticVoxelPrim::getTaper()
+{
+ return 0.0f; //not sure
+}
+/*
+| from StaticHairGenerator
+*/
+VR::Vector shaveVrayStaticVoxelPrim::getGravity()
+{
+ return VR::Vector(0.0f, 0.0f, 0.0f); //not sure
+}
+/*
+| from StaticHairGenerator
+*/
+float shaveVrayStaticVoxelPrim::getLengthRand()
+{
+ return 0.0f;
+}
+/*
+| from StaticHairGenerator
+*/
+float shaveVrayStaticVoxelPrim::getRadiusRand()
+{
+ return 0.0f;
+}
+/*
+| from StaticHairGenerator
+*/
+float shaveVrayStaticVoxelPrim::getGravityRand()
+{
+ return 0.0f;
+}
+/*
+| from StaticHairGenerator
+*/
+float shaveVrayStaticVoxelPrim::getDirRand()
+{
+ return 0.0f;
+}
+/*
+| from StaticHairGenerator
+*/
+float shaveVrayStaticVoxelPrim::getBend()
+{
+ return 0.0f;
+}
+int shaveVrayStaticVoxelPrim::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 StaticHairGenerator
+*/
+VR::Vector shaveVrayStaticVoxelPrim::getStrandBaryCoords(int faceIndex, int strandIndex) const
+{
+ return VR::Vector(1.0f, 0.0f, 0.f);
+}
+/*
+| from StaticHairGenerator
+*/
+VR::Vector* shaveVrayStaticVoxelPrim::newVectors(int threadIndex)
+{
+#if defined(VRAY30) || defined(VRAY40)
+ return NULL;
+#else
+ return (VR::Vector*) _pool_Vector().newElement();
+#endif
+}
+/*
+| from StaticHairGenerator
+*/
+void shaveVrayStaticVoxelPrim::deleteVectors(VR::Vector *x, int threadIndex)
+{
+ _pool_Vector().releaseElement(x);
+}
+
+/*
+| from GeometryGenerator
+*/
+#if defined(VRAY30)
+VR::Vector shaveVrayStaticVoxelPrim::getGNormal(VR::RSRay &rsray)
+{
+ return rsray.is.primitive->getGNormal(rsray);
+}
+VR::Vector shaveVrayStaticVoxelPrim::getNormal(VR::RSRay &rsray)
+{
+ return rsray.is.primitive->getNormal(rsray);
+}
+#elif defined(VRAY40)
+VR::ShadeVec shaveVrayStaticVoxelPrim::getGNormal(VR::RSRay &rsray)
+{
+ return rsray.is.primitive->getGNormal(rsray);
+}
+VR::ShadeVec shaveVrayStaticVoxelPrim::getNormal(VR::RSRay &rsray)
+{
+ return rsray.is.primitive->getNormal(rsray);
+}
+#endif
+
+#if defined(VRAY30) || defined(VRAY40)
+/*
+ * ###########################################
+ * Implementation for V-Ray 3.0+
+ * ###########################################
+ */
+int shaveVrayStaticVoxelPrim::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];
+
+ // hair data will hold data from voxel
+ hairData.numVertices=VR::IntRefList(numHairs);
+ hairData.vertices=VR::VectorRefList(numHairs*_numknots());
+ hairData.widths=VR::FloatRefList(numHairs*_numknots());
+ hairData.colors=VR::ColorRefList(numHairs*_numknots());
+
+ VR::Vector scnoffs=VR::toVector(sceneOffset());
+ // fill in our hair data
+ for(int i=0; i<numHairs; ++i) {
+ int pts_offset=i*numknots();
+
+ float root_radius=hair.radiusroot[i];
+ float delta_radius=hair.radiustip[i]-root_radius;
+
+ for(int j=0; j<numknots(); ++j) {
+ int vert_idx=hair.face_start[i] + j;
+ int pt_idx=pts_offset+j;
+
+ VR::Vector pt;
+ hair.GetVert(vert_idx, pt.x, pt.y, pt.z);
+ pt-=scnoffs;
+ hairData.vertices[pt_idx]=pt;
+
+ float t=float(j)/float(numknots()-1);
+ float w=VR::Max(0.0001f, root_radius+t*delta_radius);
+ hairData.widths[pt_idx]=w;
+
+ VR::Color knot_color;
+ hair.GetVertColor(i, j, knot_color.r, knot_color.g, knot_color.b);
+ hairData.colors[pt_idx]=knot_color;
+ }
+ hairData.numVertices[i]=_numknots();
+ }
+
+ hairData.initVertexOffsets();
+
+ tmHairData.hairData=&hairData;
+ tmHairData.worldSpaceVertices=hairData.vertices;
+ tmHairData.initDirs();
+
+ if (hinst()->plugin->dynHairTessel) {
+ tesselateHairData(tmHairData, &tessHairData, NULL, NULL, tessParams);
+ }
+
+ return numHairs;
+}
+
+#if defined(VRAY30)
+void shaveVrayStaticVoxelPrim::storeInGlobalTree(VR::RayServerInterface2 *rayserver)
+#elif defined(VRAY40)
+void shaveVrayStaticVoxelPrim::storeInGlobalTree(VR::RayServerInterface *rayserver)
+#endif
+{
+ if (!staticHairTree) {
+ int num_hairs=initHairData();
+ if(firstid()==-1)
+ _firstid()=rayserver->getNewRenderIDArray(num_hairs+1);
+ staticHairTree=new StaticHairTreePrimitive(firstid(), &tmHairData, NULL, 0);
+ }
+ rayserver->storeStaticHairData(staticHairTree, this, firstid(), tmHairData);
+}
+
+int shaveVrayStaticVoxelPrim::expand(VR::DynamicRaycaster< VR::StaticBox > *raycaster, int threadIndex) {
+
+ int num_hairs=initHairData();
+
+ if(firstid()==-1)
+ _firstid()=raycaster->getNewRenderIDArray(num_hairs+1);
+
+#if VRAY_DLL_VERSION < 0x31000
+ staticHairTree=new VR::StaticHairTreePrimitive(firstid()+1, &tmHairData, NULL, true);
+#else
+#if VRAY_DLL_VERSION >= 0x40000
+ RayServerInterface* rayserver = vrayCore->getSequenceData().rayserver;
+#else
+ RayServerInterface2* rayserver = vrayCore->getSequenceData().rayserver;
+#endif
+ VoxelTree * tree = rayserver->newStaticVoxelTree(&tmHairData, voxelTreeType_hairTree);
+ staticHairTree=new StaticHairTreePrimitive(firstid()+1, &tmHairData, NULL, tree);
+#endif
+
+#if VRAY_DLL_VERSION < 0x36000
+ staticHairTree->visibleToCamera=_hinst()->primary_visibility; // should we intersect this hair tree wil cam rays?
+#else
+ staticHairTree->visibleToCamera = _hinst()->getPrimaryVisibility();
+#endif
+ staticHairTree->build(prog, threadman, maxDepth, minLeaf, leafCoeff);
+
+ raycaster->insertPrimitive(threadIndex, staticHairTree, this, firstid());
+
+ int totalVertices=numknots()*num_hairs;
+ uint64 memUsage=staticHairTree->getMemUsage();
+ return memUsage+3*sizeof(VR::Vector)*totalVertices;
+}
+
+int shaveVrayStaticVoxelPrim::collapse(VR::DynamicRaycaster< VR::StaticBox > *raycaster, int threadIndex) {
+ raycaster->removePrimitive(threadIndex, staticHairTree);
+ uint64 memUsage=staticHairTree->getMemUsage();
+ delete staticHairTree;
+ staticHairTree=NULL;
+ memUsage+=3*sizeof(Vector)*tmHairData.hairData->vertices.size();
+
+ tmHairData.freeMem();
+ hairData.freeMem();
+ tessHairData.freeMem();
+
+ return memUsage;
+}
+
+void shaveVrayStaticVoxelPrim::getStaticIntersectionData(int strandIdx, int segmentIdx, const VR::Vector* &p, const VR::Vector* &dirs) {
+ int startIdx = tmHairData.hairData->vertexOffsets[strandIdx] + segmentIdx;
+ p = &tmHairData.worldSpaceVertices[startIdx];
+ dirs = &tmHairData.dirs[startIdx];
+}
+
+void shaveVrayStaticVoxelPrim::setCommonIntersectionData(VR::RSRay &rsray, void *isd, int strandIdx, int segmentIdx,
+ float wParam, const ShadeVec &gNormal, const ShadeVec &normal)
+{
+ 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
+
+ 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);
+}
+
+#if defined(VRAY30)
+void shaveVrayStaticVoxelPrim::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 shaveVrayStaticVoxelPrim::setIntersectionData(VR::RSRay &rsray, void *isd) {
+ VR::StaticHairTreePrimitive *treePrim=static_cast<VR::StaticHairTreePrimitive*>(rsray.is.primitive);
+ int strandIdx=treePrim->getStrandIndex(rsray);
+ int segmentIdx=treePrim->getSegmentIndex(rsray);
+
+ const VR::Vector *p, *dirs;
+ getStaticIntersectionData(strandIdx, segmentIdx, 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 shaveVrayStaticVoxelPrim::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 ];
+
+ VR::StaticHairTreePrimitive *treePrim=static_cast<VR::StaticHairTreePrimitive*>(result.primitives()[idx]);
+
+ int strandIdx=treePrim->getStrandIndex(params, result, idx);
+ int segmentIdx=treePrim->getSegmentIndex(params, result, idx);
+
+ const VR::Vector *p, *dirs;
+ getStaticIntersectionData(strandIdx, segmentIdx, 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 shaveVrayStaticVoxelPrim::getHairDir(const VR::VRayContext &rc) const {
+ int strandIdx, segmentIdx;
+ shaveVrayGetHairParams(rc, strandIdx, segmentIdx);
+
+ int pos=hairData.vertexOffsets[strandIdx]+segmentIdx;
+ float blend=rc.rayresult.bary[0];
+
+ VR::ShadeVec result(0.0f, 0.0f, 0.0f);
+
+ const VR::VectorRefList &vertices=tmHairData.worldSpaceVertices;
+ if (segmentIdx==0) {
+ VR::ShadeVec v=VR::toShadeVec(vertices[pos]);
+ VR::ShadeVec vnext=VR::toShadeVec(vertices[pos+1]);
+ result=normalize0(vnext-v);
+ } else {
+ VR::ShadeVec vprev=VR::toShadeVec(vertices[pos-1]);
+ VR::ShadeVec v=VR::toShadeVec(vertices[pos]);
+ VR::ShadeVec vnext=VR::toShadeVec(vertices[pos+1]);
+ VR::ShadeVec prev_dir = normalize0(v-vprev);
+ VR::ShadeVec curr_dir = normalize0(vnext-v);
+
+ result=normalize0(prev_dir + (curr_dir - prev_dir)*blend);
+ }
+
+ return result;
+}
+
+#else //VRAY30 not defined below this line
+/*
+ * ###########################################
+ * Implementation for V-Ray <= 2.99
+ * ###########################################
+ */
+/*
+| from StaticPrimitive
+*/
+int shaveVrayStaticVoxelPrim::expand (VR::DynamicRaycaster< VR::StaticBox > *raycaster, int threadIndex)
+{
+ const HairType& hair = voxel()->GetHair();
+ int numHairs = hair.GetNumStrands();
+
+ if(numHairs == 0)
+ return 0;
+
+ if(firstid() == -1)
+ _firstid() = raycaster->getNewRenderIDArray(numHairs);
+
+ //assume all hairs have the same number of segments
+ _numknots() = hair.face_end[0] - hair.face_start[0];
+
+ int nalloc = numknots()*numHairs;
+ _pts() = new VR::Vector[nalloc];
+ _uns() = new VR::Vector[nalloc];
+ _vns() = new VR::Vector[nalloc];
+
+ _strands() = new VR::StaticHairStrand[numHairs];
+ for(int i = 0; i < numHairs; i++)
+ {
+ int pts_offset = i*numknots();
+
+ float root_radius = hair.radiusroot[i];
+ float delta_radius = hair.radiustip[i] - root_radius;
+
+ 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);
+
+ for(int j = 0; j < numknots(); j++)
+ {
+ int vert_idx = hair.face_start[i] + j;
+ int pt_idx = pts_offset + j;
+
+ hair.GetVert(vert_idx,_pt(pt_idx).x,_pt(pt_idx).y,_pt(pt_idx).z);
+
+ _pt(pt_idx) -= sceneOffset();
+
+ if(j == 0)
+ {
+ float radius = root_radius;
+ if (radius<0.0001f) radius=0.0001f;
+
+ // 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;
+ if (radius<0.0001f) radius=0.0001f;
+
+ VR::Vector v0, v1;
+ hair.GetVert(vert_idx, v1.x, v1.y, v1.z);
+ hair.GetVert(vert_idx-1, v0.x, v0.y, v0.z);
+
+ 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;
+ }
+ }
+
+ _strand(i).init(static_cast<StaticHairGenerator*>(this),pts(pts_offset), uns(pts_offset), vns(pts_offset));
+
+ raycaster->insertPrimitive(threadIndex, &_strand(i), static_cast<GeometryGenerator*>(this), i + firstid());
+ }
+#ifdef _DEBUG
+#ifdef WIN32
+ assert(_CrtCheckMemory());
+#endif
+#endif
+ return numHairs*sizeof(VR::StaticHairStrand) + numknots()*numHairs*3*sizeof(VR::Vector);
+}
+
+/*
+| from StaticPrimitive
+*/
+int shaveVrayStaticVoxelPrim::collapse (VR::DynamicRaycaster< VR::StaticBox > *raycaster, int threadIndex)
+{
+ const HairType& hair = voxel()->GetHair();
+ int numHairs = hair.GetNumStrands();
+
+ if(numHairs == 0)
+ return 0;
+
+ if(strands())
+ {
+ for (int i=0; i < numHairs; i++)
+ raycaster->removePrimitive(threadIndex, &_strand(i));
+
+ delete[] strands();
+ _strands() = NULL;
+ }
+ if(pts())
+ {
+ delete [] pts();
+ _pts() = NULL;
+ }
+ if(uns())
+ {
+ delete [] uns();
+ _uns() = NULL;
+ }
+ if(vns())
+ {
+ delete [] vns();
+ _vns() = NULL;
+ }
+ _pool_Vector().freeMem();
+
+ return numHairs*sizeof(VR::StaticHairStrand) + numknots()*numHairs*3*sizeof(VR::Vector);
+}
+
+/*
+| from GeometryGenerator
+*/
+void shaveVrayStaticVoxelPrim::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::StaticHairStrand *s=(VR::StaticHairStrand*) (is.primitive->owner);
+
+// VR::RayParams* rayparams = (VR::RayParams*)rsray.rayparams;
+// assert( rayparams->currentPass == RPASS_GI);
+// assert( rayparams->currentPass == RPASS_LIGHTMAP);
+
+ isData.primitive=is.primitive;
+ isData.skipTag =is.skipTag;
+ isData.faceIndex= s->ownerIndex - firstid();
+
+ 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.gnormal.makeNormalized();
+ //if(isData.gnormal.length() < 0.99f)
+ //{
+ // printf("gn %f %f %f\n",isData.gnormal.x, isData.gnormal.y, isData.gnormal.z);
+ // fflush(stdout);
+ //}
+ isData.normal =getNormal(rsray);
+
+ isData.wpoint=rsray.p + VR::TracePoint(rsray.dir)*is.t;
+ isData.extraf=(float) s->getSegmentIndex((VR::StaticHairSegmentLine*) is.primitive);
+ isData.bary[2]=((VR::StaticHairSegmentLine*) 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 shaveVrayStaticVoxelPrim::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::StaticHairSegmentLine *segment=static_cast<VR::StaticHairSegmentLine*>(result.primitives()[idx]);
+ VR::StaticHairStrand *strand=static_cast<VR::StaticHairStrand*>(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->getSegmentIndex(segment);
+
+// result.extraFloats(6)[idx]=(float)strand->getSegmentIndex(segment); // the segment index within a hair strand
+ result.extraInts(1)[idx]=strand->ownerIndex - firstid(); // emil 10 Nov
+
+ 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