void VolumeViewer::setIsovalues(std::vector<float> isovalues) { OSPData isovaluesData = ospNewData(isovalues.size(), OSP_FLOAT, &isovalues[0]); // Remove existing isosurface geometries from models. for(size_t i=0; i<modelStates.size(); i++) { for(size_t j=0; j<modelStates[i].isosurfaces.size(); j++) ospRemoveGeometry(modelStates[i].model, modelStates[i].isosurfaces[j]); modelStates[i].isosurfaces.clear(); } // Add new isosurfaces for each volume of each model. Later we can do this only for the active model on time step change... for(size_t i=0; i<modelStates.size(); i++) { if(isovalues.size() > 0) { for(size_t j=0; j<modelStates[i].volumes.size(); j++) { OSPGeometry isosurfacesGeometry = ospNewGeometry("isosurfaces"); ospSetData(isosurfacesGeometry, "isovalues", isovaluesData); ospSetObject(isosurfacesGeometry, "volume", modelStates[i].volumes[j]); ospCommit(isosurfacesGeometry); ospAddGeometry(modelStates[i].model, isosurfacesGeometry); modelStates[i].isosurfaces.push_back(isosurfacesGeometry); } } ospCommit(modelStates[i].model); } render(); }
Renderer::Renderer(int width, int height) { renderer = ospNewRenderer("vis_renderer"); camera.setRenderer(renderer); renderProperties.setRenderer(renderer); float clips[12] = { 1.0, 0.0, 0.0, -0.9, 1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.1 }; ospSetData(renderer, "clips", ospNewData(sizeof(clips) / (4 * sizeof(float)), OSP_FLOAT4, clips)); float slice[4] = {5.0, 6.0, 7.0, 8.0}; ospSetData(renderer, "slices", ospNewData(1, OSP_FLOAT4, slice)); OSPModel dmodel = ospNewModel(); ospCommit(dmodel); ospSetObject(renderer, "dynamic_model", dmodel); window = new CinemaWindow(width, height); camera.setAspect(((float)height) / width); }
void VolumeViewer::setModel(size_t index) { modelIndex = index; // Set current model on the OSPRay renderer. ospSetObject(renderer, "model", modelStates[index].model); ospCommit(renderer); rendererInitialized = true; // Update transfer function and isosurface editor data value range with the voxel range of the current model's first volume. ospcommon::vec2f voxelRange(0.f); OSPVolume volume = modelStates[index].volumes[0]; #ifdef OSPRAY_VOLUME_VOXELRANGE_IN_APP voxelRange = VolumeFile::voxelRangeOf[volume]; #else ospGetVec2f(modelStates[index].volumes[0], "voxelRange", (osp::vec2f*)&voxelRange); #endif if(voxelRange != ospcommon::vec2f(0.f)) { transferFunctionEditor->setDataValueRange(voxelRange); isosurfaceEditor->setDataValueRange(voxelRange); } // Update active volume on probe widget. probeWidget->setVolume(modelStates[index].volumes[0]); // Update current filename information label. if (ownModelPerObject) currentFilenameInfoLabel.setText("<b>Timestep " + QString::number(index) + QString("</b>: Data value range: [") + QString::number(voxelRange.x) + ", " + QString::number(voxelRange.y) + "]"); else currentFilenameInfoLabel.setText("<b>Timestep " + QString::number(index) + QString("</b>: ") + QString(objectFileFilenames[index].c_str()).split('/').back() + ". Data value range: [" + QString::number(voxelRange.x) + ", " + QString::number(voxelRange.y) + "]"); // Enable rendering on the OSPRay window. osprayWindow->setRenderingEnabled(true); }
void OSPRayMaterial::commit() { // Do nothing until this material is instanced for a specific renderer if (!_ospMaterial || !isModified()) return; if (getCurrentType() == "simulation") osphelper::set(_ospMaterial, "apply_simulation", 1); else ospRemoveParam(_ospMaterial, "apply_simulation"); osphelper::set(_ospMaterial, "kd", Vector3f(_diffuseColor)); osphelper::set(_ospMaterial, "ks", Vector3f(_specularColor)); osphelper::set(_ospMaterial, "ns", static_cast<float>(_specularExponent)); osphelper::set(_ospMaterial, "d", static_cast<float>(_opacity)); osphelper::set(_ospMaterial, "refraction", static_cast<float>(_refractionIndex)); osphelper::set(_ospMaterial, "reflection", static_cast<float>(_reflectionIndex)); osphelper::set(_ospMaterial, "a", static_cast<float>(_emission)); osphelper::set(_ospMaterial, "glossiness", static_cast<float>(_glossiness)); osphelper::set(_ospMaterial, "skybox", _isBackGroundMaterial); // Properties toOSPRayProperties(*this, _ospMaterial); // Textures for (const auto& textureType : textureTypeMaterialAttribute) ospSetObject(_ospMaterial, textureType.attribute.c_str(), nullptr); for (const auto& textureDescriptor : _textureDescriptors) { const auto texType = textureDescriptor.first; auto texture = getTexture(texType); if (texture) { auto ospTexture = _createOSPTexture2D(texture); const auto str = textureTypeMaterialAttribute[texType].attribute.c_str(); ospSetObject(_ospMaterial, str, ospTexture); ospRelease(ospTexture); } } ospCommit(_ospMaterial); resetModified(); }
void TextureVolume::postCommit(RenderContext &ctx) { auto ospTexture = valueAs<OSPTexture>(); auto &volume = child("volume"); ospSetObject(ospTexture, "volume", volume.valueAs<OSPVolume>()); Texture::postCommit(ctx); }
void Renderer::CommitVolume() { volume.commit(); OSPModel model = ospNewModel(); ospAddVolume(model, volume.getOSPVolume()); ospCommit(model); ospSetObject(getRenderer(), "model", model); ospCommit(getRenderer()); }
void GLFWOSPRayWindow::setModel(OSPModel newModel) { model = newModel; // set the model on the renderer ospSetObject(renderer, "model", model); // commit the renderer ospCommit(renderer); // clear frame buffer ospFrameBufferClear(framebuffer, OSP_FB_COLOR | OSP_FB_ACCUM); }
void VolumeViewer::addGeometry(std::string filename) { // For now we assume PLY geometry files. Later we can support other geometry formats. // Get filename if not specified. if(filename.empty()) filename = QFileDialog::getOpenFileName(this, tr("Load geometry"), ".", "Geometry files (*.ply *.dds)").toStdString(); if(filename.empty()) return; // Attempt to load the geometry through the TriangleMeshFile loader. OSPGeometry triangleMesh = ospNewGeometry("trianglemesh"); // If successful, commit the triangle mesh and add it to all models. if(TriangleMeshFile::importTriangleMesh(filename, triangleMesh) != NULL) { // For now: if this is a DDS geometry, assume it is a horizon and its color should be mapped through the first volume's transfer function. if(QString(filename.c_str()).endsWith(".dds") && modelStates.size() > 0 && modelStates[0].volumes.size() > 0) { OSPMaterial material = ospNewMaterial(renderer, "default"); ospSet3f(material, "Kd", 1,1,1); ospSetObject(material, "volume", modelStates[0].volumes[0]); ospCommit(material); ospSetMaterial(triangleMesh, material); } ospCommit(triangleMesh); // Create an instance of the geometry and add the instance to the main model(s)--this prevents the geometry // from being rebuilt every time the main model is committed (e.g. when slices / isosurfaces are manipulated) OSPModel modelInstance = ospNewModel(); ospAddGeometry(modelInstance, triangleMesh); ospCommit(modelInstance); ospcommon::affine3f xfm = ospcommon::one; OSPGeometry triangleMeshInstance = ospNewInstance(modelInstance, (osp::affine3f&)xfm); ospCommit(triangleMeshInstance); for(size_t i=0; i<modelStates.size(); i++) { ospAddGeometry(modelStates[i].model, triangleMeshInstance); ospCommit(modelStates[i].model); } // Force render. render(); } }
void VolumeViewer::importObjectsFromFile(const std::string &filename) { if (!ownModelPerObject) // Create an OSPRay model and its associated model state. modelStates.push_back(ModelState(ospNewModel())); // Load OSPRay objects from a file. OSPObject *objects = ObjectFile::importObjects(filename.c_str()); // Iterate over the objects contained in the object list. for (size_t i=0 ; objects[i] ; i++) { if (ownModelPerObject) modelStates.push_back(ModelState(ospNewModel())); OSPDataType type; ospGetType(objects[i], NULL, &type); if (type == OSP_GEOMETRY) { // Commit the geometry. ospCommit(objects[i]); // Add the loaded geometry to the model. ospAddGeometry(modelStates.back().model, (OSPGeometry) objects[i]); } else if (type == OSP_VOLUME) { // For now we set the same transfer function on all volumes. ospSetObject(objects[i], "transferFunction", transferFunction); ospCommit(objects[i]); // Add the loaded volume(s) to the model. ospAddVolume(modelStates.back().model, (OSPVolume) objects[i]); // Add to volumes vector for the current model. modelStates.back().volumes.push_back((OSPVolume) objects[i]); } if (ownModelPerObject) ospCommit(modelStates.back().model); } if (!ownModelPerObject) // Commit the model. ospCommit(modelStates.back().model); }
void Frame::preCommit(RenderContext &) { if (child("camera").hasChild("aspect") && child("frameBuffer")["size"].lastModified() > child("camera")["aspect"].lastCommitted()) { auto fbSize = child("frameBuffer")["size"].valueAs<vec2i>(); child("camera")["aspect"] = fbSize.x / float(fbSize.y); } auto rendererNode = child("renderer").nodeAs<Renderer>(); rendererNode->updateRenderer(); auto rHandle = rendererNode->valueAs<OSPRenderer>(); auto cHandle = child("camera").valueAs<OSPCamera>(); // XXX this is not sufficient (at least for FB): // the FB can be released and re-created (i.e. on size change) and per // (high) chance get the same handle (which is just the heap address when // using the local device) bool newRenderer = currentRenderer != rHandle; bool newCamera = currentCamera != cHandle; if (newRenderer) currentRenderer = rHandle; if (newCamera) currentCamera = cHandle; if (newRenderer || newCamera) ospSetObject(rHandle, "camera", cHandle); bool rChanged = rendererNode->subtreeModifiedButNotCommitted(); bool cChanged = child("camera").subtreeModifiedButNotCommitted(); clearFB = newCamera || newRenderer || rChanged || cChanged; frameAccumulationLimit = child("frameAccumulationLimit").valueAs<int>(); // when frameAccumulationLimit is active, render at least 2 frames, // otherwise the view is stuck showing the stale navigation framebuffer // for no accumulation, disable the accumBuffer if (frameAccumulationLimit >= 0) frameAccumulationLimit = std::max(frameAccumulationLimit, 2); }
void VolumeViewer::setSlices(std::vector<SliceParameters> sliceParameters) { // Provide the slices to OSPRay as the coefficients (a,b,c,d) of the plane equation ax + by + cz + d = 0. std::vector<ospcommon::vec4f> planes; for(size_t i=0; i<sliceParameters.size(); i++) planes.push_back(ospcommon::vec4f(sliceParameters[i].normal.x, sliceParameters[i].normal.y, sliceParameters[i].normal.z, -dot(sliceParameters[i].origin, sliceParameters[i].normal))); OSPData planesData = ospNewData(planes.size(), OSP_FLOAT4, &planes[0].x); // Remove existing slice geometries from models. for(size_t i=0; i<modelStates.size(); i++) { for(size_t j=0; j<modelStates[i].slices.size(); j++) ospRemoveGeometry(modelStates[i].model, modelStates[i].slices[j]); modelStates[i].slices.clear(); } // Add new slices for each volume of each model. Later we can do this only for the active model on time step change... for(size_t i=0; i<modelStates.size(); i++) { if(planes.size() > 0) { for(size_t j=0; j<modelStates[i].volumes.size(); j++) { OSPGeometry slicesGeometry = ospNewGeometry("slices"); ospSetData(slicesGeometry, "planes", planesData); ospSetObject(slicesGeometry, "volume", modelStates[i].volumes[j]); ospCommit(slicesGeometry); ospAddGeometry(modelStates[i].model, slicesGeometry); modelStates[i].slices.push_back(slicesGeometry); } } ospCommit(modelStates[i].model); } render(); }
OSPTexture OSPRayMaterial::_createOSPTexture2D(Texture2DPtr texture) { OSPTextureFormat type = OSP_TEXTURE_R8; // smallest valid type as default if (texture->getDepth() == 1) { if (texture->getNbChannels() == 1) type = OSP_TEXTURE_R8; if (texture->getNbChannels() == 3) type = OSP_TEXTURE_RGB8; if (texture->getNbChannels() == 4) type = OSP_TEXTURE_RGBA8; } else if (texture->getDepth() == 4) { if (texture->getNbChannels() == 1) type = OSP_TEXTURE_R32F; if (texture->getNbChannels() == 3) type = OSP_TEXTURE_RGB32F; if (texture->getNbChannels() == 4) type = OSP_TEXTURE_RGBA32F; } BRAYNS_DEBUG << "Creating OSPRay texture from " << texture->getFilename() << ": " << texture->getWidth() << "x" << texture->getHeight() << "x" << (int)type << std::endl; OSPTexture ospTexture = ospNewTexture("texture2d"); const Vector2i size{int(texture->getWidth()), int(texture->getHeight())}; osphelper::set(ospTexture, "type", static_cast<int>(type)); osphelper::set(ospTexture, "size", size); auto textureData = ospNewData(texture->getSizeInBytes(), OSP_RAW, texture->getRawData(), OSP_DATA_SHARED_BUFFER); ospSetObject(ospTexture, "data", textureData); ospRelease(textureData); ospCommit(ospTexture); return ospTexture; }
void Material::render(RenderContext &ctx) { if (ospMaterial) return; ospMaterial = ospNewMaterial(ctx.integrator->getOSPHandle(), type.c_str()); //We failed to create a material of the given type, handle it if (!ospMaterial) { std::cerr << "Warning: Could not create material type '" << type << "'. Replacing with default material." << std::endl; //Replace with default static OSPMaterial defaultMaterial = NULL; if (defaultMaterial) { ospMaterial = defaultMaterial; return; } defaultMaterial = ospNewMaterial(ctx.integrator->getOSPHandle(), "OBJMaterial"); vec3f kd(.7f); vec3f ks(.3f); ospSet3fv(defaultMaterial, "Kd", &kd.x); ospSet3fv(defaultMaterial, "Ks", &ks.x); ospSet1f(defaultMaterial, "Ns", 99.f); ospCommit(defaultMaterial); return; } for(size_t i = 0; i < textures.size(); i++) { textures[i]->render(ctx); } //Forward all params on to the ospMaterial... for (ParamMap::const_iterator itr = param.begin(); itr != param.end(); ++itr) { switch(itr->second->getOSPDataType()) { case OSP_INT: case OSP_UINT: { ParamT<int> *p = (ParamT<int>*)itr->second.ptr; if(itr->second->getName().find("map_") != std::string::npos) { //Handle textures! assert(textures[p->value]->ospTexture != NULL && "Texture should not be null at this point."); ospSetObject(ospMaterial, itr->second->getName().c_str(), textures[p->value]->ospTexture); } else { ospSet1i(ospMaterial, itr->second->getName().c_str(), p->value); } } break; case OSP_INT3: case OSP_UINT3: { ParamT<vec3i> *p = (ParamT<vec3i>*)itr->second.ptr; ospSet3i(ospMaterial, itr->second->getName().c_str(), p->value.x, p->value.y, p->value.z); } break; case OSP_FLOAT: { ParamT<float> *p = (ParamT<float>*)itr->second.ptr; ospSet1f(ospMaterial, itr->second->getName().c_str(), p->value); } break; case OSP_FLOAT2: { ParamT<vec2f> *p = (ParamT<vec2f>*)itr->second.ptr; ospSet2fv(ospMaterial, itr->second->getName().c_str(), &p->value.x); } break; case OSP_FLOAT3: { ParamT<vec3f> *p = (ParamT<vec3f>*)itr->second.ptr; ospSet3fv(ospMaterial, itr->second->getName().c_str(), &p->value.x); } break; default: //Catch not yet implemented data types std::cerr << "Warning: parameter '" << itr->second->getName() << "' of material '" << name << "' had an invalid data type and will be ignored." << std::endl; } } ospCommit(ospMaterial); }
GLFWOSPRayWindow::GLFWOSPRayWindow(const ospcommon::vec2i &windowSize, const ospcommon::box3f &worldBounds, OSPModel model, OSPRenderer renderer) : windowSize(windowSize), worldBounds(worldBounds), model(model), renderer(renderer) { if (activeWindow != nullptr) throw std::runtime_error("Cannot create more than one GLFWOSPRayWindow!"); activeWindow = this; // initialize GLFW if (!glfwInit()) throw std::runtime_error("Failed to initialize GLFW!"); // create GLFW window glfwWindow = glfwCreateWindow( windowSize.x, windowSize.y, "OSPRay Tutorial", NULL, NULL); if (!glfwWindow) { glfwTerminate(); throw std::runtime_error("Failed to create GLFW window!"); } // make the window's context current glfwMakeContextCurrent(glfwWindow); ImGui_ImplGlfwGL3_Init(glfwWindow, true); // set initial OpenGL state glEnable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); // create OpenGL frame buffer texture glGenTextures(1, &framebufferTexture); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, framebufferTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // set GLFW callbacks glfwSetFramebufferSizeCallback( glfwWindow, [](GLFWwindow *, int newWidth, int newHeight) { activeWindow->reshape(ospcommon::vec2i{newWidth, newHeight}); }); glfwSetCursorPosCallback(glfwWindow, [](GLFWwindow *, double x, double y) { ImGuiIO &io = ImGui::GetIO(); if (!io.WantCaptureMouse) activeWindow->motion(ospcommon::vec2f{float(x), float(y)}); }); glfwSetKeyCallback(glfwWindow, [](GLFWwindow *, int key, int, int action, int) { if (action == GLFW_PRESS) { switch (key) { case GLFW_KEY_G: activeWindow->showUi = !(activeWindow->showUi); break; } } }); // OSPRay setup // set the model on the renderer ospSetObject(renderer, "model", model); // create the arcball camera model arcballCamera = std::unique_ptr<ArcballCamera>( new ArcballCamera(worldBounds, windowSize)); // create camera camera = ospNewCamera("perspective"); ospSetf(camera, "aspect", windowSize.x / float(windowSize.y)); ospSetVec3f(camera, "pos", osp::vec3f{arcballCamera->eyePos().x, arcballCamera->eyePos().y, arcballCamera->eyePos().z}); ospSetVec3f(camera, "dir", osp::vec3f{arcballCamera->lookDir().x, arcballCamera->lookDir().y, arcballCamera->lookDir().z}); ospSetVec3f(camera, "up", osp::vec3f{arcballCamera->upDir().x, arcballCamera->upDir().y, arcballCamera->upDir().z}); ospCommit(camera); // set camera on the renderer ospSetObject(renderer, "camera", camera); // finally, commit the renderer ospCommit(renderer); // trigger window reshape events with current window size glfwGetFramebufferSize(glfwWindow, &this->windowSize.x, &this->windowSize.y); reshape(this->windowSize); }
int main(int ac, const char **av) { // image size osp_vec2i imgSize; imgSize.x = 1024; // width imgSize.y = 768; // height // camera float cam_pos[] = {0.f, 0.f, 0.f}; float cam_up [] = {0.f, 1.f, 0.f}; float cam_view [] = {0.1f, 0.f, 1.f}; // triangle mesh data float vertex[] = { -1.0f, -1.0f, 3.0f, 0.f, -1.0f, 1.0f, 3.0f, 0.f, 1.0f, -1.0f, 3.0f, 0.f, 0.1f, 0.1f, 0.3f, 0.f }; float color[] = { 0.9f, 0.5f, 0.5f, 1.0f, 0.8f, 0.8f, 0.8f, 1.0f, 0.8f, 0.8f, 0.8f, 1.0f, 0.5f, 0.9f, 0.5f, 1.0f }; int32_t index[] = { 0, 1, 2, 1, 2, 3 }; // initialize OSPRay; OSPRay parses (and removes) its commandline parameters, e.g. "--osp:debug" ospInit(&ac, av); // create and setup camera OSPCamera camera = ospNewCamera("perspective"); ospSetf(camera, "aspect", imgSize.x/(float)imgSize.y); ospSet3fv(camera, "pos", cam_pos); ospSet3fv(camera, "dir", cam_view); ospSet3fv(camera, "up", cam_up); ospCommit(camera); // commit each object to indicate modifications are done // create and setup model and mesh OSPGeometry mesh = ospNewGeometry("triangles"); OSPData data = ospNewData(4, OSP_FLOAT3A, vertex, 0); // OSP_FLOAT3 format is also supported for vertex positions (currently not on MIC) ospCommit(data); ospSetData(mesh, "vertex", data); data = ospNewData(4, OSP_FLOAT4, color, 0); ospCommit(data); ospSetData(mesh, "vertex.color", data); data = ospNewData(2, OSP_INT3, index, 0); // OSP_INT4 format is also supported for triangle indices ospCommit(data); ospSetData(mesh, "index", data); ospCommit(mesh); OSPModel world = ospNewModel(); ospAddGeometry(world, mesh); ospCommit(world); // create and setup renderer OSPRenderer renderer = ospNewRenderer("scivis"); // choose Scientific Visualization renderer ospSet1f(renderer, "aoWeight", 1.0f); // with full Ambient Occlusion ospSet1i(renderer, "aoSamples", 1); ospSetObject(renderer, "model", world); ospSetObject(renderer, "camera", camera); ospCommit(renderer); // create and setup framebuffer OSPFrameBuffer framebuffer = ospNewFrameBuffer(&imgSize, OSP_FB_SRGBA, OSP_FB_COLOR | /*OSP_FB_DEPTH |*/ OSP_FB_ACCUM); ospFrameBufferClear(framebuffer, OSP_FB_COLOR | OSP_FB_ACCUM); // render one frame ospRenderFrame(framebuffer, renderer, OSP_FB_COLOR | OSP_FB_ACCUM); // access framebuffer and write its content as PPM file const uint32_t * fb = (uint32_t*)ospMapFrameBuffer(framebuffer, OSP_FB_COLOR); writePPM("firstFrameC.ppm", &imgSize, fb); ospUnmapFrameBuffer(fb, framebuffer); // render 10 more frames, which are accumulated to result in a better converged image for (int frames = 0; frames < 10; frames++) ospRenderFrame(framebuffer, renderer, OSP_FB_COLOR | OSP_FB_ACCUM); fb = (uint32_t*)ospMapFrameBuffer(framebuffer, OSP_FB_COLOR); writePPM("accumulatedFrameC.ppm", &imgSize, fb); ospUnmapFrameBuffer(fb, framebuffer); return 0; }