Last active
June 7, 2018 00:57
-
-
Save Twinklebear/b98dbe5ab1613e1b1917285bab50b534 to your computer and use it in GitHub Desktop.
OSPRay Transparency Test Case Repro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.5) | |
project(osp-transparency-bug) | |
set(CMAKE_CXX_STANDARD 14) | |
add_definitions(-DNOMINMAX) | |
find_package(ospray REQUIRED) | |
include_directories(${OSPRAY_INCLUDE_DIRS}) | |
add_executable(transparency-test transparency-test.cpp) | |
target_link_libraries(transparency-test ${OSPRAY_LIBRARIES}) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
PREFIX=$1 | |
vol=(0 1) | |
shadows=(0 1) | |
for s in ${shadows[@]}; do | |
SHADOW="" | |
if [[ $s == 1 ]]; then | |
SHADOW="-shadow" | |
fi | |
for v in ${vol[@]}; do | |
VOL="" | |
if [[ $v == 1 ]]; then | |
VOL="-vol" | |
fi | |
suffix="${SHADOW}${VOL}" | |
./transparency-test $SHADOW $VOL -o $1-spheres${suffix}.ppm | |
./transparency-test $SHADOW $VOL -isos -o $1-spheres-isosurface${suffix}.ppm | |
./transparency-test $SHADOW $VOL -tri -o $1-spheres-tri${suffix}.ppm | |
./transparency-test $SHADOW $VOL -instance-spheres -o $1-spheres-instance${suffix}.ppm | |
./transparency-test $SHADOW $VOL -instance-tri -o $1-spheres-tri-instance${suffix}.ppm | |
./transparency-test $SHADOW $VOL -instance-spheres -instance-tri -o $1-spheres-tri-instance${suffix}.ppm | |
done | |
done | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <vector> | |
#include <iostream> | |
#include <cstring> | |
#include <fstream> | |
#include <random> | |
#include <string> | |
#include <array> | |
#include <cstdio> | |
#include <ospray/ospray.h> | |
#include <ospcommon/vec.h> | |
using namespace ospcommon; | |
struct Particle { | |
vec3f pos; | |
float radius; | |
int atom_type; | |
Particle(float x, float y, float z, float radius, int type) | |
: pos(vec3f(x, y, z)), radius(radius), atom_type(type) | |
{} | |
}; | |
OSPMaterial mat; | |
OSPGeometry make_triangle(); | |
std::vector<OSPGeometry> make_spheres(); | |
OSPVolume make_volume(); | |
void write_ppm(const std::string &file_name, const int width, const int height, | |
const uint32_t *img); | |
int main(int argc, const char **argv) { | |
OSPError err = ospInit(&argc, argv); | |
if (err != OSP_NO_ERROR) { | |
return 1; | |
} | |
std::vector<std::string> args(argv, argv + argc); | |
bool with_spheres = true; | |
bool with_triangle = false; | |
bool with_volume = false; | |
bool instance_triangle = false; | |
bool instance_spheres = false; | |
bool isosurfaces_enabled = false; | |
bool separate_isosurfaces = false; | |
bool instance_isosurfaces = false; | |
int shadows_enabled = 0; | |
std::string output = "transparency.ppm"; | |
std::array<float, 3> cam_pos = {0.0, 2, 4.5}; | |
std::array<float, 3> cam_up = {0.0, 1.0, 0.0}; | |
std::array<float, 3> cam_at = {0.0, 0.0, 0.0}; | |
for (size_t i = 1; i < args.size(); ++i) { | |
if (args[i] == "-vp") { | |
for (size_t j = 0; j < 3; ++j) { | |
cam_pos[j] = std::stof(args[++i]); | |
} | |
} else if (args[i] == "-vu") { | |
for (size_t j = 0; j < 3; ++j) { | |
cam_up[j] = std::stof(args[++i]); | |
} | |
} else if (args[i] == "-vi") { | |
for (size_t j = 0; j < 3; ++j) { | |
cam_at[j] = std::stof(args[++i]); | |
} | |
} else if (args[i] == "-o" ) { | |
output = args[++i]; | |
} else if (args[i] == "-tri") { | |
with_triangle = true; | |
} else if (args[i] == "-instance-tri") { | |
with_triangle = true; | |
instance_triangle = true; | |
} else if (args[i] == "-instance-spheres") { | |
instance_spheres = true; | |
} else if (args[i] == "-vol") { | |
with_volume = true; | |
} else if (args[i] == "-shadow") { | |
shadows_enabled = 1; | |
} else if (args[i] == "-isos") { | |
isosurfaces_enabled = true; | |
} else if (args[i] == "-separate-isos") { | |
separate_isosurfaces = true; | |
isosurfaces_enabled = true; | |
} else if (args[i] == "-instance-isos") { | |
isosurfaces_enabled = true; | |
instance_isosurfaces = true; | |
} else if (args[i] == "-no-spheres") { | |
with_spheres = false; | |
} | |
} | |
std::array<float, 3> cam_dir; | |
for (size_t i = 0; i < 3; ++i) { | |
cam_dir[i] = cam_at[i] - cam_pos[i]; | |
} | |
OSPRenderer renderer = ospNewRenderer("scivis"); | |
mat = ospNewMaterial2("scivis", "OBJMaterial"); | |
ospSetVec3f(mat, "Ks", osp::vec3f{1.f, 1.f, 1.f}); | |
ospSet1f(mat, "Ns", 15.f); | |
ospCommit(mat); | |
osp::affine3f identity = {0}; | |
identity.l.vx.x = 1; | |
identity.l.vy.y = 1; | |
identity.l.vz.z = 1; | |
OSPModel model = ospNewModel(); | |
if (with_triangle) { | |
if (instance_triangle) { | |
std::cout << "Instanced triangle\n"; | |
OSPModel inst = ospNewModel(); | |
ospAddGeometry(inst, make_triangle()); | |
ospCommit(inst); | |
ospAddGeometry(model, ospNewInstance(inst, identity)); | |
} else { | |
std::cout << "Regular triangle\n"; | |
ospAddGeometry(model, make_triangle()); | |
} | |
} | |
if (with_spheres) { | |
if (instance_spheres) { | |
std::cout << "Instanced spheres\n"; | |
OSPModel inst = ospNewModel(); | |
auto spheres = make_spheres(); | |
for (auto &s : spheres) { | |
ospAddGeometry(inst, s); | |
} | |
ospCommit(inst); | |
ospAddGeometry(model, ospNewInstance(inst, identity)); | |
} else { | |
std::cout << "Regular spheres\n"; | |
auto spheres = make_spheres(); | |
for (auto &s : spheres) { | |
ospAddGeometry(model, s); | |
} | |
} | |
} | |
OSPVolume vol = make_volume(); | |
if (with_volume) { | |
std::cout << "Adding volume\n"; | |
ospAddVolume(model, vol); | |
} | |
if (isosurfaces_enabled) { | |
OSPMaterial iso_mat = ospNewMaterial2("scivis", "OBJMaterial"); | |
ospSetVec3f(iso_mat, "Ks", osp::vec3f{1.f, 1.f, 1.f}); | |
ospSet1f(iso_mat, "d", 0.5f); | |
ospCommit(iso_mat); | |
OSPGeometry isosurf = ospNewGeometry("isosurfaces"); | |
//const std::array<float, 2> isovals = {64.f, 192.f}; | |
const std::array<float, 2> isovals = {192.f, 64.f}; | |
if (separate_isosurfaces) { | |
for (auto &iso : isovals) { | |
OSPData isoval_data = ospNewData(1, OSP_FLOAT, &iso, 0); | |
ospCommit(isoval_data); | |
ospSetData(isosurf, "isovalues", isoval_data); | |
ospSetObject(isosurf, "volume", vol); | |
ospSetMaterial(isosurf, iso_mat); | |
ospCommit(isosurf); | |
if (instance_isosurfaces) { | |
std::cout << "Instancing separate isosurface\n"; | |
OSPModel inst = ospNewModel(); | |
ospAddGeometry(inst, isosurf); | |
ospCommit(inst); | |
ospAddGeometry(model, ospNewInstance(inst, identity)); | |
} else { | |
std::cout << "Adding separate isosurface\n"; | |
ospAddGeometry(model, isosurf); | |
} | |
} | |
} else { | |
OSPData isoval_data = ospNewData(isovals.size(), OSP_FLOAT, isovals.data(), 0); | |
ospCommit(isoval_data); | |
ospSetData(isosurf, "isovalues", isoval_data); | |
ospSetObject(isosurf, "volume", vol); | |
ospSetMaterial(isosurf, iso_mat); | |
ospCommit(isosurf); | |
if (instance_isosurfaces) { | |
std::cout << "Instancing isosurface group\n"; | |
OSPModel inst = ospNewModel(); | |
ospAddGeometry(inst, isosurf); | |
ospCommit(inst); | |
ospAddGeometry(model, ospNewInstance(inst, identity)); | |
} else { | |
std::cout << "Adding isosurface group\n"; | |
ospAddGeometry(model, isosurf); | |
} | |
} | |
} | |
ospCommit(model); | |
// Setup the camera we'll render the scene from | |
const osp::vec2i img_size{256, 256}; | |
OSPCamera camera = ospNewCamera("perspective"); | |
ospSet1f(camera, "aspect", 1.0); | |
ospSet3fv(camera, "pos", cam_pos.data()); | |
ospSet3fv(camera, "up", cam_up.data()); | |
ospSet3fv(camera, "dir", cam_dir.data()); | |
ospCommit(camera); | |
// Create and setup an ambient light, this will also compute ambient | |
// occlusion. | |
OSPLight ambient_light = ospNewLight2("scivis", "ambient"); | |
ospSet1f(ambient_light, "intensity", 0.1); | |
ospCommit(ambient_light); | |
OSPLight sun_light = ospNewLight2("scivis", "distant"); | |
ospSetVec3f(sun_light, "direction", osp::vec3f{-1.f, -1.f, -1.5f}); | |
ospSetVec3f(sun_light, "color", osp::vec3f{1.f, 1.f, 0.8f}); | |
ospSet1f(sun_light, "intensity", 1); | |
ospSet1f(sun_light, "angularDiameter", 0.5); | |
ospCommit(sun_light); | |
std::vector<OSPLight> lights_list = {ambient_light, sun_light}; | |
// Setup a list of all the lights in the scene we're rendering | |
OSPData lights = ospNewData(lights_list.size(), OSP_LIGHT, lights_list.data(), 0); | |
ospCommit(lights); | |
// Setup the parameters for the renderer | |
ospSet1i(renderer, "spp", 4); | |
ospSet1i(renderer, "shadowsEnabled", shadows_enabled); | |
ospSet1i(renderer, "aoSamples", 0); | |
ospSet1i(renderer, "aoTransparencyEnabled", 0); | |
ospSet1f(renderer, "bgColor", 1.0); | |
ospSetObject(renderer, "model", model); | |
ospSetObject(renderer, "lights", lights); | |
ospSetObject(renderer, "camera", camera); | |
ospCommit(renderer); | |
// Create a framebuffer to render the image too | |
OSPFrameBuffer framebuffer = ospNewFrameBuffer(img_size, OSP_FB_SRGBA, OSP_FB_COLOR); | |
ospFrameBufferClear(framebuffer, OSP_FB_COLOR); | |
// Render the image and save it out | |
ospRenderFrame(framebuffer, renderer, OSP_FB_COLOR); | |
const uint32_t *img = static_cast<const uint32_t*>(ospMapFrameBuffer(framebuffer, OSP_FB_COLOR)); | |
write_ppm(output.c_str(), img_size.x, img_size.y, img); | |
std::cout << "Image saved to '" << output << "'\n"; | |
ospUnmapFrameBuffer(img, framebuffer); | |
return 0; | |
} | |
OSPGeometry make_triangle() { | |
// Data for a triangle | |
const float tri_verts[] = { | |
-4, -4, 0, 0, | |
-4, 4, 0, 0, | |
4, -4, 0, 0 | |
}; | |
const float tri_color[] = { | |
1, 0, 0, 1, | |
0, 1, 0, 1, | |
0, 0, 1, 1 | |
}; | |
const int32_t tri_index[] = { 0, 1, 2 }; | |
// create and setup model and mesh | |
OSPGeometry mesh = ospNewGeometry("triangles"); | |
OSPData tri_data = ospNewData(3, OSP_FLOAT3A, tri_verts, 0); | |
ospCommit(tri_data); | |
ospSetData(mesh, "vertex", tri_data); | |
ospRelease(tri_data); | |
tri_data = ospNewData(3, OSP_FLOAT4, tri_color, 0); | |
ospCommit(tri_data); | |
ospSetData(mesh, "vertex.color", tri_data); | |
ospRelease(tri_data); | |
tri_data = ospNewData(1, OSP_INT3, tri_index, 0); | |
ospCommit(tri_data); | |
ospSetData(mesh, "index", tri_data); | |
ospRelease(tri_data); | |
ospSetMaterial(mesh, mat); | |
ospCommit(mesh); | |
return mesh; | |
} | |
std::vector<OSPGeometry> make_spheres() { | |
const std::vector<Particle> atoms({ | |
Particle(0, 0, 0, 1.5, 0), | |
Particle(1.0, 0, 0, 1.0, 1), | |
Particle(-0.75, 0.5, 0, 0.5, 2) | |
}); | |
const std::vector<float> atom_colors({ | |
1, 0, 0, 0.25, | |
0, 1, 0, 0.25, | |
0, 0, 1, 1 | |
}); | |
OSPData color_data = ospNewData(atom_colors.size(), OSP_FLOAT4, | |
atom_colors.data(), 0); | |
ospCommit(color_data); | |
// Note: the bug involves multiple transparent geometries being | |
// instanced together, so we specifically do NOT put the particles | |
// in a single sphere geometry | |
std::vector<OSPGeometry> spheres; | |
for (size_t i = 0; i < atoms.size(); ++i) { | |
OSPData sphere_data = ospNewData(sizeof(Particle), OSP_CHAR, &atoms[i], 0); | |
ospCommit(sphere_data); | |
OSPGeometry s = ospNewGeometry("spheres"); | |
ospSetData(s, "spheres", sphere_data); | |
ospSetData(s, "color", color_data); | |
ospSet1i(s, "bytes_per_sphere", sizeof(Particle)); | |
ospSet1i(s, "offset_radius", sizeof(osp::vec3f)); | |
ospSet1i(s, "offset_colorID", sizeof(osp::vec3f) + sizeof(float)); | |
ospSetMaterial(s, mat); | |
ospCommit(s); | |
spheres.push_back(s); | |
} | |
return spheres; | |
} | |
OSPVolume make_volume() { | |
const std::vector<vec3f> colors = { | |
vec3f(1, 0, 0), | |
vec3f(0, 0, 1) | |
}; | |
const std::vector<float> opacities = {0.005f, 0.01f}; | |
OSPData colors_data = ospNewData(colors.size(), OSP_FLOAT3, colors.data()); | |
ospCommit(colors_data); | |
OSPData opacity_data = ospNewData(opacities.size(), OSP_FLOAT, opacities.data()); | |
ospCommit(opacity_data); | |
OSPTransferFunction transfer_fcn = ospNewTransferFunction("piecewise_linear"); | |
const vec2f value_range(static_cast<float>(0), static_cast<float>(255)); | |
ospSetData(transfer_fcn, "colors", colors_data); | |
ospSetData(transfer_fcn, "opacities", opacity_data); | |
ospSetVec2f(transfer_fcn, "valueRange", (osp::vec2f&)value_range); | |
ospCommit(transfer_fcn); | |
const vec3i dims(256); | |
std::vector<unsigned char> volume_data(dims.x * dims.y * dims.z, 0); | |
for (size_t z = 0; z < dims.z; ++z) { | |
for (size_t y = 0; y < dims.y; ++y) { | |
for (size_t x = 0; x < dims.x; ++x) { | |
volume_data[(z * dims.y + y) * dims.x + x] = y; | |
} | |
} | |
} | |
OSPVolume volume = ospNewVolume("block_bricked_volume"); | |
ospSetString(volume, "voxelType", "uchar"); | |
ospSetVec3i(volume, "dimensions", (osp::vec3i&)dims); | |
const vec3f grid_spacing = vec3f(3.5f) / vec3f(dims); | |
const vec3f grid_origin = vec3f(-1.75f, -1.75f, -1.75f); | |
ospSetVec3f(volume, "gridSpacing", (osp::vec3f&)grid_spacing); | |
ospSetVec3f(volume, "gridOrigin", (osp::vec3f&)grid_origin); | |
ospSetObject(volume, "transferFunction", transfer_fcn); | |
// This will copy the volume data into OSPRay's volume where it'll re-organize | |
// it for better memory access | |
ospSetRegion(volume, volume_data.data(), osp::vec3i{0, 0, 0}, (osp::vec3i&)dims); | |
ospCommit(volume); | |
return volume; | |
} | |
void write_ppm(const std::string &file_name, const int width, const int height, | |
const uint32_t *img) | |
{ | |
FILE *file = fopen(file_name.c_str(), "wb"); | |
if (!file) { | |
throw std::runtime_error("Failed to open file for PPM output"); | |
} | |
fprintf(file, "P6\n%i %i\n255\n", width, height); | |
std::vector<uint8_t> out(3 * width, 0); | |
for (int y = 0; y < height; ++y) { | |
const uint8_t *in = reinterpret_cast<const uint8_t*>(&img[(height - 1 - y) * width]); | |
for (int x = 0; x < width; ++x) { | |
out[3 * x] = in[4 * x]; | |
out[3 * x + 1] = in[4 * x + 1]; | |
out[3 * x + 2] = in[4 * x + 2]; | |
} | |
fwrite(out.data(), out.size(), sizeof(uint8_t), file); | |
} | |
fprintf(file, "\n"); | |
fclose(file); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment