void LuxRenderer::defineFilm() { int width = this->mtlu_renderGlobals->imgWidth; int height = this->mtlu_renderGlobals->imgHeight; MString outputPath = this->mtlu_renderGlobals->basePath + "/" + this->mtlu_renderGlobals->imageName + "." + (int)this->mtlu_renderGlobals->currentFrame + ".lxs"; // file path without extension, will be added automatically by the renderer MString fileName = this->mtlu_renderGlobals->imagePath + "/" + this->mtlu_renderGlobals->imageName + "." + (int)this->mtlu_renderGlobals->currentFrame; const char *filename = fileName.asChar(); const int xres = width; const int yres = height; const bool write_png = true; const int halttime = this->mtlu_renderGlobals->halttime; const int haltspp = this->mtlu_renderGlobals->haltspp; int displayinterval = 3; ParamSet fp = CreateParamSet(); fp->AddInt("xresolution",&xres); fp->AddInt("yresolution",&yres); fp->AddBool("write_png",&write_png); fp->AddString("filename",&filename); if( halttime > 0) fp->AddInt("halttime", &halttime); if( haltspp > 0) fp->AddInt("haltspp", &haltspp); if( displayinterval > 0) fp->AddInt("displayinterval", &displayinterval); lux->film("fleximage", boost::get_pointer(fp)); }
void LuxRenderer::defineTriangleMesh(mtlu_MayaObject *obj, bool noObjectDef = false) { MObject meshObject = obj->mobject; MStatus stat = MStatus::kSuccess; MFnMesh meshFn(meshObject, &stat); CHECK_MSTATUS(stat); MItMeshPolygon faceIt(meshObject, &stat); CHECK_MSTATUS(stat); MPointArray points; meshFn.getPoints(points); MFloatVectorArray normals; meshFn.getNormals( normals, MSpace::kWorld ); MFloatArray uArray, vArray; meshFn.getUVs(uArray, vArray); logger.debug(MString("Translating mesh object ") + meshFn.name().asChar()); MString meshFullName = obj->fullNiceName; MIntArray trianglesPerFace, triVertices; meshFn.getTriangles(trianglesPerFace, triVertices); int numTriangles = 0; for( size_t i = 0; i < trianglesPerFace.length(); i++) numTriangles += trianglesPerFace[i]; // lux render does not have a per vertex per face normal definition, here we can use one normal and uv per vertex only // So I create the triangles with unique vertices, normals and uvs. Of course this way vertices etc. cannot be shared. int numPTFloats = numTriangles * 3 * 3; logger.debug(MString("Num Triangles: ") + numTriangles + " num tri floats " + numPTFloats); float *floatPointArray = new float[numPTFloats]; float *floatNormalArray = new float[numPTFloats]; float *floatUvArray = new float[numTriangles * 3 * 2]; logger.debug(MString("Allocated ") + numPTFloats + " floats for point and normals"); MIntArray triangelVtxIdListA; MFloatArray floatPointArrayA; MPointArray triPoints; MIntArray triVtxIds; MIntArray faceVtxIds; MIntArray faceNormalIds; int *triangelVtxIdList = new int[numTriangles * 3]; for( uint sgId = 0; sgId < obj->shadingGroups.length(); sgId++) { MString slotName = MString("slot_") + sgId; } int triCount = 0; int vtxCount = 0; for(faceIt.reset(); !faceIt.isDone(); faceIt.next()) { int faceId = faceIt.index(); int numTris; faceIt.numTriangles(numTris); faceIt.getVertices(faceVtxIds); MIntArray faceUVIndices; faceNormalIds.clear(); for( uint vtxId = 0; vtxId < faceVtxIds.length(); vtxId++) { faceNormalIds.append(faceIt.normalIndex(vtxId)); int uvIndex; faceIt.getUVIndex(vtxId, uvIndex); faceUVIndices.append(uvIndex); } int perFaceShadingGroup = 0; if( obj->perFaceAssignments.length() > 0) perFaceShadingGroup = obj->perFaceAssignments[faceId]; //logger.info(MString("Face ") + faceId + " will receive SG " + perFaceShadingGroup); for( int triId = 0; triId < numTris; triId++) { int faceRelIds[3]; faceIt.getTriangle(triId, triPoints, triVtxIds); for( uint triVtxId = 0; triVtxId < 3; triVtxId++) { for(uint faceVtxId = 0; faceVtxId < faceVtxIds.length(); faceVtxId++) { if( faceVtxIds[faceVtxId] == triVtxIds[triVtxId]) { faceRelIds[triVtxId] = faceVtxId; } } } uint vtxId0 = faceVtxIds[faceRelIds[0]]; uint vtxId1 = faceVtxIds[faceRelIds[1]]; uint vtxId2 = faceVtxIds[faceRelIds[2]]; uint normalId0 = faceNormalIds[faceRelIds[0]]; uint normalId1 = faceNormalIds[faceRelIds[1]]; uint normalId2 = faceNormalIds[faceRelIds[2]]; uint uvId0 = faceUVIndices[faceRelIds[0]]; uint uvId1 = faceUVIndices[faceRelIds[1]]; uint uvId2 = faceUVIndices[faceRelIds[2]]; floatPointArray[vtxCount * 3] = points[vtxId0].x; floatPointArray[vtxCount * 3 + 1] = points[vtxId0].y; floatPointArray[vtxCount * 3 + 2] = points[vtxId0].z; floatNormalArray[vtxCount * 3] = normals[normalId0].x; floatNormalArray[vtxCount * 3 + 1] = normals[normalId0].y; floatNormalArray[vtxCount * 3 + 2] = normals[normalId0].z; floatUvArray[vtxCount * 2] = uArray[uvId0]; floatUvArray[vtxCount * 2 + 1] = vArray[uvId0]; vtxCount++; floatPointArray[vtxCount * 3] = points[vtxId1].x; floatPointArray[vtxCount * 3 + 1] = points[vtxId1].y; floatPointArray[vtxCount * 3 + 2] = points[vtxId1].z; floatNormalArray[vtxCount * 3] = normals[normalId1].x; floatNormalArray[vtxCount * 3 + 1] = normals[normalId1].y; floatNormalArray[vtxCount * 3 + 2] = normals[normalId1].z; floatUvArray[vtxCount * 2] = uArray[uvId1]; floatUvArray[vtxCount * 2 + 1] = vArray[uvId1]; vtxCount++; floatPointArray[vtxCount * 3] = points[vtxId2].x; floatPointArray[vtxCount * 3 + 1] = points[vtxId2].y; floatPointArray[vtxCount * 3 + 2] = points[vtxId2].z; floatNormalArray[vtxCount * 3] = normals[normalId2].x; floatNormalArray[vtxCount * 3 + 1] = normals[normalId2].y; floatNormalArray[vtxCount * 3 + 2] = normals[normalId2].z; floatUvArray[vtxCount * 2] = uArray[uvId2]; floatUvArray[vtxCount * 2 + 1] = vArray[uvId2]; vtxCount++; //logger.debug(MString("Vertex count: ") + vtxCount + " maxId " + ((vtxCount - 1) * 3 + 2) + " ptArrayLen " + (numTriangles * 3 * 3)); triangelVtxIdList[triCount * 3] = triCount * 3; triangelVtxIdList[triCount * 3 + 1] = triCount * 3 + 1; triangelVtxIdList[triCount * 3 + 2] = triCount * 3 + 2; triCount++; } } //generatetangents bool Generate tangent space using miktspace, useful if mesh has a normal map that was also baked using miktspace (such as blender or xnormal) false //subdivscheme string Subdivision algorithm, options are "loop" and "microdisplacement" "loop" //displacementmap string Name of the texture used for the displacement. Subdivscheme parameter must always be provided, as load-time displacement is handled by the loop-subdivision code. none - optional. (loop subdiv can be used without displacement, microdisplacement will not affect the mesh without a displacement map specified) //dmscale float Scale of the displacement (for an LDR map, this is the maximum height of the displacement in meter) 0.1 //dmoffset float Offset of the displacement. 0 //dmnormalsmooth bool Smoothing of the normals of the subdivided faces. Only valid for loop subdivision. true //dmnormalsplit bool Force the mesh to split along breaks in the normal. If a mesh has no normals (flat-shaded) it will rip open on all edges. Only valid for loop subdivision. false //dmsharpboundary bool Try to preserve mesh boundaries during subdivision. Only valid for loop subdivision. false //nsubdivlevels integer Number of subdivision levels. This is only recursive for loop subdivision, microdisplacement will need much larger values (such as 50). 0 bool generatetangents = false; getBool(MString("mtlu_mesh_generatetangents"), meshFn, generatetangents); int subdivscheme = 0; const char *subdAlgos[] = {"loop", "microdisplacement"}; getInt(MString("mtlu_mesh_subAlgo"), meshFn, subdivscheme); const char *subdalgo = subdAlgos[subdivscheme]; float dmscale; getFloat(MString("mtlu_mesh_dmscale"), meshFn, dmscale); float dmoffset; getFloat(MString("mtlu_mesh_dmoffset"), meshFn, dmoffset); MString displacementmap; getString(MString("mtlu_mesh_displacementMap"), meshFn, displacementmap); const char *displacemap = displacementmap.asChar(); bool dmnormalsmooth = true; getBool(MString("mtlu_mesh_dmnormalsmooth"), meshFn, dmnormalsmooth); bool dmnormalsplit = false; getBool(MString("mtlu_mesh_dmnormalsplit"), meshFn, dmnormalsplit); bool dmsharpboundary = false; getBool(MString("mtlu_mesh_dmsharpboundary"), meshFn, dmsharpboundary); int nsubdivlevels = 0; getInt(MString("mtlu_mesh_subdivlevel"), meshFn, nsubdivlevels); // a displacment map needs its own texture defintion MString displacementTextureName = ""; if(displacementmap.length() > 0) { ParamSet dmParams = CreateParamSet(); dmParams->AddString("filename", &displacemap); displacementTextureName = meshFn.name() + "_displacementMap"; this->lux->texture(displacementTextureName.asChar(), "float", "imagemap", boost::get_pointer(dmParams)); } ParamSet triParams = CreateParamSet(); int numPointValues = numTriangles * 3; int numUvValues = numTriangles * 3 * 2; clock_t startTime = clock(); logger.info(MString("Adding mesh values to params.")); triParams->AddInt("indices", triangelVtxIdList, numTriangles * 3); triParams->AddPoint("P", floatPointArray, numPointValues); triParams->AddNormal("N", floatNormalArray, numPointValues); triParams->AddFloat("uv", floatUvArray, numUvValues); if( nsubdivlevels > 0) triParams->AddInt("nsubdivlevels", &nsubdivlevels, 1); triParams->AddBool("generatetangents", &generatetangents, 1); triParams->AddString("subdivscheme", &subdalgo , 1); if(displacementmap.length() > 0) { triParams->AddFloat("dmoffset", &dmoffset, 1); triParams->AddFloat("dmscale", &dmscale, 1); const char *dmft = displacementTextureName.asChar(); triParams->AddString("displacementmap", &dmft); } triParams->AddBool("dmnormalsmooth", &dmnormalsmooth, 1); triParams->AddBool("dmnormalsplit", &dmnormalsplit, 1); triParams->AddBool("dmsharpboundary", &dmsharpboundary, 1); clock_t pTime = clock(); if(!noObjectDef) this->lux->objectBegin(meshFullName.asChar()); this->lux->shape("trianglemesh", boost::get_pointer(triParams)); if(!noObjectDef) this->lux->objectEnd(); clock_t eTime = clock(); logger.info(MString("Timing: Parameters: ") + ((pTime - startTime)/CLOCKS_PER_SEC) + " objTime " + ((eTime - pTime)/CLOCKS_PER_SEC) + " all " + ((eTime - startTime)/CLOCKS_PER_SEC)); return; }
//static void processFiles(ParamSet ¶ms, std::set<string> &tmpFiles, std::iostream &stream) { static void processFiles(ParamSet ¶ms, socket_stream_t &stream) { LOG(LUX_DEBUG,LUX_NOERROR) << "Receiving file index"; string s = get_response(stream); if (s == "FILE INDEX EMPTY") { LOG(LUX_DEBUG,LUX_NOERROR) << "No files"; return; } if (s != "BEGIN FILE INDEX") { throw std::runtime_error("Expected 'BEGIN FILE INDEX', got '" + s + "'"); } stream << "BEGIN FILE INDEX OK" << "\n"; vector<std::pair<string, string> > neededFiles; while (true) { string paramName = get_response(stream); if (paramName == "END FILE INDEX") { LOG(LUX_DEBUG,LUX_NOERROR) << "End of file index"; break; } string filename = get_response(stream); string hash = get_response(stream); string empty = get_response(stream); // empty line if (paramName == "" || filename == "" || hash == "" || empty != "") { LOG( LUX_ERROR,LUX_SYSTEM)<< "Invalid file index entry " << "param: '" << paramName << "', " << "filename: '" << filename << "', " << "hash: '" << hash << "', " << "empty: '" << empty << "'"; stream << "FILE INDEX INVALID" << "\n"; return; } LOG(LUX_DEBUG,LUX_NOERROR) << "File param '" << paramName << "', filename '" << filename << "', hash '" << hash << "'"; boost::filesystem::path fname(filename); boost::filesystem::path tfile("tmp_" + hash); tfile.replace_extension(fname.extension()); //if (tmpFiles.find(tfile.string()) == tmpFiles.end()) { boost::system::error_code ec; if (!boost::filesystem::exists(tfile, ec)) { LOG( LUX_INFO,LUX_NOERROR) << "Requesting file '" << filename << "' (as '" << tfile.string() << "')"; neededFiles.push_back(std::make_pair(hash, tfile.string())); } else { LOG( LUX_DEBUG,LUX_NOERROR) << "Using existing file '" << filename << "' (as '" << tfile.string() << "')"; } // replace parameter params.AddString(paramName, &tfile.string()); } stream << "END FILE INDEX OK" << "\n"; // now lets grab the files we need if (!read_response(stream, "BEGIN FILES")) return; stream << "BEGIN FILES OK" << "\n"; for (size_t i = 0; i < neededFiles.size(); i++) { const string& hash(neededFiles[i].first); const string& fname(neededFiles[i].second); stream << hash << endl << flush; if (!receiveFile(fname, hash, stream)) { stream << "RESEND FILE" << endl << flush; if (!receiveFile(fname, hash, stream)) throw std::runtime_error("Error receiving file '" + fname + "'"); } stream << "FILE OK" << "\n"; //tmpFiles.insert(neededFiles[i].second); } stream << "END FILES" << "\n"; if (!read_response(stream, "END FILES OK")) return; }
void LuxRenderer::defineCamera() { std::shared_ptr<MayaScene> mayaScene = MayaTo::getWorldPtr()->worldScenePtr; std::shared_ptr<RenderGlobals> renderGlobals = MayaTo::getWorldPtr()->worldRenderGlobalsPtr; std::shared_ptr<MayaObject> mo = mayaScene->camList[0]; MMatrix cm = mo->dagPath.inclusiveMatrix(); MFnCamera camFn(mo->mobject); this->transformCamera(mo.get(), renderGlobals->doMb && (mo->transformMatrices.size() > 1)); // lux uses the fov of the smallest image edge double hFov = RadToDeg(camFn.horizontalFieldOfView()); double vFov = RadToDeg(camFn.verticalFieldOfView()); float fov = hFov; int width, height; renderGlobals->getWidthHeight(width, height); if( height < width) fov = vFov; // focaldist float focusDist = (float)camFn.focusDistance() * renderGlobals->sceneScale; float focalLen = (float)camFn.focalLength(); float fStop = (float)camFn.fStop(); bool useDOF = false; getBool(MString("depthOfField"), camFn, useDOF); useDOF = useDOF && renderGlobals->doDof; // hither, yon float hither = (float)camFn.nearClippingPlane(); float yon = (float)camFn.farClippingPlane(); // render region int left, bottom, right, top; renderGlobals->getRenderRegion(left, bottom, right, top); int ybot = (height - bottom); int ytop = (height - top); int ymin = ybot < ytop ? ybot : ytop; int ymax = ybot > ytop ? ybot : ytop; float lensradius = (focalLen / 1000.0) / ( 2.0 * fStop ); int blades = 0; getInt(MString("mtlu_diaphragm_blades"), camFn, blades); bool autofocus = false; getBool(MString("mtlu_autofocus"), camFn, autofocus); int dist = 0; getInt(MString("mtlu_distribution"), camFn, dist); logger.debug(MString("Lens distribution: ") + dist + " " + LensDistributions[dist]); float power = 1.0f; getFloat(MString("mtlu_power"), camFn, power); const char *lensdistribution = LensDistributions[dist]; float shutterOpen = 0.0f; float shutterClose = renderGlobals->mbLength; ParamSet cp = CreateParamSet(); cp->AddFloat("fov", &fov); cp->AddFloat("focaldistance", &focusDist); cp->AddFloat("hither", &hither); cp->AddFloat("yon", &yon); cp->AddFloat("shutteropen", &shutterOpen); cp->AddFloat("shutterclose", &shutterClose); if( blades > 0) cp->AddInt("blades", &blades); if( useDOF ) { cp->AddFloat("lensradius", &lensradius); cp->AddBool("autofocus", &autofocus); cp->AddString("distribution", &lensdistribution); cp->AddFloat("power", &power); } lux->camera("perspective", boost::get_pointer(cp)); if( renderGlobals->exportSceneFile) this->luxFile << "Camera \"perspective\" "<< "\"float fov\" [" << fov << "]" <<"\n"; }
int testSimpleScene() { ParamSet params; int xres = 500; int yres = 500; params.AddInt("xresolution", &xres, 1); params.AddInt("yresolution", &yres, 1); Transform t = LookAt(Point(0,0,0), Point(0,0,-100), Vector(0,1,0)); AnimatedTransform cam2world(&t, 0, &t, 0); params.AddString("filename", new string("render.png"), 1); //BoxFilter *filter = CreateBoxFilter(params); GaussianFilter *filter = new GaussianFilter(3, 3, 0.001f); ImageFilm *film = CreateImageFilm(params, filter); PerspectiveCamera *camera = CreatePerspectiveCamera(params, cam2world, film); //AdaptiveSampler *sampler = CreateAdaptiveSampler(params, film, camera); //Sampler *sampler = CreateRandomSampler(params, film, camera); //Sampler *sampler = CreateBestCandidateSampler(params, film, camera); //Sampler *sampler = CreateHaltonSampler(params, film, camera); //StratifiedSampler *sampler = CreateStratifiedSampler(params, film, camera); bool jitter = false; int xstart, xend, ystart, yend; film->GetSampleExtent(&xstart, &xend, &ystart, ¥d); int xsamp = 1; int ysamp = 1; StratifiedSampler *sampler = new StratifiedSampler( xstart, xend, ystart, yend, xsamp, ysamp, jitter, camera->shutterOpen, camera->shutterClose); //PathIntegrator *surfaceIg = CreatePathSurfaceIntegrator(params); //DirectLightingIntegrator *surfaceIg = CreateDirectLightingIntegrator(params); WhittedIntegrator *surfaceIg = CreateWhittedSurfaceIntegrator(params); SingleScatteringIntegrator *volumeIg = CreateSingleScatteringIntegrator(params); SamplerRenderer renderer(sampler, camera, surfaceIg, volumeIg, false); VolumeRegion *volumeRegion = NULL; vector<Light*> lights; float il1[] = {1.f,1.f,1.f}; float il2[] = {2.f,0.5f,0.3f}; float il3[] = {0.f,0.2f,1.3f}; lights.push_back(new PointLight(Translate(Vector(2,2,0)), RGBSpectrum::FromRGB(il1))); lights.push_back(new PointLight(Translate(Vector(-2,-2,-2)), RGBSpectrum::FromRGB(il2))); lights.push_back(new PointLight(Translate(Vector(-2, 2,-2)), RGBSpectrum::FromRGB(il3))); //(MCreatePointLight(Translate(Vector(2,2,0)), params)); //lights.push_back(CreatePointLight(Translate(Vector(0,4,0)), params)); Transform obj2world = Translate(Vector(0,0,-2)); Transform world2obj = Inverse(obj2world); Sphere *sphere1 = CreateSphereShape(&obj2world, &world2obj, false, params); Transform obj2world2 = Translate(Vector(0.7,0.7,2.6)); Transform world2obj2 = Inverse(obj2world2); Sphere *sphere2 = CreateSphereShape(&obj2world2, &world2obj2, false, params); TextureParams tparams(params, params, map<string, Reference<Texture<float> > >(), map<string, Reference<Texture<Spectrum> > >()); MirrorMaterial *mirror = new MirrorMaterial(new ConstantTexture<Spectrum>(Spectrum(0.9f)), NULL); ShinyMetalMaterial *metal = new ShinyMetalMaterial( new ConstantTexture<Spectrum>(Spectrum(1.f)), new ConstantTexture<float>(0.1f), new ConstantTexture<Spectrum>(Spectrum(1.f)), NULL); //CreateShinyMetalMaterial(Transform(), tparams); GlassMaterial *glass = CreateGlassMaterial(Transform(), tparams); //float c1[] = {0.f,10.99f,0.f}; float c1[] = {5.f,5.f,5.f}; Spectrum spec1 = RGBSpectrum::FromRGB(c1, SpectrumType::SPECTRUM_REFLECTANCE); MatteMaterial *matte = new MatteMaterial( new ConstantTexture<Spectrum>(spec1), new ConstantTexture<float>(0.0f), NULL); // Reference<Texture<Spectrum> > Kd = mp.GetSpectrumTexture("Kd", Spectrum(0.5f)); // Reference<Texture<float> > sigma = mp.GetFloatTexture("sigma", 0.f); // Reference<Texture<float> > bumpMap = mp.GetFloatTextureOrNull("bumpmap"); // return ; //CreateMatteMaterial(Transform(), tparams); Reference<Primitive> prim1 = new GeometricPrimitive(sphere1, matte, NULL); //Reference<Primitive> prim2 = new GeometricPrimitive(sphere2, metal, NULL); vector<Reference<Primitive> > prims; prims.push_back(prim1); //prims.push_back(prim2); Primitive *accel = CreateBVHAccelerator(prims, params); Scene *scene = new Scene(accel, lights, volumeRegion); // Scene(Primitive *accel, const vector<Light *> <s, VolumeRegion *vr); //TODO: // create scene // step through to see that something happens // start building minimal viable js version // - unit test js functionality against similar c++ unit results renderer.Render(scene); film->WriteImage(1); return 0; }