void BeginRender() { cout<<"\nBeginning Render..."; float alpha = camera.fov; float l = 1.0; float h = l * tan(alpha/2.0 *(M_PI/180)); float aspectRatio = (float)camera.imgWidth/camera.imgHeight; float s = aspectRatio * h; float dx = (2 * s)/camera.imgWidth; float dy = -(2 * h)/camera.imgHeight; float dxx = dx/2,dyy=dy/2; Point3 K(-s,h,-l); K.x += dxx; K.y += dyy; for(int i = 0; i< camera.imgHeight; i++){ for(int j = 0; j<camera.imgWidth; j++){ K.x += dx; Matrix3 RotMat; Point3 dvec = camera.dir - camera.pos; Point3 svec = camera.up.Cross(dvec); dvec.Normalize(); svec.Normalize(); camera.up.Normalize(); RotMat.Set(svec,camera.up, dvec); Ray r(camera.pos, K); r.dir=r.dir*RotMat; r.dir.Normalize(); HitInfo hInfo; hInfo.Init(); if(rootNode.GetNumChild()>0){ // for(int k=0; k < rootNode.GetNumChild(); ++k){ // RayTrace(rootNode.GetChild(k),r,i * camera.imgWidth + j); // } if(RayTrace_2(r, hInfo)) { renderImage.PutPixel(i *camera.imgWidth+j, white, hInfo.z); } else renderImage.PutPixel(i *camera.imgWidth+j, black, BIGFLOAT); } } K.x = -s; K.x += dxx; K.y += dy; } cout<<"Render Complete"<<endl; renderImage.ComputeZBufferImage(); renderImage.SaveZImage("/Users/varunk/Desktop/RayTracerProj1/RayTracerProj1/zbuffer.ppm"); renderImage.SaveImage("/Users/varunk/Desktop/RayTracerProj1/RayTracerProj1/renderimage.ppm"); }
void getOrthoNormalBasisVector(Point3 i_up, Point3 &o_out_vector /*U*/, Point3& o_vector_right /*v*/) { Point3 randomVectorW; //bool foundRandomVector = false; while (true) { randomVectorW = getRandomVector(); if ( fabs(i_up.Dot(randomVectorW)) < RANDOMCOSINEANGLE) { o_out_vector = i_up.Cross(randomVectorW); o_vector_right = i_up.Cross(o_out_vector).GetNormalized(); o_out_vector.Normalize(); break; } } }
void ResetVert (PatchMesh *patch) { // Make a edge table // Static table to avoid alloc prb CVertexNeighborhood& edgeTab=vertexNeighborhoodGlobal; edgeTab.build (*patch); // For each vertices for (int nV=0; nV<patch->numVerts; nV++) { // Selected ? if (patch->vertSel[nV]) { Point3 vert=patch->verts[nV].p; Point3 normal (0,0,0); // Count of neigbor for vertex n uint listSize=edgeTab.getNeighborCount (nV); // List of neigbor const uint* pList=edgeTab.getNeighborList (nV); // For each neigbor uint nn; for (nn=0; nn<listSize; nn++) { #if (MAX_RELEASE < 4000) // Compute average plane if (patch->edges[pList[nn]].patch1!=-1) normal+=patch->PatchNormal(patch->edges[pList[nn]].patch1); if (patch->edges[pList[nn]].patch2!=-1) normal+=patch->PatchNormal(patch->edges[pList[nn]].patch2); #else // (MAX_RELEASE <= 4000) // Compute average plane if (patch->edges[pList[nn]].patches[0]!=-1) normal+=patch->PatchNormal(patch->edges[pList[nn]].patches[0]); if (patch->edges[pList[nn]].patches[1]!=-1) normal+=patch->PatchNormal(patch->edges[pList[nn]].patches[1]); #endif // (MAX_RELEASE <= 4000) } // Normalize normal=normal.Normalize(); // Plane float fD=-DotProd(normal, vert); // Reset normales float fNorme=0.f; // For each neigbor for (nn=0; nn<listSize; nn++) { Point3 vect2=patch->verts[(patch->edges[pList[nn]].v1==nV)?patch->edges[pList[nn]].v2:patch->edges[pList[nn]].v1].p; vect2-=vert; vect2/=3.f; Point3 tmp1=CrossProd (vect2, normal); tmp1=CrossProd (normal, tmp1); tmp1=Normalize(tmp1); int nTang=(patch->edges[pList[nn]].v1==nV)?patch->edges[pList[nn]].vec12:patch->edges[pList[nn]].vec21; patch->vecs[nTang].p=vert+tmp1*DotProd (tmp1,vect2); tmp1=patch->vecs[nTang].p; tmp1-=vert; fNorme+=tmp1.Length(); } // Renorme new normal /*fNorme/=(float)edgeTab[nV].size(); ite=edgeTab[nV].begin(); while (ite!=edgeTab[nV].end()) { int nTang=(patch->edges[pList[nn]].v1==nV)?patch->edges[pList[nn]].vec12:patch->edges[pList[nn]].vec21; patch->vecs[nTang].p=fNorme*(Normalize(patch->vecs[nTang].p-vert))+vert; ite++; }*/ } } patch->computeInteriors(); patch->InvalidateGeomCache (); }
Color MtlBlinn::Shade(const Cone &ray, const HitInfo &hInfo, const LightList &lights, int bounceCount) const{ float bias = BIAS_SHADING; Color shade; Color rShade = Color(0,0,0); Color tShade = Color(0,0,0); const Material *mat; mat = hInfo.node->GetMaterial(); const MtlBlinn* mb =static_cast<const MtlBlinn*>(mat); // cout<<"HInfo front: "<<hInfo.front<<endl; /* local copy */ Point3 P; P.Set(hInfo.p.x,hInfo.p.y,hInfo.p.z); Cone iRay = ray; Color ambInt = mb->diffuse.Sample(hInfo.uvw, hInfo.duvw); Color allOther = Color(0,0,0); Color diffuse = mb->diffuse.Sample(hInfo.uvw, hInfo.duvw); Color ambComponent = Color(0,0,0); Point3 newN = hInfo.N; for ( unsigned int i=0; i<lights.size(); i++ ) { if(lights[i]->IsAmbient()){ // cout<<"ambient "<<endl; Color intensity = lights[i]->Illuminate(hInfo.p); ambComponent += (ambInt * intensity); continue; } else{ // cout<<"other lighting "<<endl; Point3 L = -lights[i]->Direction(P); L.Normalize(); Point3 V = ray.p - P; V.Normalize(); Point3 LplusV = L + V; Point3 H = (L+V)/LplusV.Length(); H.Normalize(); float alpha = mb->glossiness; // Point3 N = hInfo.N; Point3 N = newN; float S = H.Dot(N); S = pow(S,alpha); float costheta = L.Dot(N)/(L.Length() * N.Length()); Color intensity = lights[i]->Illuminate(P); // cout<<"costheta "<<endl; allOther += intensity * (costheta>0?costheta:0) * (diffuse + S * (mb->specular.Sample(hInfo.uvw, hInfo.duvw))) ; } /* finally add inta*cola + intall*costheta*(cold + s* colS)*/ shade = ambComponent + allOther; } /* Calculate refraction */ if(refraction.GetColor().r>0 && bounceCount>0){ //compute new jittered normal float gloss = refractionGlossiness; if(gloss){ float random = rand()/(float)RAND_MAX; float rRadius = sqrtf(random) * gloss; random = rand()/(float)RAND_MAX; float rAngle = random * 2.0 * M_PI; float x = rRadius * cos(rAngle); float y = rRadius * sin(rAngle); Point3 xAxis(1,0,0), yAxis(0,1,0), v1, v2, normalDir; normalDir = hInfo.N; // normalDir.Normalize(); if(normalDir.Dot(xAxis) > 0.7) v1 = normalDir.Cross(yAxis); else v1 = normalDir.Cross(xAxis); v2 = v1.Cross(normalDir); v1.Normalize(); v2.Normalize(); v1 *= x; v2 *= y; newN = hInfo.N + v1.Length() + v2.Length(); newN.Normalize(); } else{ newN = hInfo.N; } //------------------------------------- Color reflShade = Color(0,0,0); float R0, Refl = 0.0f, Trans = 0.0f; HitInfo temp; temp.Init(); // Point3 N = hInfo.N; Point3 N = newN; // Point3 V = Point3(iRay.p.x - hInfo.p.x, iRay.p.y - hInfo.p.y, iRay.p.z - hInfo.p.z); Point3 V = Point3(hInfo.p.x - iRay.p.x, hInfo.p.y - iRay.p.y, hInfo.p.z - iRay.p.z); V.Normalize(); float n1 = 1, n2 = 1; if(hInfo.front){ /* Hitting from outside */ // temp.front = false; n2 = ior; // cout<<"outside "<<endl; } else if(!hInfo.front){ /* Transmission from the inside */ // temp.front = true; n1 = ior; // cout<<"intside... "<<endl; // N = -hInfo.N; N *= -1; } float ratio_n = n1 / n2; float costheta_v = -V.Dot(N); /* refer: http://graphics.stanford.edu/courses/cs148-10-summer/docs/2006--degreve--reflection_refraction.pdf */ float sin2theta_t = ratio_n * ratio_n * (1 - costheta_v * costheta_v); Point3 T = ratio_n * V + (ratio_n * costheta_v - sqrtf(1 - sin2theta_t)) * N ; // cout<<ratio_n<<" "<<"cos_v "<<costheta_v<<" sin2theta_t "<<sin2theta_t<<endl; Cone tRay = Cone(hInfo.p,T); //tRay.dir.Normalize(); tRay.p.x = tRay.p.x + bias *tRay.dir.x; /* add bias */ tRay.p.y = tRay.p.y + bias *tRay.dir.y; tRay.p.z = tRay.p.z + bias *tRay.dir.z; // cout<<"B temp front: "<< temp.front<<endl; temp.timeInstance = hInfo.timeInstance; if(sin2theta_t <= 1){ if(RayTrace_2(tRay, temp)){ /* ray tracing after refraction */ // bounceCount--; tShade = temp.node->GetMaterial()->Shade(tRay,temp,lights,bounceCount); } else{ /* no hit after refraction */ tShade = environment.SampleEnvironment(tRay.dir); } /* Calculate Schlick's approximation */ R0 = (n1 - n2)/(n1 + n2); R0 *= R0; double X = 0.0; // if(n1 > n2){ // X = 1.0 - sqrtf(1.0 - sin2theta_t); // } // else{ X = 1.0 - costheta_v; } X = 1.0 - costheta_v; Refl = R0 + (1.0 - R0) * X * X * X * X * X; Trans = 1.0 - Refl; tShade.r *= exp(-absorption.r * temp.z); tShade.g *= exp(-absorption.g * temp.z); tShade.b *= exp(-absorption.b * temp.z); } else {/* Total internal reflection */ Refl = 1.0f; } /* Calculate reflection due to reflectance */ if(bounceCount >0){ // N = hInfo.N; N = newN; Point3 V = Point3(iRay.p.x - P.x, iRay.p.y - P.y, iRay.p.z - P.z); //V.Normalize(); Point3 VR = 2 * V.Dot(N) * N - V; //VR.Normalize(); Cone rRay = Cone(P + BIAS_SHADING * VR, VR); rRay.dir.Normalize(); HitInfo temp1; temp1.Init(); temp.timeInstance = hInfo.timeInstance; if(rootNode.GetNumChild()>0){ if(RayTrace_2(rRay, temp1)){ bounceCount --; reflShade = temp1.node->GetMaterial()->Shade(rRay, temp1, lights, bounceCount); } else{ reflShade = environment.SampleEnvironment(rRay.dir); // reflShade = Color(1,100,1); } } } // cout<<"Refl: "<<Refl<<"Trans "<<Trans<<endl; tShade = refraction.GetColor().r * (Trans * tShade + Refl * reflShade); } /* calculate reflection*/ if(reflection.GetColor().r>0 && bounceCount > 0){ //compute new jittered normal float gloss = reflectionGlossiness; if(gloss){ float random = rand()/(float)RAND_MAX; float rRadius = sqrtf(random) * gloss; random = rand()/(float)RAND_MAX; float rAngle = random * 2.0 * M_PI; float x = rRadius * cos(rAngle); float y = rRadius * sin(rAngle); Point3 xAxis(1,0,0), yAxis(0,1,0), v1, v2, normalDir; normalDir = hInfo.N; // normalDir.Normalize(); if(normalDir.Dot(xAxis) > 0.7) v1 = normalDir.Cross(yAxis); else v1 = normalDir.Cross(xAxis); v2 = v1.Cross(normalDir); v1.Normalize(); v2.Normalize(); v1 *= x; v2 *= y; newN = hInfo.N + v1+ v2; newN.Normalize(); } else{ newN = hInfo.N; } //------------------------------------- Point3 N = newN;//hInfo.N; Point3 V = Point3(iRay.p.x - P.x, iRay.p.y - P.y, iRay.p.z - P.z); // V.Normalize(); Point3 VR = 2 * V.Dot(N) * N - V; Cone rRay = Cone(P + BIAS_SHADING * VR, VR); rRay.dir.Normalize(); HitInfo temp; temp.Init(); temp.timeInstance=hInfo.timeInstance; if(rootNode.GetNumChild()>0){ if(RayTrace_2(rRay, temp)){ bounceCount--; rShade = reflection.GetColor().r * temp.node->GetMaterial()->Shade(rRay, temp, lights, bounceCount); } else{ rShade = reflection.GetColor().r *environment.SampleEnvironment(rRay.dir); // rShade = Color(1,111,1); } } } /* Add shade with reflected and refracted colors */ shade += (rShade + tShade); return shade; };
// Generate local to world from face info (pos, normal, etc) Matrix3 plDistributor::IGenerateTransform(int iRepNode, int iFace, const Point3& pt, const Point3& bary) const { const float kMinVecLengthSq = 1.e-6f; Matrix3 l2w(true); // First, set the scale Point3 scale; switch( fScaleLock ) { case kLockX | kLockY: scale.x = fRand.RandRangeF(fScaleLo.x, fScaleHi.x); scale.y = scale.x; scale.z = fRand.RandRangeF(fScaleLo.z, fScaleHi.z); break; case kLockX | kLockY | kLockZ: scale.x = fRand.RandRangeF(fScaleLo.x, fScaleHi.x); scale.y = scale.z = scale.x; break; default: scale.x = fRand.RandRangeF(fScaleLo.x, fScaleHi.x); scale.y = fRand.RandRangeF(fScaleLo.y, fScaleHi.y); scale.z = fRand.RandRangeF(fScaleLo.z, fScaleHi.z); break; } l2w.Scale(scale); // Next up, get the rotation. // First we'll randomly rotate about local Z float azimRot = fRand.RandMinusOneToOne() * fAzimuthRange; Matrix3 azimMat; azimMat.SetRotateZ(azimRot); l2w = l2w * azimMat; // Now align with the surface. // Get the interpolated surface normal. Point3 surfNorm = IGetSurfaceNormal(iFace, bary); Matrix3 repNodeTM = fRepNodes[iRepNode]->GetNodeTM(TimeValue(0)); Point3 alignVec = repNodeTM.GetRow(2); alignVec = alignVec * fWorldToSurfVec; alignVec = FNormalize(alignVec); Point3 norm = surfNorm + (alignVec - surfNorm) * fAlignWgt; // The norm can come out of this zero length, if the surace normal // is directly opposite the "natural" up direction and the weight // is 50% (for example). In that case, this is just a bad place // to drop this replicant. if( norm.LengthSquared() < kMinVecLengthSq ) { l2w.IdentityMatrix(); return l2w; } norm = norm.Normalize(); // Randomize through the cone around that. Point3 rndNorm = norm; Point3 rndDir = IPerpAxis(norm); Point3 rndOut = rndDir ^ norm; rndDir *= fRand.RandMinusOneToOne(); float len = sqrt(1.f - rndDir.LengthSquared()); rndOut *= len; if( fRand.RandMinusOneToOne() < 0 ) rndOut *= -1.f; Point3 rndPol = rndDir + rndOut; float polScale = fRand.RandZeroToOne() * fTanPolarRange; // Combine using the bunching factor polScale = polScale * (1.f - fPolarBunch) + polScale * polScale * fPolarBunch; rndPol *= polScale; rndNorm += rndPol; norm = rndNorm.Normalize(); // Have "up" alignment, now just generate random dir vector perpindicular to up Point3 dir = repNodeTM.GetRow(1); dir = dir * fWorldToSurfVec; Point3 out = dir ^ norm; if( out.LengthSquared() < kMinVecLengthSq ) { if( fAzimuthRange < M_PI * 0.5f ) { l2w.IdentityMatrix(); return l2w; } else { dir = IPerpAxis(norm); out = dir ^ norm; } } out = FNormalize(out); dir = norm ^ out; // If our "up" direction points into the surface, return an "up" direction // tangent to the surface. Also, make the "dir" direction point out from // the surface. So if the alignVec/fAlignWgt turns the replicant around // to penetrate the surface, it just lies down instead. // // There's an early out here, for the case where the surface normal is // exactly opposed to the destination normal. This usually means the // surface normal is directly opposite the alignVec. In that // case, we just want to bag it. if( DotProd(norm, surfNorm) < 0 ) { dir = surfNorm; dir = dir.Normalize(); out = dir ^ norm; if( out.LengthSquared() < kMinVecLengthSq ) { l2w.IdentityMatrix(); return l2w; } out = out.Normalize(); norm = out ^ dir; } Matrix3 align; align.Set(out, dir, norm, Point3(0,0,0)); l2w = l2w * align; // Lastly, set the position. Point3 pos = pt; const float offset = fRand.RandRangeF(fOffsetMin, fOffsetMax); pos += norm * offset; l2w.Translate(pos); l2w = l2w * fSurfNode->GetObjectTM(TimeValue(0)); return l2w; }
Color MtlBlinn::Shade(const Ray &ray, const HitInfo &hInfo, const LightList &lights, int bounceCount) const{ float bias = BIAS_SHADING; Color shade; Color rShade = Color(0,0,0); Color tShade = Color(0,0,0); const Material *mat; mat = hInfo.node->GetMaterial(); const MtlBlinn* mb =static_cast<const MtlBlinn*>(mat); // cout<<"HInfo front: "<<hInfo.front<<endl; /* local copy */ Point3 P; P.Set(hInfo.p.x,hInfo.p.y,hInfo.p.z); Ray iRay = ray; Color ambInt = mb->diffuse; Color allOther = Color(0,0,0); Color diffuse = mb->diffuse;; Color ambComponent = Color(0,0,0); for ( unsigned int i=0; i<lights.size(); i++ ) { if(lights[i]->IsAmbient()){ // cout<<"ambient "<<endl; Color intensity = lights[i]->Illuminate(hInfo.p); ambComponent += (ambInt * intensity); continue; } else{ // cout<<"other lighting "<<endl; Point3 L = -lights[i]->Direction(P); L.Normalize(); Point3 V = ray.p - P; V.Normalize(); Point3 LplusV = L + V; Point3 H = (L+V)/LplusV.Length(); H.Normalize(); float alpha = mb->glossiness; Point3 N = hInfo.N; float S = H.Dot(N); S = pow(S,alpha); float costheta = L.Dot(N)/(L.Length() * N.Length()); Color intensity = lights[i]->Illuminate(P); // cout<<"costheta "<<endl; allOther += intensity * (costheta>0?costheta:0) * (diffuse + S * (mb->specular)) ; } /* finally add inta*cola + intall*costheta*(cold + s* colS)*/ shade = ambComponent + allOther; } /* Calculate refraction */ if(refraction.Grey()>0 && bounceCount>0){ Color reflShade = Color(0,0,0); float R0, Refl = 0.0f, Trans = 0.0f; HitInfo temp; temp.Init(); Point3 N = hInfo.N; // Point3 V = Point3(iRay.p.x - hInfo.p.x, iRay.p.y - hInfo.p.y, iRay.p.z - hInfo.p.z); Point3 V = Point3(hInfo.p.x - iRay.p.x, hInfo.p.y - iRay.p.y, hInfo.p.z - iRay.p.z); V.Normalize(); float n1 = 1, n2 = 1; if(hInfo.front){ /* Hitting from outside */ // temp.front = false; n2 = ior; // cout<<"outside "<<endl; } else if(!hInfo.front){ /* Transmission from the inside */ // temp.front = true; n1 = ior; // cout<<"intside... "<<endl; N = -hInfo.N; } float ratio_n = n1 / n2; float costheta_v = -V.Dot(N); /* refer: http://graphics.stanford.edu/courses/cs148-10-summer/docs/2006--degreve--reflection_refraction.pdf */ float sin2theta_t = ratio_n * ratio_n * (1 - costheta_v * costheta_v); Point3 T = ratio_n * V + (ratio_n * costheta_v - sqrtf(1 - sin2theta_t)) * N ; // cout<<ratio_n<<" "<<"cos_v "<<costheta_v<<" sin2theta_t "<<sin2theta_t<<endl; Ray tRay = Ray(hInfo.p,T); //tRay.dir.Normalize(); tRay.p.x = tRay.p.x + bias *tRay.dir.x; /* add bias */ tRay.p.y = tRay.p.y + bias *tRay.dir.y; tRay.p.z = tRay.p.z + bias *tRay.dir.z; // cout<<"B temp front: "<< temp.front<<endl; if(sin2theta_t <= 1){ if(RayTrace_2(tRay, temp)){ // bounceCount--; // cout<<"A temp front: "<< temp.front<<endl; tShade = temp.node->GetMaterial()->Shade(tRay,temp,lights,bounceCount); tShade.r *= exp(-absorption.r * temp.z); tShade.g *= exp(-absorption.g * temp.z); tShade.b *= exp(-absorption.b * temp.z); // shade = tShade; /* remove later */ // return shade; /* Calculate Schlick's approximation */ R0 = (n1 - n2)/(n1 + n2); R0 *= R0; double X = 0.0; // if(n1 > n2){ // X = 1.0 - sqrtf(1.0 - sin2theta_t); // } // else{ X = 1.0 - costheta_v; } X = 1.0 - costheta_v; Refl = R0 + (1.0 - R0) * X * X * X * X * X; Trans = 1.0 - Refl; } } else {/* Total internal reflection */ Refl = 1.0f; } /* Calculate reflection due to reflectance */ if(bounceCount >0){ N = hInfo.N; Point3 V = Point3(iRay.p.x - P.x, iRay.p.y - P.y, iRay.p.z - P.z); //V.Normalize(); Point3 VR = 2 * V.Dot(N) * N - V; //VR.Normalize(); Ray rRay = Ray(P, VR); //rRay.dir.Normalize(); rRay.p.x = rRay.p.x + bias *rRay.dir.x; rRay.p.y = rRay.p.y + bias *rRay.dir.y; rRay.p.z = rRay.p.z + bias *rRay.dir.z; HitInfo temp1; temp1.Init(); if(rootNode.GetNumChild()>0){ if(RayTrace_2(rRay, temp1)){ bounceCount --; reflShade = temp1.node->GetMaterial()->Shade(rRay, temp1, lights, bounceCount); } } } // cout<<"Refl: "<<Refl<<"Trans "<<Trans<<endl; tShade = refraction * (Trans * tShade + Refl * reflShade); } /* calculate reflection*/ if(reflection.Grey()>0 && bounceCount > 0){ Point3 N = hInfo.N; Point3 V = Point3(iRay.p.x - P.x, iRay.p.y - P.y, iRay.p.z - P.z); // V.Normalize(); Point3 VR = 2 * V.Dot(N) * N - V; Ray rRay = Ray(hInfo.p, VR); //rRay.dir.Normalize(); rRay.p.x = rRay.p.x + bias *rRay.dir.x; rRay.p.y = rRay.p.y + bias *rRay.dir.y; rRay.p.z = rRay.p.z + bias *rRay.dir.z; HitInfo temp; temp.Init(); if(rootNode.GetNumChild()>0){ if(RayTrace_2(rRay, temp)){ bounceCount--; rShade = reflection * temp.node->GetMaterial()->Shade(rRay, temp, lights, bounceCount); } } } /* Add shade with reflected and refracted colors */ shade += (rShade + tShade); return shade; };
CVertexCandidate *CMaxMesh::GetVertexCandidate(CSkeletonCandidate *pSkeletonCandidate, int faceId, int faceVertexId) { // check for valid mesh and physique modifier if((m_pIMesh == 0)) { theExporter.SetLastError("Invalid handle.", __FILE__, __LINE__); return 0; } // check if face id is valid if((faceId < 0) || (faceId >= m_pIMesh->getNumFaces())) { theExporter.SetLastError("Invalid face id found.", __FILE__, __LINE__); return 0; } // check if face vertex id is valid if((faceVertexId < 0) || (faceVertexId >= 3)) { theExporter.SetLastError("Invalid face vertex id found.", __FILE__, __LINE__); return 0; } // allocate a new vertex candidate CVertexCandidate *pVertexCandidate; pVertexCandidate = new CVertexCandidate(); if(pVertexCandidate == 0) { theExporter.SetLastError("Memory allocation failed.", __FILE__, __LINE__); return 0; } // create the new vertex candidate if(!pVertexCandidate->Create()) { delete pVertexCandidate; return 0; } // get vertex id int vertexId; vertexId = m_pIMesh->faces[faceId].v[faceVertexId]; // get the absolute vertex position Point3 vertex; vertex = m_pIMesh->getVert(vertexId) * m_tm; // set the vertex candidate position pVertexCandidate->SetPosition(vertex.x, vertex.y, vertex.z); pVertexCandidate->SetUniqueId(vertexId); // get the absolute vertex normal Point3 normal; normal = GetVertexNormal(faceId, vertexId); normal = normal * Inverse(Transpose(m_tm)); normal = normal.Normalize(); // set the vertex candidate normal pVertexCandidate->SetNormal(normal.x, normal.y, normal.z); if(m_pIMesh->numCVerts > 0) { VertColor vc; vc = m_pIMesh->vertCol[m_pIMesh->vcFace[faceId].t[faceVertexId]]; CalVector vcCal(vc.x, vc.y, vc.z); pVertexCandidate->SetVertColor(vcCal); } // get the vertex weight array float *pVertexWeights; pVertexWeights = m_pIMesh->getVertexWeights(); //if( pVertexWeights == NULL ) { // delete pVertexCandidate; // theExporter.SetLastError("Mesh has no vertex weights", __FILE__, __LINE__); // return 0; //} // get the vertex weight (if possible) float weight; if(pVertexWeights != 0) { weight = pVertexWeights[vertexId]; } else { weight = 0.0f; } // another 3ds max weird behaviour: // zero out epsilon weights if(weight < 0.0005f) weight = 0.0f; // set the vertex candidate weight pVertexCandidate->SetPhysicalProperty(weight); // get the material id of the face int materialId; materialId = GetFaceMaterialId(faceId); if((materialId < 0) || (materialId >= (int)m_vectorStdMat.size())) { delete pVertexCandidate; theExporter.SetLastError("Invalid material id found.", __FILE__, __LINE__); return 0; } // get the material of the face StdMat *pStdMat; pStdMat = m_vectorStdMat[materialId]; // loop through all the mapping channels and extract texture coordinates int mapId; for(mapId = 0; mapId < pStdMat->NumSubTexmaps(); mapId++) { // get texture map Texmap *pTexMap; pTexMap = pStdMat->GetSubTexmap(mapId); // check if map is valid if((pTexMap != 0) && (pStdMat->MapEnabled(mapId))) { // get the mapping channel int channel; channel = pTexMap->GetMapChannel(); bool bValidUV; bValidUV = false; // extract the texture coordinate UVVert uvVert; if(m_pIMesh->mapSupport(channel)) { TVFace *pTVFace; pTVFace = m_pIMesh->mapFaces(channel); UVVert *pUVVert; pUVVert = m_pIMesh->mapVerts(channel); uvVert = pUVVert[pTVFace[faceId].t[faceVertexId]]; bValidUV = true; } else if(m_pIMesh->numTVerts > 0) { uvVert = m_pIMesh->tVerts[m_pIMesh->tvFace[faceId].t[faceVertexId]]; bValidUV = true; } // if we found valid texture coordinates, add them to the vertex candidate if(bValidUV) { // apply a possible uv generator StdUVGen *pStdUVGen; pStdUVGen = (StdUVGen *)pTexMap->GetTheUVGen(); if(pStdUVGen != 0) { Matrix3 tmUV; pStdUVGen->GetUVTransform(tmUV); uvVert = uvVert * tmUV; } // add texture coordinate to the vertex candidate, inverting the y coordinate pVertexCandidate->AddTextureCoordinate(uvVert.x, 1.0f - uvVert.y); } } } // check for physique modifier if(m_modifierType == MODIFIER_PHYSIQUE) { // create a physique export interface IPhysiqueExport *pPhysiqueExport; pPhysiqueExport = (IPhysiqueExport *)m_pModifier->GetInterface(I_PHYINTERFACE); if(pPhysiqueExport == 0) { delete pVertexCandidate; theExporter.SetLastError("Physique modifier interface not found.", __FILE__, __LINE__); return 0; } // create a context export interface IPhyContextExport *pContextExport; pContextExport = (IPhyContextExport *)pPhysiqueExport->GetContextInterface(m_pINode); if(pContextExport == 0) { m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Context export interface not found.", __FILE__, __LINE__); return 0; } // set the flags in the context export interface pContextExport->ConvertToRigid(TRUE); pContextExport->AllowBlending(TRUE); // get the vertex export interface IPhyVertexExport *pVertexExport; pVertexExport = (IPhyVertexExport *)pContextExport->GetVertexInterface(vertexId); if(pVertexExport == 0) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Vertex export interface not found.", __FILE__, __LINE__); return 0; } // get the vertex type int vertexType; vertexType = pVertexExport->GetVertexType(); // handle the specific vertex type if(vertexType == RIGID_TYPE) { // typecast to rigid vertex IPhyRigidVertex *pTypeVertex; pTypeVertex = (IPhyRigidVertex *)pVertexExport; // add the influence to the vertex candidate // get the influencing bone if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(), 1.0f)) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } else if(vertexType == RIGID_BLENDED_TYPE) { // typecast to blended vertex IPhyBlendedRigidVertex *pTypeVertex; pTypeVertex = (IPhyBlendedRigidVertex *)pVertexExport; // loop through all influencing bones int nodeId; for(nodeId = 0; nodeId < pTypeVertex->GetNumberNodes(); nodeId++) { // add the influence to the vertex candidate if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pTypeVertex->GetNode(nodeId), pTypeVertex->GetWeight(nodeId))) { pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } } // release all interfaces pPhysiqueExport->ReleaseContextInterface(pContextExport); m_pModifier->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); } #if MAX_RELEASE >= 4000 // check for skin modifier else if(m_modifierType == MODIFIER_SKIN) { // create a skin interface ISkin *pSkin; pSkin = (ISkin*)m_pModifier->GetInterface(I_SKIN); if(pSkin == 0) { delete pVertexCandidate; theExporter.SetLastError("Skin modifier interface not found.", __FILE__, __LINE__); return 0; } // create a skin context data interface ISkinContextData *pSkinContextData; pSkinContextData = (ISkinContextData *)pSkin->GetContextInterface(m_pINode); if(pSkinContextData == 0) { m_pModifier->ReleaseInterface(I_SKIN, pSkin); delete pVertexCandidate; theExporter.SetLastError("Skin context data interface not found.", __FILE__, __LINE__); return 0; } // loop through all influencing bones int nodeId; for(nodeId = 0; nodeId < pSkinContextData->GetNumAssignedBones(vertexId); nodeId++) { // get the bone id int boneId; boneId = pSkinContextData->GetAssignedBone(vertexId, nodeId); if(boneId < 0) continue; // add the influence to the vertex candidate if(!AddBoneInfluence(pSkeletonCandidate, pVertexCandidate, pSkin->GetBone(boneId), pSkinContextData->GetBoneWeight(vertexId, nodeId))) { m_pModifier->ReleaseInterface(I_SKIN, pSkin); delete pVertexCandidate; theExporter.SetLastError("Invalid bone assignment.", __FILE__, __LINE__); return 0; } } // release all interfaces m_pModifier->ReleaseInterface(I_SKIN, pSkin); } #endif else if( m_modifierType == MODIFIER_MORPHER || m_modifierType == MODIFIER_NONE ) { } else { theExporter.SetLastError("No physique/skin/morpher modifier found.", __FILE__, __LINE__); return 0; } return pVertexCandidate; }
Mesh* TriObject::GetRenderMesh(TimeValue t, INode *inode, View &view, BOOL& needDelete) { if (mDisableDisplacement || !(view.flags & RENDER_MESH_DISPLACEMENT_MAP)) { needDelete = FALSE; return &mesh; } // need to check the mesh and see if any face has a matId the requires displacment mapping BOOL needDisp = FALSE; // Get the material Mtl* pMtl = inode ? inode->GetMtl() : NULL; if (pMtl) { // does the mesh as a whole need it if (pMtl->Requirements(mesh.mtlIndex)&MTLREQ_DISPLACEMAP) needDisp = TRUE; if (!needDisp) { for (int f = 0; f < mesh.numFaces; f++) { if (pMtl->Requirements(mesh.getFaceMtlIndex(f))&MTLREQ_DISPLACEMAP) { needDisp = TRUE; break; } } } if (needDisp) { if (mesh.getNumFaces() == 0) return &mesh; Matrix3 otm; if (inode) otm = inode->GetObjectTM(t); else otm.IdentityMatrix(); GetGTessFunction(); if (mSubDivideDisplacement && psGTessFunc) { // if we have a material that does displacement mapping and if we can do it Mesh *pMesh = new Mesh(); needDelete = TRUE; (*psGTessFunc)((void *)&mesh, MAX_MESH, &otm, pMesh, NULL, &mDispApprox, &view, pMtl, FALSE, mSplitMesh); needDelete = TRUE; return pMesh; } else { Mesh *pMesh = new Mesh(mesh); needDelete = TRUE; BOOL hasUVs = pMesh->tvFace != NULL; pMesh->buildRenderNormals(); // now displace the verts BitArray vertsSet; vertsSet.SetSize(pMesh->numVerts); for (int f = 0; f < pMesh->numFaces; f++) { Face *pFace = &pMesh->faces[f]; TVFace *pTVFace = &pMesh->tvFace[f]; int matid = pFace->getMatID(); for (int v = 0; v < 3; v++) { int vidx = pFace->v[v]; if (vertsSet[vidx]) continue; // displace only once Point3 norm = pMesh->getNormal(vidx); norm.Normalize(); Point3& vert = pMesh->getVert(vidx); UVVert uvvert; if (hasUVs) uvvert = pMesh->getTVert(pTVFace->t[v]); else { uvvert.x = 0.0; uvvert.y = 0.0; } pMesh->buildBoundingBox(); Box3 bbox = pMesh->getBoundingBox(); float dispScale = Length(bbox.pmax - bbox.pmin)/10.0f; float disp = GetDisp(pMtl, pMesh, f, pFace->getMatID(), vert, uvvert.x, uvvert.y, otm) * dispScale; vert += (norm * disp); vertsSet.Set(vidx); } } return pMesh; } } } needDelete = FALSE; return &mesh; }
int MaxExporter::DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts, DWORD options) { /*if(!suppressPrompts) DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PANEL), GetActiveWindow(), MaxExporterOptionsDlgProc, (LPARAM)this);*/ #pragma message(TODO("return TRUE If the file is exported properly")) Node::s_nextID = 1; ofstream myFile; myFile.open("DebugExporter.txt"); wstring wFileName( name ); string fileName( wFileName.begin(), wFileName.end() ); //f= fopen( fileName.c_str(),"wb"); BinaryFile = loadSave( fileName.c_str() ); //BinaryFile.saveInt( 5 ); //BinaryFile.close(); myFile << "Start Export\n"; IGameScene* gameScene = GetIGameInterface(); gameScene->InitialiseIGame(); int nodeCount = gameScene->GetTopLevelNodeCount(); myFile << "Number of top level nodes: " << nodeCount << "\n"; //get all of the materials for( int nodeNumber = 0; nodeNumber < nodeCount; ++nodeNumber) { IGameNode* gameNode = gameScene->GetTopLevelNode( nodeNumber ); Node* myNode = new Node( gameNode ); m_NodeList.push_back( myNode ); findFaces( myNode, myFile ); } myFile << "Number of materials\n"; myFile << m_materialSet.size() << "\n"; int totalBatches = 0; //myFile<< "Number of triangleBatchMaps: " << m_triangleBatchesPerNode.size() << "\n"; for( auto nodeIter = m_NodeList.begin(); nodeIter != m_NodeList.end(); ++nodeIter ) { std::map< IGameMaterial*, TriangleBatch* > triangleBatches = (*nodeIter)->m_triangleBatchesPerMaterial; myFile << "Invidiual triangleBatch size: " << triangleBatches.size() << "\n"; for( auto materialIter = m_materialSet.begin(); materialIter != m_materialSet.end(); ++materialIter ) { auto found = triangleBatches.find( * materialIter ); if( found != triangleBatches.end() ) { ++totalBatches; } } } BinaryFile.saveInt( m_NodeList.size() ); myFile << "Number of Nodes: " << m_NodeList.size() << "\n"; for( auto nodeIter = m_NodeList.begin(); nodeIter != m_NodeList.end(); ++nodeIter ) { std::map< IGameMaterial*, TriangleBatch* > triangleBatches = (*nodeIter)->m_triangleBatchesPerMaterial; std::map<IGameMaterial*, std::vector< NodeFace > > facesPerMaterial = (*nodeIter)->m_facesPerMaterial; IGameNode* currentNode = (*nodeIter)->m_gameNode; IGameNode* parentNode; GMatrix parentWTM; GMatrix toParentMatrix; GMatrix worldTM; GMatrix localTM; int time = gameScene->GetSceneStartTime(); for( ; time < gameScene->GetSceneEndTime(); time += 4800/30 ) { if( (*nodeIter)->m_parentID != 0 ) { myFile << "Trying to find parent... \n"; parentNode = (*nodeIter)->m_parent->m_gameNode; if( parentNode != nullptr ) { myFile << "Parent found \n"; parentWTM = parentNode->GetWorldTM( time ); toParentMatrix = parentWTM.Inverse(); worldTM = currentNode->GetWorldTM( time ) * toParentMatrix; } } else { worldTM = currentNode->GetWorldTM( time ); } (*nodeIter)->m_toParentMatrix.push_back( Matrix4x4( worldTM[0], worldTM[1], worldTM[2], worldTM[3] ) ); } localTM = currentNode->GetWorldTM().Inverse(); (*nodeIter)->m_worldToLocal = Matrix4x4( localTM[0], localTM[1], localTM[2], localTM[3] ); //Save the node BinaryFile.saveNode( *nodeIter, myFile ); BinaryFile.saveInt( (*nodeIter)->m_triangleBatchesPerMaterial.size() ); for( auto materialIter = m_materialSet.begin(); materialIter != m_materialSet.end(); ++materialIter ) { //Set the current material's VBO and IBO // IGameMaterial* currentMaterial = *materialIter; TriangleBatch* currentBatch = triangleBatches[ currentMaterial ]; GMatrix localTMNoTrans = localTM; localTMNoTrans.SetRow( 3, Point4( 0,0,0,1) ); if( currentBatch != nullptr ) { MaxMaterial* currentMaxMaterial = currentBatch->m_material; VBO* currentVBO = currentBatch->m_vbo; IBO* currentIBO = currentBatch->m_ibo; vector< NodeFace >& faceVector = facesPerMaterial.find( currentMaterial )->second; //Get texture materials and export them // if( currentMaterial != nullptr ) { int numOfTexMaps = currentMaterial->GetNumberOfTextureMaps(); myFile << "Number of texture maps: " << numOfTexMaps << "\n"; for( int i = 0; i < numOfTexMaps; ++i ) { IGameTextureMap* gameTextureMap = currentMaterial->GetIGameTextureMap( i ); if( gameTextureMap != nullptr && gameTextureMap->IsEntitySupported() ) { int stdMapSlot = gameTextureMap->GetStdMapSlot(); if( stdMapSlot == ID_DI ) { wstring wBitmapFileName; wBitmapFileName = gameTextureMap->GetBitmapFileName(); if( wBitmapFileName.size() > 0 ) { BitmapInfo bi( gameTextureMap->GetBitmapFileName() ); BMMGetFullFilename( &bi ); wBitmapFileName = bi.Name(); std::string fullBitmapFileName( wBitmapFileName.begin(), wBitmapFileName.end() ); if( fullBitmapFileName.size() > 0 ) { int lastSlash = fullBitmapFileName.find_last_of('\\') + 1; if( lastSlash != string::npos ) { const std::string bitmapFileName = fullBitmapFileName.substr( lastSlash ); wstring nameAsWString( name ); std::string nameAsString( nameAsWString.begin(), nameAsWString.end() ); const std::string extension = nameAsString.substr( 0, nameAsString.find_last_of('\\') + 1 ); std::string newFileName = extension; newFileName.append( bitmapFileName ); wstring wNewFileName(newFileName.begin(), newFileName.end()); if( CopyFile( wBitmapFileName.c_str(), wNewFileName.c_str(), false ) ) { if( stdMapSlot == ID_DI ) { currentMaxMaterial->m_diffuseTexture = bitmapFileName; currentMaxMaterial->bHasDiffuseTexture = true; } //BinaryFile.saveString( bitmapFileName ); } else { myFile << GetLastError() << "\n"; myFile << "copying the file FAILED.\n"; } } } } } } } } myFile<< "Number of faces for this material: " << faceVector.size() << "\n"; for( int face = 0; face < faceVector.size(); ++face ) { FaceEx* meshFace = faceVector[face].m_face; IGameMesh* gameMesh = faceVector[face].m_mesh; IGameSkin* gameSkin = gameMesh->GetIGameSkin(); int position, normal, color, texCoordinate, maxPosition; for( int i = 0; i < 3; ++i) { maxPosition = (int)meshFace->vert[i]; Point3 tempPos = gameMesh->GetVertex( maxPosition ); tempPos = tempPos * localTM; Vector3D positionVec3( tempPos.x, tempPos.y, tempPos.z ); position = currentVBO->insertPosition(positionVec3); normal = (int)meshFace->norm[i]; Point3 tempNormal = gameMesh->GetNormal( normal ); tempNormal = tempNormal * localTMNoTrans; tempNormal = tempNormal.Normalize(); Vector3D normalVec3( tempNormal.x, tempNormal.y, tempNormal.z ); normal = currentVBO->insertNormal(normalVec3); //IBO texCoordinate = (int)meshFace->texCoord[i]; Point2 tempTexCoord = gameMesh->GetTexVertex( texCoordinate ); Vector2 texCoordVec2( tempTexCoord.x, tempTexCoord.y ); texCoordinate = currentVBO->insertTexCoord(texCoordVec2); VertexIndex VI( position, normal, texCoordinate ); if( gameSkin != nullptr ) { int numberOfBones = gameSkin->GetNumberOfBones( maxPosition ); for( int boneIndex = 0; boneIndex < numberOfBones; ++boneIndex ) { float boneWeight = gameSkin->GetWeight( maxPosition, boneIndex ); IGameNode* bone = gameSkin->GetIGameBone( maxPosition, boneIndex ); myFile << "Bone node ID: " << bone->GetNodeID() << "\n"; int nodeIDForBone = m_boneIDToNodeID[ bone->GetNodeID() ]; myFile << "Node ID: " << nodeIDForBone << "\n"; VI.addBoneWeight( nodeIDForBone, boneWeight ); /*for( auto boneIter = m_NodeList.begin(); boneIter != m_NodeList.end(); ++boneIter ) { if( (*boneIter)->m_gameNode == bone ) { myFile << "Found the bone!\n"; } }*/ } VI.topBoneWeights(); } int vertIndex = currentVBO->insertVertex( VI ); currentIBO->addIndex( vertIndex ); } } BinaryFile.saveTriangleMesh( currentBatch, myFile ); } } } myFile.close(); for( int nodeNumber = 0; nodeNumber < nodeCount; ++nodeNumber) { IGameNode* gameNode = gameScene->GetTopLevelNode( nodeNumber ); if( gameNode != nullptr ) { tearDown( gameNode ); } } BinaryFile.close(); return TRUE; //return FALSE; }