Skip to content

Instantly share code, notes, and snippets.

@Twinklebear
Last active June 7, 2018 00:57
Show Gist options
  • Save Twinklebear/b98dbe5ab1613e1b1917285bab50b534 to your computer and use it in GitHub Desktop.
Save Twinklebear/b98dbe5ab1613e1b1917285bab50b534 to your computer and use it in GitHub Desktop.
OSPRay Transparency Test Case Repro
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})
#!/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
#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