// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 /********************************************************************** *< FILE: shaveVrayVoxelPrim.cpp ( was shaveVrayVoxelPrim.cpp ) -- implementation file DESCRIPTION: Generic hair voxel primitive CREATED BY: Vladimir Dubovoy HISTORY: created 02-09-2008 ( as part of 3ds Max + VRay hair shaders) merged 30-03-2010 *> **********************************************************************/ #include "assert.h" #include "shaveVrayVoxelPrim.h" //#include "shaveVrayPrimsSharedFunctions.h" #include "shaveVrayShadeable.h" #include "shaveVrayShadeInstance.h" #include "shaveVrayShadeData.h" #include "shaveVrayInstance.h" shaveVrayVoxelPrim::shaveVrayVoxelPrim(IHairVoxel* vox, VR::VRayCore *vray, shaveVrayInstance *inst): shaveVrayVoxelPrimBase(vox,vray) { _hinst() = inst; _numknots() = eDefNumKnots; for (int i=0; i < eNumSides; i++) { float angle=2.0f*VR::pi()*float(i)/float(eNumSides); _uc(i)=cosf(angle); _vc(i)=sinf(angle); } if(voxel()) { const HairType& hair = voxel()->GetHair(); int numHairs = hair.GetNumStrands(); if(numHairs == 0) { //assume all hairs have the same number of segments _numknots() = hair.face_end[0] - hair.face_start[0]; } } shaveVrayShadeable* sh = new shaveVrayShadeable(this); if(vray) { sh->initBSDFpool(vray); } _shade() = sh; //_shinst() = new shaveVrayShadeInstance(this); _shinst() = (VR::VRayShadeInstance*) new shaveVrayShadeInstance(this); // _shdata() = new HairVrShadeData(); //_shdata() = new shaveVrayShadeData(hinst()); _shdata() = inst->GetShData(); // _sfprops() = new VR::SurfaceProperties; _tipfade() = false; } shaveVrayVoxelPrim::~shaveVrayVoxelPrim() { if(shade()) delete shade(); if(shinst()) delete shinst(); //if(shdata()) // delete shdata(); //if(sfprops()) // delete sfprops(); } bool shaveVrayVoxelPrim::IsColorConst(int strandidx) const { const HairType& hair = voxel()->GetHair(); return hair.IsColorConst(strandidx); } void shaveVrayVoxelPrim::GetRootColor(int strandidx,VR::Color& c) const { const HairType& hair = voxel()->GetHair(); return hair.GetRootColor(strandidx,c.r,c.g,c.b); } float shaveVrayVoxelPrim::GetOpacity(int strandidx) const { const HairType& hair = voxel()->GetHair(); return hair.GetStrandOpacity(strandidx); } float shaveVrayVoxelPrim::GetAmbDiff(int strandidx) const { const HairType& hair = voxel()->GetHair(); return hair.GetStrandAmbDiff(strandidx); } float shaveVrayVoxelPrim::GetGlossiness(int strandidx) const { const HairType& hair = voxel()->GetHair(); return hair.GetStrandGlossiness(strandidx); } float shaveVrayVoxelPrim::GetSpecLevel(int strandidx) const { const HairType& hair = voxel()->GetHair(); return hair.GetStrandSpecLevel(strandidx); } VR::ShadeVec shaveVrayVoxelPrim::GetUVW(int segmentIdx, int strandidx, float segmentOffset, int channel) const { #if 0 //vlad|22jan2013 - we still do not have valid data in UVSETS const HairUVs& hairUVs=voxel()->GetUVs(); if (channel<0 || channel>=hairUVs.totalUVSets) return VR::Vector(0.0f, 0.0f, 0.0f); if (strandidx<0 || strandidx>=hairUVs.totalRoots) return VR::Vector(0.0f, 0.0f, 0.0f); const VERT &uv=hairUVs.uvRoot[strandidx*hairUVs.totalUVSets+channel]; return VR::Vector(uv.x, uv.y, uv.z); #else //grabbing it form defaut set of HAIRTYPE const HairType& hair = voxel()->GetHair(); int numHairs = hair.GetNumStrands(); if (strandidx >= numHairs || strandidx < 0) return VR::ShadeVec(0.0f, 0.0f, 0.0f); int start; int end; hair.GetStrand(strandidx, start, end); int numKnots=end-start; if (segmentIdx<0 || segmentIdx>=numKnots-1) return VR::ShadeVec(0.0f, 0.0f, 0.0f); VR::ShadeVec uvw0; VR::ShadeVec uvw1; int min_i=segmentIdx+start; GetUV(hair, min_i+0, uvw0); GetUV(hair, min_i+1, uvw1); return uvw0+(uvw1-uvw0)*segmentOffset; #endif } //not optimized routine void shaveVrayVoxelPrim::GetInterpColor(int segmentIdx, int strandidx, float segmentOffset, VR::Color& res) const { ///////////// test /////////// //res = VR::Color(1.0f, 0.0f, 0.0f); //return; ////////////////////////////// const HairType& hair = voxel()->GetHair(); int numHairs = hair.GetNumStrands(); if(strandidx >= numHairs || strandidx < 0) { //red hair will be a signal that something goes wrong res = VR::Color(1.0f, 0.0f, 0.0f); return; } int start; int end; hair.GetStrand(strandidx,start,end); int nknots = end - start; float t=segmentOffset; float T=(float) (segmentIdx); float d=(T+t)/(float) nknots; hair.GetColor(strandidx,d,res.r,res.g,res.b); } //not optimized routine float shaveVrayVoxelPrim::GetInterpOpacity(int segmentIdx, int strandidx, float segmentOffset) const { ///////////// test ///////// //return 1.0f; /////////////////////////// const HairType& hair = voxel()->GetHair(); int numHairs = hair.GetNumStrands(); if(strandidx >= numHairs || strandidx < 0) { return 1.0f; } int start; int end; hair.GetStrand(strandidx,start,end); int nknots = end - start; float t=segmentOffset; float T=(float) (segmentIdx); float d=(T+t)/(float) nknots; if(d > 1.0f) d = 1.0f; if(d < 0.0f) d = 0.0f; float op = hair.GetStrandOpacity(strandidx); return op*(1.0f-d); } VR::ShadeVec shaveVrayVoxelPrim::GetHairDir(const VR::ShadeVec &hit, int segmentIdx, int strandidx, float segmentOffset) const { //////////// test //////////// //return VR::Vector(0.0f, 0.0f, 1.0f); //////////////////////////// const HairType& hair = voxel()->GetHair(); int numHairs = hair.GetNumStrands(); if(strandidx >= numHairs || strandidx < 0) { return VR::ShadeVec(0.0f, 0.0f, 1.0f); } int start; int end; hair.GetStrand(strandidx,start,end); int nknots = end - start; VR::ShadeVec knot0; VR::ShadeVec knot1; int min_i=segmentIdx+start; GetVert(hair, min_i, knot0); GetVert(hair, min_i+1, knot1); VR::ShadeVec sg = knot1 - knot0; float t=segmentOffset; float T=(float) (segmentIdx); float d=(T+t)/(float) nknots; float sgLen=sg.length(); VR::ShadeVec dir1=(sgLen<1e-12f)? VR::ShadeVec(0.0f, 0.0f, 0.0f) : (sg/sg.length()); // The direction of the current segment VR::ShadeVec dir0; // The direction of the previous segment if (min_i-1-start<0) { GetSurfNormal(hair, strandidx, dir0); dir0.makeNormalized0(); } else { VR::ShadeVec knotb; GetVert(hair, min_i-1, knotb); dir0=knot0-knotb; dir0.makeNormalized0(); } dir0+=(dir1-dir0)*t; dir0.makeNormalized0(); return dir0; //return VR::normalize0(dir0+(dir1-dir0)*t); }