Cycles render engine, initial commit. This is the engine itself, blender modifications and build instructions will follow later.
Cycles uses code from some great open source projects, many thanks them: * BVH building and traversal code from NVidia's "Understanding the Efficiency of Ray Traversal on GPUs": http://code.google.com/p/understanding-the-efficiency-of-ray-traversal-on-gpus/ * Open Shading Language for a large part of the shading system: http://code.google.com/p/openshadinglanguage/ * Blender for procedural textures and a few other nodes. * Approximate Catmull Clark subdivision from NVidia Mesh tools: http://code.google.com/p/nvidia-mesh-tools/ * Sobol direction vectors from: http://web.maths.unsw.edu.au/~fkuo/sobol/ * Film response functions from: http://www.cs.columbia.edu/CAVE/software/softlib/dorf.php
This commit is contained in:
parent
6937800743
commit
da376e0237
59
intern/cycles/CMakeLists.txt
Normal file
59
intern/cycles/CMakeLists.txt
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
PROJECT(cycles)
|
||||
SET(CYCLES_VERSION_MAJOR 0)
|
||||
SET(CYCLES_VERSION_MINOR 0)
|
||||
SET(CYCLES_VERSION ${CYCLES_VERSION_MAJOR}.${CYCLES_VERSION_MINOR})
|
||||
|
||||
# Options
|
||||
|
||||
OPTION(WITH_OSL "Build with Open Shading Language support" OFF)
|
||||
OPTION(WITH_CUDA "Build with CUDA support" OFF)
|
||||
OPTION(WITH_OPENCL "Build with OpenCL support (not working)" OFF)
|
||||
OPTION(WITH_BLENDER "Build Blender Python extension" OFF)
|
||||
OPTION(WITH_PARTIO "Build with Partio point cloud support (unfinished)" OFF)
|
||||
OPTION(WITH_NETWORK "Build with network rendering support (unfinished)" OFF)
|
||||
OPTION(WITH_MULTI "Build with network rendering support (unfinished)" OFF)
|
||||
OPTION(WITH_DOCS "Build html documentation" OFF)
|
||||
|
||||
# Flags
|
||||
SET(CUDA_ARCH sm_10 sm_11 sm_12 sm_13 sm_20 sm_21 CACHE STRING "CUDA architectures to build for")
|
||||
SET(CUDA_MAXREG 24 CACHE STRING "CUDA maximum number of register to use")
|
||||
|
||||
# Paths
|
||||
|
||||
SET(OSL_PATH "" CACHE PATH "Path to OpenShadingLanguage installation")
|
||||
SET(OIIO_PATH "" CACHE PATH "Path to OpenImageIO installation")
|
||||
SET(BOOST_PATH "/usr" CACHE PATH "Path to Boost installation")
|
||||
SET(CUDA_PATH "/usr/local/cuda" CACHE PATH "Path to CUDA installation")
|
||||
SET(OPENCL_PATH "" CACHE PATH "Path to OpenCL installation")
|
||||
SET(PYTHON_PATH "" CACHE PATH "Path to Python installation")
|
||||
SET(BLENDER_PATH "" CACHE PATH "Path to Blender installation")
|
||||
SET(PARTIO_PATH "" CACHE PATH "Path to Partio installation")
|
||||
SET(GLEW_PATH "" CACHE PATH "Path to GLEW installation")
|
||||
SET(GLUT_PATH "" CACHE PATH "Path to GLUT installation")
|
||||
SET(INSTALL_PATH "${CMAKE_BINARY_DIR}/install" CACHE PATH "Path to install to")
|
||||
|
||||
# External Libraries
|
||||
|
||||
INCLUDE(cmake/external_libs.cmake)
|
||||
|
||||
# Platforms
|
||||
|
||||
INCLUDE(cmake/platforms.cmake)
|
||||
|
||||
# Subdirectories
|
||||
|
||||
IF(WITH_BLENDER)
|
||||
ADD_SUBDIRECTORY(blender)
|
||||
ENDIF(WITH_BLENDER)
|
||||
|
||||
ADD_SUBDIRECTORY(app)
|
||||
ADD_SUBDIRECTORY(bvh)
|
||||
ADD_SUBDIRECTORY(device)
|
||||
ADD_SUBDIRECTORY(doc)
|
||||
ADD_SUBDIRECTORY(kernel)
|
||||
ADD_SUBDIRECTORY(render)
|
||||
ADD_SUBDIRECTORY(subd)
|
||||
ADD_SUBDIRECTORY(util)
|
||||
|
48
intern/cycles/app/CMakeLists.txt
Normal file
48
intern/cycles/app/CMakeLists.txt
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
INCLUDE_DIRECTORIES(. ../device ../kernel ../kernel/svm ../bvh ../util ../render ../subd)
|
||||
|
||||
SET(LIBRARIES
|
||||
device
|
||||
kernel
|
||||
render
|
||||
bvh
|
||||
subd
|
||||
util
|
||||
${Boost_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
${GLEW_LIBRARIES}
|
||||
${OPENIMAGEIO_LIBRARY}
|
||||
${GLUT_LIBRARIES})
|
||||
|
||||
IF(WITH_OSL)
|
||||
LIST(APPEND LIBRARIES kernel_osl ${OSL_LIBRARIES})
|
||||
ENDIF(WITH_OSL)
|
||||
|
||||
IF(WITH_PARTIO)
|
||||
LIST(APPEND LIBRARIES ${PARTIO_LIBRARIES})
|
||||
ENDIF(WITH_PARTIO)
|
||||
|
||||
IF(WITH_OPENCL)
|
||||
LIST(APPEND LIBRARIES ${OPENCL_LIBRARIES})
|
||||
ENDIF(WITH_OPENCL)
|
||||
|
||||
ADD_EXECUTABLE(cycles_test cycles_test.cpp cycles_xml.cpp cycles_xml.h)
|
||||
TARGET_LINK_LIBRARIES(cycles_test ${LIBRARIES})
|
||||
INSTALL(TARGETS cycles_test DESTINATION ${INSTALL_PATH}/cycles)
|
||||
|
||||
IF(UNIX AND NOT APPLE)
|
||||
SET_TARGET_PROPERTIES(cycles_test PROPERTIES INSTALL_RPATH $ORIGIN/lib)
|
||||
ENDIF()
|
||||
|
||||
IF(WITH_NETWORK)
|
||||
ADD_EXECUTABLE(cycles_server cycles_server.cpp)
|
||||
TARGET_LINK_LIBRARIES(cycles_server ${LIBRARIES})
|
||||
INSTALL(TARGETS cycles_server DESTINATION ${INSTALL_PATH}/cycles)
|
||||
|
||||
IF(UNIX AND NOT APPLE)
|
||||
SET_TARGET_PROPERTIES(cycles_server PROPERTIES INSTALL_RPATH $ORIGIN/lib)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
INSTALL(CODE "FILE(MAKE_DIRECTORY ${INSTALL_PATH}/cycles/cache)")
|
||||
|
71
intern/cycles/app/cycles_server.cpp
Normal file
71
intern/cycles/app/cycles_server.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "device.h"
|
||||
|
||||
#include "util_args.h"
|
||||
#include "util_foreach.h"
|
||||
#include "util_path.h"
|
||||
#include "util_string.h"
|
||||
|
||||
using namespace ccl;
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
path_init();
|
||||
|
||||
/* device types */
|
||||
string devices = "";
|
||||
string devicename = "cpu";
|
||||
|
||||
vector<DeviceType> types = Device::available_types();
|
||||
|
||||
foreach(DeviceType type, types) {
|
||||
if(devices != "")
|
||||
devices += ", ";
|
||||
|
||||
devices += Device::string_from_type(type);
|
||||
}
|
||||
|
||||
/* parse options */
|
||||
ArgParse ap;
|
||||
|
||||
ap.options ("Usage: cycles_server [options]",
|
||||
"--device %s", &devicename, ("Devices to use: " + devices).c_str(),
|
||||
NULL);
|
||||
|
||||
if(ap.parse(argc, argv) < 0) {
|
||||
fprintf(stderr, "%s\n", ap.error_message().c_str());
|
||||
ap.usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
DeviceType dtype = Device::type_from_string(devicename.c_str());
|
||||
|
||||
while(1) {
|
||||
Device *device = Device::create(dtype);
|
||||
printf("Cycles Server with device: %s\n", device->description().c_str());
|
||||
device->server_run();
|
||||
delete device;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
306
intern/cycles/app/cycles_test.cpp
Normal file
306
intern/cycles/app/cycles_test.cpp
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "buffers.h"
|
||||
#include "camera.h"
|
||||
#include "device.h"
|
||||
#include "scene.h"
|
||||
#include "session.h"
|
||||
|
||||
#include "util_args.h"
|
||||
#include "util_foreach.h"
|
||||
#include "util_function.h"
|
||||
#include "util_path.h"
|
||||
#include "util_progress.h"
|
||||
#include "util_string.h"
|
||||
#include "util_time.h"
|
||||
#include "util_view.h"
|
||||
|
||||
#include "cycles_xml.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
struct Options {
|
||||
Session *session;
|
||||
Scene *scene;
|
||||
string filepath;
|
||||
int width, height;
|
||||
SceneParams scene_params;
|
||||
SessionParams session_params;
|
||||
bool quiet;
|
||||
} options;
|
||||
|
||||
static void session_print(const string& str)
|
||||
{
|
||||
/* print with carriage return to overwrite previous */
|
||||
printf("\r%s", str.c_str());
|
||||
|
||||
/* add spaces to overwrite longer previous print */
|
||||
static int maxlen = 0;
|
||||
int len = str.size();
|
||||
maxlen = max(len, maxlen);
|
||||
|
||||
for(int i = len; i < maxlen; i++)
|
||||
printf(" ");
|
||||
|
||||
/* flush because we don't write an end of line */
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void session_print_status()
|
||||
{
|
||||
int pass;
|
||||
double total_time, pass_time;
|
||||
string status, substatus;
|
||||
|
||||
/* get status */
|
||||
options.session->progress.get_pass(pass, total_time, pass_time);
|
||||
options.session->progress.get_status(status, substatus);
|
||||
|
||||
if(substatus != "")
|
||||
status += ": " + substatus;
|
||||
|
||||
/* print status */
|
||||
status = string_printf("Pass %d %s", pass, status.c_str());
|
||||
session_print(status);
|
||||
}
|
||||
|
||||
static void session_init()
|
||||
{
|
||||
options.session = new Session(options.session_params);
|
||||
options.session->reset(options.width, options.height);
|
||||
options.session->scene = options.scene;
|
||||
|
||||
if(options.session_params.background && !options.quiet)
|
||||
options.session->progress.set_update_callback(function_bind(&session_print_status));
|
||||
else
|
||||
options.session->progress.set_update_callback(function_bind(&view_redraw));
|
||||
|
||||
options.session->start();
|
||||
|
||||
options.scene = NULL;
|
||||
}
|
||||
|
||||
static void scene_init()
|
||||
{
|
||||
options.scene = new Scene(options.scene_params);
|
||||
xml_read_file(options.scene, options.filepath.c_str());
|
||||
options.width = options.scene->camera->width;
|
||||
options.height = options.scene->camera->height;
|
||||
}
|
||||
|
||||
static void session_exit()
|
||||
{
|
||||
if(options.session) {
|
||||
delete options.session;
|
||||
options.session = NULL;
|
||||
}
|
||||
if(options.scene) {
|
||||
delete options.scene;
|
||||
options.scene = NULL;
|
||||
}
|
||||
|
||||
if(options.session_params.background && !options.quiet) {
|
||||
session_print("Finished Rendering.");
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void display_info(Progress& progress)
|
||||
{
|
||||
static double latency = 0.0;
|
||||
static double last = 0;
|
||||
double elapsed = time_dt();
|
||||
string str;
|
||||
|
||||
latency = (elapsed - last);
|
||||
last = elapsed;
|
||||
|
||||
int pass;
|
||||
double total_time, pass_time;
|
||||
string status, substatus;
|
||||
|
||||
progress.get_pass(pass, total_time, pass_time);
|
||||
progress.get_status(status, substatus);
|
||||
|
||||
if(substatus != "")
|
||||
status += ": " + substatus;
|
||||
|
||||
str = string_printf("latency: %.4f pass: %d total: %.4f average: %.4f %s",
|
||||
latency, pass, total_time, pass_time, status.c_str());
|
||||
|
||||
view_display_info(str.c_str());
|
||||
}
|
||||
|
||||
static void display()
|
||||
{
|
||||
options.session->draw(options.width, options.height);
|
||||
|
||||
display_info(options.session->progress);
|
||||
}
|
||||
|
||||
static void resize(int width, int height)
|
||||
{
|
||||
options.width= width;
|
||||
options.height= height;
|
||||
|
||||
if(options.session)
|
||||
options.session->reset(options.width, options.height);
|
||||
}
|
||||
|
||||
void keyboard(unsigned char key)
|
||||
{
|
||||
if(key == 'r')
|
||||
options.session->reset(options.width, options.height);
|
||||
else if(key == 27) // escape
|
||||
options.session->progress.set_cancel("Cancelled");
|
||||
}
|
||||
|
||||
static int files_parse(int argc, const char *argv[])
|
||||
{
|
||||
if(argc > 0)
|
||||
options.filepath = argv[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void options_parse(int argc, const char **argv)
|
||||
{
|
||||
options.width= 1024;
|
||||
options.height= 512;
|
||||
options.filepath = path_get("../../../test/models/elephants.xml");
|
||||
options.session = NULL;
|
||||
options.quiet = false;
|
||||
|
||||
/* devices */
|
||||
string devices = "";
|
||||
string devicename = "cpu";
|
||||
|
||||
vector<DeviceType> types = Device::available_types();
|
||||
|
||||
foreach(DeviceType type, types) {
|
||||
if(devices != "")
|
||||
devices += ", ";
|
||||
|
||||
devices += Device::string_from_type(type);
|
||||
}
|
||||
|
||||
/* shading system */
|
||||
string ssname = "svm";
|
||||
string shadingsystems = "Shading system to use: svm";
|
||||
|
||||
#ifdef WITH_OSL
|
||||
shadingsystems += ", osl";
|
||||
#endif
|
||||
|
||||
/* parse options */
|
||||
ArgParse ap;
|
||||
bool help = false;
|
||||
|
||||
ap.options ("Usage: cycles_test [options] file.xml",
|
||||
"%*", files_parse, "",
|
||||
"--device %s", &devicename, ("Devices to use: " + devices).c_str(),
|
||||
"--shadingsys %s", &ssname, "Shading system to use: svm, osl",
|
||||
"--background", &options.session_params.background, "Render in background, without user interface",
|
||||
"--quiet", &options.quiet, "In background mode, don't print progress messages",
|
||||
"--passes %d", &options.session_params.passes, "Number of passes to render",
|
||||
"--output %s", &options.session_params.output_path, "File path to write output image",
|
||||
"--help", &help, "Print help message",
|
||||
NULL);
|
||||
|
||||
if(ap.parse(argc, argv) < 0) {
|
||||
fprintf(stderr, "%s\n", ap.error_message().c_str());
|
||||
ap.usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if(help || options.filepath == "") {
|
||||
ap.usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
options.session_params.device_type = Device::type_from_string(devicename.c_str());
|
||||
|
||||
if(ssname == "osl")
|
||||
options.scene_params.shadingsystem = SceneParams::OSL;
|
||||
else if(ssname == "svm")
|
||||
options.scene_params.shadingsystem = SceneParams::SVM;
|
||||
|
||||
/* handle invalid configurations */
|
||||
bool type_available = false;
|
||||
|
||||
foreach(DeviceType dtype, types)
|
||||
if(options.session_params.device_type == dtype)
|
||||
type_available = true;
|
||||
|
||||
if(options.session_params.device_type == DEVICE_NONE || !type_available) {
|
||||
fprintf(stderr, "Unknown device: %s\n", devicename.c_str());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#ifdef WITH_OSL
|
||||
else if(!(ssname == "osl" || ssname == "svm")) {
|
||||
#else
|
||||
else if(!(ssname == "svm")) {
|
||||
#endif
|
||||
fprintf(stderr, "Unknown shading system: %s\n", ssname.c_str());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if(options.scene_params.shadingsystem == SceneParams::OSL && options.session_params.device_type != DEVICE_CPU) {
|
||||
fprintf(stderr, "OSL shading system only works with CPU device\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if(options.session_params.passes < 0) {
|
||||
fprintf(stderr, "Invalid number of passes: %d\n", options.session_params.passes);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if(options.filepath == "") {
|
||||
fprintf(stderr, "No file path specified\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* load scene */
|
||||
scene_init();
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
using namespace ccl;
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
path_init();
|
||||
|
||||
options_parse(argc, argv);
|
||||
|
||||
if(options.session_params.background) {
|
||||
session_init();
|
||||
options.session->wait();
|
||||
session_exit();
|
||||
}
|
||||
else {
|
||||
string title = "Cycles: " + path_filename(options.filepath);
|
||||
|
||||
/* init/exit are callback so they run while GL is initialized */
|
||||
view_main_loop(title.c_str(), options.width, options.height,
|
||||
session_init, session_exit, resize, display, keyboard);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
936
intern/cycles/app/cycles_xml.cpp
Normal file
936
intern/cycles/app/cycles_xml.cpp
Normal file
@ -0,0 +1,936 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include "camera.h"
|
||||
#include "film.h"
|
||||
#include "graph.h"
|
||||
#include "integrator.h"
|
||||
#include "light.h"
|
||||
#include "mesh.h"
|
||||
#include "nodes.h"
|
||||
#include "object.h"
|
||||
#include "shader.h"
|
||||
#include "scene.h"
|
||||
|
||||
#include "subd_mesh.h"
|
||||
#include "subd_patch.h"
|
||||
#include "subd_split.h"
|
||||
|
||||
#include "util_debug.h"
|
||||
#include "util_foreach.h"
|
||||
#include "util_path.h"
|
||||
#include "util_transform.h"
|
||||
#include "util_xml.h"
|
||||
|
||||
#include "cycles_xml.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* XML reading state */
|
||||
|
||||
struct XMLReadState {
|
||||
Scene *scene; /* scene pointer */
|
||||
Transform tfm; /* current transform state */
|
||||
bool smooth; /* smooth normal state */
|
||||
int shader; /* current shader */
|
||||
string base; /* base path to current file*/
|
||||
float dicing_rate; /* current dicing rate */
|
||||
Mesh::DisplacementMethod displacement_method;
|
||||
};
|
||||
|
||||
/* Attribute Reading */
|
||||
|
||||
static bool xml_read_bool(bool *value, pugi::xml_node node, const char *name)
|
||||
{
|
||||
pugi::xml_attribute attr = node.attribute(name);
|
||||
|
||||
if(attr) {
|
||||
*value = (string_iequals(attr.value(), "true")) || (atoi(attr.value()) != 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xml_read_int(int *value, pugi::xml_node node, const char *name)
|
||||
{
|
||||
pugi::xml_attribute attr = node.attribute(name);
|
||||
|
||||
if(attr) {
|
||||
*value = atoi(attr.value());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xml_read_int_array(vector<int>& value, pugi::xml_node node, const char *name)
|
||||
{
|
||||
pugi::xml_attribute attr = node.attribute(name);
|
||||
|
||||
if(attr) {
|
||||
vector<string> tokens;
|
||||
string_split(tokens, attr.value());
|
||||
|
||||
foreach(const string& token, tokens)
|
||||
value.push_back(atoi(token.c_str()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xml_read_float(float *value, pugi::xml_node node, const char *name)
|
||||
{
|
||||
pugi::xml_attribute attr = node.attribute(name);
|
||||
|
||||
if(attr) {
|
||||
*value = atof(attr.value());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xml_read_float_array(vector<float>& value, pugi::xml_node node, const char *name)
|
||||
{
|
||||
pugi::xml_attribute attr = node.attribute(name);
|
||||
|
||||
if(attr) {
|
||||
vector<string> tokens;
|
||||
string_split(tokens, attr.value());
|
||||
|
||||
foreach(const string& token, tokens)
|
||||
value.push_back(atof(token.c_str()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xml_read_float3(float3 *value, pugi::xml_node node, const char *name)
|
||||
{
|
||||
vector<float> array;
|
||||
|
||||
if(xml_read_float_array(array, node, name) && array.size() == 3) {
|
||||
*value = make_float3(array[0], array[1], array[2]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xml_read_float3_array(vector<float3>& value, pugi::xml_node node, const char *name)
|
||||
{
|
||||
vector<float> array;
|
||||
|
||||
if(xml_read_float_array(array, node, name)) {
|
||||
for(size_t i = 0; i < array.size(); i += 3)
|
||||
value.push_back(make_float3(array[i+0], array[i+1], array[i+2]));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xml_read_float4(float4 *value, pugi::xml_node node, const char *name)
|
||||
{
|
||||
vector<float> array;
|
||||
|
||||
if(xml_read_float_array(array, node, name) && array.size() == 4) {
|
||||
*value = make_float4(array[0], array[1], array[2], array[3]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xml_read_string(string *str, pugi::xml_node node, const char *name)
|
||||
{
|
||||
pugi::xml_attribute attr = node.attribute(name);
|
||||
|
||||
if(attr) {
|
||||
*str = attr.value();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xml_read_ustring(ustring *str, pugi::xml_node node, const char *name)
|
||||
{
|
||||
pugi::xml_attribute attr = node.attribute(name);
|
||||
|
||||
if(attr) {
|
||||
*str = ustring(attr.value());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xml_equal_string(pugi::xml_node node, const char *name, const char *value)
|
||||
{
|
||||
pugi::xml_attribute attr = node.attribute(name);
|
||||
|
||||
if(attr)
|
||||
return string_iequals(attr.value(), value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xml_read_enum(ustring *str, ShaderEnum& enm, pugi::xml_node node, const char *name)
|
||||
{
|
||||
pugi::xml_attribute attr = node.attribute(name);
|
||||
|
||||
if(attr) {
|
||||
ustring ustr(attr.value());
|
||||
|
||||
if(enm.exists(ustr)) {
|
||||
*str = ustr;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", ustr.c_str(), name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Film */
|
||||
|
||||
static void xml_read_film(const XMLReadState& state, pugi::xml_node node)
|
||||
{
|
||||
Camera *cam = state.scene->camera;
|
||||
|
||||
xml_read_int(&cam->width, node, "width");
|
||||
xml_read_int(&cam->height, node, "height");
|
||||
|
||||
float aspect = (float)cam->width/(float)cam->height;
|
||||
|
||||
if(cam->width >= cam->height) {
|
||||
cam->left = -aspect;
|
||||
cam->right = aspect;
|
||||
cam->bottom = -1.0f;
|
||||
cam->top = 1.0f;
|
||||
}
|
||||
else {
|
||||
cam->left = -1.0f;
|
||||
cam->right = 1.0f;
|
||||
cam->bottom = -1.0f/aspect;
|
||||
cam->top = 1.0f/aspect;
|
||||
}
|
||||
|
||||
cam->need_update = true;
|
||||
cam->update();
|
||||
}
|
||||
|
||||
/* Integrator */
|
||||
|
||||
static void xml_read_integrator(const XMLReadState& state, pugi::xml_node node)
|
||||
{
|
||||
Integrator *integrator = state.scene->integrator;
|
||||
|
||||
xml_read_int(&integrator->minbounce, node, "min_bounce");
|
||||
xml_read_int(&integrator->maxbounce, node, "max_bounce");
|
||||
xml_read_bool(&integrator->no_caustics, node, "no_caustics");
|
||||
xml_read_float(&integrator->blur_caustics, node, "blur_caustics");
|
||||
}
|
||||
|
||||
/* Camera */
|
||||
|
||||
static void xml_read_camera(const XMLReadState& state, pugi::xml_node node)
|
||||
{
|
||||
Camera *cam = state.scene->camera;
|
||||
|
||||
if(xml_read_float(&cam->fov, node, "fov"))
|
||||
cam->fov *= M_PI/180.0f;
|
||||
|
||||
xml_read_float(&cam->nearclip, node, "nearclip");
|
||||
xml_read_float(&cam->farclip, node, "farclip");
|
||||
xml_read_float(&cam->lensradius, node, "lensradius"); // 0.5*focallength/fstop
|
||||
xml_read_float(&cam->focaldistance, node, "focaldistance");
|
||||
xml_read_float(&cam->shutteropen, node, "shutteropen");
|
||||
xml_read_float(&cam->shutterclose, node, "shutterclose");
|
||||
|
||||
if(xml_equal_string(node, "type", "orthographic"))
|
||||
cam->ortho = true;
|
||||
else if(xml_equal_string(node, "type", "perspective"))
|
||||
cam->ortho = false;
|
||||
|
||||
cam->matrix = state.tfm;
|
||||
|
||||
cam->need_update = true;
|
||||
cam->update();
|
||||
}
|
||||
|
||||
/* Shader */
|
||||
|
||||
static string xml_socket_name(const char *name)
|
||||
{
|
||||
string sname = name;
|
||||
size_t i;
|
||||
|
||||
while((i = sname.find(" ")) != string::npos)
|
||||
sname.replace(i, 1, "");
|
||||
|
||||
return sname;
|
||||
}
|
||||
|
||||
static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pugi::xml_node graph_node)
|
||||
{
|
||||
ShaderGraph *graph = new ShaderGraph();
|
||||
|
||||
map<string, ShaderNode*> nodemap;
|
||||
|
||||
nodemap["output"] = graph->output();
|
||||
|
||||
for(pugi::xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
|
||||
ShaderNode *snode = NULL;
|
||||
|
||||
if(string_iequals(node.name(), "image_texture")) {
|
||||
ImageTextureNode *img = new ImageTextureNode();
|
||||
|
||||
xml_read_string(&img->filename, node, "src");
|
||||
img->filename = path_join(state.base, img->filename);
|
||||
|
||||
snode = img;
|
||||
}
|
||||
else if(string_iequals(node.name(), "environment_texture")) {
|
||||
EnvironmentTextureNode *env = new EnvironmentTextureNode();
|
||||
|
||||
xml_read_string(&env->filename, node, "src");
|
||||
env->filename = path_join(state.base, env->filename);
|
||||
|
||||
snode = env;
|
||||
}
|
||||
else if(string_iequals(node.name(), "sky_texture")) {
|
||||
SkyTextureNode *sky = new SkyTextureNode();
|
||||
|
||||
xml_read_float3(&sky->sun_direction, node, "sun_direction");
|
||||
xml_read_float(&sky->turbidity, node, "turbidity");
|
||||
|
||||
snode = sky;
|
||||
}
|
||||
else if(string_iequals(node.name(), "noise_texture")) {
|
||||
snode = new NoiseTextureNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "blend_texture")) {
|
||||
BlendTextureNode *blend = new BlendTextureNode();
|
||||
xml_read_enum(&blend->progression, BlendTextureNode::progression_enum, node, "progression");
|
||||
xml_read_enum(&blend->axis, BlendTextureNode::axis_enum, node, "axis");
|
||||
snode = blend;
|
||||
}
|
||||
else if(string_iequals(node.name(), "clouds_texture")) {
|
||||
CloudsTextureNode *clouds = new CloudsTextureNode();
|
||||
xml_read_bool(&clouds->hard, node, "hard");
|
||||
xml_read_int(&clouds->depth, node, "depth");
|
||||
xml_read_enum(&clouds->basis, CloudsTextureNode::basis_enum, node, "basis");
|
||||
snode = clouds;
|
||||
}
|
||||
else if(string_iequals(node.name(), "voronoi_texture")) {
|
||||
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
|
||||
xml_read_enum(&voronoi->distance_metric, VoronoiTextureNode::distance_metric_enum, node, "distance_metric");
|
||||
xml_read_enum(&voronoi->coloring, VoronoiTextureNode::coloring_enum, node, "coloring");
|
||||
snode = voronoi;
|
||||
}
|
||||
else if(string_iequals(node.name(), "musgrave_texture")) {
|
||||
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
|
||||
xml_read_enum(&musgrave->type, MusgraveTextureNode::type_enum, node, "type");
|
||||
xml_read_enum(&musgrave->basis, MusgraveTextureNode::basis_enum, node, "basis");
|
||||
snode = musgrave;
|
||||
}
|
||||
else if(string_iequals(node.name(), "marble_texture")) {
|
||||
MarbleTextureNode *marble = new MarbleTextureNode();
|
||||
xml_read_enum(&marble->type, MarbleTextureNode::type_enum, node, "type");
|
||||
xml_read_enum(&marble->wave, MarbleTextureNode::wave_enum, node, "wave");
|
||||
xml_read_enum(&marble->basis, MarbleTextureNode::basis_enum, node, "basis");
|
||||
xml_read_bool(&marble->hard, node, "hard");
|
||||
xml_read_int(&marble->depth, node, "depth");
|
||||
snode = marble;
|
||||
}
|
||||
else if(string_iequals(node.name(), "magic_texture")) {
|
||||
MagicTextureNode *magic = new MagicTextureNode();
|
||||
xml_read_int(&magic->depth, node, "depth");
|
||||
snode = magic;
|
||||
}
|
||||
else if(string_iequals(node.name(), "stucci_texture")) {
|
||||
StucciTextureNode *stucci = new StucciTextureNode();
|
||||
xml_read_enum(&stucci->type, StucciTextureNode::type_enum, node, "type");
|
||||
xml_read_enum(&stucci->basis, StucciTextureNode::basis_enum, node, "basis");
|
||||
xml_read_bool(&stucci->hard, node, "hard");
|
||||
snode = stucci;
|
||||
}
|
||||
else if(string_iequals(node.name(), "distorted_noise_texture")) {
|
||||
DistortedNoiseTextureNode *dist = new DistortedNoiseTextureNode();
|
||||
xml_read_enum(&dist->basis, DistortedNoiseTextureNode::basis_enum, node, "basis");
|
||||
xml_read_enum(&dist->distortion_basis, DistortedNoiseTextureNode::basis_enum, node, "distortion_basis");
|
||||
snode = dist;
|
||||
}
|
||||
else if(string_iequals(node.name(), "wood_texture")) {
|
||||
WoodTextureNode *wood = new WoodTextureNode();
|
||||
xml_read_enum(&wood->type, WoodTextureNode::type_enum, node, "type");
|
||||
xml_read_enum(&wood->wave, WoodTextureNode::wave_enum, node, "wave");
|
||||
xml_read_enum(&wood->basis, WoodTextureNode::basis_enum, node, "basis");
|
||||
xml_read_bool(&wood->hard, node, "hard");
|
||||
snode = wood;
|
||||
}
|
||||
else if(string_iequals(node.name(), "mapping")) {
|
||||
snode = new MappingNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "ward_bsdf")) {
|
||||
snode = new WardBsdfNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "diffuse_bsdf")) {
|
||||
snode = new DiffuseBsdfNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "translucent_bsdf")) {
|
||||
snode = new TranslucentBsdfNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "transparent_bsdf")) {
|
||||
snode = new TransparentBsdfNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "velvet_bsdf")) {
|
||||
snode = new VelvetBsdfNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "glossy_bsdf")) {
|
||||
GlossyBsdfNode *glossy = new GlossyBsdfNode();
|
||||
xml_read_enum(&glossy->distribution, GlossyBsdfNode::distribution_enum, node, "distribution");
|
||||
snode = glossy;
|
||||
}
|
||||
else if(string_iequals(node.name(), "glass_bsdf")) {
|
||||
GlassBsdfNode *diel = new GlassBsdfNode();
|
||||
xml_read_enum(&diel->distribution, GlassBsdfNode::distribution_enum, node, "distribution");
|
||||
snode = diel;
|
||||
}
|
||||
else if(string_iequals(node.name(), "emission")) {
|
||||
EmissionNode *emission = new EmissionNode();
|
||||
xml_read_bool(&emission->total_power, node, "total_power");
|
||||
snode = emission;
|
||||
}
|
||||
else if(string_iequals(node.name(), "background")) {
|
||||
snode = new BackgroundNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "geometry")) {
|
||||
snode = new GeometryNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "texture_coordinate")) {
|
||||
snode = new TextureCoordinateNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "lightPath")) {
|
||||
snode = new LightPathNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "value")) {
|
||||
ValueNode *value = new ValueNode();
|
||||
xml_read_float(&value->value, node, "value");
|
||||
snode = value;
|
||||
}
|
||||
else if(string_iequals(node.name(), "color")) {
|
||||
ColorNode *color = new ColorNode();
|
||||
xml_read_float3(&color->value, node, "value");
|
||||
snode = color;
|
||||
}
|
||||
else if(string_iequals(node.name(), "mix_closure")) {
|
||||
snode = new MixClosureNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "add_closure")) {
|
||||
snode = new AddClosureNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "mix")) {
|
||||
MixNode *mix = new MixNode();
|
||||
xml_read_enum(&mix->type, MixNode::type_enum, node, "type");
|
||||
snode = mix;
|
||||
}
|
||||
else if(string_iequals(node.name(), "attribute")) {
|
||||
AttributeNode *attr = new AttributeNode();
|
||||
xml_read_ustring(&attr->attribute, node, "attribute");
|
||||
snode = attr;
|
||||
}
|
||||
else if(string_iequals(node.name(), "fresnel")) {
|
||||
snode = new FresnelNode();
|
||||
}
|
||||
else if(string_iequals(node.name(), "math")) {
|
||||
MathNode *math = new MathNode();
|
||||
xml_read_enum(&math->type, MathNode::type_enum, node, "type");
|
||||
snode = math;
|
||||
}
|
||||
else if(string_iequals(node.name(), "vector_math")) {
|
||||
VectorMathNode *vmath = new VectorMathNode();
|
||||
xml_read_enum(&vmath->type, VectorMathNode::type_enum, node, "type");
|
||||
snode = vmath;
|
||||
}
|
||||
else if(string_iequals(node.name(), "connect")) {
|
||||
/* connect nodes */
|
||||
vector<string> from_tokens, to_tokens;
|
||||
|
||||
string_split(from_tokens, node.attribute("from").value());
|
||||
string_split(to_tokens, node.attribute("to").value());
|
||||
|
||||
if(from_tokens.size() == 2 && to_tokens.size() == 2) {
|
||||
/* find nodes and sockets */
|
||||
ShaderOutput *output = NULL;
|
||||
ShaderInput *input = NULL;
|
||||
|
||||
if(nodemap.find(from_tokens[0]) != nodemap.end()) {
|
||||
ShaderNode *fromnode = nodemap[from_tokens[0]];
|
||||
|
||||
foreach(ShaderOutput *out, fromnode->outputs)
|
||||
if(string_iequals(xml_socket_name(out->name), from_tokens[1]))
|
||||
output = out;
|
||||
|
||||
if(!output)
|
||||
fprintf(stderr, "Unknown output socket name \"%s\" on \"%s\".\n", from_tokens[1].c_str(), from_tokens[0].c_str());
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Unknown shader node name \"%s\".\n", from_tokens[0].c_str());
|
||||
|
||||
if(nodemap.find(to_tokens[0]) != nodemap.end()) {
|
||||
ShaderNode *tonode = nodemap[to_tokens[0]];
|
||||
|
||||
foreach(ShaderInput *in, tonode->inputs)
|
||||
if(string_iequals(xml_socket_name(in->name), to_tokens[1]))
|
||||
input = in;
|
||||
|
||||
if(!input)
|
||||
fprintf(stderr, "Unknown input socket name \"%s\" on \"%s\".\n", to_tokens[1].c_str(), to_tokens[0].c_str());
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Unknown shader node name \"%s\".\n", to_tokens[0].c_str());
|
||||
|
||||
/* connect */
|
||||
if(output && input)
|
||||
graph->connect(output, input);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Invalid from or to value for connect node.\n");
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Unknown shader node \"%s\".\n", node.name());
|
||||
|
||||
if(snode) {
|
||||
/* add to graph */
|
||||
graph->add(snode);
|
||||
|
||||
/* add to map for name lookups */
|
||||
string name = "";
|
||||
xml_read_string(&name, node, "name");
|
||||
|
||||
nodemap[name] = snode;
|
||||
|
||||
/* read input values */
|
||||
for(pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute()) {
|
||||
foreach(ShaderInput *in, snode->inputs) {
|
||||
if(string_iequals(in->name, attr.name())) {
|
||||
switch(in->type) {
|
||||
case SHADER_SOCKET_FLOAT:
|
||||
xml_read_float(&in->value.x, node, attr.name());
|
||||
break;
|
||||
case SHADER_SOCKET_COLOR:
|
||||
case SHADER_SOCKET_VECTOR:
|
||||
case SHADER_SOCKET_POINT:
|
||||
case SHADER_SOCKET_NORMAL:
|
||||
xml_read_float3(&in->value, node, attr.name());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shader->set_graph(graph);
|
||||
shader->tag_update(state.scene);
|
||||
}
|
||||
|
||||
static void xml_read_shader(const XMLReadState& state, pugi::xml_node node)
|
||||
{
|
||||
Shader *shader = new Shader();
|
||||
xml_read_string(&shader->name, node, "name");
|
||||
xml_read_shader_graph(state, shader, node);
|
||||
state.scene->shaders.push_back(shader);
|
||||
}
|
||||
|
||||
/* Background */
|
||||
|
||||
static void xml_read_background(const XMLReadState& state, pugi::xml_node node)
|
||||
{
|
||||
Shader *shader = state.scene->shaders[state.scene->default_background];
|
||||
|
||||
xml_read_shader_graph(state, shader, node);
|
||||
}
|
||||
|
||||
/* Mesh */
|
||||
|
||||
static Mesh *xml_add_mesh(Scene *scene, const Transform& tfm)
|
||||
{
|
||||
/* create mesh */
|
||||
Mesh *mesh = new Mesh();
|
||||
scene->meshes.push_back(mesh);
|
||||
|
||||
/* create object*/
|
||||
Object *object = new Object();
|
||||
object->mesh = mesh;
|
||||
object->tfm = tfm;
|
||||
scene->objects.push_back(object);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
|
||||
{
|
||||
/* add mesh */
|
||||
Mesh *mesh = xml_add_mesh(state.scene, state.tfm);
|
||||
mesh->used_shaders.push_back(state.shader);
|
||||
|
||||
/* read state */
|
||||
int shader = state.shader;
|
||||
bool smooth = state.smooth;
|
||||
|
||||
mesh->displacement_method = state.displacement_method;
|
||||
|
||||
/* read vertices and polygons, RIB style */
|
||||
vector<float3> P;
|
||||
vector<int> verts, nverts;
|
||||
|
||||
xml_read_float3_array(P, node, "P");
|
||||
xml_read_int_array(verts, node, "verts");
|
||||
xml_read_int_array(nverts, node, "nverts");
|
||||
|
||||
if(xml_equal_string(node, "subdivision", "catmull-clark")) {
|
||||
/* create subd mesh */
|
||||
SubdMesh sdmesh;
|
||||
|
||||
/* create subd vertices */
|
||||
for(size_t i = 0; i < P.size(); i++)
|
||||
sdmesh.add_vert(P[i]);
|
||||
|
||||
/* create subd faces */
|
||||
int index_offset = 0;
|
||||
|
||||
for(size_t i = 0; i < nverts.size(); i++) {
|
||||
if(nverts[i] == 4) {
|
||||
int v0 = verts[index_offset + 0];
|
||||
int v1 = verts[index_offset + 1];
|
||||
int v2 = verts[index_offset + 2];
|
||||
int v3 = verts[index_offset + 3];
|
||||
|
||||
sdmesh.add_face(v0, v1, v2, v3);
|
||||
}
|
||||
else {
|
||||
for(int j = 0; j < nverts[i]-2; j++) {
|
||||
int v0 = verts[index_offset];
|
||||
int v1 = verts[index_offset + j + 1];
|
||||
int v2 = verts[index_offset + j + 2];;
|
||||
|
||||
sdmesh.add_face(v0, v1, v2);
|
||||
}
|
||||
}
|
||||
|
||||
index_offset += nverts[i];
|
||||
}
|
||||
|
||||
/* finalize subd mesh */
|
||||
sdmesh.link_boundary();
|
||||
|
||||
/* subdivide */
|
||||
DiagSplit dsplit;
|
||||
//dsplit.camera = state.scene->camera;
|
||||
//dsplit.dicing_rate = 5.0f;
|
||||
dsplit.dicing_rate = state.dicing_rate;
|
||||
xml_read_float(&dsplit.dicing_rate, node, "dicing_rate");
|
||||
sdmesh.tesselate(&dsplit, false, mesh, shader, smooth);
|
||||
}
|
||||
else {
|
||||
/* create vertices */
|
||||
mesh->verts = P;
|
||||
|
||||
/* create triangles */
|
||||
int index_offset = 0;
|
||||
|
||||
for(size_t i = 0; i < nverts.size(); i++) {
|
||||
for(int j = 0; j < nverts[i]-2; j++) {
|
||||
int v0 = verts[index_offset];
|
||||
int v1 = verts[index_offset + j + 1];
|
||||
int v2 = verts[index_offset + j + 2];
|
||||
|
||||
assert(v0 < (int)P.size());
|
||||
assert(v1 < (int)P.size());
|
||||
assert(v2 < (int)P.size());
|
||||
|
||||
mesh->add_triangle(v0, v1, v2, shader, smooth);
|
||||
}
|
||||
|
||||
index_offset += nverts[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* temporary for test compatibility */
|
||||
mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
|
||||
}
|
||||
|
||||
/* Patch */
|
||||
|
||||
static void xml_read_patch(const XMLReadState& state, pugi::xml_node node)
|
||||
{
|
||||
/* read patch */
|
||||
Patch *patch = NULL;
|
||||
|
||||
vector<float3> P;
|
||||
xml_read_float3_array(P, node, "P");
|
||||
|
||||
if(xml_equal_string(node, "type", "bilinear")) {
|
||||
/* bilinear patch */
|
||||
if(P.size() == 4) {
|
||||
LinearQuadPatch *bpatch = new LinearQuadPatch();
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
P[i] = transform(&state.tfm, P[i]);
|
||||
memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
|
||||
|
||||
patch = bpatch;
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Invalid number of control points for bilinear patch.\n");
|
||||
}
|
||||
else if(xml_equal_string(node, "type", "bicubic")) {
|
||||
/* bicubic patch */
|
||||
if(P.size() == 16) {
|
||||
BicubicPatch *bpatch = new BicubicPatch();
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
P[i] = transform(&state.tfm, P[i]);
|
||||
memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
|
||||
|
||||
patch = bpatch;
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Invalid number of control points for bicubic patch.\n");
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Unknown patch type.\n");
|
||||
|
||||
if(patch) {
|
||||
/* add mesh */
|
||||
Mesh *mesh = xml_add_mesh(state.scene, transform_identity());
|
||||
|
||||
mesh->used_shaders.push_back(state.shader);
|
||||
|
||||
/* split */
|
||||
DiagSplit dsplit;
|
||||
//dsplit.camera = state.scene->camera;
|
||||
//dsplit.dicing_rate = 5.0f;
|
||||
dsplit.dicing_rate = state.dicing_rate;
|
||||
xml_read_float(&dsplit.dicing_rate, node, "dicing_rate");
|
||||
dsplit.split_quad(mesh, patch, state.shader, state.smooth);
|
||||
|
||||
delete patch;
|
||||
|
||||
/* temporary for test compatibility */
|
||||
mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Light */
|
||||
|
||||
static void xml_read_light(const XMLReadState& state, pugi::xml_node node)
|
||||
{
|
||||
Light *light = new Light();
|
||||
light->shader = state.shader;
|
||||
xml_read_float3(&light->co, node, "P");
|
||||
light->co = transform(&state.tfm, light->co);
|
||||
|
||||
state.scene->lights.push_back(light);
|
||||
}
|
||||
|
||||
/* Transform */
|
||||
|
||||
static void xml_read_transform(pugi::xml_node node, Transform& tfm)
|
||||
{
|
||||
if(node.attribute("matrix")) {
|
||||
vector<float> matrix;
|
||||
if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16)
|
||||
tfm = tfm * transform_transpose((*(Transform*)&matrix[0]));
|
||||
}
|
||||
|
||||
if(node.attribute("translate")) {
|
||||
float3 translate = make_float3(0.0f, 0.0f, 0.0f);
|
||||
xml_read_float3(&translate, node, "translate");
|
||||
tfm = tfm * transform_translate(translate);
|
||||
}
|
||||
|
||||
if(node.attribute("rotate")) {
|
||||
float4 rotate = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
xml_read_float4(&rotate, node, "rotate");
|
||||
tfm = tfm * transform_rotate(rotate.x*M_PI/180.0f, make_float3(rotate.y, rotate.z, rotate.w));
|
||||
}
|
||||
|
||||
if(node.attribute("scale")) {
|
||||
float3 scale = make_float3(0.0f, 0.0f, 0.0f);
|
||||
xml_read_float3(&scale, node, "scale");
|
||||
tfm = tfm * transform_scale(scale);
|
||||
}
|
||||
}
|
||||
|
||||
/* State */
|
||||
|
||||
static void xml_read_state(XMLReadState& state, pugi::xml_node node)
|
||||
{
|
||||
/* read shader */
|
||||
string shadername;
|
||||
|
||||
if(xml_read_string(&shadername, node, "shader")) {
|
||||
int i = 0;
|
||||
bool found = false;
|
||||
|
||||
foreach(Shader *shader, state.scene->shaders) {
|
||||
if(shader->name == shadername) {
|
||||
state.shader = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if(!found)
|
||||
fprintf(stderr, "Unknown shader \"%s\".\n", shadername.c_str());
|
||||
}
|
||||
|
||||
xml_read_float(&state.dicing_rate, node, "dicing_rate");
|
||||
|
||||
/* read smooth/flat */
|
||||
if(xml_equal_string(node, "interpolation", "smooth"))
|
||||
state.smooth = true;
|
||||
else if(xml_equal_string(node, "interpolation", "flat"))
|
||||
state.smooth = false;
|
||||
|
||||
/* read displacement method */
|
||||
if(xml_equal_string(node, "displacement_method", "true"))
|
||||
state.displacement_method = Mesh::DISPLACE_TRUE;
|
||||
else if(xml_equal_string(node, "displacement_method", "bump"))
|
||||
state.displacement_method = Mesh::DISPLACE_BUMP;
|
||||
else if(xml_equal_string(node, "displacement_method", "both"))
|
||||
state.displacement_method = Mesh::DISPLACE_BOTH;
|
||||
}
|
||||
|
||||
/* Scene */
|
||||
|
||||
static void xml_read_include(const XMLReadState& state, const string& src);
|
||||
|
||||
static void xml_read_scene(const XMLReadState& state, pugi::xml_node scene_node)
|
||||
{
|
||||
for(pugi::xml_node node = scene_node.first_child(); node; node = node.next_sibling()) {
|
||||
if(string_iequals(node.name(), "film")) {
|
||||
xml_read_film(state, node);
|
||||
}
|
||||
else if(string_iequals(node.name(), "integrator")) {
|
||||
xml_read_integrator(state, node);
|
||||
}
|
||||
else if(string_iequals(node.name(), "camera")) {
|
||||
xml_read_camera(state, node);
|
||||
}
|
||||
else if(string_iequals(node.name(), "shader")) {
|
||||
xml_read_shader(state, node);
|
||||
}
|
||||
else if(string_iequals(node.name(), "background")) {
|
||||
xml_read_background(state, node);
|
||||
}
|
||||
else if(string_iequals(node.name(), "mesh")) {
|
||||
xml_read_mesh(state, node);
|
||||
}
|
||||
else if(string_iequals(node.name(), "patch")) {
|
||||
xml_read_patch(state, node);
|
||||
}
|
||||
else if(string_iequals(node.name(), "light")) {
|
||||
xml_read_light(state, node);
|
||||
}
|
||||
else if(string_iequals(node.name(), "transform")) {
|
||||
XMLReadState substate = state;
|
||||
|
||||
xml_read_transform(node, substate.tfm);
|
||||
xml_read_scene(substate, node);
|
||||
}
|
||||
else if(string_iequals(node.name(), "state")) {
|
||||
XMLReadState substate = state;
|
||||
|
||||
xml_read_state(substate, node);
|
||||
xml_read_scene(substate, node);
|
||||
}
|
||||
else if(string_iequals(node.name(), "include")) {
|
||||
string src;
|
||||
|
||||
if(xml_read_string(&src, node, "src"))
|
||||
xml_read_include(state, src);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Unknown node \"%s\".\n", node.name());
|
||||
}
|
||||
}
|
||||
|
||||
/* Include */
|
||||
|
||||
static void xml_read_include(const XMLReadState& state, const string& src)
|
||||
{
|
||||
/* open XML document */
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result parse_result;
|
||||
|
||||
string path = path_join(state.base, src);
|
||||
parse_result = doc.load_file(path.c_str());
|
||||
|
||||
if(parse_result) {
|
||||
XMLReadState substate = state;
|
||||
substate.base = path_dirname(path);
|
||||
|
||||
xml_read_scene(substate, doc);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "%s read error: %s\n", src.c_str(), parse_result.description());
|
||||
}
|
||||
|
||||
/* File */
|
||||
|
||||
void xml_read_file(Scene *scene, const char *filepath)
|
||||
{
|
||||
XMLReadState state;
|
||||
|
||||
state.scene = scene;
|
||||
state.tfm = transform_identity();
|
||||
state.shader = scene->default_surface;
|
||||
state.smooth = false;
|
||||
state.dicing_rate = 0.1f;
|
||||
state.base = path_dirname(filepath);
|
||||
|
||||
xml_read_include(state, path_filename(filepath));
|
||||
|
||||
scene->params.bvh_type = SceneParams::BVH_STATIC;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
31
intern/cycles/app/cycles_xml.h
Normal file
31
intern/cycles/app/cycles_xml.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CYCLES_XML__
|
||||
#define __CYCLES_XML__
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Scene;
|
||||
|
||||
void xml_read_file(Scene *scene, const char *filepath);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __CYCLES_XML__ */
|
||||
|
72
intern/cycles/blender/CMakeLists.txt
Normal file
72
intern/cycles/blender/CMakeLists.txt
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
SET(sources
|
||||
blender_camera.cpp
|
||||
blender_mesh.cpp
|
||||
blender_object.cpp
|
||||
blender_python.cpp
|
||||
blender_session.cpp
|
||||
blender_shader.cpp
|
||||
blender_sync.cpp)
|
||||
|
||||
SET(headers
|
||||
blender_sync.h
|
||||
blender_session.h
|
||||
blender_util.h)
|
||||
|
||||
SET(addonfiles
|
||||
addon/__init__.py
|
||||
addon/engine.py
|
||||
addon/enums.py
|
||||
addon/properties.py
|
||||
addon/ui.py
|
||||
addon/xml.py)
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
../render
|
||||
../device
|
||||
../kernel
|
||||
../kernel/svm
|
||||
../util
|
||||
../subd
|
||||
${BLENDER_INCLUDE_DIRS}
|
||||
${PYTHON_INCLUDE_DIRS})
|
||||
|
||||
SET(LIBRARIES
|
||||
render
|
||||
bvh
|
||||
device
|
||||
kernel
|
||||
util
|
||||
subd
|
||||
${Boost_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
${OPENIMAGEIO_LIBRARY}
|
||||
${PYTHON_LIBRARIES}
|
||||
${GLUT_LIBRARIES}
|
||||
${GLEW_LIBRARIES}
|
||||
${BLENDER_LIBRARIES})
|
||||
|
||||
IF(WITH_OSL)
|
||||
LIST(APPEND LIBRARIES kernel_osl ${OSL_LIBRARIES})
|
||||
ENDIF(WITH_OSL)
|
||||
|
||||
IF(WITH_PARTIO)
|
||||
LIST(APPEND LIBRARIES ${PARTIO_LIBRARIES})
|
||||
ENDIF(WITH_PARTIO)
|
||||
|
||||
IF(WITH_OPENCL)
|
||||
LIST(APPEND LIBRARIES ${OPENCL_LIBRARIES})
|
||||
ENDIF(WITH_OPENCL)
|
||||
|
||||
SET(CMAKE_MODULE_LINKER_FLAGS ${PYTHON_MODULE_FLAGS})
|
||||
|
||||
ADD_LIBRARY(cycles_blender MODULE ${sources} ${headers})
|
||||
TARGET_LINK_LIBRARIES(cycles_blender ${LIBRARIES})
|
||||
|
||||
INSTALL(FILES ${addonfiles} DESTINATION ${INSTALL_PATH}/cycles)
|
||||
INSTALL(TARGETS cycles_blender LIBRARY DESTINATION ${INSTALL_PATH}/cycles)
|
||||
|
||||
IF(UNIX AND NOT APPLE)
|
||||
SET_TARGET_PROPERTIES(cycles_blender PROPERTIES INSTALL_RPATH $ORIGIN/lib)
|
||||
ENDIF()
|
||||
|
73
intern/cycles/blender/addon/__init__.py
Normal file
73
intern/cycles/blender/addon/__init__.py
Normal file
@ -0,0 +1,73 @@
|
||||
#
|
||||
# Copyright 2011, Blender Foundation.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
bl_info = {
|
||||
"name": "Cycles Render Engine",
|
||||
"author": "",
|
||||
"version": (0,0),
|
||||
"blender": (2, 5, 6),
|
||||
"api": 34462,
|
||||
"location": "Info header, render engine menu",
|
||||
"description": "Cycles Render Engine integration.",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Render"}
|
||||
|
||||
import bpy
|
||||
|
||||
from cycles import ui
|
||||
from cycles import properties
|
||||
from cycles import xml
|
||||
from cycles import engine
|
||||
|
||||
class CyclesRender(bpy.types.RenderEngine):
|
||||
bl_idname = 'CYCLES'
|
||||
bl_label = "Cycles"
|
||||
|
||||
def __init__(self):
|
||||
engine.init()
|
||||
self.session = None
|
||||
|
||||
def __del__(self):
|
||||
engine.free(self)
|
||||
|
||||
def render(self, scene):
|
||||
engine.create(self, scene, True)
|
||||
engine.render(self, scene)
|
||||
|
||||
def draw(self, scene):
|
||||
if not self.session:
|
||||
engine.create(self, scene, False)
|
||||
engine.draw(self, scene)
|
||||
|
||||
def update(self, scene):
|
||||
engine.update(self, scene)
|
||||
|
||||
def register():
|
||||
properties.register()
|
||||
ui.register()
|
||||
xml.register()
|
||||
bpy.utils.register_module(__name__)
|
||||
|
||||
def unregister():
|
||||
xml.unregister()
|
||||
ui.unregister()
|
||||
properties.unregister()
|
||||
bpy.utils.unregister_module(__name__)
|
||||
|
107
intern/cycles/blender/addon/engine.py
Normal file
107
intern/cycles/blender/addon/engine.py
Normal file
@ -0,0 +1,107 @@
|
||||
#
|
||||
# Copyright 2011, Blender Foundation.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
import bpy
|
||||
|
||||
def init():
|
||||
from cycles import libcycles_blender as lib
|
||||
import os.path
|
||||
lib.init(os.path.dirname(__file__))
|
||||
|
||||
def create(engine, scene, offline):
|
||||
from cycles import libcycles_blender as lib
|
||||
data = bpy.data.as_pointer()
|
||||
scene = scene.as_pointer()
|
||||
|
||||
if not offline and bpy.context.area.type == 'VIEW_3D':
|
||||
region = bpy.context.region.as_pointer()
|
||||
v3d = bpy.context.space_data.as_pointer()
|
||||
rv3d = bpy.context.region_data.as_pointer()
|
||||
else:
|
||||
region = 0
|
||||
v3d = 0
|
||||
rv3d = 0
|
||||
|
||||
engine.session = lib.create(engine.as_pointer(), data, scene, region, v3d, rv3d)
|
||||
|
||||
def free(engine):
|
||||
if "session" in dir(engine):
|
||||
if engine.session:
|
||||
from cycles import libcycles_blender as lib
|
||||
lib.free(engine.session)
|
||||
del engine.session
|
||||
|
||||
def render(engine, scene):
|
||||
from cycles import libcycles_blender as lib
|
||||
lib.render(engine.session)
|
||||
|
||||
def update(engine, scene):
|
||||
from cycles import libcycles_blender as lib
|
||||
lib.sync(engine.session)
|
||||
|
||||
def draw(engine, scene):
|
||||
from cycles import libcycles_blender as lib
|
||||
v3d = bpy.context.space_data.as_pointer()
|
||||
rv3d = bpy.context.region_data.as_pointer()
|
||||
region = bpy.context.region
|
||||
|
||||
# draw render image
|
||||
status, substatus = lib.draw(engine.session, v3d, rv3d)
|
||||
|
||||
# draw text over image
|
||||
if status != "":
|
||||
import blf
|
||||
import bgl
|
||||
|
||||
fontid = 0 # todo, find out how to set this
|
||||
dim = blf.dimensions(fontid, status)
|
||||
dim_sub = blf.dimensions(fontid, substatus)
|
||||
|
||||
padding = 5
|
||||
|
||||
x = (region.width - max(dim[0], dim_sub[0]))*0.5 - padding
|
||||
y = (region.height - (dim[1] + dim_sub[1] + padding))*0.5 - padding
|
||||
|
||||
bgl.glColor4f(0.0, 0.0, 0.0, 0.5)
|
||||
bgl.glEnable(bgl.GL_BLEND)
|
||||
bgl.glBlendFunc(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA)
|
||||
bgl.glRectf(x, y, x+max(dim[0], dim_sub[0])+padding+padding, y+dim[1]+dim_sub[1]+padding+padding+2)
|
||||
bgl.glDisable(bgl.GL_BLEND)
|
||||
|
||||
x = (region.width - dim[0])*0.5
|
||||
y = (region.height - (dim[1] + dim_sub[1] + padding))*0.5 + dim_sub[1] + padding
|
||||
|
||||
bgl.glColor3f(0.8, 0.8, 0.8)
|
||||
blf.position(fontid, x, y, 0)
|
||||
blf.draw(fontid, status)
|
||||
|
||||
x = (region.width - dim_sub[0])*0.5
|
||||
y = (region.height - (dim[1] + dim_sub[1] + padding))*0.5
|
||||
|
||||
bgl.glColor3f(0.6, 0.6, 0.6)
|
||||
blf.position(fontid, x, y, 0)
|
||||
blf.draw(fontid, substatus)
|
||||
|
||||
def available_devices():
|
||||
from cycles import libcycles_blender as lib
|
||||
return lib.available_devices()
|
||||
|
||||
def with_osl():
|
||||
from cycles import libcycles_blender as lib
|
||||
return lib.with_osl()
|
||||
|
113
intern/cycles/blender/addon/enums.py
Normal file
113
intern/cycles/blender/addon/enums.py
Normal file
@ -0,0 +1,113 @@
|
||||
#
|
||||
# Copyright 2011, Blender Foundation.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
devices = (
|
||||
("CPU", "CPU", "Processor"),
|
||||
("GPU", "GPU", "Graphics card (NVidia only)"))
|
||||
|
||||
shading_systems = (
|
||||
("GPU_COMPATIBLE", "GPU Compatible", "Restricted shading system compatible with GPU rendering"),
|
||||
("OSL", "Open Shading Language", "Open Shading Language shading system that only runs on the CPU"))
|
||||
|
||||
displacement_methods = (
|
||||
("BUMP", "Bump", "Bump mapping to simulate the appearance of displacement"),
|
||||
("TRUE", "True", "Use true displacement only, requires fine subdivision"),
|
||||
("BOTH", "Both", "Combination of displacement and bump mapping"))
|
||||
|
||||
bvh_types = (
|
||||
("DYNAMIC_BVH", "Dynamic BVH", "Objects can be individually updated, at the cost of slower render time"),
|
||||
("STATIC_BVH", "Static BVH", "Any object modification requires a complete BVH rebuild, but renders faster"))
|
||||
|
||||
response_curves = (
|
||||
("None", "None", ""),
|
||||
("", "Agfa", ""),
|
||||
("Agfacolor Futura 100", "Futura 100", ""),
|
||||
("Agfacolor Futura 200", "Futura 200", ""),
|
||||
("Agfacolor Futura 400", "Futura 400", ""),
|
||||
("Agfacolor Futura II 100", "Futura II 100", ""),
|
||||
("Agfacolor Futura II 200", "Futura II 200", ""),
|
||||
("Agfacolor Futura II 400", "Futura II 400", ""),
|
||||
("Agfacolor HDC 100 plus", "HDC 100 plus", ""),
|
||||
("Agfacolor HDC 400 plus", "HDC 400 plus", ""),
|
||||
("Agfacolor HDC 200 plus", "HDC 200 plus", ""),
|
||||
("Agfacolor Optima II 100", "Optima II 100", ""),
|
||||
("Agfacolor Optima II 200", "Optima II 200", ""),
|
||||
("Agfacolor Ultra 050", "Ultra 050", ""),
|
||||
("", "Agfa", ""),
|
||||
("Agfacolor Vista 100", "Vista 100", ""),
|
||||
("Agfacolor Vista 200", "Vista 200", ""),
|
||||
("Agfacolor Vista 400", "Vista 400", ""),
|
||||
("Agfacolor Vista 800", "Vista 800", ""),
|
||||
("Agfachrome CT Precisa 100", "CT Precisa 100", ""),
|
||||
("Agfachrome CT Precisa 200", "CT Precisa 200", ""),
|
||||
("Agfachrome RSX2 050", "Agfachrome RSX2 050", ""),
|
||||
("Agfachrome RSX2 100", "Agfachrome RSX2 100", ""),
|
||||
("Agfachrome RSX2 200", "Agfachrome RSX2 200", ""),
|
||||
("Advantix 100", "Advantix 100", ""),
|
||||
("Advantix 200", "Advantix 200", ""),
|
||||
("Advantix 400", "Advantix 400", ""),
|
||||
("", "Kodak", ""),
|
||||
("Gold 100", "Gold 100", ""),
|
||||
("Gold 200", "Gold 200", ""),
|
||||
("Max Zoom 800", "Max Zoom 800", ""),
|
||||
("Portra 100T", "Portra 100T", ""),
|
||||
("Portra 160NC", "Portra 160NC", ""),
|
||||
("Portra 160VC", "Portra 160VC", ""),
|
||||
("Portra 800", "Portra 800", ""),
|
||||
("Portra 400VC", "Portra 400VC", ""),
|
||||
("Portra 400NC", "Portra 400NC", ""),
|
||||
("", "Kodak", ""),
|
||||
("Ektachrome 100 plus", "Ektachrome 100 plus", ""),
|
||||
("Ektachrome 320T", "Ektachrome 320T", ""),
|
||||
("Ektachrome 400X", "Ektachrome 400X", ""),
|
||||
("Ektachrome 64", "Ektachrome 64", ""),
|
||||
("Ektachrome 64T", "Ektachrome 64T", ""),
|
||||
("Ektachrome E100S", "Ektachrome E100S", ""),
|
||||
("Ektachrome 100", "Ektachrome 100", ""),
|
||||
("Kodachrome 200", "Kodachrome 200", ""),
|
||||
("Kodachrome 25", "Kodachrome 25", ""),
|
||||
("Kodachrome 64", "Kodachrome 64", ""),
|
||||
#("DSCS 3151", "DSCS 3151", ""),
|
||||
#("DSCS 3152", "DSCS 3152", ""),
|
||||
#("DSCS 3153", "DSCS 3153", ""),
|
||||
#("DSCS 3154", "DSCS 3154", ""),
|
||||
#("DSCS 3155", "DSCS 3155", ""),
|
||||
#("DSCS 3156", "DSCS 3156", ""),
|
||||
#("KAI-0311", "KAI-0311", ""),
|
||||
#("KAF-2001", "KAF-2001", ""),
|
||||
#("KAF-3000", "KAF-3000", ""),
|
||||
#("KAI-0372", "KAI-0372", ""),
|
||||
#("KAI-1010", "KAI-1010", ""),
|
||||
("", "Fujifilm", ""),
|
||||
("F-125", "F-125", ""),
|
||||
("F-250", "F-250", ""),
|
||||
("F-400", "F-400", ""),
|
||||
("FCI", "FCI", ""),
|
||||
("FP2900Z", "FP2900Z", ""),
|
||||
("", "Eastman", ""),
|
||||
("Double X Neg 12min", "Double X Neg 12min", ""),
|
||||
("Double X Neg 6min", "Double X Neg 6min", ""),
|
||||
("Double X Neg 5min", "Double X Neg 5min", ""),
|
||||
("Double X Neg 4min", "Double X Neg 4min", ""),
|
||||
("", "Canon", ""),
|
||||
("Optura 981111", "Optura 981111", ""),
|
||||
("Optura 981113", "Optura 981113", ""),
|
||||
("Optura 981114", "Optura 981114", ""),
|
||||
("Optura 981111.SLRR", "Optura 981111.SLRR", "")
|
||||
)
|
||||
|
120
intern/cycles/blender/addon/properties.py
Normal file
120
intern/cycles/blender/addon/properties.py
Normal file
@ -0,0 +1,120 @@
|
||||
#
|
||||
# Copyright 2011, Blender Foundation.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
|
||||
from cycles import enums
|
||||
|
||||
class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
@classmethod
|
||||
def register(cls):
|
||||
bpy.types.Scene.cycles = PointerProperty(type=cls, name="Cycles Render Settings", description="Cycles Render Settings")
|
||||
|
||||
cls.device = EnumProperty(name="Device", description="Device to use for rendering",
|
||||
items=enums.devices, default="CPU")
|
||||
|
||||
cls.shading_system = EnumProperty(name="Shading System", description="Shading system to use for rendering",
|
||||
items=enums.shading_systems, default="GPU_COMPATIBLE")
|
||||
|
||||
cls.passes = IntProperty(name="Passes", description="Number of passes to render",
|
||||
default=10, min=1, max=2147483647)
|
||||
cls.min_bounces = IntProperty(name="Min Bounces", description="Minimum number of bounces",
|
||||
default=3, min=0, max=1024)
|
||||
cls.max_bounces = IntProperty(name="Max Bounces", description="Maximum number of bounces",
|
||||
default=8, min=0, max=1024)
|
||||
cls.no_caustics = BoolProperty(name="No Caustics", description="Leave out caustics, resulting in a darker image with less noise",
|
||||
default=False)
|
||||
cls.blur_caustics = FloatProperty(name="Blur Caustics", description="Blur caustics to reduce noise",
|
||||
default=0.0, min=0.0, max=1.0)
|
||||
|
||||
cls.exposure = FloatProperty(name="Exposure", description="Image brightness scale",
|
||||
default=1.0, min=0.0, max=10.0)
|
||||
cls.response_curve = EnumProperty(name="Response Curve", description="Measured camera film response",
|
||||
items=enums.response_curves, default="Advantix 400")
|
||||
|
||||
cls.debug_tile_size = IntProperty(name="Tile Size", description="",
|
||||
default=1024, min=1, max=4096)
|
||||
cls.debug_min_size = IntProperty(name="Min Size", description="",
|
||||
default=64, min=1, max=4096)
|
||||
cls.debug_reset_timeout = FloatProperty(name="Reset timeout", description="",
|
||||
default=0.1, min=0.01, max=10.0)
|
||||
cls.debug_cancel_timeout = FloatProperty(name="Cancel timeout", description="",
|
||||
default=0.1, min=0.01, max=10.0)
|
||||
cls.debug_text_timeout = FloatProperty(name="Text timeout", description="",
|
||||
default=1.0, min=0.01, max=10.0)
|
||||
|
||||
cls.debug_bvh_type = EnumProperty(name="BVH Type", description="Choose between faster updates, or faster render",
|
||||
items=enums.bvh_types, default="DYNAMIC_BVH")
|
||||
cls.debug_use_spatial_splits = BoolProperty(name="Use Spatial Splits", description="Use BVH spatial splits: longer builder time, faster render",
|
||||
default=False)
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.Scene.cycles
|
||||
|
||||
class CyclesCameraSettings(bpy.types.PropertyGroup):
|
||||
@classmethod
|
||||
def register(cls):
|
||||
bpy.types.Camera.cycles = PointerProperty(type=cls, name="Cycles Camera Settings", description="Cycles Camera Settings")
|
||||
|
||||
cls.lens_radius = FloatProperty(name="Lens radius", description="Lens radius for depth of field",
|
||||
default=0.0, min=0.0, max=10.0)
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.Camera.cycles
|
||||
|
||||
class CyclesMaterialSettings(bpy.types.PropertyGroup):
|
||||
@classmethod
|
||||
def register(cls):
|
||||
bpy.types.Material.cycles = PointerProperty(type=cls, name="Cycles Material Settings", description="Cycles Material Settings")
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.Material.cycles
|
||||
|
||||
class CyclesMeshSettings(bpy.types.PropertyGroup):
|
||||
@classmethod
|
||||
def register(cls):
|
||||
bpy.types.Mesh.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles Mesh Settings")
|
||||
bpy.types.Curve.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles Mesh Settings")
|
||||
bpy.types.MetaBall.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles Mesh Settings")
|
||||
|
||||
cls.displacement_method = EnumProperty(name="Displacement Method", description="Method to use for the displacement",
|
||||
items=enums.displacement_methods, default="BUMP")
|
||||
cls.use_subdivision = BoolProperty(name="Use Subdivision", description="Subdivide mesh for rendering",
|
||||
default=False)
|
||||
cls.dicing_rate = FloatProperty(name="Dicing Rate", description="", default=1.0, min=0.001, max=1000.0)
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.Mesh.cycles
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(CyclesRenderSettings)
|
||||
bpy.utils.register_class(CyclesCameraSettings)
|
||||
bpy.utils.register_class(CyclesMaterialSettings)
|
||||
bpy.utils.register_class(CyclesMeshSettings)
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_class(CyclesRenderSettings)
|
||||
bpy.utils.unregister_class(CyclesCameraSettings)
|
||||
bpy.utils.unregister_class(CyclesMaterialSettings)
|
||||
bpy.utils.unregister_class(CyclesMeshSettings)
|
||||
|
388
intern/cycles/blender/addon/ui.py
Normal file
388
intern/cycles/blender/addon/ui.py
Normal file
@ -0,0 +1,388 @@
|
||||
#
|
||||
# Copyright 2011, Blender Foundation.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
import bpy
|
||||
|
||||
from cycles import enums
|
||||
from cycles import engine
|
||||
|
||||
class CyclesButtonsPanel():
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "render"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
rd = context.scene.render
|
||||
return rd.engine == 'CYCLES'
|
||||
|
||||
class CyclesRender_PT_integrator(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Integrator"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
scene = context.scene
|
||||
cycles = scene.cycles
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop(cycles, "passes")
|
||||
col.prop(cycles, "no_caustics")
|
||||
|
||||
col = split.column()
|
||||
col = col.column(align=True)
|
||||
col.prop(cycles, "max_bounces")
|
||||
col.prop(cycles, "min_bounces")
|
||||
|
||||
#row = col.row()
|
||||
#row.prop(cycles, "blur_caustics")
|
||||
#row.active = not cycles.no_caustics
|
||||
|
||||
class CyclesRender_PT_film(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Film"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
scene = context.scene
|
||||
cycles = scene.cycles
|
||||
|
||||
split = layout.split()
|
||||
|
||||
split.prop(cycles, "exposure")
|
||||
split.prop(cycles, "response_curve", text="")
|
||||
|
||||
class CyclesRender_PT_debug(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Debug"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
scene = context.scene
|
||||
cycles = scene.cycles
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
|
||||
sub = col.column(align=True)
|
||||
sub.prop(cycles, "debug_bvh_type", text="")
|
||||
sub.prop(cycles, "debug_use_spatial_splits")
|
||||
|
||||
sub = col.column(align=True)
|
||||
sub.prop(cycles, "debug_tile_size")
|
||||
sub.prop(cycles, "debug_min_size")
|
||||
|
||||
col = split.column(align=True)
|
||||
col.prop(cycles, "debug_cancel_timeout")
|
||||
col.prop(cycles, "debug_reset_timeout")
|
||||
col.prop(cycles, "debug_text_timeout")
|
||||
|
||||
class Cycles_PT_post_processing(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Post Processing"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
rd = context.scene.render
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop(rd, "use_compositing")
|
||||
col.prop(rd, "use_sequencer")
|
||||
|
||||
col = split.column()
|
||||
col.prop(rd, "dither_intensity", text="Dither", slider=True)
|
||||
|
||||
class Cycles_PT_camera(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Cycles"
|
||||
bl_context = "data"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.camera
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
camera = context.camera
|
||||
cycles = camera.cycles
|
||||
|
||||
layout.prop(cycles, "lens_radius")
|
||||
|
||||
class Cycles_PT_context_material(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Surface"
|
||||
bl_context = "material"
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.material or context.object) and CyclesButtonsPanel.poll(context)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material
|
||||
ob = context.object
|
||||
slot = context.material_slot
|
||||
space = context.space_data
|
||||
|
||||
if ob:
|
||||
row = layout.row()
|
||||
|
||||
row.template_list(ob, "material_slots", ob, "active_material_index", rows=2)
|
||||
|
||||
col = row.column(align=True)
|
||||
col.operator("object.material_slot_add", icon='ZOOMIN', text="")
|
||||
col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")
|
||||
|
||||
col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
if ob.mode == 'EDIT':
|
||||
row = layout.row(align=True)
|
||||
row.operator("object.material_slot_assign", text="Assign")
|
||||
row.operator("object.material_slot_select", text="Select")
|
||||
row.operator("object.material_slot_deselect", text="Deselect")
|
||||
|
||||
split = layout.split(percentage=0.65)
|
||||
|
||||
if ob:
|
||||
split.template_ID(ob, "active_material", new="material.new")
|
||||
row = split.row()
|
||||
|
||||
if slot:
|
||||
row.prop(slot, "link", text="")
|
||||
else:
|
||||
row.label()
|
||||
elif mat:
|
||||
split.template_ID(space, "pin_id")
|
||||
split.separator()
|
||||
|
||||
class Cycles_PT_mesh_displacement(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Displacement"
|
||||
bl_context = "data"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.mesh or context.curve or context.meta_ball
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mesh = context.mesh
|
||||
curve = context.curve
|
||||
mball = context.meta_ball
|
||||
|
||||
if mesh:
|
||||
cycles = mesh.cycles
|
||||
elif curve:
|
||||
cycles = curve.cycles
|
||||
elif mball:
|
||||
cycles = mball.cycles
|
||||
|
||||
layout.prop(cycles, "displacement_method", text="Method")
|
||||
layout.prop(cycles, "use_subdivision");
|
||||
layout.prop(cycles, "dicing_rate");
|
||||
|
||||
def find_node(material, nodetype):
|
||||
if material and material.node_tree:
|
||||
ntree = material.node_tree
|
||||
|
||||
for node in ntree.nodes:
|
||||
if type(node) is not bpy.types.NodeGroup and node.type == nodetype:
|
||||
return node
|
||||
|
||||
return None
|
||||
|
||||
def find_node_input(node, name):
|
||||
for input in node.inputs:
|
||||
if input.name == name:
|
||||
return input
|
||||
|
||||
return None
|
||||
|
||||
def panel_node_draw(layout, id, output_type, input_name):
|
||||
if not id.node_tree:
|
||||
layout.prop(id, "use_nodes")
|
||||
return
|
||||
|
||||
ntree = id.node_tree
|
||||
|
||||
node = find_node(id, output_type)
|
||||
if not node:
|
||||
layout.label(text="No output node.")
|
||||
|
||||
input = find_node_input(node, input_name)
|
||||
layout.template_node_view(id, ntree, node, input);
|
||||
|
||||
class CyclesLamp_PT_lamp(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Surface"
|
||||
bl_context = "data"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.lamp and CyclesButtonsPanel.poll(context)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.lamp
|
||||
panel_node_draw(layout, mat, 'OUTPUT_LAMP', 'Surface')
|
||||
|
||||
class CyclesWorld_PT_surface(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Surface"
|
||||
bl_context = "world"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.world and CyclesButtonsPanel.poll(context)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.world
|
||||
panel_node_draw(layout, mat, 'OUTPUT_WORLD', 'Surface')
|
||||
|
||||
class CyclesWorld_PT_volume(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Volume"
|
||||
bl_context = "world"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.world and CyclesButtonsPanel.poll(context)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.active = False
|
||||
|
||||
mat = context.world
|
||||
panel_node_draw(layout, mat, 'OUTPUT_WORLD', 'Volume')
|
||||
|
||||
class CyclesMaterial_PT_surface(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Surface"
|
||||
bl_context = "material"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.material and CyclesButtonsPanel.poll(context)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material
|
||||
panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface')
|
||||
|
||||
class CyclesMaterial_PT_volume(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Volume"
|
||||
bl_context = "material"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.material and CyclesButtonsPanel.poll(context)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.active = False
|
||||
|
||||
mat = context.material
|
||||
panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
|
||||
|
||||
class CyclesMaterial_PT_displacement(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Displacement"
|
||||
bl_context = "material"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.material and CyclesButtonsPanel.poll(context)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material
|
||||
panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
|
||||
|
||||
class CyclesMaterial_PT_settings(CyclesButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Settings"
|
||||
bl_context = "material"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
# return context.material and CyclesButtonsPanel.poll(context)
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material
|
||||
|
||||
row = layout.row()
|
||||
row.label(text="Light Group:")
|
||||
row.prop(mat, "light_group", text="")
|
||||
|
||||
def draw_device(self, context):
|
||||
scene = context.scene
|
||||
layout = self.layout
|
||||
|
||||
if scene.render.engine == "CYCLES":
|
||||
cycles = scene.cycles
|
||||
|
||||
if 'cuda' in engine.available_devices():
|
||||
layout.prop(cycles, "device")
|
||||
if cycles.device == 'CPU' and engine.with_osl():
|
||||
layout.prop(cycles, "shading_system")
|
||||
|
||||
def get_panels():
|
||||
return [
|
||||
bpy.types.RENDER_PT_render,
|
||||
bpy.types.RENDER_PT_output,
|
||||
bpy.types.RENDER_PT_encoding,
|
||||
bpy.types.RENDER_PT_dimensions,
|
||||
bpy.types.RENDER_PT_stamp,
|
||||
bpy.types.WORLD_PT_context_world,
|
||||
bpy.types.DATA_PT_context_mesh,
|
||||
bpy.types.DATA_PT_vertex_groups,
|
||||
bpy.types.DATA_PT_shape_keys,
|
||||
bpy.types.DATA_PT_uv_texture,
|
||||
bpy.types.DATA_PT_vertex_colors,
|
||||
bpy.types.DATA_PT_custom_props_mesh,
|
||||
bpy.types.DATA_PT_context_camera,
|
||||
bpy.types.DATA_PT_camera,
|
||||
bpy.types.DATA_PT_camera_display,
|
||||
bpy.types.DATA_PT_custom_props_camera,
|
||||
bpy.types.DATA_PT_context_lamp,
|
||||
bpy.types.DATA_PT_custom_props_lamp,
|
||||
bpy.types.TEXTURE_PT_context_texture]
|
||||
|
||||
def register():
|
||||
bpy.types.RENDER_PT_render.append(draw_device)
|
||||
|
||||
for panel in get_panels():
|
||||
panel.COMPAT_ENGINES.add('CYCLES')
|
||||
|
||||
def unregister():
|
||||
bpy.types.RENDER_PT_render.remove(draw_device)
|
||||
|
||||
for panel in get_panels():
|
||||
panel.COMPAT_ENGINES.remove('CYCLES')
|
||||
|
99
intern/cycles/blender/addon/xml.py
Normal file
99
intern/cycles/blender/addon/xml.py
Normal file
@ -0,0 +1,99 @@
|
||||
#
|
||||
# Copyright 2011, Blender Foundation.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
# XML exporter for generating test files, not intended for end users
|
||||
|
||||
import os
|
||||
import bpy
|
||||
import io_utils
|
||||
import xml.etree.ElementTree as etree
|
||||
import xml.dom.minidom as dom
|
||||
|
||||
def strip(root):
|
||||
root.text = None
|
||||
root.tail = None
|
||||
|
||||
for elem in root:
|
||||
strip(elem)
|
||||
|
||||
def write(node, fname):
|
||||
strip(node)
|
||||
|
||||
s = etree.tostring(node)
|
||||
s = dom.parseString(s).toprettyxml()
|
||||
|
||||
f = open(fname, "w")
|
||||
f.write(s)
|
||||
|
||||
class ExportCyclesXML(bpy.types.Operator, io_utils.ExportHelper):
|
||||
''''''
|
||||
bl_idname = "export_mesh.cycles_xml"
|
||||
bl_label = "Export Cycles XML"
|
||||
|
||||
filename_ext = ".xml"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_object != None
|
||||
|
||||
def execute(self, context):
|
||||
filepath = bpy.path.ensure_ext(self.filepath, ".xml")
|
||||
|
||||
# get mesh
|
||||
scene = context.scene
|
||||
object = context.object
|
||||
|
||||
if not object:
|
||||
raise Exception("No active object")
|
||||
|
||||
mesh = object.create_mesh(scene, True, 'PREVIEW')
|
||||
|
||||
if not mesh:
|
||||
raise Exception("No mesh data in active object")
|
||||
|
||||
# generate mesh node
|
||||
nverts = ""
|
||||
verts = ""
|
||||
P = ""
|
||||
|
||||
for v in mesh.vertices:
|
||||
P += "%f %f %f " % (v.co[0], v.co[1], v.co[2])
|
||||
|
||||
for i, f in enumerate(mesh.faces):
|
||||
nverts += str(len(f.vertices)) + " "
|
||||
|
||||
for v in f.vertices:
|
||||
verts += str(v) + " "
|
||||
verts += " "
|
||||
|
||||
node = etree.Element('mesh', attrib={'nverts': nverts, 'verts': verts, 'P': P})
|
||||
|
||||
# write to file
|
||||
write(node, filepath)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def register():
|
||||
pass
|
||||
|
||||
def unregister():
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
249
intern/cycles/blender/blender_camera.cpp
Normal file
249
intern/cycles/blender/blender_camera.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "camera.h"
|
||||
#include "scene.h"
|
||||
|
||||
#include "blender_sync.h"
|
||||
#include "blender_util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Blender Camera Intermediate: we first convert both the offline and 3d view
|
||||
* render camera to this, and from there convert to our native camera format. */
|
||||
|
||||
struct BlenderCamera {
|
||||
float nearclip;
|
||||
float farclip;
|
||||
|
||||
bool ortho;
|
||||
float ortho_scale;
|
||||
|
||||
float lens;
|
||||
float lensradius;
|
||||
float focaldistance;
|
||||
|
||||
float2 shift;
|
||||
float2 offset;
|
||||
float zoom;
|
||||
|
||||
float2 pixelaspect;
|
||||
|
||||
Transform matrix;
|
||||
};
|
||||
|
||||
static void blender_camera_init(BlenderCamera *bcam)
|
||||
{
|
||||
memset(bcam, 0, sizeof(BlenderCamera));
|
||||
|
||||
bcam->zoom = 1.0f;
|
||||
bcam->pixelaspect = make_float2(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera)
|
||||
{
|
||||
BL::Object b_dof_object = b_camera.dof_object();
|
||||
|
||||
if(!b_dof_object)
|
||||
return b_camera.dof_distance();
|
||||
|
||||
/* for dof object, return distance along camera direction. this is
|
||||
* compatible with blender, but does it fit our dof model? */
|
||||
Transform obmat = get_transform(b_ob.matrix_world());
|
||||
Transform dofmat = get_transform(b_dof_object.matrix_world());
|
||||
|
||||
float3 cam_p = transform_get_column(&obmat, 3);
|
||||
float3 cam_dir = normalize(transform_get_column(&obmat, 2));
|
||||
float3 dof_p = transform_get_column(&dofmat, 3);
|
||||
float3 proj_p = dot(dof_p, cam_dir) * cam_dir;
|
||||
|
||||
return len(proj_p - cam_p);
|
||||
}
|
||||
|
||||
static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob)
|
||||
{
|
||||
BL::ID b_ob_data = b_ob.data();
|
||||
|
||||
if(b_ob_data.is_a(&RNA_Camera)) {
|
||||
BL::Camera b_camera(b_ob_data);
|
||||
PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
|
||||
|
||||
bcam->nearclip = b_camera.clip_start();
|
||||
bcam->farclip = b_camera.clip_end();
|
||||
|
||||
bcam->ortho = (b_camera.type() == BL::Camera::type_ORTHO);
|
||||
bcam->ortho_scale = b_camera.ortho_scale();
|
||||
|
||||
bcam->lens = b_camera.lens();
|
||||
bcam->lensradius = RNA_float_get(&ccamera, "lens_radius");
|
||||
bcam->focaldistance = blender_camera_focal_distance(b_ob, b_camera);
|
||||
|
||||
bcam->shift.x = b_camera.shift_x();
|
||||
bcam->shift.y = b_camera.shift_y();
|
||||
}
|
||||
else {
|
||||
/* from lamp not implemented yet */
|
||||
}
|
||||
}
|
||||
|
||||
static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height)
|
||||
{
|
||||
/* copy camera to compare later */
|
||||
Camera prevcam = *cam;
|
||||
|
||||
/* dimensions */
|
||||
float xratio = width*bcam->pixelaspect.x;
|
||||
float yratio = height*bcam->pixelaspect.y;
|
||||
|
||||
/* compute x/y aspect and ratio */
|
||||
float aspectratio, xaspect, yaspect;
|
||||
|
||||
if(xratio > yratio) {
|
||||
aspectratio= xratio/yratio;
|
||||
xaspect= aspectratio;
|
||||
yaspect= 1.0f;
|
||||
}
|
||||
else {
|
||||
aspectratio= yratio/xratio;
|
||||
xaspect= 1.0f;
|
||||
yaspect= aspectratio;
|
||||
}
|
||||
|
||||
/* modify aspect for orthographic scale */
|
||||
if(bcam->ortho) {
|
||||
xaspect = xaspect*bcam->ortho_scale/(aspectratio*2.0f);
|
||||
yaspect = yaspect*bcam->ortho_scale/(aspectratio*2.0f);
|
||||
aspectratio = bcam->ortho_scale/2.0f;
|
||||
}
|
||||
|
||||
/* set viewplane */
|
||||
cam->left = -xaspect;
|
||||
cam->right = xaspect;
|
||||
cam->bottom = -yaspect;
|
||||
cam->top = yaspect;
|
||||
|
||||
/* zoom for 3d camera view */
|
||||
cam->left *= bcam->zoom;
|
||||
cam->right *= bcam->zoom;
|
||||
cam->bottom *= bcam->zoom;
|
||||
cam->top *= bcam->zoom;
|
||||
|
||||
/* modify viewplane with camera shift and 3d camera view offset */
|
||||
float dx = 2.0f*(aspectratio*bcam->shift.x + bcam->offset.x*xaspect*2.0f);
|
||||
float dy = 2.0f*(aspectratio*bcam->shift.y + bcam->offset.y*yaspect*2.0f);
|
||||
|
||||
cam->left += dx;
|
||||
cam->right += dx;
|
||||
cam->bottom += dy;
|
||||
cam->top += dy;
|
||||
|
||||
/* clipping distances */
|
||||
cam->nearclip = bcam->nearclip;
|
||||
cam->farclip = bcam->farclip;
|
||||
|
||||
/* orthographic */
|
||||
cam->ortho = bcam->ortho;
|
||||
|
||||
/* perspective */
|
||||
cam->fov = 2.0f*atan(16.0f/bcam->lens/aspectratio);
|
||||
cam->focaldistance = bcam->focaldistance;
|
||||
cam->lensradius = bcam->lensradius;
|
||||
|
||||
/* transform, note the blender camera points along the negative z-axis */
|
||||
cam->matrix = bcam->matrix * transform_scale(1.0f, 1.0f, -1.0f);
|
||||
|
||||
/* set update flag */
|
||||
if(cam->modified(prevcam))
|
||||
cam->tag_update();
|
||||
}
|
||||
|
||||
/* Sync Render Camera */
|
||||
|
||||
void BlenderSync::sync_camera(int width, int height)
|
||||
{
|
||||
BlenderCamera bcam;
|
||||
blender_camera_init(&bcam);
|
||||
|
||||
/* pixel aspect */
|
||||
BL::RenderSettings r = b_scene.render();
|
||||
|
||||
bcam.pixelaspect.x = r.pixel_aspect_x();
|
||||
bcam.pixelaspect.y = r.pixel_aspect_y();
|
||||
|
||||
/* camera object */
|
||||
BL::Object b_ob = b_scene.camera();
|
||||
|
||||
if(b_ob) {
|
||||
blender_camera_from_object(&bcam, b_ob);
|
||||
bcam.matrix = get_transform(b_ob.matrix_world());
|
||||
}
|
||||
|
||||
/* sync */
|
||||
Camera *cam = scene->camera;
|
||||
blender_camera_sync(cam, &bcam, width, height);
|
||||
}
|
||||
|
||||
/* Sync 3D View Camera */
|
||||
|
||||
void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
|
||||
{
|
||||
BlenderCamera bcam;
|
||||
blender_camera_init(&bcam);
|
||||
|
||||
/* 3d view parameters */
|
||||
bcam.nearclip = b_v3d.clip_start();
|
||||
bcam.farclip = b_v3d.clip_end();
|
||||
bcam.lens = b_v3d.lens();
|
||||
|
||||
if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
|
||||
/* camera view */
|
||||
BL::Object b_ob = b_scene.camera();
|
||||
|
||||
if(b_ob) {
|
||||
blender_camera_from_object(&bcam, b_ob);
|
||||
|
||||
/* magic zoom formula */
|
||||
bcam.zoom = b_rv3d.view_camera_zoom();
|
||||
bcam.zoom = (1.41421f + bcam.zoom/50.0f);
|
||||
bcam.zoom *= bcam.zoom;
|
||||
bcam.zoom = 2.0f/bcam.zoom;
|
||||
|
||||
/* offset */
|
||||
bcam.offset = get_float2(b_rv3d.view_camera_offset());
|
||||
}
|
||||
}
|
||||
else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
|
||||
/* orthographic view */
|
||||
bcam.farclip *= 0.5;
|
||||
bcam.nearclip = -bcam.farclip;
|
||||
|
||||
bcam.ortho = true;
|
||||
bcam.ortho_scale = b_rv3d.view_distance();
|
||||
}
|
||||
|
||||
bcam.zoom *= 2.0f;
|
||||
|
||||
/* 3d view transform */
|
||||
bcam.matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
|
||||
|
||||
/* sync */
|
||||
blender_camera_sync(scene->camera, &bcam, width, height);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
300
intern/cycles/blender/blender_mesh.cpp
Normal file
300
intern/cycles/blender/blender_mesh.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "mesh.h"
|
||||
#include "object.h"
|
||||
#include "scene.h"
|
||||
|
||||
#include "blender_sync.h"
|
||||
#include "blender_util.h"
|
||||
|
||||
#include "subd_mesh.h"
|
||||
#include "subd_patch.h"
|
||||
#include "subd_split.h"
|
||||
|
||||
#include "util_foreach.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Find/Add */
|
||||
|
||||
static bool mesh_need_attribute(Scene *scene, Mesh *mesh, Attribute::Standard std)
|
||||
{
|
||||
if(std == Attribute::STD_NONE)
|
||||
return false;
|
||||
|
||||
foreach(uint shader, mesh->used_shaders)
|
||||
if(scene->shaders[shader]->attributes.find(std))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mesh_need_attribute(Scene *scene, Mesh *mesh, ustring name)
|
||||
{
|
||||
if(name == ustring())
|
||||
return false;
|
||||
|
||||
foreach(uint shader, mesh->used_shaders)
|
||||
if(scene->shaders[shader]->attributes.find(name))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
|
||||
{
|
||||
/* create vertices */
|
||||
BL::Mesh::vertices_iterator v;
|
||||
|
||||
for(v = b_mesh.vertices.begin(); v != b_mesh.vertices.end(); ++v)
|
||||
mesh->verts.push_back(get_float3(v->co()));
|
||||
|
||||
/* create faces */
|
||||
BL::Mesh::faces_iterator f;
|
||||
vector<int> nverts;
|
||||
|
||||
for(f = b_mesh.faces.begin(); f != b_mesh.faces.end(); ++f) {
|
||||
int4 vi = get_int4(f->vertices_raw());
|
||||
int n= (vi[3] == 0)? 3: 4;
|
||||
int shader = used_shaders[f->material_index()];
|
||||
bool smooth = f->use_smooth();
|
||||
|
||||
mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
|
||||
|
||||
if(n == 4)
|
||||
mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);
|
||||
|
||||
nverts.push_back(n);
|
||||
}
|
||||
|
||||
/* create generated coordinates. todo: we should actually get the orco
|
||||
coordinates from modifiers, for now we use texspace loc/size which
|
||||
is available in the api. */
|
||||
if(mesh_need_attribute(scene, mesh, Attribute::STD_GENERATED)) {
|
||||
Attribute *attr = mesh->attributes.add(Attribute::STD_GENERATED);
|
||||
float3 loc = get_float3(b_mesh.texspace_location());
|
||||
float3 size = get_float3(b_mesh.texspace_size());
|
||||
|
||||
if(size.x != 0.0f) size.x = 0.5f/size.x;
|
||||
if(size.y != 0.0f) size.y = 0.5f/size.y;
|
||||
if(size.z != 0.0f) size.z = 0.5f/size.z;
|
||||
|
||||
loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
|
||||
|
||||
float3 *fdata = attr->data_float3();
|
||||
BL::Mesh::vertices_iterator v;
|
||||
size_t i = 0;
|
||||
|
||||
for(v = b_mesh.vertices.begin(); v != b_mesh.vertices.end(); ++v)
|
||||
fdata[i++] = get_float3(v->co())*size - loc;
|
||||
}
|
||||
|
||||
/* create vertex color attributes */
|
||||
{
|
||||
BL::Mesh::vertex_colors_iterator l;
|
||||
|
||||
for(l = b_mesh.vertex_colors.begin(); l != b_mesh.vertex_colors.end(); ++l) {
|
||||
if(!mesh_need_attribute(scene, mesh, ustring(l->name())))
|
||||
continue;
|
||||
|
||||
Attribute *attr = mesh->attributes.add(
|
||||
ustring(l->name()), TypeDesc::TypeColor, Attribute::CORNER);
|
||||
|
||||
BL::MeshColorLayer::data_iterator c;
|
||||
float3 *fdata = attr->data_float3();
|
||||
size_t i = 0;
|
||||
|
||||
for(c = l->data.begin(); c != l->data.end(); ++c, ++i) {
|
||||
fdata[0] = get_float3(c->color1());
|
||||
fdata[1] = get_float3(c->color2());
|
||||
fdata[2] = get_float3(c->color3());
|
||||
fdata += 3;
|
||||
|
||||
if(nverts[i] == 4) {
|
||||
fdata[0] = get_float3(c->color1());
|
||||
fdata[1] = get_float3(c->color3());
|
||||
fdata[2] = get_float3(c->color4());
|
||||
fdata += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* create uv layer attributes */
|
||||
{
|
||||
BL::Mesh::uv_textures_iterator l;
|
||||
|
||||
for(l = b_mesh.uv_textures.begin(); l != b_mesh.uv_textures.end(); ++l) {
|
||||
Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE;
|
||||
ustring name = ustring(l->name());
|
||||
|
||||
if(!(mesh_need_attribute(scene, mesh, name) || mesh_need_attribute(scene, mesh, std)))
|
||||
continue;
|
||||
|
||||
Attribute *attr;
|
||||
|
||||
if(l->active_render())
|
||||
attr = mesh->attributes.add(std, name);
|
||||
else
|
||||
attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER);
|
||||
|
||||
BL::MeshTextureFaceLayer::data_iterator t;
|
||||
float3 *fdata = attr->data_float3();
|
||||
size_t i = 0;
|
||||
|
||||
for(t = l->data.begin(); t != l->data.end(); ++t, ++i) {
|
||||
fdata[0] = get_float3(t->uv1());
|
||||
fdata[1] = get_float3(t->uv2());
|
||||
fdata[2] = get_float3(t->uv3());
|
||||
fdata += 3;
|
||||
|
||||
if(nverts[i] == 4) {
|
||||
fdata[0] = get_float3(t->uv1());
|
||||
fdata[1] = get_float3(t->uv3());
|
||||
fdata[2] = get_float3(t->uv4());
|
||||
fdata += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
|
||||
{
|
||||
/* create subd mesh */
|
||||
SubdMesh sdmesh;
|
||||
|
||||
/* create vertices */
|
||||
BL::Mesh::vertices_iterator v;
|
||||
|
||||
for(v = b_mesh.vertices.begin(); v != b_mesh.vertices.end(); ++v)
|
||||
sdmesh.add_vert(get_float3(v->co()));
|
||||
|
||||
/* create faces */
|
||||
BL::Mesh::faces_iterator f;
|
||||
|
||||
for(f = b_mesh.faces.begin(); f != b_mesh.faces.end(); ++f) {
|
||||
int4 vi = get_int4(f->vertices_raw());
|
||||
int n= (vi[3] == 0)? 3: 4;
|
||||
//int shader = used_shaders[f->material_index()];
|
||||
|
||||
if(n == 4)
|
||||
sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]);
|
||||
/*else
|
||||
sdmesh.add_face(vi[0], vi[1], vi[2]);*/
|
||||
}
|
||||
|
||||
/* finalize subd mesh */
|
||||
sdmesh.link_boundary();
|
||||
|
||||
/* subdivide */
|
||||
DiagSplit dsplit;
|
||||
dsplit.camera = NULL;
|
||||
dsplit.dicing_rate = RNA_float_get(cmesh, "dicing_rate");
|
||||
|
||||
sdmesh.tesselate(&dsplit, false, mesh, used_shaders[0], true);
|
||||
}
|
||||
|
||||
/* Sync */
|
||||
|
||||
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
|
||||
{
|
||||
/* test if we can instance or if the object is modified */
|
||||
BL::ID b_ob_data = b_ob.data();
|
||||
BL::ID key = (object_is_modified(b_ob))? b_ob: b_ob_data;
|
||||
|
||||
/* find shader indices */
|
||||
vector<uint> used_shaders;
|
||||
|
||||
BL::Object::material_slots_iterator slot;
|
||||
for(slot = b_ob.material_slots.begin(); slot != b_ob.material_slots.end(); ++slot)
|
||||
find_shader(slot->material(), used_shaders);
|
||||
|
||||
if(used_shaders.size() == 0)
|
||||
used_shaders.push_back(scene->default_surface);
|
||||
|
||||
/* test if we need to sync */
|
||||
Mesh *mesh;
|
||||
|
||||
if(!mesh_map.sync(&mesh, key)) {
|
||||
/* if transform was applied to mesh, need full update */
|
||||
if(object_updated && mesh->transform_applied);
|
||||
/* test if shaders changed, these can be object level so mesh
|
||||
does not get tagged for recalc */
|
||||
else if(mesh->used_shaders != used_shaders);
|
||||
else {
|
||||
/* even if not tagged for recalc, we may need to sync anyway
|
||||
* because the shader needs different mesh attributes */
|
||||
bool attribute_recalc = false;
|
||||
|
||||
foreach(uint shader, mesh->used_shaders)
|
||||
if(scene->shaders[shader]->need_update_attributes)
|
||||
attribute_recalc = true;
|
||||
|
||||
if(!attribute_recalc)
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
|
||||
/* create derived mesh */
|
||||
BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
|
||||
/* todo: this will crash on non-mesh types! */
|
||||
PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
|
||||
|
||||
vector<Mesh::Triangle> oldtriangle = mesh->triangles;
|
||||
|
||||
mesh->clear();
|
||||
mesh->used_shaders = used_shaders;
|
||||
mesh->name = ustring(b_ob_data.name());
|
||||
|
||||
if(cmesh.data && RNA_boolean_get(&cmesh, "use_subdivision"))
|
||||
create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
|
||||
else
|
||||
create_mesh(scene, mesh, b_mesh, used_shaders);
|
||||
|
||||
/* free derived mesh */
|
||||
object_remove_mesh(b_data, b_mesh);
|
||||
|
||||
/* displacement method */
|
||||
if(cmesh.data) {
|
||||
int method = RNA_enum_get(&cmesh, "displacement_method");
|
||||
|
||||
if(method == 0)
|
||||
mesh->displacement_method = Mesh::DISPLACE_BUMP;
|
||||
else if(method == 1)
|
||||
mesh->displacement_method = Mesh::DISPLACE_TRUE;
|
||||
else
|
||||
mesh->displacement_method = Mesh::DISPLACE_BOTH;
|
||||
}
|
||||
|
||||
/* tag update */
|
||||
bool rebuild = false;
|
||||
|
||||
if(oldtriangle.size() != mesh->triangles.size())
|
||||
rebuild = true;
|
||||
else if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
|
||||
rebuild = true;
|
||||
|
||||
mesh->tag_update(scene, rebuild);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
183
intern/cycles/blender/blender_object.cpp
Normal file
183
intern/cycles/blender/blender_object.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "light.h"
|
||||
#include "mesh.h"
|
||||
#include "object.h"
|
||||
#include "scene.h"
|
||||
|
||||
#include "blender_sync.h"
|
||||
#include "blender_util.h"
|
||||
|
||||
#include "util_foreach.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Utilities */
|
||||
|
||||
bool BlenderSync::object_is_modified(BL::Object b_ob)
|
||||
{
|
||||
/* test if we can instance or if the object is modified */
|
||||
if(ccl::object_is_modified(b_ob, b_scene, preview)) {
|
||||
/* modifiers */
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
/* object level material links */
|
||||
BL::Object::material_slots_iterator slot;
|
||||
for(slot = b_ob.material_slots.begin(); slot != b_ob.material_slots.end(); ++slot)
|
||||
if(slot->link() == BL::MaterialSlot::link_OBJECT)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BlenderSync::object_is_mesh(BL::Object b_ob)
|
||||
{
|
||||
BL::ID b_ob_data = b_ob.data();
|
||||
|
||||
return (b_ob_data && (b_ob_data.is_a(&RNA_Mesh) ||
|
||||
b_ob_data.is_a(&RNA_Curve) || b_ob_data.is_a(&RNA_MetaBall)));
|
||||
}
|
||||
|
||||
bool BlenderSync::object_is_light(BL::Object b_ob)
|
||||
{
|
||||
BL::ID b_ob_data = b_ob.data();
|
||||
|
||||
return (b_ob_data && b_ob_data.is_a(&RNA_Lamp));
|
||||
}
|
||||
|
||||
/* Light */
|
||||
|
||||
void BlenderSync::sync_light(BL::Object b_ob, Transform& tfm)
|
||||
{
|
||||
/* test if we need to sync */
|
||||
Light *light;
|
||||
|
||||
/* todo: account for instancing */
|
||||
if(!light_map.sync(&light, b_ob))
|
||||
return;
|
||||
|
||||
/* location */
|
||||
light->co = make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
|
||||
|
||||
/* shader */
|
||||
BL::Lamp b_lamp(b_ob.data());
|
||||
vector<uint> used_shaders;
|
||||
|
||||
find_shader(b_lamp, used_shaders);
|
||||
|
||||
if(used_shaders.size() == 0)
|
||||
used_shaders.push_back(scene->default_light);
|
||||
|
||||
light->shader = used_shaders[0];
|
||||
|
||||
/* tag */
|
||||
light->tag_update(scene);
|
||||
}
|
||||
|
||||
/* Object */
|
||||
|
||||
void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm)
|
||||
{
|
||||
/* light is handled separately */
|
||||
if(object_is_light(b_ob)) {
|
||||
sync_light(b_ob, tfm);
|
||||
return;
|
||||
}
|
||||
|
||||
/* only interested in object that we can create meshes from */
|
||||
if(!object_is_mesh(b_ob))
|
||||
return;
|
||||
|
||||
/* test if we need to sync */
|
||||
ObjectKey key(b_parent, b_index, b_ob);
|
||||
Object *object;
|
||||
bool object_updated = false;
|
||||
|
||||
/* object sync */
|
||||
if(object_map.sync(&object, b_ob, key)) {
|
||||
object->name = b_ob.name();
|
||||
object->tfm = tfm;
|
||||
object->tag_update(scene);
|
||||
object_updated = true;
|
||||
}
|
||||
|
||||
/* mesh sync */
|
||||
object->mesh = sync_mesh(b_ob, object_updated);
|
||||
}
|
||||
|
||||
/* Object Loop */
|
||||
|
||||
void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
|
||||
{
|
||||
/* layer data */
|
||||
uint layer;
|
||||
|
||||
if(b_v3d)
|
||||
layer = get_layer(b_v3d.layers());
|
||||
else
|
||||
layer = get_layer(b_scene.layers());
|
||||
|
||||
/* prepare for sync */
|
||||
light_map.pre_sync();
|
||||
mesh_map.pre_sync();
|
||||
object_map.pre_sync();
|
||||
|
||||
/* object loop */
|
||||
BL::Scene::objects_iterator b_ob;
|
||||
|
||||
for(b_ob = b_scene.objects.begin(); b_ob != b_scene.objects.end(); ++b_ob) {
|
||||
bool hide = (b_v3d)? b_ob->hide(): b_ob->hide_render();
|
||||
|
||||
if(!hide && get_layer(b_ob->layers()) & layer) {
|
||||
if(b_ob->is_duplicator()) {
|
||||
/* dupli objects */
|
||||
object_create_duplilist(*b_ob, b_scene);
|
||||
|
||||
BL::Object::dupli_list_iterator b_dup;
|
||||
int b_index = 0;
|
||||
|
||||
for(b_dup = b_ob->dupli_list.begin(); b_dup != b_ob->dupli_list.end(); ++b_dup) {
|
||||
Transform tfm = get_transform(b_dup->matrix());
|
||||
sync_object(*b_ob, b_index, b_dup->object(), tfm);
|
||||
b_index++;
|
||||
}
|
||||
|
||||
object_free_duplilist(*b_ob);
|
||||
}
|
||||
else {
|
||||
/* object itself */
|
||||
Transform tfm = get_transform(b_ob->matrix_world());
|
||||
sync_object(*b_ob, 0, *b_ob, tfm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* handle removed data and modified pointers */
|
||||
if(light_map.post_sync())
|
||||
scene->light_manager->tag_update(scene);
|
||||
if(mesh_map.post_sync())
|
||||
scene->mesh_manager->tag_update(scene);
|
||||
if(object_map.post_sync())
|
||||
scene->object_manager->tag_update(scene);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
230
intern/cycles/blender/blender_python.cpp
Normal file
230
intern/cycles/blender/blender_python.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "blender_sync.h"
|
||||
#include "blender_session.h"
|
||||
|
||||
#include "util_opengl.h"
|
||||
#include "util_path.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
static PyObject *init_func(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *path;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "s", &path))
|
||||
return NULL;
|
||||
|
||||
path_init(path);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *create_func(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t pyengine, pydata, pyscene, pyregion, pyv3d, pyrv3d;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "nnnnnn", &pyengine, &pydata, &pyscene, &pyregion, &pyv3d, &pyrv3d))
|
||||
return NULL;
|
||||
|
||||
/* RNA */
|
||||
PointerRNA engineptr;
|
||||
RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)pyengine, &engineptr);
|
||||
BL::RenderEngine engine(engineptr);
|
||||
|
||||
PointerRNA dataptr;
|
||||
RNA_id_pointer_create((ID*)pydata, &dataptr);
|
||||
BL::BlendData data(dataptr);
|
||||
|
||||
PointerRNA sceneptr;
|
||||
RNA_id_pointer_create((ID*)pyscene, &sceneptr);
|
||||
BL::Scene scene(sceneptr);
|
||||
|
||||
PointerRNA regionptr;
|
||||
RNA_id_pointer_create((ID*)pyregion, ®ionptr);
|
||||
BL::Region region(regionptr);
|
||||
|
||||
PointerRNA v3dptr;
|
||||
RNA_id_pointer_create((ID*)pyv3d, &v3dptr);
|
||||
BL::SpaceView3D v3d(v3dptr);
|
||||
|
||||
PointerRNA rv3dptr;
|
||||
RNA_id_pointer_create((ID*)pyrv3d, &rv3dptr);
|
||||
BL::RegionView3D rv3d(rv3dptr);
|
||||
|
||||
/* create session */
|
||||
BlenderSession *session;
|
||||
|
||||
if(rv3d) {
|
||||
/* interactive session */
|
||||
int width = region.width();
|
||||
int height = region.height();
|
||||
|
||||
session = new BlenderSession(engine, data, scene, v3d, rv3d, width, height);
|
||||
}
|
||||
else {
|
||||
/* offline session */
|
||||
session = new BlenderSession(engine, data, scene);
|
||||
}
|
||||
|
||||
return PyLong_FromVoidPtr(session);
|
||||
}
|
||||
|
||||
static PyObject *free_func(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t pysession;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "n", &pysession))
|
||||
return NULL;
|
||||
|
||||
delete (BlenderSession*)pysession;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *render_func(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t pysession;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "n", &pysession))
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
|
||||
BlenderSession *session = (BlenderSession*)pysession;
|
||||
session->render();
|
||||
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *draw_func(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t pysession, pyv3d, pyrv3d;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "nnn", &pysession, &pyv3d, &pyrv3d))
|
||||
return NULL;
|
||||
|
||||
BlenderSession *session = (BlenderSession*)pysession;
|
||||
|
||||
bool draw_text = false;
|
||||
|
||||
if(pyrv3d) {
|
||||
/* 3d view drawing */
|
||||
int viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
|
||||
draw_text = session->draw(viewport[2], viewport[3]);
|
||||
}
|
||||
else {
|
||||
/* image editor drawing */
|
||||
draw_text = session->draw();
|
||||
}
|
||||
|
||||
/* draw */
|
||||
PyObject *ret = PyTuple_New(2);
|
||||
|
||||
if(!draw_text) {
|
||||
PyTuple_SetItem(ret, 0, PyUnicode_FromString(""));
|
||||
PyTuple_SetItem(ret, 1, PyUnicode_FromString(""));
|
||||
}
|
||||
else {
|
||||
string status, substatus;
|
||||
|
||||
session->get_status(status, substatus);
|
||||
|
||||
PyTuple_SetItem(ret, 0, PyUnicode_FromString(status.c_str()));
|
||||
PyTuple_SetItem(ret, 1, PyUnicode_FromString(substatus.c_str()));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *sync_func(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t pysession;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "n", &pysession))
|
||||
return NULL;
|
||||
|
||||
BlenderSession *session = (BlenderSession*)pysession;
|
||||
session->synchronize();
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *available_devices_func(PyObject *self, PyObject *args)
|
||||
{
|
||||
vector<DeviceType> types = Device::available_types();
|
||||
|
||||
PyObject *ret = PyTuple_New(types.size());
|
||||
|
||||
for(size_t i = 0; i < types.size(); i++) {
|
||||
string name = Device::string_from_type(types[i]);
|
||||
PyTuple_SetItem(ret, i, PyUnicode_FromString(name.c_str()));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *with_osl_func(PyObject *self, PyObject *args)
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
PyObject *ret = Py_True;
|
||||
#else
|
||||
PyObject *ret = Py_False;
|
||||
#endif
|
||||
|
||||
return Py_INCREF(ret), ret;
|
||||
}
|
||||
|
||||
static PyMethodDef methods[] = {
|
||||
{"init", init_func, METH_VARARGS, ""},
|
||||
{"create", create_func, METH_VARARGS, ""},
|
||||
{"free", free_func, METH_VARARGS, ""},
|
||||
{"render", render_func, METH_VARARGS, ""},
|
||||
{"draw", draw_func, METH_VARARGS, ""},
|
||||
{"sync", sync_func, METH_VARARGS, ""},
|
||||
{"available_devices", available_devices_func, METH_NOARGS, ""},
|
||||
{"with_osl", with_osl_func, METH_NOARGS, ""},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static struct PyModuleDef module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"libcycles_blender",
|
||||
"Blender RNA to render exporter",
|
||||
-1,
|
||||
methods
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
PyMODINIT_FUNC PyInit_libcycles_blender()
|
||||
{
|
||||
return PyModule_Create(&ccl::module);
|
||||
}
|
||||
|
280
intern/cycles/blender/blender_session.cpp
Normal file
280
intern/cycles/blender/blender_session.cpp
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "background.h"
|
||||
#include "buffers.h"
|
||||
#include "camera.h"
|
||||
#include "device.h"
|
||||
#include "integrator.h"
|
||||
#include "light.h"
|
||||
#include "scene.h"
|
||||
#include "session.h"
|
||||
#include "shader.h"
|
||||
|
||||
#include "util_color.h"
|
||||
#include "util_foreach.h"
|
||||
#include "util_function.h"
|
||||
#include "util_progress.h"
|
||||
#include "util_time.h"
|
||||
|
||||
#include "blender_sync.h"
|
||||
#include "blender_session.h"
|
||||
#include "blender_util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_)
|
||||
: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL)
|
||||
{
|
||||
/* offline render */
|
||||
BL::RenderSettings r = b_scene.render();
|
||||
|
||||
width = (int)(r.resolution_x()*r.resolution_percentage()*0.01f);
|
||||
height = (int)(r.resolution_y()*r.resolution_percentage()*0.01f);
|
||||
background = true;
|
||||
last_redraw_time = 0.0f;
|
||||
|
||||
create_session();
|
||||
}
|
||||
|
||||
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_,
|
||||
BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_)
|
||||
: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(b_v3d_), b_rv3d(b_rv3d_)
|
||||
{
|
||||
/* 3d view render */
|
||||
width = width_;
|
||||
height = height_;
|
||||
background = false;
|
||||
last_redraw_time = 0.0f;
|
||||
|
||||
create_session();
|
||||
}
|
||||
|
||||
BlenderSession::~BlenderSession()
|
||||
{
|
||||
free_session();
|
||||
}
|
||||
|
||||
void BlenderSession::create_session()
|
||||
{
|
||||
SceneParams scene_params = BlenderSync::get_scene_params(b_scene);
|
||||
SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
|
||||
|
||||
/* create scene */
|
||||
scene = new Scene(scene_params);
|
||||
|
||||
/* create sync */
|
||||
sync = new BlenderSync(b_data, b_scene, scene, !background);
|
||||
sync->sync_data(b_v3d);
|
||||
|
||||
if(b_rv3d)
|
||||
sync->sync_view(b_v3d, b_rv3d, width, height);
|
||||
else
|
||||
sync->sync_camera(width, height);
|
||||
|
||||
/* create session */
|
||||
session = new Session(session_params);
|
||||
session->scene = scene;
|
||||
session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
|
||||
session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
|
||||
|
||||
/* start rendering */
|
||||
session->reset(width, height);
|
||||
session->start();
|
||||
}
|
||||
|
||||
void BlenderSession::free_session()
|
||||
{
|
||||
delete sync;
|
||||
delete session;
|
||||
}
|
||||
|
||||
void BlenderSession::render()
|
||||
{
|
||||
session->wait();
|
||||
|
||||
if(session->progress.get_cancel())
|
||||
return;
|
||||
|
||||
/* write result */
|
||||
write_render_result();
|
||||
}
|
||||
|
||||
void BlenderSession::write_render_result()
|
||||
{
|
||||
/* get result */
|
||||
DisplayBuffer *display = session->display;
|
||||
Device *device = session->device;
|
||||
|
||||
if(!display->rgba.device_pointer)
|
||||
return;
|
||||
|
||||
/* todo: get float buffer */
|
||||
device->pixels_copy_from(display->rgba, 0, width, height);
|
||||
uchar4 *rgba = (uchar4*)display->rgba.data_pointer;
|
||||
|
||||
vector<float4> buffer(width*height);
|
||||
float fac = 1.0f/255.0f;
|
||||
|
||||
/* normalize */
|
||||
for(int i = width*height - 1; i >= 0; i--) {
|
||||
uchar4 f = rgba[i];
|
||||
float r = color_srgb_to_scene_linear(f.x*fac);
|
||||
float g = color_srgb_to_scene_linear(f.y*fac);
|
||||
float b = color_srgb_to_scene_linear(f.z*fac);
|
||||
buffer[i] = make_float4(r, g, b, 1.0f);
|
||||
}
|
||||
|
||||
struct RenderResult *rrp = RE_engine_begin_result((RenderEngine*)b_engine.ptr.data, 0, 0, width, height);
|
||||
PointerRNA rrptr;
|
||||
RNA_pointer_create(NULL, &RNA_RenderResult, rrp, &rrptr);
|
||||
BL::RenderResult rr(rrptr);
|
||||
|
||||
rna_RenderLayer_rect_set(&rr.layers.begin()->ptr, (float*)&buffer[0]);
|
||||
|
||||
RE_engine_end_result((RenderEngine*)b_engine.ptr.data, rrp);
|
||||
}
|
||||
|
||||
void BlenderSession::synchronize()
|
||||
{
|
||||
/* on session/scene parameter changes, we recreate session entirely */
|
||||
SceneParams scene_params = BlenderSync::get_scene_params(b_scene);
|
||||
SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
|
||||
|
||||
if(session->params.modified(session_params) ||
|
||||
scene->params.modified(scene_params)) {
|
||||
free_session();
|
||||
create_session();
|
||||
return;
|
||||
}
|
||||
|
||||
/* copy recalc flags, outside of mutex so we can decide to do the real
|
||||
synchronization at a later time to not block on running updates */
|
||||
sync->sync_recalc();
|
||||
|
||||
/* try to acquire mutex. if we don't want to or can't, come back later */
|
||||
if(!session->ready_to_reset() || !session->scene->mutex.try_lock()) {
|
||||
tag_update();
|
||||
return;
|
||||
}
|
||||
|
||||
/* data and camera synchronize */
|
||||
sync->sync_data(b_v3d);
|
||||
|
||||
if(b_rv3d)
|
||||
sync->sync_view(b_v3d, b_rv3d, width, height);
|
||||
else
|
||||
sync->sync_camera(width, height);
|
||||
|
||||
/* reset if needed */
|
||||
if(scene->need_reset())
|
||||
session->reset(width, height);
|
||||
|
||||
/* unlock */
|
||||
session->scene->mutex.unlock();
|
||||
}
|
||||
|
||||
bool BlenderSession::draw(int w, int h)
|
||||
{
|
||||
/* before drawing, we verify camera and viewport size changes, because
|
||||
we do not get update callbacks for those, we must detect them here */
|
||||
if(session->ready_to_reset()) {
|
||||
bool reset = false;
|
||||
|
||||
/* try to acquire mutex. if we can't, come back later */
|
||||
if(!session->scene->mutex.try_lock()) {
|
||||
tag_update();
|
||||
}
|
||||
else {
|
||||
/* update camera from 3d view */
|
||||
bool need_update = scene->camera->need_update;
|
||||
|
||||
sync->sync_view(b_v3d, b_rv3d, w, h);
|
||||
|
||||
if(scene->camera->need_update && !need_update)
|
||||
reset = true;
|
||||
|
||||
session->scene->mutex.unlock();
|
||||
}
|
||||
|
||||
/* if dimensions changed, reset */
|
||||
if(width != w || height != h) {
|
||||
width = w;
|
||||
height = h;
|
||||
reset = true;
|
||||
}
|
||||
|
||||
/* reset if requested */
|
||||
if(reset)
|
||||
session->reset(width, height);
|
||||
}
|
||||
|
||||
/* draw */
|
||||
return !session->draw(width, height);
|
||||
}
|
||||
|
||||
bool BlenderSession::draw()
|
||||
{
|
||||
return !session->draw(width, height);
|
||||
}
|
||||
|
||||
void BlenderSession::get_status(string& status, string& substatus)
|
||||
{
|
||||
session->progress.get_status(status, substatus);
|
||||
}
|
||||
|
||||
void BlenderSession::tag_update()
|
||||
{
|
||||
/* tell blender that we want to get another update callback */
|
||||
engine_tag_update((RenderEngine*)b_engine.ptr.data);
|
||||
}
|
||||
|
||||
void BlenderSession::tag_redraw()
|
||||
{
|
||||
if(background) {
|
||||
/* offline render, set stats and redraw if timeout passed */
|
||||
string status, substatus;
|
||||
get_status(status, substatus);
|
||||
|
||||
if(substatus.size() > 0)
|
||||
status += " | " + substatus;
|
||||
|
||||
RE_engine_update_stats((RenderEngine*)b_engine.ptr.data, "", status.c_str());
|
||||
|
||||
if(time_dt() - last_redraw_time > 1.0f) {
|
||||
write_render_result();
|
||||
engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
|
||||
last_redraw_time = time_dt();
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* tell blender that we want to redraw */
|
||||
engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
|
||||
}
|
||||
}
|
||||
|
||||
void BlenderSession::test_cancel()
|
||||
{
|
||||
/* test if we need to cancel rendering */
|
||||
if(background)
|
||||
if(RE_engine_test_break((RenderEngine*)b_engine.ptr.data))
|
||||
session->progress.set_cancel("Cancelled");
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
77
intern/cycles/blender/blender_session.h
Normal file
77
intern/cycles/blender/blender_session.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __BLENDER_SESSION_H__
|
||||
#define __BLENDER_SESSION_H__
|
||||
|
||||
#include "device.h"
|
||||
#include "scene.h"
|
||||
#include "session.h"
|
||||
|
||||
#include "util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Scene;
|
||||
class Session;
|
||||
|
||||
class BlenderSession {
|
||||
public:
|
||||
BlenderSession(BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene);
|
||||
BlenderSession(BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene,
|
||||
BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
|
||||
|
||||
~BlenderSession();
|
||||
|
||||
/* session */
|
||||
void create_session();
|
||||
void free_session();
|
||||
|
||||
/* offline render */
|
||||
void render();
|
||||
void write_render_result();
|
||||
|
||||
/* interactive updates */
|
||||
void synchronize();
|
||||
|
||||
/* drawing */
|
||||
bool draw();
|
||||
bool draw(int w, int h);
|
||||
void tag_redraw();
|
||||
void tag_update();
|
||||
void get_status(string& status, string& substatus);
|
||||
void test_cancel();
|
||||
|
||||
bool background;
|
||||
Session *session;
|
||||
Scene *scene;
|
||||
BlenderSync *sync;
|
||||
double last_redraw_time;
|
||||
|
||||
BL::RenderEngine b_engine;
|
||||
BL::BlendData b_data;
|
||||
BL::Scene b_scene;
|
||||
BL::SpaceView3D b_v3d;
|
||||
BL::RegionView3D b_rv3d;
|
||||
|
||||
int width, height;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __BLENDER_SESSION_H__ */
|
629
intern/cycles/blender/blender_shader.cpp
Normal file
629
intern/cycles/blender/blender_shader.cpp
Normal file
@ -0,0 +1,629 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "background.h"
|
||||
#include "graph.h"
|
||||
#include "light.h"
|
||||
#include "nodes.h"
|
||||
#include "scene.h"
|
||||
#include "shader.h"
|
||||
|
||||
#include "blender_sync.h"
|
||||
#include "blender_util.h"
|
||||
|
||||
#include "util_debug.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
typedef map<void*, ShaderNode*> PtrNodeMap;
|
||||
typedef pair<ShaderNode*, std::string> SocketPair;
|
||||
typedef map<void*, SocketPair> PtrSockMap;
|
||||
|
||||
/* Find */
|
||||
|
||||
void BlenderSync::find_shader(BL::ID id, vector<uint>& used_shaders)
|
||||
{
|
||||
Shader *shader = shader_map.find(id);
|
||||
|
||||
for(size_t i = 0; i < scene->shaders.size(); i++) {
|
||||
if(scene->shaders[i] == shader) {
|
||||
used_shaders.push_back(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Graph */
|
||||
|
||||
static BL::NodeSocket get_node_input(BL::Node *b_group_node, BL::Node b_node, const string& name)
|
||||
{
|
||||
BL::Node::inputs_iterator b_in;
|
||||
|
||||
for(b_in = b_node.inputs.begin(); b_in != b_node.inputs.end(); ++b_in) {
|
||||
if(b_in->name() == name) {
|
||||
if(b_group_node) {
|
||||
|
||||
BL::NodeTree b_ntree = BL::NodeGroup(*b_group_node).node_tree();
|
||||
BL::NodeTree::links_iterator b_link;
|
||||
|
||||
for(b_link = b_ntree.links.begin(); b_link != b_ntree.links.end(); ++b_link) {
|
||||
if(b_link->to_socket().ptr.data == b_in->ptr.data) {
|
||||
BL::Node::inputs_iterator b_gin;
|
||||
|
||||
for(b_gin = b_group_node->inputs.begin(); b_gin != b_group_node->inputs.end(); ++b_gin)
|
||||
if(b_gin->group_socket().ptr.data == b_link->from_socket().ptr.data)
|
||||
return *b_gin;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return *b_in;
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
|
||||
return *b_in;
|
||||
}
|
||||
|
||||
static BL::NodeSocket get_node_output(BL::Node b_node, const string& name)
|
||||
{
|
||||
BL::Node::outputs_iterator b_out;
|
||||
|
||||
for(b_out = b_node.outputs.begin(); b_out != b_node.outputs.end(); ++b_out)
|
||||
if(b_out->name() == name)
|
||||
return *b_out;
|
||||
|
||||
assert(0);
|
||||
|
||||
return *b_out;
|
||||
}
|
||||
|
||||
static float3 get_node_output_rgba(BL::Node b_node, const string& name)
|
||||
{
|
||||
BL::RGBANodeSocket sock(get_node_output(b_node, name));
|
||||
return get_float3(sock.default_value());
|
||||
}
|
||||
|
||||
static float get_node_output_value(BL::Node b_node, const string& name)
|
||||
{
|
||||
BL::ValueNodeSocket sock(get_node_output(b_node, name));
|
||||
return sock.default_value()[0];
|
||||
}
|
||||
|
||||
static ShaderNode *add_node(BL::BlendData b_data, ShaderGraph *graph, BL::Node *b_group_node, BL::ShaderNode b_node)
|
||||
{
|
||||
ShaderNode *node = NULL;
|
||||
|
||||
switch(b_node.type()) {
|
||||
/* not supported */
|
||||
case BL::ShaderNode::type_CAMERA: break;
|
||||
case BL::ShaderNode::type_COMBRGB: break;
|
||||
case BL::ShaderNode::type_CURVE_RGB: break;
|
||||
case BL::ShaderNode::type_CURVE_VEC: break;
|
||||
case BL::ShaderNode::type_GEOM: break;
|
||||
case BL::ShaderNode::type_HUE_SAT: break;
|
||||
case BL::ShaderNode::type_INVERT: break;
|
||||
case BL::ShaderNode::type_MATERIAL: break;
|
||||
case BL::ShaderNode::type_MATERIAL_EXT: break;
|
||||
case BL::ShaderNode::type_NORMAL: break;
|
||||
case BL::ShaderNode::type_OUTPUT: break;
|
||||
case BL::ShaderNode::type_SCRIPT: break;
|
||||
case BL::ShaderNode::type_SEPRGB: break;
|
||||
case BL::ShaderNode::type_SQUEEZE: break;
|
||||
case BL::ShaderNode::type_TEXTURE: break;
|
||||
case BL::ShaderNode::type_VALTORGB: break;
|
||||
/* handled outside this function */
|
||||
case BL::ShaderNode::type_GROUP: break;
|
||||
/* existing blender nodes */
|
||||
case BL::ShaderNode::type_RGB: {
|
||||
ColorNode *color = new ColorNode();
|
||||
color->value = get_node_output_rgba(b_node, "Color");
|
||||
node = color;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_VALUE: {
|
||||
ValueNode *value = new ValueNode();
|
||||
value->value = get_node_output_value(b_node, "Value");
|
||||
node = value;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_MIX_RGB: {
|
||||
BL::ShaderNodeMixRGB b_mix_node(b_node);
|
||||
MixNode *mix = new MixNode();
|
||||
mix->type = MixNode::type_enum[b_mix_node.blend_type()];
|
||||
node = mix;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_RGBTOBW: {
|
||||
node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_MATH: {
|
||||
BL::ShaderNodeMath b_math_node(b_node);
|
||||
MathNode *math = new MathNode();
|
||||
math->type = MathNode::type_enum[b_math_node.operation()];
|
||||
node = math;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_VECT_MATH: {
|
||||
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
|
||||
VectorMathNode *vmath = new VectorMathNode();
|
||||
vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
|
||||
node = vmath;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_MAPPING: {
|
||||
BL::ShaderNodeMapping b_mapping_node(b_node);
|
||||
MappingNode *mapping = new MappingNode();
|
||||
mapping->translation = get_float3(b_mapping_node.location());
|
||||
mapping->rotation = get_float3(b_mapping_node.rotation());
|
||||
mapping->scale = get_float3(b_mapping_node.scale());
|
||||
node = mapping;
|
||||
break;
|
||||
}
|
||||
|
||||
/* new nodes */
|
||||
case BL::ShaderNode::type_OUTPUT_MATERIAL:
|
||||
case BL::ShaderNode::type_OUTPUT_WORLD:
|
||||
case BL::ShaderNode::type_OUTPUT_LAMP: {
|
||||
node = graph->output();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_FRESNEL: {
|
||||
node = new FresnelNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_ADD_CLOSURE: {
|
||||
node = new AddClosureNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_MIX_CLOSURE: {
|
||||
node = new MixClosureNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_ATTRIBUTE: {
|
||||
AttributeNode *attr = new AttributeNode();
|
||||
attr->attribute = "";
|
||||
node = attr;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_BACKGROUND: {
|
||||
node = new BackgroundNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_BSDF_ANISOTROPIC: {
|
||||
node = new WardBsdfNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_BSDF_DIFFUSE: {
|
||||
node = new DiffuseBsdfNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_BSDF_GLOSSY: {
|
||||
BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
|
||||
GlossyBsdfNode *glossy = new GlossyBsdfNode();
|
||||
|
||||
switch(b_glossy_node.distribution()) {
|
||||
case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
|
||||
glossy->distribution = ustring("Sharp");
|
||||
break;
|
||||
case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
|
||||
glossy->distribution = ustring("Beckmann");
|
||||
break;
|
||||
case BL::ShaderNodeBsdfGlossy::distribution_GGX:
|
||||
glossy->distribution = ustring("GGX");
|
||||
break;
|
||||
}
|
||||
node = glossy;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_BSDF_GLASS: {
|
||||
BL::ShaderNodeBsdfGlass b_glass_node(b_node);
|
||||
GlassBsdfNode *glass = new GlassBsdfNode();
|
||||
switch(b_glass_node.distribution()) {
|
||||
case BL::ShaderNodeBsdfGlass::distribution_SHARP:
|
||||
glass->distribution = ustring("Sharp");
|
||||
break;
|
||||
case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
|
||||
glass->distribution = ustring("Beckmann");
|
||||
break;
|
||||
case BL::ShaderNodeBsdfGlass::distribution_GGX:
|
||||
glass->distribution = ustring("GGX");
|
||||
break;
|
||||
}
|
||||
node = glass;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_BSDF_TRANSLUCENT: {
|
||||
node = new TranslucentBsdfNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_BSDF_TRANSPARENT: {
|
||||
node = new TransparentBsdfNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_BSDF_VELVET: {
|
||||
node = new VelvetBsdfNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_EMISSION: {
|
||||
node = new EmissionNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_GEOMETRY: {
|
||||
node = new GeometryNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_LIGHT_PATH: {
|
||||
node = new LightPathNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_IMAGE: {
|
||||
BL::ShaderNodeTexImage b_image_node(b_node);
|
||||
BL::Image b_image(b_image_node.image());
|
||||
ImageTextureNode *image = new ImageTextureNode();
|
||||
/* todo: handle generated/builtin images */
|
||||
if(b_image)
|
||||
image->filename = blender_absolute_path(b_data, b_image, b_image.filepath());
|
||||
node = image;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_ENVIRONMENT: {
|
||||
BL::ShaderNodeTexEnvironment b_environment_node(b_node);
|
||||
BL::Image b_image(b_environment_node.image());
|
||||
EnvironmentTextureNode *env = new EnvironmentTextureNode();
|
||||
if(b_image)
|
||||
env->filename = blender_absolute_path(b_data, b_image, b_image.filepath());
|
||||
node = env;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_NOISE: {
|
||||
node = new NoiseTextureNode();
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_BLEND: {
|
||||
BL::ShaderNodeTexBlend b_blend_node(b_node);
|
||||
BlendTextureNode *blend = new BlendTextureNode();
|
||||
blend->progression = BlendTextureNode::progression_enum[(int)b_blend_node.progression()];
|
||||
blend->axis = BlendTextureNode::axis_enum[(int)b_blend_node.axis()];
|
||||
node = blend;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_VORONOI: {
|
||||
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
|
||||
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
|
||||
voronoi->distance_metric = VoronoiTextureNode::distance_metric_enum[(int)b_voronoi_node.distance_metric()];
|
||||
voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
|
||||
node = voronoi;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_MAGIC: {
|
||||
BL::ShaderNodeTexMagic b_magic_node(b_node);
|
||||
MagicTextureNode *magic = new MagicTextureNode();
|
||||
magic->depth = b_magic_node.turbulence_depth();
|
||||
node = magic;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_MARBLE: {
|
||||
BL::ShaderNodeTexMarble b_marble_node(b_node);
|
||||
MarbleTextureNode *marble = new MarbleTextureNode();
|
||||
marble->depth = b_marble_node.turbulence_depth();
|
||||
marble->basis = MarbleTextureNode::basis_enum[(int)b_marble_node.noise_basis()];
|
||||
marble->type = MarbleTextureNode::type_enum[(int)b_marble_node.marble_type()];
|
||||
marble->wave = MarbleTextureNode::wave_enum[(int)b_marble_node.wave_type()];
|
||||
marble->hard = b_marble_node.noise_type() == BL::ShaderNodeTexMarble::noise_type_HARD;
|
||||
node = marble;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_CLOUDS: {
|
||||
BL::ShaderNodeTexClouds b_clouds_node(b_node);
|
||||
CloudsTextureNode *clouds = new CloudsTextureNode();
|
||||
clouds->depth = b_clouds_node.turbulence_depth();
|
||||
clouds->basis = CloudsTextureNode::basis_enum[(int)b_clouds_node.noise_basis()];
|
||||
clouds->hard = b_clouds_node.noise_type() == BL::ShaderNodeTexClouds::noise_type_HARD;
|
||||
node = clouds;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_WOOD: {
|
||||
BL::ShaderNodeTexWood b_wood_node(b_node);
|
||||
WoodTextureNode *wood = new WoodTextureNode();
|
||||
wood->type = WoodTextureNode::type_enum[(int)b_wood_node.wood_type()];
|
||||
wood->basis = WoodTextureNode::basis_enum[(int)b_wood_node.noise_basis()];
|
||||
wood->hard = b_wood_node.noise_type() == BL::ShaderNodeTexWood::noise_type_HARD;
|
||||
wood->wave = WoodTextureNode::wave_enum[(int)b_wood_node.wave_type()];
|
||||
node = wood;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_MUSGRAVE: {
|
||||
BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
|
||||
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
|
||||
musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
|
||||
musgrave->basis = MusgraveTextureNode::basis_enum[(int)b_musgrave_node.noise_basis()];
|
||||
node = musgrave;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_STUCCI: {
|
||||
BL::ShaderNodeTexStucci b_stucci_node(b_node);
|
||||
StucciTextureNode *stucci = new StucciTextureNode();
|
||||
stucci->type = StucciTextureNode::type_enum[(int)b_stucci_node.stucci_type()];
|
||||
stucci->basis = StucciTextureNode::basis_enum[(int)b_stucci_node.noise_basis()];
|
||||
stucci->hard = b_stucci_node.noise_type() == BL::ShaderNodeTexStucci::noise_type_HARD;
|
||||
node = stucci;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_DISTORTED_NOISE: {
|
||||
BL::ShaderNodeTexDistortedNoise b_distnoise_node(b_node);
|
||||
DistortedNoiseTextureNode *distnoise = new DistortedNoiseTextureNode();
|
||||
distnoise->basis = DistortedNoiseTextureNode::basis_enum[(int)b_distnoise_node.noise_basis()];
|
||||
distnoise->distortion_basis = DistortedNoiseTextureNode::basis_enum[(int)b_distnoise_node.noise_distortion()];
|
||||
node = distnoise;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_COORD: {
|
||||
node = new TextureCoordinateNode();;
|
||||
break;
|
||||
}
|
||||
case BL::ShaderNode::type_TEX_SKY: {
|
||||
BL::ShaderNodeTexSky b_sky_node(b_node);
|
||||
SkyTextureNode *sky = new SkyTextureNode();
|
||||
sky->sun_direction = get_float3(b_sky_node.sun_direction());
|
||||
sky->turbidity = b_sky_node.turbidity();
|
||||
node = sky;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(node != graph->output())
|
||||
graph->add(node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void add_nodes(BL::BlendData b_data, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, BL::Node *b_group_node, PtrSockMap& sockets_map)
|
||||
{
|
||||
/* add nodes */
|
||||
BL::ShaderNodeTree::nodes_iterator b_node;
|
||||
PtrNodeMap node_map;
|
||||
map<void*, PtrSockMap> node_groups;
|
||||
|
||||
for(b_node = b_ntree.nodes.begin(); b_node != b_ntree.nodes.end(); ++b_node) {
|
||||
if(b_node->is_a(&RNA_NodeGroup)) {
|
||||
BL::NodeGroup b_gnode(*b_node);
|
||||
BL::ShaderNodeTree b_group_ntree(b_gnode.node_tree());
|
||||
|
||||
node_groups[b_node->ptr.data] = PtrSockMap();
|
||||
add_nodes(b_data, graph, b_group_ntree, &b_gnode, node_groups[b_node->ptr.data]);
|
||||
}
|
||||
else {
|
||||
ShaderNode *node = add_node(b_data, graph, b_group_node, BL::ShaderNode(*b_node));
|
||||
|
||||
if(node) {
|
||||
BL::Node::inputs_iterator b_input;
|
||||
BL::Node::outputs_iterator b_output;
|
||||
|
||||
node_map[b_node->ptr.data] = node;
|
||||
|
||||
for(b_input = b_node->inputs.begin(); b_input != b_node->inputs.end(); ++b_input) {
|
||||
ShaderInput *input = node->input(b_input->name().c_str());
|
||||
BL::NodeSocket sock(get_node_input(b_group_node, *b_node, b_input->name()));
|
||||
|
||||
assert(input);
|
||||
|
||||
/* copy values for non linked inputs */
|
||||
switch(input->type) {
|
||||
case SHADER_SOCKET_FLOAT: {
|
||||
BL::ValueNodeSocket value_sock(sock);
|
||||
input->set(value_sock.default_value()[0]);
|
||||
break;
|
||||
}
|
||||
case SHADER_SOCKET_COLOR: {
|
||||
BL::RGBANodeSocket rgba_sock(sock);
|
||||
input->set(get_float3(rgba_sock.default_value()));
|
||||
break;
|
||||
}
|
||||
case SHADER_SOCKET_NORMAL:
|
||||
case SHADER_SOCKET_POINT:
|
||||
case SHADER_SOCKET_VECTOR: {
|
||||
BL::VectorNodeSocket vec_sock(sock);
|
||||
input->set(get_float3(vec_sock.default_value()));
|
||||
break;
|
||||
}
|
||||
case SHADER_SOCKET_CLOSURE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* connect nodes */
|
||||
BL::NodeTree::links_iterator b_link;
|
||||
|
||||
for(b_link = b_ntree.links.begin(); b_link != b_ntree.links.end(); ++b_link) {
|
||||
/* get blender link data */
|
||||
BL::Node b_from_node = b_link->from_node();
|
||||
BL::Node b_to_node = b_link->to_node();
|
||||
|
||||
BL::NodeSocket b_from_sock = b_link->from_socket();
|
||||
BL::NodeSocket b_to_sock = b_link->to_socket();
|
||||
|
||||
/* if link with group socket, add to map so we can connect it later */
|
||||
if(b_group_node) {
|
||||
if(!b_from_node) {
|
||||
sockets_map[b_from_sock.ptr.data] =
|
||||
SocketPair(node_map[b_to_node.ptr.data], b_to_sock.name());
|
||||
|
||||
continue;
|
||||
}
|
||||
else if(!b_to_node) {
|
||||
sockets_map[b_to_sock.ptr.data] =
|
||||
SocketPair(node_map[b_from_node.ptr.data], b_from_sock.name());
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ShaderNode *from_node, *to_node;
|
||||
string from_name, to_name;
|
||||
|
||||
/* from sock */
|
||||
if(b_from_node.is_a(&RNA_NodeGroup)) {
|
||||
/* group node */
|
||||
BL::NodeSocket group_sock = b_from_sock.group_socket();
|
||||
SocketPair& pair = node_groups[b_from_node.ptr.data][group_sock.ptr.data];
|
||||
|
||||
from_node = pair.first;
|
||||
from_name = pair.second;
|
||||
}
|
||||
else {
|
||||
/* regular node */
|
||||
from_node = node_map[b_from_node.ptr.data];
|
||||
from_name = b_from_sock.name();
|
||||
}
|
||||
|
||||
/* to sock */
|
||||
if(b_to_node.is_a(&RNA_NodeGroup)) {
|
||||
/* group node */
|
||||
BL::NodeSocket group_sock = b_to_sock.group_socket();
|
||||
SocketPair& pair = node_groups[b_to_node.ptr.data][group_sock.ptr.data];
|
||||
|
||||
to_node = pair.first;
|
||||
to_name = pair.second;
|
||||
}
|
||||
else {
|
||||
/* regular node */
|
||||
to_node = node_map[b_to_node.ptr.data];
|
||||
to_name = b_to_sock.name();
|
||||
}
|
||||
|
||||
graph->connect(from_node->output(from_name.c_str()), to_node->input(to_name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
/* Sync Materials */
|
||||
|
||||
void BlenderSync::sync_materials()
|
||||
{
|
||||
shader_map.set_default(scene->shaders[scene->default_surface]);
|
||||
|
||||
/* material loop */
|
||||
BL::BlendData::materials_iterator b_mat;
|
||||
|
||||
for(b_mat = b_data.materials.begin(); b_mat != b_data.materials.end(); ++b_mat) {
|
||||
Shader *shader;
|
||||
|
||||
/* test if we need to sync */
|
||||
if(shader_map.sync(&shader, *b_mat)) {
|
||||
ShaderGraph *graph = new ShaderGraph();
|
||||
|
||||
/* create nodes */
|
||||
if(b_mat && b_mat->node_tree()) {
|
||||
shader->name = b_mat->name();
|
||||
|
||||
PtrSockMap sock_to_node;
|
||||
BL::ShaderNodeTree b_ntree(b_mat->node_tree());
|
||||
|
||||
add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
|
||||
}
|
||||
|
||||
shader->set_graph(graph);
|
||||
shader->tag_update(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sync World */
|
||||
|
||||
void BlenderSync::sync_world()
|
||||
{
|
||||
Background *background = scene->background;
|
||||
Background prevbackground = *background;
|
||||
|
||||
BL::World b_world = b_scene.world();
|
||||
|
||||
if(world_recalc || b_world.ptr.data != world_map) {
|
||||
Shader *shader = scene->shaders[scene->default_background];
|
||||
ShaderGraph *graph = new ShaderGraph();
|
||||
|
||||
/* create nodes */
|
||||
if(b_world && b_world.node_tree()) {
|
||||
PtrSockMap sock_to_node;
|
||||
BL::ShaderNodeTree b_ntree(b_world.node_tree());
|
||||
|
||||
add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
|
||||
}
|
||||
|
||||
shader->set_graph(graph);
|
||||
shader->tag_update(scene);
|
||||
}
|
||||
|
||||
if(background->modified(prevbackground))
|
||||
background->tag_update(scene);
|
||||
|
||||
world_map = b_world.ptr.data;
|
||||
world_recalc = false;
|
||||
}
|
||||
|
||||
/* Sync Lamps */
|
||||
|
||||
void BlenderSync::sync_lamps()
|
||||
{
|
||||
shader_map.set_default(scene->shaders[scene->default_light]);
|
||||
|
||||
/* lamp loop */
|
||||
BL::BlendData::lamps_iterator b_lamp;
|
||||
|
||||
for(b_lamp = b_data.lamps.begin(); b_lamp != b_data.lamps.end(); ++b_lamp) {
|
||||
Shader *shader;
|
||||
|
||||
/* test if we need to sync */
|
||||
if(shader_map.sync(&shader, *b_lamp)) {
|
||||
ShaderGraph *graph = new ShaderGraph();
|
||||
|
||||
/* create nodes */
|
||||
if(b_lamp && b_lamp->node_tree()) {
|
||||
shader->name = b_lamp->name();
|
||||
|
||||
PtrSockMap sock_to_node;
|
||||
BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
|
||||
|
||||
add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
|
||||
}
|
||||
|
||||
shader->set_graph(graph);
|
||||
shader->tag_update(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlenderSync::sync_shaders()
|
||||
{
|
||||
shader_map.pre_sync();
|
||||
|
||||
sync_world();
|
||||
sync_lamps();
|
||||
sync_materials();
|
||||
|
||||
/* false = don't delete unused shaders, not supported */
|
||||
shader_map.post_sync(false);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
210
intern/cycles/blender/blender_sync.cpp
Normal file
210
intern/cycles/blender/blender_sync.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "background.h"
|
||||
#include "film.h"
|
||||
#include "graph.h"
|
||||
#include "integrator.h"
|
||||
#include "light.h"
|
||||
#include "mesh.h"
|
||||
#include "nodes.h"
|
||||
#include "object.h"
|
||||
#include "scene.h"
|
||||
#include "shader.h"
|
||||
|
||||
#include "device.h"
|
||||
|
||||
#include "blender_sync.h"
|
||||
#include "blender_util.h"
|
||||
|
||||
#include "util_debug.h"
|
||||
#include "util_foreach.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Constructor */
|
||||
|
||||
BlenderSync::BlenderSync(BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_)
|
||||
: b_data(b_data_), b_scene(b_scene_),
|
||||
shader_map(&scene_->shaders),
|
||||
object_map(&scene_->objects),
|
||||
mesh_map(&scene_->meshes),
|
||||
light_map(&scene_->lights),
|
||||
world_map(NULL),
|
||||
world_recalc(false)
|
||||
{
|
||||
scene = scene_;
|
||||
preview = preview_;
|
||||
}
|
||||
|
||||
BlenderSync::~BlenderSync()
|
||||
{
|
||||
}
|
||||
|
||||
/* Sync */
|
||||
|
||||
bool BlenderSync::sync_recalc()
|
||||
{
|
||||
BL::BlendData::materials_iterator b_mat;
|
||||
|
||||
for(b_mat = b_data.materials.begin(); b_mat != b_data.materials.end(); ++b_mat)
|
||||
if(b_mat->recalc())
|
||||
shader_map.set_recalc(*b_mat);
|
||||
|
||||
BL::BlendData::lamps_iterator b_lamp;
|
||||
|
||||
for(b_lamp = b_data.lamps.begin(); b_lamp != b_data.lamps.end(); ++b_lamp)
|
||||
if(b_lamp->recalc())
|
||||
shader_map.set_recalc(*b_lamp);
|
||||
|
||||
BL::BlendData::objects_iterator b_ob;
|
||||
|
||||
for(b_ob = b_data.objects.begin(); b_ob != b_data.objects.end(); ++b_ob) {
|
||||
if(b_ob->recalc()) {
|
||||
object_map.set_recalc(*b_ob);
|
||||
light_map.set_recalc(*b_ob);
|
||||
}
|
||||
if(object_is_mesh(*b_ob)) {
|
||||
if(b_ob->recalc_data() || b_ob->data().recalc()) {
|
||||
BL::ID key = object_is_modified(*b_ob)? *b_ob: b_ob->data();
|
||||
mesh_map.set_recalc(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BL::BlendData::meshes_iterator b_mesh;
|
||||
|
||||
for(b_mesh = b_data.meshes.begin(); b_mesh != b_data.meshes.end(); ++b_mesh)
|
||||
if(b_mesh->recalc())
|
||||
mesh_map.set_recalc(*b_mesh);
|
||||
|
||||
BL::BlendData::worlds_iterator b_world;
|
||||
|
||||
for(b_world = b_data.worlds.begin(); b_world != b_data.worlds.end(); ++b_world)
|
||||
if(world_map == b_world->ptr.data && b_world->recalc())
|
||||
world_recalc = true;
|
||||
|
||||
bool recalc =
|
||||
shader_map.has_recalc() ||
|
||||
object_map.has_recalc() ||
|
||||
light_map.has_recalc() ||
|
||||
mesh_map.has_recalc() ||
|
||||
world_recalc;
|
||||
|
||||
return recalc;
|
||||
}
|
||||
|
||||
void BlenderSync::sync_data(BL::SpaceView3D b_v3d)
|
||||
{
|
||||
sync_integrator();
|
||||
sync_film();
|
||||
sync_shaders();
|
||||
sync_objects(b_v3d);
|
||||
}
|
||||
|
||||
/* Integrator */
|
||||
|
||||
void BlenderSync::sync_integrator()
|
||||
{
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
|
||||
Integrator *integrator = scene->integrator;
|
||||
Integrator previntegrator = *integrator;
|
||||
|
||||
integrator->minbounce = get_int(cscene, "min_bounces");
|
||||
integrator->maxbounce = get_int(cscene, "max_bounces");
|
||||
integrator->no_caustics = get_boolean(cscene, "no_caustics");
|
||||
integrator->blur_caustics = get_float(cscene, "blur_caustics");
|
||||
|
||||
if(integrator->modified(previntegrator))
|
||||
integrator->tag_update(scene);
|
||||
}
|
||||
|
||||
/* Film */
|
||||
|
||||
void BlenderSync::sync_film()
|
||||
{
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
|
||||
Film *film = scene->film;
|
||||
Film prevfilm = *film;
|
||||
|
||||
film->exposure = get_float(cscene, "exposure");
|
||||
film->response = get_enum_identifier(cscene, "response_curve");
|
||||
|
||||
if(film->modified(prevfilm))
|
||||
film->tag_update(scene);
|
||||
}
|
||||
|
||||
/* Scene Parameters */
|
||||
|
||||
SceneParams BlenderSync::get_scene_params(BL::Scene b_scene)
|
||||
{
|
||||
SceneParams params;
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
int shadingsystem = RNA_enum_get(&cscene, "shading_system");
|
||||
|
||||
if(shadingsystem == 0)
|
||||
params.shadingsystem = SceneParams::SVM;
|
||||
else if(shadingsystem == 1)
|
||||
params.shadingsystem = SceneParams::OSL;
|
||||
|
||||
params.bvh_type = (SceneParams::BVHType)RNA_enum_get(&cscene, "debug_bvh_type");
|
||||
params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/* Session Parameters */
|
||||
|
||||
SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background)
|
||||
{
|
||||
SessionParams params;
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
|
||||
/* device type */
|
||||
DeviceType dtype = (RNA_enum_get(&cscene, "device") == 1)? DEVICE_CUDA: DEVICE_CPU;
|
||||
|
||||
params.device_type = DEVICE_CPU;
|
||||
vector<DeviceType> types = Device::available_types();
|
||||
|
||||
foreach(DeviceType dt, types)
|
||||
if(dt == dtype)
|
||||
params.device_type = dtype;
|
||||
|
||||
/* other parameters */
|
||||
params.background = background;
|
||||
params.passes = (background)? get_int(cscene, "passes"): INT_MAX;
|
||||
params.tile_size = get_int(cscene, "debug_tile_size");
|
||||
params.min_size = get_int(cscene, "debug_min_size");
|
||||
params.cancel_timeout = get_float(cscene, "debug_cancel_timeout");
|
||||
params.reset_timeout = get_float(cscene, "debug_reset_timeout");
|
||||
params.text_timeout = get_float(cscene, "debug_text_timeout");
|
||||
|
||||
if(background) {
|
||||
params.progressive = true;
|
||||
params.min_size = INT_MAX;
|
||||
}
|
||||
else
|
||||
params.progressive = true;
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
105
intern/cycles/blender/blender_sync.h
Normal file
105
intern/cycles/blender/blender_sync.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __BLENDER_SYNC_H__
|
||||
#define __BLENDER_SYNC_H__
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
#include "RNA_types.h"
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_blender_cpp.h"
|
||||
|
||||
#include "blender_util.h"
|
||||
|
||||
#include "scene.h"
|
||||
#include "session.h"
|
||||
|
||||
#include "util_map.h"
|
||||
#include "util_set.h"
|
||||
#include "util_transform.h"
|
||||
#include "util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Background;
|
||||
class Camera;
|
||||
class Film;
|
||||
class Light;
|
||||
class Mesh;
|
||||
class Object;
|
||||
class Scene;
|
||||
class Shader;
|
||||
class ShaderGraph;
|
||||
class ShaderNode;
|
||||
|
||||
class BlenderSync {
|
||||
public:
|
||||
BlenderSync(BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_);
|
||||
~BlenderSync();
|
||||
|
||||
/* sync */
|
||||
bool sync_recalc();
|
||||
void sync_data(BL::SpaceView3D b_v3d);
|
||||
void sync_camera(int width, int height);
|
||||
void sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
|
||||
|
||||
/* get parameters */
|
||||
static SceneParams get_scene_params(BL::Scene b_scene);
|
||||
static SessionParams get_session_params(BL::Scene b_scene, bool background);
|
||||
|
||||
private:
|
||||
/* sync */
|
||||
void sync_lamps();
|
||||
void sync_materials();
|
||||
void sync_objects(BL::SpaceView3D b_v3d);
|
||||
void sync_film();
|
||||
void sync_integrator();
|
||||
void sync_view();
|
||||
void sync_world();
|
||||
void sync_shaders();
|
||||
|
||||
void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
|
||||
Mesh *sync_mesh(BL::Object b_ob, bool object_updated);
|
||||
void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm);
|
||||
void sync_light(BL::Object b_ob, Transform& tfm);
|
||||
|
||||
/* util */
|
||||
void find_shader(BL::ID id, vector<uint>& used_shaders);
|
||||
bool object_is_modified(BL::Object b_ob);
|
||||
bool object_is_mesh(BL::Object b_ob);
|
||||
bool object_is_light(BL::Object b_ob);
|
||||
|
||||
/* variables */
|
||||
BL::BlendData b_data;
|
||||
BL::Scene b_scene;
|
||||
|
||||
id_map<void*, Shader> shader_map;
|
||||
id_map<ObjectKey, Object> object_map;
|
||||
id_map<void*, Mesh> mesh_map;
|
||||
id_map<void*, Light> light_map;
|
||||
void *world_map;
|
||||
bool world_recalc;
|
||||
|
||||
Scene *scene;
|
||||
bool preview;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __BLENDER_SYNC_H__ */
|
||||
|
326
intern/cycles/blender/blender_util.h
Normal file
326
intern/cycles/blender/blender_util.h
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __BLENDER_UTIL_H__
|
||||
#define __BLENDER_UTIL_H__
|
||||
|
||||
#include "util_map.h"
|
||||
#include "util_path.h"
|
||||
#include "util_set.h"
|
||||
#include "util_transform.h"
|
||||
#include "util_types.h"
|
||||
#include "util_vector.h"
|
||||
|
||||
/* Hacks to hook into Blender API */
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct RenderEngine;
|
||||
struct RenderResult;
|
||||
|
||||
ID *rna_Object_to_mesh(void *_self, void *reports, void *scene, int apply_modifiers, int settings);
|
||||
void rna_Main_meshes_remove(void *bmain, void *reports, void *mesh);
|
||||
void rna_Object_create_duplilist(void *ob, void *reports, void *sce);
|
||||
void rna_Object_free_duplilist(void *ob, void *reports);
|
||||
void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values);
|
||||
void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values);
|
||||
struct RenderResult *RE_engine_begin_result(struct RenderEngine *engine, int x, int y, int w, int h);
|
||||
void RE_engine_update_result(struct RenderEngine *engine, struct RenderResult *result);
|
||||
void RE_engine_end_result(struct RenderEngine *engine, struct RenderResult *result);
|
||||
int RE_engine_test_break(struct RenderEngine *engine);
|
||||
void RE_engine_update_stats(struct RenderEngine *engine, const char *stats, const char *info);
|
||||
void engine_tag_redraw(void *engine);
|
||||
void engine_tag_update(void *engine);
|
||||
int rna_Object_is_modified(void *ob, void *scene, int settings);
|
||||
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
static inline BL::Mesh object_to_mesh(BL::Object self, BL::Scene scene, bool apply_modifiers, bool render)
|
||||
{
|
||||
ID *data = rna_Object_to_mesh(self.ptr.data, NULL, scene.ptr.data, apply_modifiers, render);
|
||||
PointerRNA ptr;
|
||||
RNA_id_pointer_create(data, &ptr);
|
||||
return BL::Mesh(ptr);
|
||||
}
|
||||
|
||||
static inline void object_remove_mesh(BL::BlendData data, BL::Mesh mesh)
|
||||
{
|
||||
rna_Main_meshes_remove(data.ptr.data, NULL, mesh.ptr.data);
|
||||
}
|
||||
|
||||
static inline void object_create_duplilist(BL::Object self, BL::Scene scene)
|
||||
{
|
||||
rna_Object_create_duplilist(self.ptr.data, NULL, scene.ptr.data);
|
||||
}
|
||||
|
||||
static inline void object_free_duplilist(BL::Object self)
|
||||
{
|
||||
rna_Object_free_duplilist(self.ptr.data, NULL);
|
||||
}
|
||||
|
||||
static inline bool object_is_modified(BL::Object self, BL::Scene scene, bool preview)
|
||||
{
|
||||
return rna_Object_is_modified(self.ptr.data, scene.ptr.data, (preview)? (1<<0): (1<<1));
|
||||
}
|
||||
|
||||
/* Utilities */
|
||||
|
||||
static inline Transform get_transform(BL::Array<float, 16> array)
|
||||
{
|
||||
Transform tfm;
|
||||
|
||||
/* we assume both types to be just 16 floats, and transpose because blender
|
||||
use column major matrix order while we use row major */
|
||||
memcpy(&tfm, &array, sizeof(float)*16);
|
||||
tfm = transform_transpose(tfm);
|
||||
|
||||
return tfm;
|
||||
}
|
||||
|
||||
static inline float2 get_float2(BL::Array<float, 2> array)
|
||||
{
|
||||
return make_float2(array[0], array[1]);
|
||||
}
|
||||
|
||||
static inline float3 get_float3(BL::Array<float, 2> array)
|
||||
{
|
||||
return make_float3(array[0], array[1], 0.0f);
|
||||
}
|
||||
|
||||
static inline float3 get_float3(BL::Array<float, 3> array)
|
||||
{
|
||||
return make_float3(array[0], array[1], array[2]);
|
||||
}
|
||||
|
||||
static inline float3 get_float3(BL::Array<float, 4> array)
|
||||
{
|
||||
return make_float3(array[0], array[1], array[2]);
|
||||
}
|
||||
|
||||
static inline int4 get_int4(BL::Array<int, 4> array)
|
||||
{
|
||||
return make_int4(array[0], array[1], array[2], array[3]);
|
||||
}
|
||||
|
||||
static inline uint get_layer(BL::Array<int, 20> array)
|
||||
{
|
||||
uint layer = 0;
|
||||
|
||||
for(uint i = 0; i < 20; i++)
|
||||
if(array[i])
|
||||
layer |= (1 << i);
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
/*static inline float3 get_float3(PointerRNA& ptr, const char *name)
|
||||
{
|
||||
float3 f;
|
||||
RNA_float_get_array(&ptr, name, &f.x);
|
||||
return f;
|
||||
}*/
|
||||
|
||||
static inline bool get_boolean(PointerRNA& ptr, const char *name)
|
||||
{
|
||||
return RNA_boolean_get(&ptr, name);
|
||||
}
|
||||
|
||||
static inline float get_float(PointerRNA& ptr, const char *name)
|
||||
{
|
||||
return RNA_float_get(&ptr, name);
|
||||
}
|
||||
|
||||
static inline int get_int(PointerRNA& ptr, const char *name)
|
||||
{
|
||||
return RNA_int_get(&ptr, name);
|
||||
}
|
||||
|
||||
static inline int get_enum(PointerRNA& ptr, const char *name)
|
||||
{
|
||||
return RNA_enum_get(&ptr, name);
|
||||
}
|
||||
|
||||
static inline string get_enum_identifier(PointerRNA& ptr, const char *name)
|
||||
{
|
||||
PropertyRNA *prop = RNA_struct_find_property(&ptr, name);
|
||||
const char *identifier = "";
|
||||
int value = RNA_property_enum_get(&ptr, prop);
|
||||
|
||||
RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier);
|
||||
|
||||
return string(identifier);
|
||||
}
|
||||
|
||||
/* Relative Paths */
|
||||
|
||||
static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, const string& path)
|
||||
{
|
||||
if(path.size() >= 2 && path[0] == '/' && path[1] == '/') {
|
||||
string dirname = (b_id.library())? b_id.library().filepath(): b_data.filepath();
|
||||
return path_join(path_dirname(dirname), path.substr(2));
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* ID Map
|
||||
*
|
||||
* Utility class to keep in sync with blender data.
|
||||
* Used for objects, meshes, lights and shaders. */
|
||||
|
||||
template<typename K, typename T>
|
||||
class id_map {
|
||||
public:
|
||||
id_map(vector<T*> *scene_data_)
|
||||
{
|
||||
scene_data = scene_data_;
|
||||
}
|
||||
|
||||
T *find(BL::ID id)
|
||||
{
|
||||
return find(id.ptr.id.data);
|
||||
}
|
||||
|
||||
T *find(const K& key)
|
||||
{
|
||||
if(b_map.find(key) != b_map.end()) {
|
||||
T *data = b_map[key];
|
||||
return data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void set_recalc(BL::ID id)
|
||||
{
|
||||
b_recalc.insert(id.ptr.data);
|
||||
}
|
||||
|
||||
bool has_recalc()
|
||||
{
|
||||
return !(b_recalc.empty());
|
||||
}
|
||||
|
||||
void pre_sync()
|
||||
{
|
||||
used_set.clear();
|
||||
}
|
||||
|
||||
bool sync(T **r_data, BL::ID id)
|
||||
{
|
||||
return sync(r_data, id, id.ptr.id.data);
|
||||
}
|
||||
|
||||
bool sync(T **r_data, BL::ID id, const K& key)
|
||||
{
|
||||
T *data = find(key);
|
||||
bool recalc;
|
||||
|
||||
if(!data) {
|
||||
/* add data if it didn't exist yet */
|
||||
data = new T();
|
||||
scene_data->push_back(data);
|
||||
b_map[key] = data;
|
||||
recalc = true;
|
||||
}
|
||||
else
|
||||
recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
|
||||
|
||||
used(data);
|
||||
|
||||
*r_data = data;
|
||||
return recalc;
|
||||
}
|
||||
|
||||
void used(T *data)
|
||||
{
|
||||
/* tag data as still in use */
|
||||
used_set.insert(data);
|
||||
}
|
||||
|
||||
void set_default(T *data)
|
||||
{
|
||||
b_map[NULL] = data;
|
||||
}
|
||||
|
||||
bool post_sync(bool do_delete = true)
|
||||
{
|
||||
/* remove unused data */
|
||||
vector<T*> new_scene_data;
|
||||
typename vector<T*>::iterator it;
|
||||
bool deleted = false;
|
||||
|
||||
for(it = scene_data->begin(); it != scene_data->end(); it++) {
|
||||
T *data = *it;
|
||||
|
||||
if(do_delete && used_set.find(data) == used_set.end()) {
|
||||
delete data;
|
||||
deleted = true;
|
||||
}
|
||||
else
|
||||
new_scene_data.push_back(data);
|
||||
}
|
||||
|
||||
*scene_data = new_scene_data;
|
||||
|
||||
/* update mapping */
|
||||
map<K, T*> new_map;
|
||||
typedef pair<const K, T*> TMapPair;
|
||||
typename map<K, T*>::iterator jt;
|
||||
|
||||
for(jt = b_map.begin(); jt != b_map.end(); jt++) {
|
||||
TMapPair& pair = *jt;
|
||||
|
||||
if(used_set.find(pair.second) != used_set.end())
|
||||
new_map[pair.first] = pair.second;
|
||||
}
|
||||
|
||||
used_set.clear();
|
||||
b_recalc.clear();
|
||||
b_map = new_map;
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
protected:
|
||||
vector<T*> *scene_data;
|
||||
map<K, T*> b_map;
|
||||
set<T*> used_set;
|
||||
set<void*> b_recalc;
|
||||
};
|
||||
|
||||
/* Object Key */
|
||||
|
||||
struct ObjectKey {
|
||||
void *parent;
|
||||
int index;
|
||||
void *ob;
|
||||
|
||||
ObjectKey(void *parent_, int index_, void *ob_)
|
||||
: parent(parent_), index(index_), ob(ob_) {}
|
||||
|
||||
bool operator<(const ObjectKey& k) const
|
||||
{ return (parent < k.parent || (parent == k.parent && (index < k.index || (index == k.index && ob < k.ob)))); }
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __BLENDER_UTIL_H__ */
|
||||
|
18
intern/cycles/bvh/CMakeLists.txt
Normal file
18
intern/cycles/bvh/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
INCLUDE_DIRECTORIES(. ../kernel ../kernel/svm ../render ../util ../device)
|
||||
|
||||
SET(sources
|
||||
bvh.cpp
|
||||
bvh_build.cpp
|
||||
bvh_node.cpp
|
||||
bvh_sort.cpp)
|
||||
|
||||
SET(headers
|
||||
bvh.h
|
||||
bvh_build.h
|
||||
bvh_node.h
|
||||
bvh_params.h
|
||||
bvh_sort.h)
|
||||
|
||||
ADD_LIBRARY(bvh ${sources} ${headers})
|
||||
|
661
intern/cycles/bvh/bvh.cpp
Normal file
661
intern/cycles/bvh/bvh.cpp
Normal file
@ -0,0 +1,661 @@
|
||||
/*
|
||||
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mesh.h"
|
||||
#include "object.h"
|
||||
#include "scene.h"
|
||||
|
||||
#include "bvh.h"
|
||||
#include "bvh_build.h"
|
||||
#include "bvh_node.h"
|
||||
#include "bvh_params.h"
|
||||
|
||||
#include "util_cache.h"
|
||||
#include "util_debug.h"
|
||||
#include "util_foreach.h"
|
||||
#include "util_progress.h"
|
||||
#include "util_types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Pack Utility */
|
||||
|
||||
struct BVHStackEntry
|
||||
{
|
||||
const BVHNode *node;
|
||||
int idx;
|
||||
|
||||
BVHStackEntry(const BVHNode* n = 0, int i = 0)
|
||||
: node(n), idx(i)
|
||||
{
|
||||
}
|
||||
|
||||
int encodeIdx() const
|
||||
{
|
||||
return (node->is_leaf())? ~idx: idx;
|
||||
}
|
||||
};
|
||||
|
||||
/* BVH */
|
||||
|
||||
BVH::BVH(const BVHParams& params_, const vector<Object*>& objects_)
|
||||
: params(params_), objects(objects_)
|
||||
{
|
||||
}
|
||||
|
||||
BVH *BVH::create(const BVHParams& params, const vector<Object*>& objects)
|
||||
{
|
||||
if(params.use_qbvh)
|
||||
return new QBVH(params, objects);
|
||||
else
|
||||
return new RegularBVH(params, objects);
|
||||
}
|
||||
|
||||
/* Cache */
|
||||
|
||||
bool BVH::cache_read(CacheData& key)
|
||||
{
|
||||
key.add(¶ms, sizeof(params));
|
||||
|
||||
foreach(Object *ob, objects) {
|
||||
key.add(ob->mesh->verts);
|
||||
key.add(ob->mesh->triangles);
|
||||
}
|
||||
|
||||
CacheData value;
|
||||
|
||||
if(Cache::global.lookup(key, value)) {
|
||||
value.read(pack.root_index);
|
||||
|
||||
value.read(pack.nodes);
|
||||
value.read(pack.object_node);
|
||||
value.read(pack.tri_woop);
|
||||
value.read(pack.prim_index);
|
||||
value.read(pack.prim_object);
|
||||
value.read(pack.is_leaf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void BVH::cache_write(CacheData& key)
|
||||
{
|
||||
CacheData value;
|
||||
|
||||
value.add(pack.root_index);
|
||||
|
||||
value.add(pack.nodes);
|
||||
value.add(pack.object_node);
|
||||
value.add(pack.tri_woop);
|
||||
value.add(pack.prim_index);
|
||||
value.add(pack.prim_object);
|
||||
value.add(pack.is_leaf);
|
||||
|
||||
Cache::global.insert(key, value);
|
||||
}
|
||||
|
||||
/* Building */
|
||||
|
||||
void BVH::build(Progress& progress)
|
||||
{
|
||||
progress.set_substatus("Building BVH");
|
||||
|
||||
/* cache read */
|
||||
CacheData key("bvh");
|
||||
|
||||
if(params.use_cache) {
|
||||
progress.set_substatus("Looking in BVH cache");
|
||||
|
||||
if(cache_read(key))
|
||||
return;
|
||||
}
|
||||
|
||||
/* build nodes */
|
||||
vector<int> prim_index;
|
||||
vector<int> prim_object;
|
||||
|
||||
BVHBuild bvh_build(objects, prim_index, prim_object, params, progress);
|
||||
BVHNode *root = bvh_build.run();
|
||||
|
||||
if(progress.get_cancel()) {
|
||||
if(root) root->deleteSubtree();
|
||||
return;
|
||||
}
|
||||
|
||||
/* todo: get rid of this copy */
|
||||
pack.prim_index = prim_index;
|
||||
pack.prim_object = prim_object;
|
||||
|
||||
/* compute SAH */
|
||||
if(!params.top_level)
|
||||
pack.SAH = root->computeSubtreeSAHCost(params);
|
||||
|
||||
if(progress.get_cancel()) {
|
||||
root->deleteSubtree();
|
||||
return;
|
||||
}
|
||||
|
||||
/* pack triangles */
|
||||
progress.set_substatus("Packing BVH triangles");
|
||||
pack_triangles();
|
||||
|
||||
if(progress.get_cancel()) {
|
||||
root->deleteSubtree();
|
||||
return;
|
||||
}
|
||||
|
||||
/* pack nodes */
|
||||
progress.set_substatus("Packing BVH nodes");
|
||||
array<int> tmp_prim_object = pack.prim_object;
|
||||
pack_nodes(tmp_prim_object, root);
|
||||
|
||||
/* free build nodes */
|
||||
root->deleteSubtree();
|
||||
|
||||
if(progress.get_cancel()) return;
|
||||
|
||||
/* cache write */
|
||||
if(params.use_cache) {
|
||||
progress.set_substatus("Writing BVH cache");
|
||||
cache_write(key);
|
||||
}
|
||||
}
|
||||
|
||||
/* Refitting */
|
||||
|
||||
void BVH::refit(Progress& progress)
|
||||
{
|
||||
progress.set_substatus("Packing BVH triangles");
|
||||
pack_triangles();
|
||||
|
||||
if(progress.get_cancel()) return;
|
||||
|
||||
progress.set_substatus("Refitting BVH nodes");
|
||||
refit_nodes();
|
||||
}
|
||||
|
||||
/* Triangles */
|
||||
|
||||
void BVH::pack_triangle(int idx, float4 woop[3])
|
||||
{
|
||||
/* create Woop triangle */
|
||||
int tob = pack.prim_object[idx];
|
||||
const Mesh *mesh = objects[tob]->mesh;
|
||||
int tidx = pack.prim_index[idx];
|
||||
const int *vidx = mesh->triangles[tidx].v;
|
||||
const float3* vpos = &mesh->verts[0];
|
||||
float3 v0 = vpos[vidx[0]];
|
||||
float3 v1 = vpos[vidx[1]];
|
||||
float3 v2 = vpos[vidx[2]];
|
||||
|
||||
float3 r0 = v0 - v2;
|
||||
float3 r1 = v1 - v2;
|
||||
float3 r2 = cross(r0, r1);
|
||||
|
||||
if(dot(r0, r0) == 0.0f || dot(r1, r1) == 0.0f || dot(r2, r2) == 0.0f) {
|
||||
/* degenerate */
|
||||
woop[0] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
woop[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
woop[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
else {
|
||||
Transform t = make_transform(
|
||||
r0.x, r1.x, r2.x, v2.x,
|
||||
r0.y, r1.y, r2.y, v2.y,
|
||||
r0.z, r1.z, r2.z, v2.z,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
t = transform_inverse(t);
|
||||
|
||||
woop[0] = make_float4(t.z.x, t.z.y, t.z.z, -t.z.w);
|
||||
woop[1] = make_float4(t.x.x, t.x.y, t.x.z, t.x.w);
|
||||
woop[2] = make_float4(t.y.x, t.y.y, t.y.z, t.y.w);
|
||||
}
|
||||
}
|
||||
|
||||
void BVH::pack_triangles()
|
||||
{
|
||||
int nsize = TRI_NODE_SIZE;
|
||||
size_t tidx_size = pack.prim_index.size();
|
||||
|
||||
pack.tri_woop.clear();
|
||||
pack.tri_woop.resize(tidx_size * nsize);
|
||||
|
||||
for(unsigned int i = 0; i < tidx_size; i++) {
|
||||
if(pack.prim_index[i] != -1) {
|
||||
float4 woop[3];
|
||||
|
||||
pack_triangle(i, woop);
|
||||
memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Pack Instances */
|
||||
|
||||
void BVH::pack_instances(size_t nodes_size)
|
||||
{
|
||||
/* The BVH's for instances are built separately, but for traversal all
|
||||
BVH's are stored in global arrays. This function merges them into the
|
||||
top level BVH, adjusting indexes and offsets where appropriate. */
|
||||
bool use_qbvh = params.use_qbvh;
|
||||
size_t nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE;
|
||||
|
||||
/* adjust primitive index to point to the triangle in the global array, for
|
||||
meshes with transform applied and already in the top level BVH */
|
||||
for(size_t i = 0; i < pack.prim_index.size(); i++)
|
||||
if(pack.prim_index[i] != -1)
|
||||
pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
|
||||
|
||||
/* track offsets of instanced BVH data in global array */
|
||||
size_t tri_offset = pack.prim_index.size();
|
||||
size_t nodes_offset = nodes_size;
|
||||
|
||||
/* clear array that gives the node indexes for instanced objects */
|
||||
pack.object_node.clear();
|
||||
|
||||
/* reserve */
|
||||
size_t prim_index_size = pack.prim_index.size();
|
||||
size_t tri_woop_size = pack.tri_woop.size();
|
||||
|
||||
size_t pack_prim_index_offset = prim_index_size;
|
||||
size_t pack_tri_woop_offset = tri_woop_size;
|
||||
size_t pack_nodes_offset = nodes_size;
|
||||
size_t object_offset = 0;
|
||||
|
||||
foreach(Object *ob, objects) {
|
||||
Mesh *mesh = ob->mesh;
|
||||
BVH *bvh = mesh->bvh;
|
||||
|
||||
if(!mesh->transform_applied) {
|
||||
prim_index_size += bvh->pack.prim_index.size();
|
||||
tri_woop_size += bvh->pack.tri_woop.size();
|
||||
nodes_size += bvh->pack.nodes.size()*nsize;
|
||||
}
|
||||
}
|
||||
|
||||
pack.prim_index.resize(prim_index_size);
|
||||
pack.prim_object.resize(prim_index_size);
|
||||
pack.tri_woop.resize(tri_woop_size);
|
||||
pack.nodes.resize(nodes_size);
|
||||
pack.object_node.resize(objects.size());
|
||||
|
||||
int *pack_prim_index = &pack.prim_index[0];
|
||||
int *pack_prim_object = &pack.prim_object[0];
|
||||
float4 *pack_tri_woop = &pack.tri_woop[0];
|
||||
int4 *pack_nodes = &pack.nodes[0];
|
||||
|
||||
/* merge */
|
||||
foreach(Object *ob, objects) {
|
||||
Mesh *mesh = ob->mesh;
|
||||
|
||||
/* if mesh transform is applied, that means it's already in the top
|
||||
level BVH, and we don't need to merge it in */
|
||||
if(mesh->transform_applied) {
|
||||
pack.object_node[object_offset++] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
BVH *bvh = mesh->bvh;
|
||||
|
||||
int noffset = nodes_offset/nsize;
|
||||
int mesh_tri_offset = mesh->tri_offset;
|
||||
|
||||
/* fill in node indexes for instances */
|
||||
if(bvh->pack.is_leaf[0])
|
||||
pack.object_node[object_offset++] = -noffset-1;
|
||||
else
|
||||
pack.object_node[object_offset++] = noffset;
|
||||
|
||||
/* merge primitive and object indexes */
|
||||
{
|
||||
size_t bvh_prim_index_size = bvh->pack.prim_index.size();
|
||||
int *bvh_prim_index = &bvh->pack.prim_index[0];
|
||||
|
||||
for(size_t i = 0; i < bvh_prim_index_size; i++) {
|
||||
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
|
||||
pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
|
||||
pack_prim_index_offset++;
|
||||
}
|
||||
}
|
||||
|
||||
/* merge triangle intersection data */
|
||||
{
|
||||
memcpy(pack_tri_woop+pack_tri_woop_offset, &bvh->pack.tri_woop[0],
|
||||
bvh->pack.tri_woop.size()*sizeof(float4));
|
||||
pack_tri_woop_offset += bvh->pack.tri_woop.size();
|
||||
}
|
||||
|
||||
/* merge nodes */
|
||||
{
|
||||
size_t nsize_bbox = (use_qbvh)? nsize-2: nsize-1;
|
||||
int4 *bvh_nodes = &bvh->pack.nodes[0];
|
||||
size_t bvh_nodes_size = bvh->pack.nodes.size();
|
||||
int *bvh_is_leaf = &bvh->pack.is_leaf[0];
|
||||
|
||||
for(size_t i = 0, j = 0; i < bvh_nodes_size; i+=nsize, j++) {
|
||||
memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox*sizeof(int4));
|
||||
|
||||
/* modify offsets into arrays */
|
||||
int4 data = bvh_nodes[i + nsize_bbox];
|
||||
|
||||
if(bvh_is_leaf[j]) {
|
||||
data.x += tri_offset;
|
||||
data.y += tri_offset;
|
||||
}
|
||||
else {
|
||||
data.x += (data.x < 0)? -noffset: noffset;
|
||||
data.y += (data.y < 0)? -noffset: noffset;
|
||||
|
||||
if(use_qbvh) {
|
||||
data.z += (data.z < 0)? -noffset: noffset;
|
||||
data.w += (data.w < 0)? -noffset: noffset;
|
||||
}
|
||||
}
|
||||
|
||||
pack_nodes[pack_nodes_offset + nsize_bbox] = data;
|
||||
|
||||
if(use_qbvh)
|
||||
pack_nodes[pack_nodes_offset + nsize_bbox+1] = bvh_nodes[i + nsize_bbox+1];
|
||||
|
||||
pack_nodes_offset += nsize;
|
||||
}
|
||||
}
|
||||
|
||||
nodes_offset += bvh->pack.nodes.size();
|
||||
tri_offset += bvh->pack.prim_index.size();
|
||||
}
|
||||
}
|
||||
|
||||
/* Regular BVH */
|
||||
|
||||
RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_)
|
||||
: BVH(params_, objects_)
|
||||
{
|
||||
}
|
||||
|
||||
void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
|
||||
{
|
||||
if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1)
|
||||
/* object */
|
||||
pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, ~(leaf->m_lo), 0);
|
||||
else
|
||||
/* triangle */
|
||||
pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, leaf->m_lo, leaf->m_hi);
|
||||
}
|
||||
|
||||
void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1)
|
||||
{
|
||||
pack_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx());
|
||||
}
|
||||
|
||||
void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1)
|
||||
{
|
||||
int4 data[BVH_NODE_SIZE] =
|
||||
{
|
||||
make_int4(__float_as_int(b0.min.x), __float_as_int(b0.max.x), __float_as_int(b0.min.y), __float_as_int(b0.max.y)),
|
||||
make_int4(__float_as_int(b1.min.x), __float_as_int(b1.max.x), __float_as_int(b1.min.y), __float_as_int(b1.max.y)),
|
||||
make_int4(__float_as_int(b0.min.z), __float_as_int(b0.max.z), __float_as_int(b1.min.z), __float_as_int(b1.max.z)),
|
||||
make_int4(c0, c1, 0, 0)
|
||||
};
|
||||
|
||||
memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE);
|
||||
}
|
||||
|
||||
void RegularBVH::pack_nodes(const array<int>& prims, const BVHNode *root)
|
||||
{
|
||||
size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
|
||||
|
||||
/* resize arrays */
|
||||
pack.nodes.clear();
|
||||
pack.is_leaf.clear();
|
||||
pack.is_leaf.resize(node_size);
|
||||
|
||||
/* for top level BVH, first merge existing BVH's so we know the offsets */
|
||||
if(params.top_level)
|
||||
pack_instances(node_size*BVH_NODE_SIZE);
|
||||
else
|
||||
pack.nodes.resize(node_size*BVH_NODE_SIZE);
|
||||
|
||||
int nextNodeIdx = 0;
|
||||
|
||||
vector<BVHStackEntry> stack;
|
||||
stack.push_back(BVHStackEntry(root, nextNodeIdx++));
|
||||
|
||||
while(stack.size()) {
|
||||
BVHStackEntry e = stack.back();
|
||||
stack.pop_back();
|
||||
|
||||
pack.is_leaf[e.idx] = e.node->is_leaf();
|
||||
|
||||
if(e.node->is_leaf()) {
|
||||
/* leaf node */
|
||||
const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
|
||||
pack_leaf(e, leaf);
|
||||
}
|
||||
else {
|
||||
/* innner node */
|
||||
stack.push_back(BVHStackEntry(e.node->get_child(0), nextNodeIdx++));
|
||||
stack.push_back(BVHStackEntry(e.node->get_child(1), nextNodeIdx++));
|
||||
|
||||
pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* root index to start traversal at, to handle case of single leaf node */
|
||||
pack.root_index = (pack.is_leaf[0])? -1: 0;
|
||||
}
|
||||
|
||||
void RegularBVH::refit_nodes()
|
||||
{
|
||||
assert(!params.top_level);
|
||||
|
||||
BoundBox bbox;
|
||||
refit_node(0, pack.is_leaf[0], bbox);
|
||||
}
|
||||
|
||||
void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox)
|
||||
{
|
||||
int4 *data = &pack.nodes[idx*4];
|
||||
|
||||
int c0 = data[3].x;
|
||||
int c1 = data[3].y;
|
||||
|
||||
if(leaf) {
|
||||
/* refit leaf node */
|
||||
for(int tri = c0; tri < c1; tri++) {
|
||||
int tidx = pack.prim_index[tri];
|
||||
int tob = pack.prim_object[tri];
|
||||
Object *ob = objects[tob];
|
||||
|
||||
if(tidx == -1) {
|
||||
/* object instance */
|
||||
bbox.grow(ob->bounds);
|
||||
}
|
||||
else {
|
||||
/* triangles */
|
||||
const Mesh *mesh = ob->mesh;
|
||||
int tri_offset = (params.top_level)? mesh->tri_offset: 0;
|
||||
const int *vidx = mesh->triangles[tidx - tri_offset].v;
|
||||
const float3 *vpos = &mesh->verts[0];
|
||||
|
||||
bbox.grow(vpos[vidx[0]]);
|
||||
bbox.grow(vpos[vidx[1]]);
|
||||
bbox.grow(vpos[vidx[2]]);
|
||||
}
|
||||
}
|
||||
|
||||
pack_node(idx, bbox, bbox, c0, c1);
|
||||
}
|
||||
else {
|
||||
/* refit inner node, set bbox from children */
|
||||
BoundBox bbox0, bbox1;
|
||||
|
||||
refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0);
|
||||
refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1);
|
||||
|
||||
bbox.grow(bbox0);
|
||||
bbox.grow(bbox1);
|
||||
|
||||
pack_node(idx, bbox0, bbox1, c0, c1);
|
||||
}
|
||||
}
|
||||
|
||||
/* QBVH */
|
||||
|
||||
QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_)
|
||||
: BVH(params_, objects_)
|
||||
{
|
||||
params.use_qbvh = true;
|
||||
}
|
||||
|
||||
void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
|
||||
{
|
||||
float4 data[BVH_QNODE_SIZE];
|
||||
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) {
|
||||
/* object */
|
||||
data[6].x = __int_as_float(~(leaf->m_lo));
|
||||
data[6].y = __int_as_float(0);
|
||||
}
|
||||
else {
|
||||
/* triangle */
|
||||
data[6].x = __int_as_float(leaf->m_lo);
|
||||
data[6].y = __int_as_float(leaf->m_hi);
|
||||
}
|
||||
|
||||
memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
|
||||
}
|
||||
|
||||
void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num)
|
||||
{
|
||||
float4 data[BVH_QNODE_SIZE];
|
||||
|
||||
for(int i = 0; i < num; i++) {
|
||||
float3 bb_min = en[i].node->m_bounds.min;
|
||||
float3 bb_max = en[i].node->m_bounds.max;
|
||||
|
||||
data[0][i] = bb_min.x;
|
||||
data[1][i] = bb_max.x;
|
||||
data[2][i] = bb_min.y;
|
||||
data[3][i] = bb_max.y;
|
||||
data[4][i] = bb_min.z;
|
||||
data[5][i] = bb_max.z;
|
||||
|
||||
data[6][i] = __int_as_float(en[i].encodeIdx());
|
||||
data[7][i] = 0.0f;
|
||||
}
|
||||
|
||||
for(int i = num; i < 4; i++) {
|
||||
data[0][i] = 0.0f;
|
||||
data[1][i] = 0.0f;
|
||||
data[2][i] = 0.0f;
|
||||
|
||||
data[3][i] = 0.0f;
|
||||
data[4][i] = 0.0f;
|
||||
data[5][i] = 0.0f;
|
||||
|
||||
data[6][i] = __int_as_float(0);
|
||||
data[7][i] = 0.0f;
|
||||
}
|
||||
|
||||
memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
|
||||
}
|
||||
|
||||
/* Quad SIMD Nodes */
|
||||
|
||||
void QBVH::pack_nodes(const array<int>& prims, const BVHNode *root)
|
||||
{
|
||||
size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
|
||||
|
||||
/* resize arrays */
|
||||
pack.nodes.clear();
|
||||
pack.is_leaf.clear();
|
||||
pack.is_leaf.resize(node_size);
|
||||
|
||||
/* for top level BVH, first merge existing BVH's so we know the offsets */
|
||||
if(params.top_level)
|
||||
pack_instances(node_size*BVH_QNODE_SIZE);
|
||||
else
|
||||
pack.nodes.resize(node_size*BVH_QNODE_SIZE);
|
||||
|
||||
int nextNodeIdx = 0;
|
||||
|
||||
vector<BVHStackEntry> stack;
|
||||
stack.push_back(BVHStackEntry(root, nextNodeIdx++));
|
||||
|
||||
while(stack.size()) {
|
||||
BVHStackEntry e = stack.back();
|
||||
stack.pop_back();
|
||||
|
||||
pack.is_leaf[e.idx] = e.node->is_leaf();
|
||||
|
||||
if(e.node->is_leaf()) {
|
||||
/* leaf node */
|
||||
const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
|
||||
pack_leaf(e, leaf);
|
||||
}
|
||||
else {
|
||||
/* inner node */
|
||||
const BVHNode *node = e.node;
|
||||
const BVHNode *node0 = node->get_child(0);
|
||||
const BVHNode *node1 = node->get_child(1);
|
||||
|
||||
/* collect nodes */
|
||||
const BVHNode *nodes[4];
|
||||
int numnodes = 0;
|
||||
|
||||
if(node0->is_leaf()) {
|
||||
nodes[numnodes++] = node0;
|
||||
}
|
||||
else {
|
||||
nodes[numnodes++] = node0->get_child(0);
|
||||
nodes[numnodes++] = node0->get_child(1);
|
||||
}
|
||||
|
||||
if(node1->is_leaf()) {
|
||||
nodes[numnodes++] = node1;
|
||||
}
|
||||
else {
|
||||
nodes[numnodes++] = node1->get_child(0);
|
||||
nodes[numnodes++] = node1->get_child(1);
|
||||
}
|
||||
|
||||
/* push entries on the stack */
|
||||
for(int i = 0; i < numnodes; i++)
|
||||
stack.push_back(BVHStackEntry(nodes[i], nextNodeIdx++));
|
||||
|
||||
/* set node */
|
||||
pack_inner(e, &stack[stack.size()-numnodes], numnodes);
|
||||
}
|
||||
}
|
||||
|
||||
/* root index to start traversal at, to handle case of single leaf node */
|
||||
pack.root_index = (pack.is_leaf[0])? -1: 0;
|
||||
}
|
||||
|
||||
void QBVH::refit_nodes()
|
||||
{
|
||||
assert(0); /* todo */
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
152
intern/cycles/bvh/bvh.h
Normal file
152
intern/cycles/bvh/bvh.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __BVH_H__
|
||||
#define __BVH_H__
|
||||
|
||||
#include "bvh_params.h"
|
||||
|
||||
#include "util_types.h"
|
||||
#include "util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class BVHNode;
|
||||
class BVHStackEntry;
|
||||
class BVHParams;
|
||||
class BoundBox;
|
||||
class CacheData;
|
||||
class LeafNode;
|
||||
class Object;
|
||||
class Progress;
|
||||
|
||||
#define BVH_NODE_SIZE 4
|
||||
#define BVH_QNODE_SIZE 8
|
||||
#define BVH_ALIGN 4096
|
||||
#define TRI_NODE_SIZE 3
|
||||
|
||||
/* Packed BVH
|
||||
*
|
||||
* BVH stored as it will be used for traversal on the rendering device. */
|
||||
|
||||
struct PackedBVH {
|
||||
/* BVH nodes storage, one node is 4x int4, and contains two bounding boxes,
|
||||
and child, triangle or object indexes dependening on the node type */
|
||||
array<int4> nodes;
|
||||
/* object index to BVH node index mapping for instances */
|
||||
array<int> object_node;
|
||||
/* precomputed triangle intersection data, one triangle is 4x float4 */
|
||||
array<float4> tri_woop;
|
||||
/* mapping from BVH primitive index to true primitive index, as primitives
|
||||
may be duplicated due to spatial splits. -1 for instances. */
|
||||
array<int> prim_index;
|
||||
/* mapping from BVH primitive index, to the object id of that primitive. */
|
||||
array<int> prim_object;
|
||||
/* quick array to lookup if a node is a leaf, not used for traversal, only
|
||||
for instance BVH merging */
|
||||
array<int> is_leaf;
|
||||
|
||||
/* index of the root node. */
|
||||
int root_index;
|
||||
|
||||
/* surface area heuristic, for building top level BVH */
|
||||
float SAH;
|
||||
|
||||
PackedBVH()
|
||||
{
|
||||
root_index = 0;
|
||||
SAH = 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
/* BVH */
|
||||
|
||||
class BVH
|
||||
{
|
||||
public:
|
||||
PackedBVH pack;
|
||||
BVHParams params;
|
||||
vector<Object*> objects;
|
||||
|
||||
static BVH *create(const BVHParams& params, const vector<Object*>& objects);
|
||||
|
||||
void build(Progress& progress);
|
||||
void refit(Progress& progress);
|
||||
|
||||
protected:
|
||||
BVH(const BVHParams& params, const vector<Object*>& objects);
|
||||
|
||||
/* cache */
|
||||
bool cache_read(CacheData& key);
|
||||
void cache_write(CacheData& key);
|
||||
|
||||
/* triangles */
|
||||
void pack_triangles();
|
||||
void pack_triangle(int idx, float4 woop[3]);
|
||||
|
||||
/* merge instance BVH's */
|
||||
void pack_instances(size_t nodes_size);
|
||||
|
||||
/* for subclasses to implement */
|
||||
virtual void pack_nodes(const array<int>& prims, const BVHNode *root) = 0;
|
||||
virtual void refit_nodes() = 0;
|
||||
};
|
||||
|
||||
/* Regular BVH
|
||||
*
|
||||
* Typical BVH with each node having two children. */
|
||||
|
||||
class RegularBVH : public BVH {
|
||||
protected:
|
||||
/* constructor */
|
||||
friend class BVH;
|
||||
RegularBVH(const BVHParams& params, const vector<Object*>& objects);
|
||||
|
||||
/* pack */
|
||||
void pack_nodes(const array<int>& prims, const BVHNode *root);
|
||||
void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
|
||||
void pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1);
|
||||
void pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1);
|
||||
|
||||
/* refit */
|
||||
void refit_nodes();
|
||||
void refit_node(int idx, bool leaf, BoundBox& bbox);
|
||||
};
|
||||
|
||||
/* QBVH
|
||||
*
|
||||
* Quad BVH, with each node having four children, to use with SIMD instructions. */
|
||||
|
||||
class QBVH : public BVH {
|
||||
protected:
|
||||
/* constructor */
|
||||
friend class BVH;
|
||||
QBVH(const BVHParams& params, const vector<Object*>& objects);
|
||||
|
||||
/* pack */
|
||||
void pack_nodes(const array<int>& prims, const BVHNode *root);
|
||||
void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
|
||||
void pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num);
|
||||
|
||||
/* refit */
|
||||
void refit_nodes();
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __BVH_H__ */
|
||||
|
545
intern/cycles/bvh/bvh_build.cpp
Normal file
545
intern/cycles/bvh/bvh_build.cpp
Normal file
@ -0,0 +1,545 @@
|
||||
/*
|
||||
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bvh_build.h"
|
||||
#include "bvh_node.h"
|
||||
#include "bvh_params.h"
|
||||
#include "bvh_sort.h"
|
||||
|
||||
#include "mesh.h"
|
||||
#include "object.h"
|
||||
#include "scene.h"
|
||||
|
||||
#include "util_algorithm.h"
|
||||
#include "util_foreach.h"
|
||||
#include "util_progress.h"
|
||||
#include "util_time.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Constructor / Destructor */
|
||||
|
||||
BVHBuild::BVHBuild(const vector<Object*>& objects_,
|
||||
vector<int>& prim_index_, vector<int>& prim_object_,
|
||||
const BVHParams& params_, Progress& progress_)
|
||||
: objects(objects_),
|
||||
prim_index(prim_index_),
|
||||
prim_object(prim_object_),
|
||||
params(params_),
|
||||
progress(progress_),
|
||||
progress_start_time(0.0)
|
||||
{
|
||||
spatial_min_overlap = 0.0f;
|
||||
progress_num_duplicates = 0;
|
||||
}
|
||||
|
||||
BVHBuild::~BVHBuild()
|
||||
{
|
||||
}
|
||||
|
||||
/* Adding References */
|
||||
|
||||
void BVHBuild::add_reference_mesh(NodeSpec& root, Mesh *mesh, int i)
|
||||
{
|
||||
for(uint j = 0; j < mesh->triangles.size(); j++) {
|
||||
Mesh::Triangle t = mesh->triangles[j];
|
||||
Reference ref;
|
||||
|
||||
ref.prim_index = j;
|
||||
ref.prim_object = i;
|
||||
|
||||
for(int k = 0; k < 3; k++) {
|
||||
float3 pt = mesh->verts[t.v[k]];
|
||||
ref.bounds.grow(pt);
|
||||
}
|
||||
|
||||
references.push_back(ref);
|
||||
root.bounds.grow(ref.bounds);
|
||||
}
|
||||
}
|
||||
|
||||
void BVHBuild::add_reference_object(NodeSpec& root, Object *ob, int i)
|
||||
{
|
||||
Reference ref;
|
||||
|
||||
ref.prim_index = -1;
|
||||
ref.prim_object = i;
|
||||
ref.bounds = ob->bounds;
|
||||
|
||||
references.push_back(ref);
|
||||
root.bounds.grow(ref.bounds);
|
||||
}
|
||||
|
||||
void BVHBuild::add_references(NodeSpec& root)
|
||||
{
|
||||
/* init root spec */
|
||||
root.num = 0;
|
||||
root.bounds = BoundBox();
|
||||
|
||||
/* add objects */
|
||||
int i = 0;
|
||||
|
||||
foreach(Object *ob, objects) {
|
||||
if(params.top_level) {
|
||||
if(ob->mesh->transform_applied)
|
||||
add_reference_mesh(root, ob->mesh, i);
|
||||
else
|
||||
add_reference_object(root, ob, i);
|
||||
}
|
||||
else
|
||||
add_reference_mesh(root, ob->mesh, i);
|
||||
|
||||
i++;
|
||||
|
||||
if(progress.get_cancel()) return;
|
||||
}
|
||||
|
||||
/* happens mostly on empty meshes */
|
||||
if(!root.bounds.valid())
|
||||
root.bounds.grow(make_float3(0.0f, 0.0f, 0.0f));
|
||||
|
||||
root.num = references.size();
|
||||
}
|
||||
|
||||
/* Build */
|
||||
|
||||
BVHNode* BVHBuild::run()
|
||||
{
|
||||
NodeSpec root;
|
||||
|
||||
/* add references */
|
||||
add_references(root);
|
||||
|
||||
if(progress.get_cancel()) return NULL;
|
||||
|
||||
/* init spatial splits */
|
||||
if(params.top_level) /* todo: get rid of this */
|
||||
params.use_spatial_split = false;
|
||||
|
||||
spatial_min_overlap = root.bounds.area() * params.spatial_split_alpha;
|
||||
spatial_right_bounds.clear();
|
||||
spatial_right_bounds.resize(max(root.num, (int)BVHParams::NUM_SPATIAL_BINS) - 1);
|
||||
|
||||
/* init progress updates */
|
||||
progress_num_duplicates = 0;
|
||||
progress_start_time = time_dt();
|
||||
|
||||
/* build recursively */
|
||||
return build_node(root, 0, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void BVHBuild::progress_update(float progress_start, float progress_end)
|
||||
{
|
||||
if(time_dt() - progress_start_time < 0.25f)
|
||||
return;
|
||||
|
||||
float duplicates = (float)progress_num_duplicates/(float)references.size();
|
||||
string msg = string_printf("Building BVH %.0f%%, duplicates %.0f%%",
|
||||
progress_start*100.0f, duplicates*100.0f);
|
||||
|
||||
progress.set_substatus(msg);
|
||||
progress_start_time = time_dt();
|
||||
}
|
||||
|
||||
BVHNode* BVHBuild::build_node(const NodeSpec& spec, int level, float progress_start, float progress_end)
|
||||
{
|
||||
/* progress update */
|
||||
progress_update(progress_start, progress_end);
|
||||
if(progress.get_cancel()) return NULL;
|
||||
|
||||
/* small enough or too deep => create leaf. */
|
||||
if(spec.num <= params.min_leaf_size || level >= BVHParams::MAX_DEPTH)
|
||||
return create_leaf_node(spec);
|
||||
|
||||
/* find split candidates. */
|
||||
float area = spec.bounds.area();
|
||||
float leafSAH = area * params.triangle_cost(spec.num);
|
||||
float nodeSAH = area * params.node_cost(2);
|
||||
ObjectSplit object = find_object_split(spec, nodeSAH);
|
||||
SpatialSplit spatial;
|
||||
|
||||
if(params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) {
|
||||
BoundBox overlap = object.left_bounds;
|
||||
overlap.intersect(object.right_bounds);
|
||||
|
||||
if(overlap.area() >= spatial_min_overlap)
|
||||
spatial = find_spatial_split(spec, nodeSAH);
|
||||
}
|
||||
|
||||
/* leaf SAH is the lowest => create leaf. */
|
||||
float minSAH = min(min(leafSAH, object.sah), spatial.sah);
|
||||
|
||||
if(minSAH == leafSAH && spec.num <= params.max_leaf_size)
|
||||
return create_leaf_node(spec);
|
||||
|
||||
/* perform split. */
|
||||
NodeSpec left, right;
|
||||
|
||||
if(params.use_spatial_split && minSAH == spatial.sah)
|
||||
do_spatial_split(left, right, spec, spatial);
|
||||
if(!left.num || !right.num)
|
||||
do_object_split(left, right, spec, object);
|
||||
|
||||
/* create inner node. */
|
||||
progress_num_duplicates += left.num + right.num - spec.num;
|
||||
|
||||
float progress_mid = lerp(progress_start, progress_end, (float)right.num / (float)(left.num + right.num));
|
||||
|
||||
BVHNode* rightNode = build_node(right, level + 1, progress_start, progress_mid);
|
||||
if(progress.get_cancel()) {
|
||||
if(rightNode) rightNode->deleteSubtree();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BVHNode* leftNode = build_node(left, level + 1, progress_mid, progress_end);
|
||||
if(progress.get_cancel()) {
|
||||
if(leftNode) leftNode->deleteSubtree();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new InnerNode(spec.bounds, leftNode, rightNode);
|
||||
}
|
||||
|
||||
BVHNode *BVHBuild::create_object_leaf_nodes(const Reference *ref, int num)
|
||||
{
|
||||
if(num == 0) {
|
||||
BoundBox bounds;
|
||||
return new LeafNode(bounds, 0, 0);
|
||||
}
|
||||
else if(num == 1) {
|
||||
prim_index.push_back(ref[0].prim_index);
|
||||
prim_object.push_back(ref[0].prim_object);
|
||||
return new LeafNode(ref[0].bounds, prim_index.size()-1, prim_index.size());
|
||||
}
|
||||
else {
|
||||
int mid = num/2;
|
||||
BVHNode *leaf0 = create_object_leaf_nodes(ref, mid);
|
||||
BVHNode *leaf1 = create_object_leaf_nodes(ref+mid, num-mid);
|
||||
|
||||
BoundBox bounds;
|
||||
bounds.grow(leaf0->m_bounds);
|
||||
bounds.grow(leaf1->m_bounds);
|
||||
|
||||
return new InnerNode(bounds, leaf0, leaf1);
|
||||
}
|
||||
}
|
||||
|
||||
BVHNode* BVHBuild::create_leaf_node(const NodeSpec& spec)
|
||||
{
|
||||
vector<int>& p_index = prim_index;
|
||||
vector<int>& p_object = prim_object;
|
||||
BoundBox bounds;
|
||||
int num = 0;
|
||||
|
||||
for(int i = 0; i < spec.num; i++) {
|
||||
if(references.back().prim_index != -1) {
|
||||
p_index.push_back(references.back().prim_index);
|
||||
p_object.push_back(references.back().prim_object);
|
||||
bounds.grow(references.back().bounds);
|
||||
references.pop_back();
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
BVHNode *leaf = NULL;
|
||||
|
||||
if(num > 0) {
|
||||
leaf = new LeafNode(bounds, p_index.size() - num, p_index.size());
|
||||
|
||||
if(num == spec.num)
|
||||
return leaf;
|
||||
}
|
||||
|
||||
/* while there may be multiple triangles in a leaf, for object primitives
|
||||
* we want them to be the only one, so we */
|
||||
int ob_num = spec.num - num;
|
||||
BVHNode *oleaf = create_object_leaf_nodes(&references.back() - (ob_num - 1), ob_num);
|
||||
for(int i = 0; i < ob_num; i++)
|
||||
references.pop_back();
|
||||
|
||||
if(leaf)
|
||||
return new InnerNode(spec.bounds, leaf, oleaf);
|
||||
else
|
||||
return oleaf;
|
||||
}
|
||||
|
||||
/* Object Split */
|
||||
|
||||
BVHBuild::ObjectSplit BVHBuild::find_object_split(const NodeSpec& spec, float nodeSAH)
|
||||
{
|
||||
ObjectSplit split;
|
||||
const Reference *ref_ptr = &references[references.size() - spec.num];
|
||||
|
||||
for(int dim = 0; dim < 3; dim++) {
|
||||
/* sort references */
|
||||
bvh_reference_sort(references.size() - spec.num, references.size(), &references[0], dim);
|
||||
|
||||
/* sweep right to left and determine bounds. */
|
||||
BoundBox right_bounds;
|
||||
|
||||
for(int i = spec.num - 1; i > 0; i--) {
|
||||
right_bounds.grow(ref_ptr[i].bounds);
|
||||
spatial_right_bounds[i - 1] = right_bounds;
|
||||
}
|
||||
|
||||
/* sweep left to right and select lowest SAH. */
|
||||
BoundBox left_bounds;
|
||||
|
||||
for(int i = 1; i < spec.num; i++) {
|
||||
left_bounds.grow(ref_ptr[i - 1].bounds);
|
||||
right_bounds = spatial_right_bounds[i - 1];
|
||||
|
||||
float sah = nodeSAH +
|
||||
left_bounds.area() * params.triangle_cost(i) +
|
||||
right_bounds.area() * params.triangle_cost(spec.num - i);
|
||||
|
||||
if(sah < split.sah) {
|
||||
split.sah = sah;
|
||||
split.dim = dim;
|
||||
split.num_left = i;
|
||||
split.left_bounds = left_bounds;
|
||||
split.right_bounds = right_bounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return split;
|
||||
}
|
||||
|
||||
void BVHBuild::do_object_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const ObjectSplit& split)
|
||||
{
|
||||
/* sort references according to split */
|
||||
int start = references.size() - spec.num;
|
||||
int end = references.size(); /* todo: is this right? */
|
||||
|
||||
bvh_reference_sort(start, end, &references[0], split.dim);
|
||||
|
||||
/* split node specs */
|
||||
left.num = split.num_left;
|
||||
left.bounds = split.left_bounds;
|
||||
right.num = spec.num - split.num_left;
|
||||
right.bounds = split.right_bounds;
|
||||
}
|
||||
|
||||
/* Spatial Split */
|
||||
|
||||
BVHBuild::SpatialSplit BVHBuild::find_spatial_split(const NodeSpec& spec, float nodeSAH)
|
||||
{
|
||||
/* initialize bins. */
|
||||
float3 origin = spec.bounds.min;
|
||||
float3 binSize = (spec.bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
|
||||
float3 invBinSize = 1.0f / binSize;
|
||||
|
||||
for(int dim = 0; dim < 3; dim++) {
|
||||
for(int i = 0; i < BVHParams::NUM_SPATIAL_BINS; i++) {
|
||||
SpatialBin& bin = spatial_bins[dim][i];
|
||||
|
||||
bin.bounds = BoundBox();
|
||||
bin.enter = 0;
|
||||
bin.exit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* chop references into bins. */
|
||||
for(unsigned int refIdx = references.size() - spec.num; refIdx < references.size(); refIdx++) {
|
||||
const Reference& ref = references[refIdx];
|
||||
float3 firstBinf = (ref.bounds.min - origin) * invBinSize;
|
||||
float3 lastBinf = (ref.bounds.max - origin) * invBinSize;
|
||||
int3 firstBin = make_int3(firstBinf.x, firstBinf.y, firstBinf.z);
|
||||
int3 lastBin = make_int3(lastBinf.x, lastBinf.y, lastBinf.z);
|
||||
|
||||
firstBin = clamp(firstBin, 0, BVHParams::NUM_SPATIAL_BINS - 1);
|
||||
lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);
|
||||
|
||||
for(int dim = 0; dim < 3; dim++) {
|
||||
Reference currRef = ref;
|
||||
|
||||
for(int i = firstBin[dim]; i < lastBin[dim]; i++) {
|
||||
Reference leftRef, rightRef;
|
||||
|
||||
split_reference(leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (float)(i + 1));
|
||||
spatial_bins[dim][i].bounds.grow(leftRef.bounds);
|
||||
currRef = rightRef;
|
||||
}
|
||||
|
||||
spatial_bins[dim][lastBin[dim]].bounds.grow(currRef.bounds);
|
||||
spatial_bins[dim][firstBin[dim]].enter++;
|
||||
spatial_bins[dim][lastBin[dim]].exit++;
|
||||
}
|
||||
}
|
||||
|
||||
/* select best split plane. */
|
||||
SpatialSplit split;
|
||||
|
||||
for(int dim = 0; dim < 3; dim++) {
|
||||
/* sweep right to left and determine bounds. */
|
||||
BoundBox right_bounds;
|
||||
|
||||
for(int i = BVHParams::NUM_SPATIAL_BINS - 1; i > 0; i--) {
|
||||
right_bounds.grow(spatial_bins[dim][i].bounds);
|
||||
spatial_right_bounds[i - 1] = right_bounds;
|
||||
}
|
||||
|
||||
/* sweep left to right and select lowest SAH. */
|
||||
BoundBox left_bounds;
|
||||
int leftNum = 0;
|
||||
int rightNum = spec.num;
|
||||
|
||||
for(int i = 1; i < BVHParams::NUM_SPATIAL_BINS; i++) {
|
||||
left_bounds.grow(spatial_bins[dim][i - 1].bounds);
|
||||
leftNum += spatial_bins[dim][i - 1].enter;
|
||||
rightNum -= spatial_bins[dim][i - 1].exit;
|
||||
|
||||
float sah = nodeSAH +
|
||||
left_bounds.area() * params.triangle_cost(leftNum) +
|
||||
spatial_right_bounds[i - 1].area() * params.triangle_cost(rightNum);
|
||||
|
||||
if(sah < split.sah) {
|
||||
split.sah = sah;
|
||||
split.dim = dim;
|
||||
split.pos = origin[dim] + binSize[dim] * (float)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return split;
|
||||
}
|
||||
|
||||
void BVHBuild::do_spatial_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const SpatialSplit& split)
|
||||
{
|
||||
/* Categorize references and compute bounds.
|
||||
*
|
||||
* Left-hand side: [left_start, left_end[
|
||||
* Uncategorized/split: [left_end, right_start[
|
||||
* Right-hand side: [right_start, refs.size()[ */
|
||||
|
||||
vector<Reference>& refs = references;
|
||||
int left_start = refs.size() - spec.num;
|
||||
int left_end = left_start;
|
||||
int right_start = refs.size();
|
||||
|
||||
left.bounds = right.bounds = BoundBox();
|
||||
|
||||
for(int i = left_end; i < right_start; i++) {
|
||||
if(refs[i].bounds.max[split.dim] <= split.pos) {
|
||||
/* entirely on the left-hand side */
|
||||
left.bounds.grow(refs[i].bounds);
|
||||
swap(refs[i], refs[left_end++]);
|
||||
}
|
||||
else if(refs[i].bounds.min[split.dim] >= split.pos) {
|
||||
/* entirely on the right-hand side */
|
||||
right.bounds.grow(refs[i].bounds);
|
||||
swap(refs[i--], refs[--right_start]);
|
||||
}
|
||||
}
|
||||
|
||||
/* duplicate or unsplit references intersecting both sides. */
|
||||
while(left_end < right_start) {
|
||||
/* split reference. */
|
||||
Reference lref, rref;
|
||||
|
||||
split_reference(lref, rref, refs[left_end], split.dim, split.pos);
|
||||
|
||||
/* compute SAH for duplicate/unsplit candidates. */
|
||||
BoundBox lub = left.bounds; // Unsplit to left: new left-hand bounds.
|
||||
BoundBox rub = right.bounds; // Unsplit to right: new right-hand bounds.
|
||||
BoundBox ldb = left.bounds; // Duplicate: new left-hand bounds.
|
||||
BoundBox rdb = right.bounds; // Duplicate: new right-hand bounds.
|
||||
|
||||
lub.grow(refs[left_end].bounds);
|
||||
rub.grow(refs[left_end].bounds);
|
||||
ldb.grow(lref.bounds);
|
||||
rdb.grow(rref.bounds);
|
||||
|
||||
float lac = params.triangle_cost(left_end - left_start);
|
||||
float rac = params.triangle_cost(refs.size() - right_start);
|
||||
float lbc = params.triangle_cost(left_end - left_start + 1);
|
||||
float rbc = params.triangle_cost(refs.size() - right_start + 1);
|
||||
|
||||
float unsplitLeftSAH = lub.area() * lbc + right.bounds.area() * rac;
|
||||
float unsplitRightSAH = left.bounds.area() * lac + rub.area() * rbc;
|
||||
float duplicateSAH = ldb.area() * lbc + rdb.area() * rbc;
|
||||
float minSAH = min(min(unsplitLeftSAH, unsplitRightSAH), duplicateSAH);
|
||||
|
||||
if(minSAH == unsplitLeftSAH) {
|
||||
/* unsplit to left */
|
||||
left.bounds = lub;
|
||||
left_end++;
|
||||
}
|
||||
else if(minSAH == unsplitRightSAH) {
|
||||
/* unsplit to right */
|
||||
right.bounds = rub;
|
||||
swap(refs[left_end], refs[--right_start]);
|
||||
}
|
||||
else {
|
||||
/* duplicate */
|
||||
left.bounds = ldb;
|
||||
right.bounds = rdb;
|
||||
refs[left_end++] = lref;
|
||||
refs.push_back(rref);
|
||||
}
|
||||
}
|
||||
|
||||
left.num = left_end - left_start;
|
||||
right.num = refs.size() - right_start;
|
||||
}
|
||||
|
||||
void BVHBuild::split_reference(Reference& left, Reference& right, const Reference& ref, int dim, float pos)
|
||||
{
|
||||
/* initialize references. */
|
||||
left.prim_index = right.prim_index = ref.prim_index;
|
||||
left.prim_object = right.prim_object = ref.prim_object;
|
||||
left.bounds = right.bounds = BoundBox();
|
||||
|
||||
/* loop over vertices/edges. */
|
||||
Object *ob = objects[ref.prim_object];
|
||||
const Mesh *mesh = ob->mesh;
|
||||
const int *inds = mesh->triangles[ref.prim_index].v;
|
||||
const float3 *verts = &mesh->verts[0];
|
||||
const float3* v1 = &verts[inds[2]];
|
||||
|
||||
for(int i = 0; i < 3; i++) {
|
||||
const float3* v0 = v1;
|
||||
int vindex = inds[i];
|
||||
v1 = &verts[vindex];
|
||||
float v0p = (*v0)[dim];
|
||||
float v1p = (*v1)[dim];
|
||||
|
||||
/* insert vertex to the boxes it belongs to. */
|
||||
if(v0p <= pos)
|
||||
left.bounds.grow(*v0);
|
||||
|
||||
if(v0p >= pos)
|
||||
right.bounds.grow(*v0);
|
||||
|
||||
/* edge intersects the plane => insert intersection to both boxes. */
|
||||
if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
|
||||
float3 t = lerp(*v0, *v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
|
||||
left.bounds.grow(t);
|
||||
right.bounds.grow(t);
|
||||
}
|
||||
}
|
||||
|
||||
/* intersect with original bounds. */
|
||||
left.bounds.max[dim] = pos;
|
||||
right.bounds.min[dim] = pos;
|
||||
left.bounds.intersect(ref.bounds);
|
||||
right.bounds.intersect(ref.bounds);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
152
intern/cycles/bvh/bvh_build.h
Normal file
152
intern/cycles/bvh/bvh_build.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __BVH_BUILD_H__
|
||||
#define __BVH_BUILD_H__
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include "bvh.h"
|
||||
|
||||
#include "util_boundbox.h"
|
||||
#include "util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class BVHParams;
|
||||
class Mesh;
|
||||
class Object;
|
||||
class Progress;
|
||||
|
||||
/* BVH Builder */
|
||||
|
||||
class BVHBuild
|
||||
{
|
||||
public:
|
||||
struct Reference
|
||||
{
|
||||
int prim_index;
|
||||
int prim_object;
|
||||
BoundBox bounds;
|
||||
|
||||
Reference()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct NodeSpec
|
||||
{
|
||||
int num;
|
||||
BoundBox bounds;
|
||||
|
||||
NodeSpec()
|
||||
{
|
||||
num = 0;
|
||||
}
|
||||
};
|
||||
|
||||
BVHBuild(
|
||||
const vector<Object*>& objects,
|
||||
vector<int>& prim_index,
|
||||
vector<int>& prim_object,
|
||||
const BVHParams& params,
|
||||
Progress& progress);
|
||||
~BVHBuild();
|
||||
|
||||
BVHNode *run();
|
||||
|
||||
protected:
|
||||
/* adding references */
|
||||
void add_reference_mesh(NodeSpec& root, Mesh *mesh, int i);
|
||||
void add_reference_object(NodeSpec& root, Object *ob, int i);
|
||||
void add_references(NodeSpec& root);
|
||||
|
||||
/* building */
|
||||
BVHNode *build_node(const NodeSpec& spec, int level, float progress_start, float progress_end);
|
||||
BVHNode *create_leaf_node(const NodeSpec& spec);
|
||||
BVHNode *create_object_leaf_nodes(const Reference *ref, int num);
|
||||
|
||||
void progress_update(float progress_start, float progress_end);
|
||||
|
||||
/* object splits */
|
||||
struct ObjectSplit
|
||||
{
|
||||
float sah;
|
||||
int dim;
|
||||
int num_left;
|
||||
BoundBox left_bounds;
|
||||
BoundBox right_bounds;
|
||||
|
||||
ObjectSplit()
|
||||
: sah(FLT_MAX), dim(0), num_left(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
ObjectSplit find_object_split(const NodeSpec& spec, float nodeSAH);
|
||||
void do_object_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const ObjectSplit& split);
|
||||
|
||||
/* spatial splits */
|
||||
struct SpatialSplit
|
||||
{
|
||||
float sah;
|
||||
int dim;
|
||||
float pos;
|
||||
|
||||
SpatialSplit()
|
||||
: sah(FLT_MAX), dim(0), pos(0.0f)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct SpatialBin
|
||||
{
|
||||
BoundBox bounds;
|
||||
int enter;
|
||||
int exit;
|
||||
};
|
||||
|
||||
SpatialSplit find_spatial_split(const NodeSpec& spec, float nodeSAH);
|
||||
void do_spatial_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const SpatialSplit& split);
|
||||
void split_reference(Reference& left, Reference& right, const Reference& ref, int dim, float pos);
|
||||
|
||||
/* objects and primitive references */
|
||||
vector<Object*> objects;
|
||||
vector<Reference> references;
|
||||
|
||||
/* output primitive indexes and objects */
|
||||
vector<int>& prim_index;
|
||||
vector<int>& prim_object;
|
||||
|
||||
/* build parameters */
|
||||
BVHParams params;
|
||||
|
||||
/* progress reporting */
|
||||
Progress& progress;
|
||||
double progress_start_time;
|
||||
int progress_num_duplicates;
|
||||
|
||||
/* spatial splitting */
|
||||
float spatial_min_overlap;
|
||||
vector<BoundBox> spatial_right_bounds;
|
||||
SpatialBin spatial_bins[3][BVHParams::NUM_SPATIAL_BINS];
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __BVH_BUILD_H__ */
|
||||
|
101
intern/cycles/bvh/bvh_node.cpp
Normal file
101
intern/cycles/bvh/bvh_node.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bvh.h"
|
||||
#include "bvh_build.h"
|
||||
#include "bvh_node.h"
|
||||
|
||||
#include "util_debug.h"
|
||||
#include "util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
int BVHNode::getSubtreeSize(BVH_STAT stat) const
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
switch(stat)
|
||||
{
|
||||
case BVH_STAT_NODE_COUNT:
|
||||
cnt = 1;
|
||||
break;
|
||||
case BVH_STAT_LEAF_COUNT:
|
||||
cnt = is_leaf() ? 1 : 0;
|
||||
break;
|
||||
case BVH_STAT_INNER_COUNT:
|
||||
cnt = is_leaf() ? 0 : 1;
|
||||
break;
|
||||
case BVH_STAT_TRIANGLE_COUNT:
|
||||
cnt = is_leaf() ? reinterpret_cast<const LeafNode*>(this)->num_triangles() : 0;
|
||||
break;
|
||||
case BVH_STAT_CHILDNODE_COUNT:
|
||||
cnt = num_children();
|
||||
break;
|
||||
default:
|
||||
assert(0); /* unknown mode */
|
||||
}
|
||||
|
||||
if(!is_leaf())
|
||||
for(int i=0;i<num_children();i++)
|
||||
cnt += get_child(i)->getSubtreeSize(stat);
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void BVHNode::deleteSubtree()
|
||||
{
|
||||
for(int i=0;i<num_children();i++)
|
||||
get_child(i)->deleteSubtree();
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
float BVHNode::computeSubtreeSAHCost(const BVHParams& p, float probability) const
|
||||
{
|
||||
float SAH = probability * p.cost(num_children(), num_triangles());
|
||||
|
||||
for(int i=0;i<num_children();i++) {
|
||||
BVHNode *child = get_child(i);
|
||||
SAH += child->computeSubtreeSAHCost(p, probability * child->m_bounds.area()/m_bounds.area());
|
||||
}
|
||||
|
||||
return SAH;
|
||||
}
|
||||
|
||||
void InnerNode::print(int depth) const
|
||||
{
|
||||
for(int i = 0; i < depth; i++)
|
||||
printf(" ");
|
||||
|
||||
printf("inner node %p\n", (void*)this);
|
||||
|
||||
if(children[0])
|
||||
children[0]->print(depth+1);
|
||||
if(children[1])
|
||||
children[1]->print(depth+1);
|
||||
}
|
||||
|
||||
void LeafNode::print(int depth) const
|
||||
{
|
||||
for(int i = 0; i < depth; i++)
|
||||
printf(" ");
|
||||
|
||||
printf("leaf node %d to %d\n", m_lo, m_hi);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
108
intern/cycles/bvh/bvh_node.h
Normal file
108
intern/cycles/bvh/bvh_node.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __BVH_NODE_H__
|
||||
#define __BVH_NODE_H__
|
||||
|
||||
#include "util_boundbox.h"
|
||||
#include "util_debug.h"
|
||||
#include "util_types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
enum BVH_STAT
|
||||
{
|
||||
BVH_STAT_NODE_COUNT,
|
||||
BVH_STAT_INNER_COUNT,
|
||||
BVH_STAT_LEAF_COUNT,
|
||||
BVH_STAT_TRIANGLE_COUNT,
|
||||
BVH_STAT_CHILDNODE_COUNT
|
||||
};
|
||||
|
||||
class BVHParams;
|
||||
|
||||
class BVHNode
|
||||
{
|
||||
public:
|
||||
BVHNode()
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool is_leaf() const = 0;
|
||||
virtual int num_children() const = 0;
|
||||
virtual BVHNode *get_child(int i) const = 0;
|
||||
virtual int num_triangles() const { return 0; }
|
||||
virtual void print(int depth = 0) const = 0;
|
||||
|
||||
float getArea() const { return m_bounds.area(); }
|
||||
|
||||
BoundBox m_bounds;
|
||||
|
||||
// Subtree functions
|
||||
int getSubtreeSize(BVH_STAT stat=BVH_STAT_NODE_COUNT) const;
|
||||
float computeSubtreeSAHCost(const BVHParams& p, float probability = 1.0f) const;
|
||||
void deleteSubtree();
|
||||
};
|
||||
|
||||
class InnerNode : public BVHNode
|
||||
{
|
||||
public:
|
||||
InnerNode(const BoundBox& bounds, BVHNode* child0, BVHNode* child1)
|
||||
{
|
||||
m_bounds = bounds;
|
||||
children[0] = child0;
|
||||
children[1] = child1;
|
||||
}
|
||||
|
||||
bool is_leaf() const { return false; }
|
||||
int num_children() const { return 2; }
|
||||
BVHNode *get_child(int i) const{ assert(i>=0 && i<2); return children[i]; }
|
||||
void print(int depth) const;
|
||||
|
||||
BVHNode *children[2];
|
||||
};
|
||||
|
||||
class LeafNode : public BVHNode
|
||||
{
|
||||
public:
|
||||
LeafNode(const BoundBox& bounds, int lo, int hi)
|
||||
{
|
||||
m_bounds = bounds;
|
||||
m_lo = lo;
|
||||
m_hi = hi;
|
||||
}
|
||||
|
||||
LeafNode(const LeafNode& s)
|
||||
: BVHNode()
|
||||
{
|
||||
*this = s;
|
||||
}
|
||||
|
||||
bool is_leaf() const { return true; }
|
||||
int num_children() const { return 0; }
|
||||
BVHNode *get_child(int) const { return NULL; }
|
||||
int num_triangles() const { return m_hi - m_lo; }
|
||||
void print(int depth) const;
|
||||
|
||||
int m_lo;
|
||||
int m_hi;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __BVH_NODE_H__ */
|
||||
|
86
intern/cycles/bvh/bvh_params.h
Normal file
86
intern/cycles/bvh/bvh_params.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __BVH_PARAMS_H__
|
||||
#define __BVH_PARAMS_H__
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* BVH Parameters */
|
||||
|
||||
class BVHParams
|
||||
{
|
||||
public:
|
||||
/* spatial split area threshold */
|
||||
bool use_spatial_split;
|
||||
float spatial_split_alpha;
|
||||
|
||||
/* SAH costs */
|
||||
float sah_node_cost;
|
||||
float sah_triangle_cost;
|
||||
|
||||
/* number of triangles in leaf */
|
||||
int min_leaf_size;
|
||||
int max_leaf_size;
|
||||
|
||||
/* object or mesh level bvh */
|
||||
bool top_level;
|
||||
|
||||
/* disk cache */
|
||||
bool use_cache;
|
||||
|
||||
/* QBVH */
|
||||
bool use_qbvh;
|
||||
|
||||
/* fixed parameters */
|
||||
enum {
|
||||
MAX_DEPTH = 64,
|
||||
MAX_SPATIAL_DEPTH = 48,
|
||||
NUM_SPATIAL_BINS = 32
|
||||
};
|
||||
|
||||
BVHParams()
|
||||
{
|
||||
use_spatial_split = true;
|
||||
spatial_split_alpha = 1e-5f;
|
||||
|
||||
sah_node_cost = 1.0f;
|
||||
sah_triangle_cost = 1.0f;
|
||||
|
||||
min_leaf_size = 1;
|
||||
max_leaf_size = 0x7FFFFFF;
|
||||
|
||||
top_level = false;
|
||||
use_cache = false;
|
||||
use_qbvh = false;
|
||||
}
|
||||
|
||||
/* SAH costs */
|
||||
float cost(int num_nodes, int num_tris) const
|
||||
{ return node_cost(num_nodes) + triangle_cost(num_tris); }
|
||||
|
||||
float triangle_cost(int n) const
|
||||
{ return n*sah_triangle_cost; }
|
||||
|
||||
float node_cost(int n) const
|
||||
{ return n*sah_node_cost; }
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __BVH_PARAMS_H__ */
|
||||
|
57
intern/cycles/bvh/bvh_sort.cpp
Normal file
57
intern/cycles/bvh/bvh_sort.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bvh_build.h"
|
||||
#include "bvh_sort.h"
|
||||
|
||||
#include "util_algorithm.h"
|
||||
#include "util_debug.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
struct BVHReferenceCompare {
|
||||
public:
|
||||
int dim;
|
||||
|
||||
BVHReferenceCompare(int dim_)
|
||||
{
|
||||
dim = dim_;
|
||||
}
|
||||
|
||||
bool operator()(const BVHBuild::Reference& ra, const BVHBuild::Reference& rb)
|
||||
{
|
||||
float ca = ra.bounds.min[dim] + ra.bounds.max[dim];
|
||||
float cb = rb.bounds.min[dim] + rb.bounds.max[dim];
|
||||
|
||||
if(ca < cb) return true;
|
||||
else if(ca > cb) return false;
|
||||
else if(ra.prim_object < rb.prim_object) return true;
|
||||
else if(ra.prim_object > rb.prim_object) return false;
|
||||
else if(ra.prim_index < rb.prim_index) return true;
|
||||
else if(ra.prim_index > rb.prim_index) return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void bvh_reference_sort(int start, int end, BVHBuild::Reference *data, int dim)
|
||||
{
|
||||
sort(data+start, data+end, BVHReferenceCompare(dim));
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
28
intern/cycles/bvh/bvh_sort.h
Normal file
28
intern/cycles/bvh/bvh_sort.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Adapted from code copyright 2009-2010 NVIDIA Corporation
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __BVH_SORT_H__
|
||||
#define __BVH_SORT_H__
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
void bvh_reference_sort(int start, int end, BVHBuild::Reference *data, int dim);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __BVH_SORT_H__ */
|
||||
|
14
intern/cycles/cmake/create_dmg.py
Executable file
14
intern/cycles/cmake/create_dmg.py
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import os
|
||||
import string
|
||||
import sys
|
||||
|
||||
name = string.replace(sys.argv[1], ".zip", "")
|
||||
|
||||
os.system("rm -f %s.dmg" % (name))
|
||||
os.system("mkdir -p /tmp/cycles_dmg")
|
||||
os.system("rm /tmp/cycles_dmg/*")
|
||||
os.system("cp %s.zip /tmp/cycles_dmg/" % (name))
|
||||
os.system("/usr/bin/hdiutil create -fs HFS+ -srcfolder /tmp/cycles_dmg -volname %s %s.dmg" % (name, name))
|
||||
|
210
intern/cycles/cmake/external_libs.cmake
Normal file
210
intern/cycles/cmake/external_libs.cmake
Normal file
@ -0,0 +1,210 @@
|
||||
###########################################################################
|
||||
# Boost setup
|
||||
|
||||
MESSAGE(STATUS "BOOST_PATH ${BOOST_PATH}")
|
||||
SET(BOOST_ROOT ${BOOST_PATH})
|
||||
|
||||
SET(Boost_ADDITIONAL_VERSIONS "1.45" "1.44"
|
||||
"1.43" "1.43.0" "1.42" "1.42.0"
|
||||
"1.41" "1.41.0" "1.40" "1.40.0"
|
||||
"1.39" "1.39.0" "1.38" "1.38.0"
|
||||
"1.37" "1.37.0" "1.34.1" "1_34_1")
|
||||
IF(LINKSTATIC)
|
||||
SET(Boost_USE_STATIC_LIBS ON)
|
||||
ENDIF()
|
||||
|
||||
SET(Boost_USE_MULTITHREADED ON)
|
||||
|
||||
FIND_PACKAGE(Boost 1.34 REQUIRED COMPONENTS filesystem regex system serialization thread)
|
||||
|
||||
MESSAGE(STATUS "Boost found ${Boost_FOUND}")
|
||||
MESSAGE(STATUS "Boost version ${Boost_VERSION}")
|
||||
MESSAGE(STATUS "Boost include dirs ${Boost_INCLUDE_DIRS}")
|
||||
MESSAGE(STATUS "Boost library dirs ${Boost_LIBRARY_DIRS}")
|
||||
MESSAGE(STATUS "Boost libraries ${Boost_LIBRARIES}")
|
||||
|
||||
INCLUDE_DIRECTORIES("${Boost_INCLUDE_DIRS}")
|
||||
LINK_DIRECTORIES("${Boost_LIBRARY_DIRS}")
|
||||
|
||||
IF(WITH_NETWORK)
|
||||
ADD_DEFINITIONS(-DWITH_NETWORK)
|
||||
ENDIF()
|
||||
|
||||
IF(WITH_MULTI)
|
||||
ADD_DEFINITIONS(-DWITH_MULTI)
|
||||
ENDIF()
|
||||
|
||||
###########################################################################
|
||||
# OpenImageIO
|
||||
|
||||
MESSAGE(STATUS "OIIO_PATH = ${OIIO_PATH}")
|
||||
|
||||
FIND_LIBRARY(OPENIMAGEIO_LIBRARY NAMES OpenImageIO PATHS ${OIIO_PATH}/lib)
|
||||
FIND_PATH(OPENIMAGEIO_INCLUDES OpenImageIO/imageio.h ${OIIO_PATH}/include)
|
||||
FIND_PROGRAM(OPENIMAGEIO_IDIFF NAMES idiff PATHS ${OIIO_PATH}/bin)
|
||||
|
||||
IF(OPENIMAGEIO_INCLUDES AND OPENIMAGEIO_LIBRARY)
|
||||
SET(OPENIMAGEIO_FOUND TRUE)
|
||||
MESSAGE(STATUS "OpenImageIO includes = ${OPENIMAGEIO_INCLUDES}")
|
||||
MESSAGE(STATUS "OpenImageIO library = ${OPENIMAGEIO_LIBRARY}")
|
||||
ELSE()
|
||||
MESSAGE(STATUS "OpenImageIO not found")
|
||||
ENDIF()
|
||||
|
||||
ADD_DEFINITIONS(-DWITH_OIIO)
|
||||
INCLUDE_DIRECTORIES(${OPENIMAGEIO_INCLUDES} ${OPENIMAGEIO_INCLUDES}/OpenImageIO)
|
||||
|
||||
###########################################################################
|
||||
# OpenGL
|
||||
|
||||
FIND_PACKAGE(OpenGL)
|
||||
MESSAGE(STATUS "OPENGL_FOUND=${OPENGL_FOUND}")
|
||||
|
||||
INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR})
|
||||
|
||||
###########################################################################
|
||||
# GLUT
|
||||
|
||||
SET(GLUT_ROOT_PATH ${GLUT_PATH})
|
||||
|
||||
FIND_PACKAGE(GLUT)
|
||||
MESSAGE(STATUS "GLUT_FOUND=${GLUT_FOUND}")
|
||||
|
||||
INCLUDE_DIRECTORIES(${GLUT_INCLUDE_DIR})
|
||||
|
||||
###########################################################################
|
||||
# GLEW
|
||||
|
||||
SET(GLEW_VERSION 1.5.1)
|
||||
FIND_LIBRARY(GLEW_LIBRARIES NAMES GLEW PATHS ${GLEW_PATH}/lib)
|
||||
FIND_PATH(GLEW_INCLUDES NAMES glew.h PATH_SUFFIXES GL PATHS ${GLEW_PATH}/include)
|
||||
|
||||
IF(GLEW_INCLUDES AND GLEW_LIBRARIES)
|
||||
MESSAGE(STATUS "GLEW includes = ${GLEW_INCLUDES}")
|
||||
MESSAGE(STATUS "GLEW library = ${GLEW_LIBRARIES}")
|
||||
ELSE()
|
||||
MESSAGE(STATUS "GLEW not found")
|
||||
ENDIF()
|
||||
|
||||
INCLUDE_DIRECTORIES("${GLEW_INCLUDES}")
|
||||
|
||||
###########################################################################
|
||||
# OpenShadingLanguage
|
||||
|
||||
IF(WITH_OSL)
|
||||
|
||||
MESSAGE(STATUS "OSL_PATH = ${OSL_PATH}")
|
||||
|
||||
FIND_LIBRARY(OSL_LIBRARIES NAMES oslexec oslcomp oslquery PATHS ${OSL_PATH}/lib)
|
||||
FIND_PATH(OSL_INCLUDES OSL/oslclosure.h ${OSL_PATH}/include)
|
||||
FIND_PROGRAM(OSL_COMPILER NAMES oslc PATHS ${OSL_PATH}/bin)
|
||||
|
||||
IF(OSL_INCLUDES AND OSL_LIBRARIES AND OSL_COMPILER)
|
||||
SET(OSL_FOUND TRUE)
|
||||
MESSAGE(STATUS "OSL includes = ${OSL_INCLUDES}")
|
||||
MESSAGE(STATUS "OSL library = ${OSL_LIBRARIES}")
|
||||
MESSAGE(STATUS "OSL compiler = ${OSL_COMPILER}")
|
||||
ELSE()
|
||||
MESSAGE(STATUS "OSL not found")
|
||||
ENDIF()
|
||||
|
||||
ADD_DEFINITIONS(-DWITH_OSL)
|
||||
INCLUDE_DIRECTORIES(${OSL_INCLUDES} ${OSL_INCLUDES}/OSL ${OSL_INCLUDES}/../../../src/liboslexec)
|
||||
|
||||
ENDIF()
|
||||
|
||||
###########################################################################
|
||||
# Partio
|
||||
|
||||
IF(WITH_PARTIO)
|
||||
|
||||
MESSAGE(STATUS "PARTIO_PATH = ${PARTIO_PATH}")
|
||||
|
||||
FIND_LIBRARY(PARTIO_LIBRARIES NAMES partio PATHS ${PARTIO_PATH}/lib)
|
||||
FIND_PATH(PARTIO_INCLUDES Partio.h ${PARTIO_PATH}/include)
|
||||
|
||||
FIND_PACKAGE(ZLIB)
|
||||
|
||||
IF(PARTIO_INCLUDES AND PARTIO_LIBRARIES AND ZLIB_LIBRARIES)
|
||||
LIST(APPEND PARTIO_LIBRARIES ${ZLIB_LIBRARIES})
|
||||
SET(PARTIO_FOUND TRUE)
|
||||
MESSAGE(STATUS "PARTIO includes = ${PARTIO_INCLUDES}")
|
||||
MESSAGE(STATUS "PARTIO library = ${PARTIO_LIBRARIES}")
|
||||
ELSE()
|
||||
MESSAGE(STATUS "PARTIO not found")
|
||||
ENDIF()
|
||||
|
||||
ADD_DEFINITIONS(-DWITH_PARTIO)
|
||||
INCLUDE_DIRECTORIES(${PARTIO_INCLUDES})
|
||||
|
||||
ENDIF()
|
||||
|
||||
###########################################################################
|
||||
# Python
|
||||
|
||||
IF(WITH_BLENDER)
|
||||
|
||||
FIND_PATH(PYTHON_INCLUDE_DIRS Python.h PATHS ${PYTHON_PATH} ${PYTHON_PATH}/include ${PYTHON_PATH}/include/python3.1 ${PYTHON_PATH}/include/python3.2 NO_DEFAULT_PATH)
|
||||
IF(WIN32)
|
||||
FIND_LIBRARY(PYTHON_LIBRARIES NAMES python31 PATHS ${PYTHON_PATH}/lib)
|
||||
ENDIF()
|
||||
|
||||
ENDIF()
|
||||
|
||||
###########################################################################
|
||||
# Blender
|
||||
|
||||
IF(WITH_BLENDER)
|
||||
FIND_PATH(BLENDER_INCLUDE_DIRS RNA_blender.h PATHS ${BLENDER_PATH}/include)
|
||||
IF(WIN32)
|
||||
SET(BLENDER_LIBRARIES ${BLENDER_PATH}/bin/Release/blender.lib)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
###########################################################################
|
||||
# CUDA
|
||||
|
||||
IF(WITH_CUDA)
|
||||
|
||||
FIND_LIBRARY(CUDA_LIBRARIES NAMES cuda PATHS ${CUDA_PATH}/lib ${CUDA_PATH}/lib/Win32 NO_DEFAULT_PATH)
|
||||
FIND_PATH(CUDA_INCLUDES cuda.h ${CUDA_PATH}/include NO_DEFAULT_PATH)
|
||||
FIND_PROGRAM(CUDA_NVCC NAMES nvcc PATHS ${CUDA_PATH}/bin NO_DEFAULT_PATH)
|
||||
|
||||
IF(CUDA_INCLUDES AND CUDA_LIBRARIES AND CUDA_NVCC)
|
||||
MESSAGE(STATUS "CUDA includes = ${CUDA_INCLUDES}")
|
||||
MESSAGE(STATUS "CUDA library = ${CUDA_LIBRARIES}")
|
||||
MESSAGE(STATUS "CUDA nvcc = ${CUDA_NVCC}")
|
||||
ELSE()
|
||||
MESSAGE(STATUS "CUDA not found")
|
||||
ENDIF()
|
||||
|
||||
ADD_DEFINITIONS(-DWITH_CUDA)
|
||||
INCLUDE_DIRECTORIES(${CUDA_INCLUDES})
|
||||
|
||||
ENDIF()
|
||||
|
||||
###########################################################################
|
||||
# OpenCL
|
||||
|
||||
IF(WITH_OPENCL)
|
||||
|
||||
IF(APPLE)
|
||||
SET(OPENCL_INCLUDES "/System/Library/Frameworks/OpenCL.framework/Headers")
|
||||
SET(OPENCL_LIBRARIES "-framework OpenCL")
|
||||
ENDIF()
|
||||
|
||||
IF(WIN32)
|
||||
SET(OPENCL_INCLUDES "")
|
||||
SET(OPENCL_LIRBARIES "OpenCL")
|
||||
ENDIF()
|
||||
|
||||
IF(UNIX AND NOT APPLE)
|
||||
SET(OPENCL_INCLUDES ${OPENCL_PATH})
|
||||
SET(OPENCL_LIRBARIES "OpenCL")
|
||||
ENDIF()
|
||||
|
||||
ADD_DEFINITIONS(-DWITH_OPENCL)
|
||||
INCLUDE_DIRECTORIES(${OPENCL_INCLUDES})
|
||||
|
||||
ENDIF()
|
||||
|
27
intern/cycles/cmake/platforms.cmake
Normal file
27
intern/cycles/cmake/platforms.cmake
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
# Platform specific build flags
|
||||
|
||||
SET(GCC_WARNING_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-long-long") # -pedantic
|
||||
SET(GCC_OPTIM_FLAGS "-ffast-math -fPIC -msse -msse2 -msse3 -mtune=native")
|
||||
|
||||
IF(APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${GCC_WARNING_FLAGS} ${GCC_OPTIM_FLAGS}")
|
||||
SET(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
|
||||
SET(PYTHON_MODULE_FLAGS "-undefined dynamic_lookup")
|
||||
ENDIF(APPLE)
|
||||
|
||||
IF(WIN32)
|
||||
SET(CMAKE_CXX_FLAGS "-D_CRT_SECURE_NO_WARNINGS /EHsc /fp:fast")
|
||||
SET(RTTI_DISABLE_FLAGS "/GR- -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
|
||||
SET(PYTHON_MODULE_FLAGS "-DLL")
|
||||
ENDIF(WIN32)
|
||||
|
||||
IF(UNIX AND NOT APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${GCC_WARNING_FLAGS} ${GCC_OPTIM_FLAGS}")
|
||||
SET(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
|
||||
SET(PYTHON_MODULE_FLAGS "-fPIC")
|
||||
ENDIF(UNIX AND NOT APPLE)
|
||||
|
||||
ADD_DEFINITIONS(-DCCL_NAMESPACE_BEGIN=namespace\ ccl\ {)
|
||||
ADD_DEFINITIONS(-DCCL_NAMESPACE_END=})
|
||||
|
18
intern/cycles/device/CMakeLists.txt
Normal file
18
intern/cycles/device/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
INCLUDE_DIRECTORIES(. ../kernel ../kernel/svm ../kernel/osl ../util ../render)
|
||||
|
||||
SET(sources
|
||||
device.cpp
|
||||
device_cpu.cpp
|
||||
device_cuda.cpp
|
||||
device_multi.cpp
|
||||
device_network.cpp
|
||||
device_opencl.cpp)
|
||||
|
||||
SET(headers
|
||||
device.h
|
||||
device_intern.h
|
||||
device_network.h)
|
||||
|
||||
ADD_LIBRARY(device ${sources} ${headers})
|
||||
|
198
intern/cycles/device/device.cpp
Normal file
198
intern/cycles/device/device.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "device_intern.h"
|
||||
|
||||
#include "util_cuda.h"
|
||||
#include "util_debug.h"
|
||||
#include "util_opengl.h"
|
||||
#include "util_types.h"
|
||||
#include "util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Device Task */
|
||||
|
||||
DeviceTask::DeviceTask(Type type_)
|
||||
: type(type_), x(0), y(0), w(0), h(0), rng_state(0), rgba(0), buffer(0),
|
||||
pass(0), resolution(0),
|
||||
displace_input(0), displace_offset(0), displace_x(0), displace_w(0)
|
||||
{
|
||||
}
|
||||
|
||||
void DeviceTask::split(ThreadQueue<DeviceTask>& tasks, int num)
|
||||
{
|
||||
if(type == DISPLACE) {
|
||||
for(int i = 0; i < num; i++) {
|
||||
int tx = displace_x + (displace_w/num)*i;
|
||||
int tw = (i == num-1)? displace_w - i*(displace_w/num): displace_w/num;
|
||||
|
||||
DeviceTask task = *this;
|
||||
|
||||
task.displace_x = tx;
|
||||
task.displace_w = tw;
|
||||
|
||||
tasks.push(task);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(int i = 0; i < num; i++) {
|
||||
int ty = y + (h/num)*i;
|
||||
int th = (i == num-1)? h - i*(h/num): h/num;
|
||||
|
||||
DeviceTask task = *this;
|
||||
|
||||
task.y = ty;
|
||||
task.h = th;
|
||||
|
||||
tasks.push(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Device */
|
||||
|
||||
void Device::pixels_alloc(device_memory& mem)
|
||||
{
|
||||
mem_alloc(mem, MEM_READ_WRITE);
|
||||
}
|
||||
|
||||
void Device::pixels_copy_from(device_memory& mem, int y, int w, int h)
|
||||
{
|
||||
mem_copy_from(mem, sizeof(uchar)*4*y*w, sizeof(uchar)*4*w*h);
|
||||
}
|
||||
|
||||
void Device::pixels_free(device_memory& mem)
|
||||
{
|
||||
mem_free(mem);
|
||||
}
|
||||
|
||||
void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int width, int height)
|
||||
{
|
||||
pixels_copy_from(rgba, y, w, h);
|
||||
|
||||
glPixelZoom((float)width/(float)w, (float)height/(float)h);
|
||||
glRasterPos2f(0, y);
|
||||
|
||||
glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)rgba.data_pointer);
|
||||
|
||||
glRasterPos2f(0.0f, 0.0f);
|
||||
glPixelZoom(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
Device *Device::create(DeviceType type, bool background)
|
||||
{
|
||||
Device *device;
|
||||
|
||||
switch(type) {
|
||||
case DEVICE_CPU:
|
||||
device = device_cpu_create();
|
||||
break;
|
||||
#ifdef WITH_CUDA
|
||||
case DEVICE_CUDA:
|
||||
if(cuLibraryInit())
|
||||
device = device_cuda_create(background);
|
||||
else
|
||||
device = NULL;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WITH_MULTI
|
||||
case DEVICE_MULTI:
|
||||
device = device_multi_create(background);
|
||||
break;
|
||||
#endif
|
||||
#ifdef WITH_NETWORK
|
||||
case DEVICE_NETWORK:
|
||||
device = device_network_create("127.0.0.1");
|
||||
break;
|
||||
#endif
|
||||
#ifdef WITH_OPENCL
|
||||
case DEVICE_OPENCL:
|
||||
device = device_opencl_create(background);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
DeviceType Device::type_from_string(const char *name)
|
||||
{
|
||||
if(strcmp(name, "cpu") == 0)
|
||||
return DEVICE_CPU;
|
||||
else if(strcmp(name, "cuda") == 0)
|
||||
return DEVICE_CUDA;
|
||||
else if(strcmp(name, "opencl") == 0)
|
||||
return DEVICE_OPENCL;
|
||||
else if(strcmp(name, "network") == 0)
|
||||
return DEVICE_NETWORK;
|
||||
else if(strcmp(name, "multi") == 0)
|
||||
return DEVICE_MULTI;
|
||||
|
||||
return DEVICE_NONE;
|
||||
}
|
||||
|
||||
string Device::string_from_type(DeviceType type)
|
||||
{
|
||||
if(type == DEVICE_CPU)
|
||||
return "cpu";
|
||||
else if(type == DEVICE_CUDA)
|
||||
return "cuda";
|
||||
else if(type == DEVICE_OPENCL)
|
||||
return "opencl";
|
||||
else if(type == DEVICE_NETWORK)
|
||||
return "network";
|
||||
else if(type == DEVICE_MULTI)
|
||||
return "multi";
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
vector<DeviceType> Device::available_types()
|
||||
{
|
||||
vector<DeviceType> types;
|
||||
|
||||
types.push_back(DEVICE_CPU);
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
if(cuLibraryInit())
|
||||
types.push_back(DEVICE_CUDA);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENCL
|
||||
types.push_back(DEVICE_OPENCL);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_NETWORK
|
||||
types.push_back(DEVICE_NETWORK);
|
||||
#endif
|
||||
#ifdef WITH_MULTI
|
||||
types.push_back(DEVICE_MULTI);
|
||||
#endif
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
136
intern/cycles/device/device.h
Normal file
136
intern/cycles/device/device.h
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __DEVICE_H__
|
||||
#define __DEVICE_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "device_memory.h"
|
||||
|
||||
#include "util_string.h"
|
||||
#include "util_thread.h"
|
||||
#include "util_types.h"
|
||||
#include "util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Progress;
|
||||
|
||||
enum DeviceType {
|
||||
DEVICE_NONE,
|
||||
DEVICE_CPU,
|
||||
DEVICE_OPENCL,
|
||||
DEVICE_CUDA,
|
||||
DEVICE_NETWORK,
|
||||
DEVICE_MULTI
|
||||
};
|
||||
|
||||
enum MemoryType {
|
||||
MEM_READ_ONLY,
|
||||
MEM_WRITE_ONLY,
|
||||
MEM_READ_WRITE
|
||||
};
|
||||
|
||||
/* Device Task */
|
||||
|
||||
class DeviceTask {
|
||||
public:
|
||||
typedef enum { PATH_TRACE, TONEMAP, DISPLACE } Type;
|
||||
Type type;
|
||||
|
||||
int x, y, w, h;
|
||||
device_ptr rng_state;
|
||||
device_ptr rgba;
|
||||
device_ptr buffer;
|
||||
int pass;
|
||||
int resolution;
|
||||
|
||||
device_ptr displace_input;
|
||||
device_ptr displace_offset;
|
||||
int displace_x, displace_w;
|
||||
|
||||
DeviceTask(Type type = PATH_TRACE);
|
||||
void split(ThreadQueue<DeviceTask>& tasks, int num);
|
||||
};
|
||||
|
||||
/* Device */
|
||||
|
||||
class Device {
|
||||
protected:
|
||||
Device() {}
|
||||
|
||||
DeviceType type;
|
||||
bool background;
|
||||
|
||||
public:
|
||||
virtual ~Device() {}
|
||||
|
||||
/* info */
|
||||
virtual string description() = 0;
|
||||
|
||||
/* regular memory */
|
||||
virtual void mem_alloc(device_memory& mem, MemoryType type) = 0;
|
||||
virtual void mem_copy_to(device_memory& mem) = 0;
|
||||
virtual void mem_copy_from(device_memory& mem,
|
||||
size_t offset, size_t size) = 0;
|
||||
virtual void mem_zero(device_memory& mem) = 0;
|
||||
virtual void mem_free(device_memory& mem) = 0;
|
||||
|
||||
/* constant memory */
|
||||
virtual void const_copy_to(const char *name, void *host, size_t size) = 0;
|
||||
|
||||
/* texture memory */
|
||||
virtual void tex_alloc(const char *name, device_memory& mem,
|
||||
bool interpolation = false, bool periodic = false) {};
|
||||
virtual void tex_free(device_memory& mem) {};
|
||||
|
||||
/* pixel memory */
|
||||
virtual void pixels_alloc(device_memory& mem);
|
||||
virtual void pixels_copy_from(device_memory& mem, int y, int w, int h);
|
||||
virtual void pixels_free(device_memory& mem);
|
||||
|
||||
/* open shading language, only for CPU device */
|
||||
virtual void *osl_memory() { return NULL; }
|
||||
|
||||
/* tasks */
|
||||
virtual void task_add(DeviceTask& task) = 0;
|
||||
virtual void task_wait() = 0;
|
||||
virtual void task_cancel() = 0;
|
||||
|
||||
/* opengl drawing */
|
||||
virtual void draw_pixels(device_memory& mem, int y, int w, int h,
|
||||
int width, int height);
|
||||
|
||||
#ifdef WITH_NETWORK
|
||||
/* networking */
|
||||
void server_run();
|
||||
#endif
|
||||
|
||||
/* static */
|
||||
static Device *create(DeviceType type, bool background = true);
|
||||
|
||||
static DeviceType type_from_string(const char *name);
|
||||
static string string_from_type(DeviceType type);
|
||||
static vector<DeviceType> available_types();
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __DEVICE_H__ */
|
||||
|
216
intern/cycles/device/device_cpu.cpp
Normal file
216
intern/cycles/device/device_cpu.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "device_intern.h"
|
||||
|
||||
#include "kernel.h"
|
||||
#include "kernel_types.h"
|
||||
|
||||
#include "osl_shader.h"
|
||||
|
||||
#include "util_debug.h"
|
||||
#include "util_foreach.h"
|
||||
#include "util_function.h"
|
||||
#include "util_opengl.h"
|
||||
#include "util_progress.h"
|
||||
#include "util_system.h"
|
||||
#include "util_thread.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class CPUDevice : public Device
|
||||
{
|
||||
public:
|
||||
vector<thread*> threads;
|
||||
ThreadQueue<DeviceTask> tasks;
|
||||
KernelGlobals *kg;
|
||||
|
||||
CPUDevice()
|
||||
{
|
||||
kg = kernel_globals_create();
|
||||
threads.resize(system_cpu_thread_count());
|
||||
|
||||
for(size_t i = 0; i < threads.size(); i++)
|
||||
threads[i] = new thread(function_bind(&CPUDevice::thread_run, this, i));
|
||||
}
|
||||
|
||||
~CPUDevice()
|
||||
{
|
||||
tasks.stop();
|
||||
|
||||
foreach(thread *t, threads) {
|
||||
t->join();
|
||||
delete t;
|
||||
}
|
||||
|
||||
kernel_globals_free(kg);
|
||||
}
|
||||
|
||||
string description()
|
||||
{
|
||||
return system_cpu_brand_string();
|
||||
}
|
||||
|
||||
void mem_alloc(device_memory& mem, MemoryType type)
|
||||
{
|
||||
mem.device_pointer = mem.data_pointer;
|
||||
}
|
||||
|
||||
void mem_copy_to(device_memory& mem)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
void mem_zero(device_memory& mem)
|
||||
{
|
||||
memset((void*)mem.device_pointer, 0, mem.memory_size());
|
||||
}
|
||||
|
||||
void mem_free(device_memory& mem)
|
||||
{
|
||||
mem.device_pointer = 0;
|
||||
}
|
||||
|
||||
void const_copy_to(const char *name, void *host, size_t size)
|
||||
{
|
||||
kernel_const_copy(kg, name, host, size);
|
||||
}
|
||||
|
||||
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
|
||||
{
|
||||
kernel_tex_copy(kg, name, mem.data_pointer, mem.data_width, mem.data_height);
|
||||
mem.device_pointer = mem.data_pointer;
|
||||
}
|
||||
|
||||
void tex_free(device_memory& mem)
|
||||
{
|
||||
mem.device_pointer = 0;
|
||||
}
|
||||
|
||||
void *osl_memory()
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
return kernel_osl_memory(kg);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void thread_run(int t)
|
||||
{
|
||||
DeviceTask task;
|
||||
|
||||
while(tasks.worker_wait_pop(task)) {
|
||||
if(task.type == DeviceTask::PATH_TRACE)
|
||||
thread_path_trace(task);
|
||||
else if(task.type == DeviceTask::TONEMAP)
|
||||
thread_tonemap(task);
|
||||
else if(task.type == DeviceTask::DISPLACE)
|
||||
thread_displace(task);
|
||||
|
||||
tasks.worker_done();
|
||||
}
|
||||
}
|
||||
|
||||
void thread_path_trace(DeviceTask& task)
|
||||
{
|
||||
if(tasks.worker_cancel())
|
||||
return;
|
||||
|
||||
#ifdef WITH_OSL
|
||||
if(kernel_osl_use(kg))
|
||||
OSLShader::thread_init(kg);
|
||||
#endif
|
||||
|
||||
for(int y = task.y; y < task.y + task.h; y++) {
|
||||
for(int x = task.x; x < task.x + task.w; x++)
|
||||
kernel_cpu_path_trace(kg, (float4*)task.buffer, (unsigned int*)task.rng_state, task.pass, x, y);
|
||||
|
||||
if(tasks.worker_cancel())
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WITH_OSL
|
||||
if(kernel_osl_use(kg))
|
||||
OSLShader::thread_free(kg);
|
||||
#endif
|
||||
}
|
||||
|
||||
void thread_tonemap(DeviceTask& task)
|
||||
{
|
||||
for(int y = task.y; y < task.y + task.h; y++) {
|
||||
for(int x = task.x; x < task.x + task.w; x++)
|
||||
kernel_cpu_tonemap(kg, (uchar4*)task.rgba, (float4*)task.buffer, task.pass, task.resolution, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void thread_displace(DeviceTask& task)
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
if(kernel_osl_use(kg))
|
||||
OSLShader::thread_init(kg);
|
||||
#endif
|
||||
|
||||
for(int x = task.displace_x; x < task.displace_x + task.displace_w; x++) {
|
||||
kernel_cpu_displace(kg, (uint4*)task.displace_input, (float3*)task.displace_offset, x);
|
||||
|
||||
if(tasks.worker_cancel())
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WITH_OSL
|
||||
if(kernel_osl_use(kg))
|
||||
OSLShader::thread_free(kg);
|
||||
#endif
|
||||
}
|
||||
|
||||
void task_add(DeviceTask& task)
|
||||
{
|
||||
if(task.type == DeviceTask::TONEMAP)
|
||||
tasks.push(task);
|
||||
else
|
||||
task.split(tasks, threads.size());
|
||||
}
|
||||
|
||||
void task_wait()
|
||||
{
|
||||
tasks.wait_done();
|
||||
}
|
||||
|
||||
void task_cancel()
|
||||
{
|
||||
tasks.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
Device *device_cpu_create()
|
||||
{
|
||||
return new CPUDevice();
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
682
intern/cycles/device/device_cuda.cpp
Normal file
682
intern/cycles/device/device_cuda.cpp
Normal file
@ -0,0 +1,682 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "device_intern.h"
|
||||
|
||||
#include "util_cuda.h"
|
||||
#include "util_debug.h"
|
||||
#include "util_map.h"
|
||||
#include "util_opengl.h"
|
||||
#include "util_path.h"
|
||||
#include "util_types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class CUDADevice : public Device
|
||||
{
|
||||
public:
|
||||
CUdevice cuDevice;
|
||||
CUcontext cuContext;
|
||||
CUmodule cuModule;
|
||||
map<device_ptr, bool> tex_interp_map;
|
||||
int cuDevId;
|
||||
|
||||
struct PixelMem {
|
||||
GLuint cuPBO;
|
||||
CUgraphicsResource cuPBOresource;
|
||||
GLuint cuTexId;
|
||||
int w, h;
|
||||
};
|
||||
|
||||
map<device_ptr, PixelMem> pixel_mem_map;
|
||||
|
||||
CUdeviceptr cuda_device_ptr(device_ptr mem)
|
||||
{
|
||||
return (CUdeviceptr)mem;
|
||||
}
|
||||
|
||||
const char *cuda_error_string(CUresult result)
|
||||
{
|
||||
switch(result) {
|
||||
case CUDA_SUCCESS: return "No errors";
|
||||
case CUDA_ERROR_INVALID_VALUE: return "Invalid value";
|
||||
case CUDA_ERROR_OUT_OF_MEMORY: return "Out of memory";
|
||||
case CUDA_ERROR_NOT_INITIALIZED: return "Driver not initialized";
|
||||
case CUDA_ERROR_DEINITIALIZED: return "Driver deinitialized";
|
||||
|
||||
case CUDA_ERROR_NO_DEVICE: return "No CUDA-capable device available";
|
||||
case CUDA_ERROR_INVALID_DEVICE: return "Invalid device";
|
||||
|
||||
case CUDA_ERROR_INVALID_IMAGE: return "Invalid kernel image";
|
||||
case CUDA_ERROR_INVALID_CONTEXT: return "Invalid context";
|
||||
case CUDA_ERROR_CONTEXT_ALREADY_CURRENT: return "Context already current";
|
||||
case CUDA_ERROR_MAP_FAILED: return "Map failed";
|
||||
case CUDA_ERROR_UNMAP_FAILED: return "Unmap failed";
|
||||
case CUDA_ERROR_ARRAY_IS_MAPPED: return "Array is mapped";
|
||||
case CUDA_ERROR_ALREADY_MAPPED: return "Already mapped";
|
||||
case CUDA_ERROR_NO_BINARY_FOR_GPU: return "No binary for GPU";
|
||||
case CUDA_ERROR_ALREADY_ACQUIRED: return "Already acquired";
|
||||
case CUDA_ERROR_NOT_MAPPED: return "Not mapped";
|
||||
case CUDA_ERROR_NOT_MAPPED_AS_ARRAY: return "Mapped resource not available for access as an array";
|
||||
case CUDA_ERROR_NOT_MAPPED_AS_POINTER: return "Mapped resource not available for access as a pointer";
|
||||
case CUDA_ERROR_ECC_UNCORRECTABLE: return "Uncorrectable ECC error detected";
|
||||
case CUDA_ERROR_UNSUPPORTED_LIMIT: return "CUlimit not supported by device";
|
||||
|
||||
case CUDA_ERROR_INVALID_SOURCE: return "Invalid source";
|
||||
case CUDA_ERROR_FILE_NOT_FOUND: return "File not found";
|
||||
case CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND: return "Link to a shared object failed to resolve";
|
||||
case CUDA_ERROR_SHARED_OBJECT_INIT_FAILED: return "Shared object initialization failed";
|
||||
|
||||
case CUDA_ERROR_INVALID_HANDLE: return "Invalid handle";
|
||||
|
||||
case CUDA_ERROR_NOT_FOUND: return "Not found";
|
||||
|
||||
case CUDA_ERROR_NOT_READY: return "CUDA not ready";
|
||||
|
||||
case CUDA_ERROR_LAUNCH_FAILED: return "Launch failed";
|
||||
case CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES: return "Launch exceeded resources";
|
||||
case CUDA_ERROR_LAUNCH_TIMEOUT: return "Launch exceeded timeout";
|
||||
case CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING: return "Launch with incompatible texturing";
|
||||
|
||||
case CUDA_ERROR_UNKNOWN: return "Unknown error";
|
||||
|
||||
default: return "Unknown CUDA error value";
|
||||
}
|
||||
}
|
||||
|
||||
static int cuda_align_up(int& offset, int alignment)
|
||||
{
|
||||
return (offset + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define cuda_abort()
|
||||
#else
|
||||
#define cuda_abort() abort()
|
||||
#endif
|
||||
|
||||
#define cuda_assert(stmt) \
|
||||
{ \
|
||||
CUresult result = stmt; \
|
||||
\
|
||||
if(result != CUDA_SUCCESS) { \
|
||||
fprintf(stderr, "CUDA error: %s in %s\n", cuda_error_string(result), #stmt); \
|
||||
cuda_abort(); \
|
||||
} \
|
||||
}
|
||||
|
||||
void cuda_push_context()
|
||||
{
|
||||
cuda_assert(cuCtxSetCurrent(cuContext))
|
||||
}
|
||||
|
||||
void cuda_pop_context()
|
||||
{
|
||||
cuda_assert(cuCtxSetCurrent(NULL));
|
||||
}
|
||||
|
||||
CUDADevice(bool background_)
|
||||
{
|
||||
int major, minor;
|
||||
background = background_;
|
||||
|
||||
cuDevId = 0;
|
||||
|
||||
/* intialize */
|
||||
cuda_assert(cuInit(0))
|
||||
|
||||
/* setup device and context */
|
||||
cuda_assert(cuDeviceGet(&cuDevice, cuDevId))
|
||||
|
||||
if(background)
|
||||
cuda_assert(cuCtxCreate(&cuContext, 0, cuDevice))
|
||||
else
|
||||
cuda_assert(cuGLCtxCreate(&cuContext, 0, cuDevice))
|
||||
|
||||
/* open module */
|
||||
cuDeviceComputeCapability(&major, &minor, cuDevId);
|
||||
string cubin = string_printf("lib/kernel_sm_%d%d.cubin", major, minor);
|
||||
cuda_assert(cuModuleLoad(&cuModule, path_get(cubin).c_str()))
|
||||
|
||||
cuda_pop_context();
|
||||
}
|
||||
|
||||
~CUDADevice()
|
||||
{
|
||||
cuda_push_context();
|
||||
cuda_assert(cuCtxDetach(cuContext))
|
||||
}
|
||||
|
||||
string description()
|
||||
{
|
||||
/* print device information */
|
||||
char deviceName[100];
|
||||
|
||||
cuda_push_context();
|
||||
cuDeviceGetName(deviceName, 256, cuDevId);
|
||||
cuda_pop_context();
|
||||
|
||||
return string("CUDA ") + deviceName;
|
||||
}
|
||||
|
||||
void mem_alloc(device_memory& mem, MemoryType type)
|
||||
{
|
||||
cuda_push_context();
|
||||
CUdeviceptr device_pointer;
|
||||
cuda_assert(cuMemAlloc(&device_pointer, mem.memory_size()))
|
||||
mem.device_pointer = (device_ptr)device_pointer;
|
||||
cuda_pop_context();
|
||||
}
|
||||
|
||||
void mem_copy_to(device_memory& mem)
|
||||
{
|
||||
cuda_push_context();
|
||||
cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size()))
|
||||
cuda_pop_context();
|
||||
}
|
||||
|
||||
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
|
||||
{
|
||||
/* todo: offset is ignored */
|
||||
cuda_push_context();
|
||||
cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset,
|
||||
(CUdeviceptr)((uchar*)mem.device_pointer + offset), size))
|
||||
cuda_pop_context();
|
||||
}
|
||||
|
||||
void mem_zero(device_memory& mem)
|
||||
{
|
||||
memset((void*)mem.data_pointer, 0, mem.memory_size());
|
||||
|
||||
cuda_push_context();
|
||||
cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size()))
|
||||
cuda_pop_context();
|
||||
}
|
||||
|
||||
void mem_free(device_memory& mem)
|
||||
{
|
||||
if(mem.device_pointer) {
|
||||
cuda_push_context();
|
||||
cuda_assert(cuMemFree(cuda_device_ptr(mem.device_pointer)))
|
||||
cuda_pop_context();
|
||||
|
||||
mem.device_pointer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void const_copy_to(const char *name, void *host, size_t size)
|
||||
{
|
||||
CUdeviceptr mem;
|
||||
size_t bytes;
|
||||
|
||||
cuda_push_context();
|
||||
cuda_assert(cuModuleGetGlobal(&mem, &bytes, cuModule, name))
|
||||
assert(bytes == size);
|
||||
cuda_assert(cuMemcpyHtoD(mem, host, size))
|
||||
cuda_pop_context();
|
||||
}
|
||||
|
||||
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
|
||||
{
|
||||
/* determine format */
|
||||
CUarray_format_enum format;
|
||||
size_t dsize = datatype_size(mem.data_type);
|
||||
size_t size = mem.memory_size();
|
||||
|
||||
switch(mem.data_type) {
|
||||
case TYPE_UCHAR: format = CU_AD_FORMAT_UNSIGNED_INT8; break;
|
||||
case TYPE_UINT: format = CU_AD_FORMAT_UNSIGNED_INT32; break;
|
||||
case TYPE_INT: format = CU_AD_FORMAT_SIGNED_INT32; break;
|
||||
case TYPE_FLOAT: format = CU_AD_FORMAT_FLOAT; break;
|
||||
default: assert(0); return;
|
||||
}
|
||||
|
||||
CUtexref texref;
|
||||
|
||||
cuda_push_context();
|
||||
cuda_assert(cuModuleGetTexRef(&texref, cuModule, name))
|
||||
|
||||
if(interpolation) {
|
||||
CUarray handle;
|
||||
CUDA_ARRAY_DESCRIPTOR desc;
|
||||
|
||||
desc.Width = mem.data_width;
|
||||
desc.Height = mem.data_height;
|
||||
desc.Format = format;
|
||||
desc.NumChannels = mem.data_elements;
|
||||
|
||||
cuda_assert(cuArrayCreate(&handle, &desc))
|
||||
|
||||
if(mem.data_height > 1) {
|
||||
CUDA_MEMCPY2D param;
|
||||
memset(¶m, 0, sizeof(param));
|
||||
param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
|
||||
param.dstArray = handle;
|
||||
param.srcMemoryType = CU_MEMORYTYPE_HOST;
|
||||
param.srcHost = (void*)mem.data_pointer;
|
||||
param.srcPitch = mem.data_width*dsize*mem.data_elements;
|
||||
param.WidthInBytes = param.srcPitch;
|
||||
param.Height = mem.data_height;
|
||||
|
||||
cuda_assert(cuMemcpy2D(¶m))
|
||||
}
|
||||
else
|
||||
cuda_assert(cuMemcpyHtoA(handle, 0, (void*)mem.data_pointer, size))
|
||||
|
||||
cuda_assert(cuTexRefSetArray(texref, handle, CU_TRSA_OVERRIDE_FORMAT))
|
||||
|
||||
cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_LINEAR))
|
||||
cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_NORMALIZED_COORDINATES))
|
||||
|
||||
mem.device_pointer = (device_ptr)handle;
|
||||
}
|
||||
else {
|
||||
cuda_pop_context();
|
||||
|
||||
mem_alloc(mem, MEM_READ_ONLY);
|
||||
mem_copy_to(mem);
|
||||
|
||||
cuda_push_context();
|
||||
|
||||
cuda_assert(cuTexRefSetAddress(NULL, texref, cuda_device_ptr(mem.device_pointer), size))
|
||||
cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_POINT))
|
||||
cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_READ_AS_INTEGER))
|
||||
}
|
||||
|
||||
if(periodic) {
|
||||
cuda_assert(cuTexRefSetAddressMode(texref, 0, CU_TR_ADDRESS_MODE_WRAP))
|
||||
cuda_assert(cuTexRefSetAddressMode(texref, 1, CU_TR_ADDRESS_MODE_WRAP))
|
||||
}
|
||||
else {
|
||||
cuda_assert(cuTexRefSetAddressMode(texref, 0, CU_TR_ADDRESS_MODE_CLAMP))
|
||||
cuda_assert(cuTexRefSetAddressMode(texref, 1, CU_TR_ADDRESS_MODE_CLAMP))
|
||||
}
|
||||
cuda_assert(cuTexRefSetFormat(texref, format, mem.data_elements))
|
||||
|
||||
cuda_pop_context();
|
||||
|
||||
tex_interp_map[mem.device_pointer] = interpolation;
|
||||
}
|
||||
|
||||
void tex_free(device_memory& mem)
|
||||
{
|
||||
if(mem.device_pointer) {
|
||||
if(tex_interp_map[mem.device_pointer]) {
|
||||
cuda_push_context();
|
||||
cuArrayDestroy((CUarray)mem.device_pointer);
|
||||
cuda_pop_context();
|
||||
|
||||
tex_interp_map.erase(tex_interp_map.find(mem.device_pointer));
|
||||
mem.device_pointer = 0;
|
||||
}
|
||||
else {
|
||||
tex_interp_map.erase(tex_interp_map.find(mem.device_pointer));
|
||||
mem_free(mem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void path_trace(DeviceTask& task)
|
||||
{
|
||||
cuda_push_context();
|
||||
|
||||
CUfunction cuPathTrace;
|
||||
CUdeviceptr d_buffer = cuda_device_ptr(task.buffer);
|
||||
CUdeviceptr d_rng_state = cuda_device_ptr(task.rng_state);
|
||||
|
||||
/* get kernel function */
|
||||
cuda_assert(cuModuleGetFunction(&cuPathTrace, cuModule, "kernel_cuda_path_trace"))
|
||||
|
||||
/* pass in parameters */
|
||||
int offset = 0;
|
||||
|
||||
cuda_assert(cuParamSetv(cuPathTrace, offset, &d_buffer, sizeof(d_buffer)))
|
||||
offset += sizeof(d_buffer);
|
||||
|
||||
cuda_assert(cuParamSetv(cuPathTrace, offset, &d_rng_state, sizeof(d_rng_state)))
|
||||
offset += sizeof(d_rng_state);
|
||||
|
||||
offset = cuda_align_up(offset, __alignof(task.pass));
|
||||
|
||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.pass))
|
||||
offset += sizeof(task.pass);
|
||||
|
||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.x))
|
||||
offset += sizeof(task.x);
|
||||
|
||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.y))
|
||||
offset += sizeof(task.y);
|
||||
|
||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.w))
|
||||
offset += sizeof(task.w);
|
||||
|
||||
cuda_assert(cuParamSeti(cuPathTrace, offset, task.h))
|
||||
offset += sizeof(task.h);
|
||||
|
||||
cuda_assert(cuParamSetSize(cuPathTrace, offset))
|
||||
|
||||
/* launch kernel: todo find optimal size, cache config for fermi */
|
||||
#ifndef __APPLE__
|
||||
int xthreads = 16;
|
||||
int ythreads = 16;
|
||||
#else
|
||||
int xthreads = 8;
|
||||
int ythreads = 8;
|
||||
#endif
|
||||
int xblocks = (task.w + xthreads - 1)/xthreads;
|
||||
int yblocks = (task.h + ythreads - 1)/ythreads;
|
||||
|
||||
cuda_assert(cuFuncSetCacheConfig(cuPathTrace, CU_FUNC_CACHE_PREFER_L1))
|
||||
cuda_assert(cuFuncSetBlockShape(cuPathTrace, xthreads, ythreads, 1))
|
||||
cuda_assert(cuLaunchGrid(cuPathTrace, xblocks, yblocks))
|
||||
|
||||
cuda_pop_context();
|
||||
}
|
||||
|
||||
void tonemap(DeviceTask& task)
|
||||
{
|
||||
cuda_push_context();
|
||||
|
||||
CUfunction cuFilmConvert;
|
||||
CUdeviceptr d_rgba = map_pixels(task.rgba);
|
||||
CUdeviceptr d_buffer = cuda_device_ptr(task.buffer);
|
||||
|
||||
/* get kernel function */
|
||||
cuda_assert(cuModuleGetFunction(&cuFilmConvert, cuModule, "kernel_cuda_tonemap"))
|
||||
|
||||
/* pass in parameters */
|
||||
int offset = 0;
|
||||
|
||||
cuda_assert(cuParamSetv(cuFilmConvert, offset, &d_rgba, sizeof(d_rgba)))
|
||||
offset += sizeof(d_rgba);
|
||||
|
||||
cuda_assert(cuParamSetv(cuFilmConvert, offset, &d_buffer, sizeof(d_buffer)))
|
||||
offset += sizeof(d_buffer);
|
||||
|
||||
offset = cuda_align_up(offset, __alignof(task.pass));
|
||||
|
||||
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.pass))
|
||||
offset += sizeof(task.pass);
|
||||
|
||||
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.resolution))
|
||||
offset += sizeof(task.resolution);
|
||||
|
||||
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.x))
|
||||
offset += sizeof(task.x);
|
||||
|
||||
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.y))
|
||||
offset += sizeof(task.y);
|
||||
|
||||
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.w))
|
||||
offset += sizeof(task.w);
|
||||
|
||||
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.h))
|
||||
offset += sizeof(task.h);
|
||||
|
||||
cuda_assert(cuParamSetSize(cuFilmConvert, offset))
|
||||
|
||||
/* launch kernel: todo find optimal size, cache config for fermi */
|
||||
#ifndef __APPLE__
|
||||
int xthreads = 16;
|
||||
int ythreads = 16;
|
||||
#else
|
||||
int xthreads = 8;
|
||||
int ythreads = 8;
|
||||
#endif
|
||||
int xblocks = (task.w + xthreads - 1)/xthreads;
|
||||
int yblocks = (task.h + ythreads - 1)/ythreads;
|
||||
|
||||
cuda_assert(cuFuncSetCacheConfig(cuFilmConvert, CU_FUNC_CACHE_PREFER_L1))
|
||||
cuda_assert(cuFuncSetBlockShape(cuFilmConvert, xthreads, ythreads, 1))
|
||||
cuda_assert(cuLaunchGrid(cuFilmConvert, xblocks, yblocks))
|
||||
|
||||
unmap_pixels(task.rgba);
|
||||
|
||||
cuda_pop_context();
|
||||
}
|
||||
|
||||
void displace(DeviceTask& task)
|
||||
{
|
||||
cuda_push_context();
|
||||
|
||||
CUfunction cuDisplace;
|
||||
CUdeviceptr d_input = cuda_device_ptr(task.displace_input);
|
||||
CUdeviceptr d_offset = cuda_device_ptr(task.displace_offset);
|
||||
|
||||
/* get kernel function */
|
||||
cuda_assert(cuModuleGetFunction(&cuDisplace, cuModule, "kernel_cuda_displace"))
|
||||
|
||||
/* pass in parameters */
|
||||
int offset = 0;
|
||||
|
||||
cuda_assert(cuParamSetv(cuDisplace, offset, &d_input, sizeof(d_input)))
|
||||
offset += sizeof(d_input);
|
||||
|
||||
cuda_assert(cuParamSetv(cuDisplace, offset, &d_offset, sizeof(d_offset)))
|
||||
offset += sizeof(d_offset);
|
||||
|
||||
offset = cuda_align_up(offset, __alignof(task.displace_x));
|
||||
|
||||
cuda_assert(cuParamSeti(cuDisplace, offset, task.displace_x))
|
||||
offset += sizeof(task.displace_x);
|
||||
|
||||
cuda_assert(cuParamSetSize(cuDisplace, offset))
|
||||
|
||||
/* launch kernel: todo find optimal size, cache config for fermi */
|
||||
#ifndef __APPLE__
|
||||
int xthreads = 16;
|
||||
#else
|
||||
int xthreads = 8;
|
||||
#endif
|
||||
int xblocks = (task.displace_w + xthreads - 1)/xthreads;
|
||||
|
||||
cuda_assert(cuFuncSetCacheConfig(cuDisplace, CU_FUNC_CACHE_PREFER_L1))
|
||||
cuda_assert(cuFuncSetBlockShape(cuDisplace, xthreads, 1, 1))
|
||||
cuda_assert(cuLaunchGrid(cuDisplace, xblocks, 1))
|
||||
|
||||
cuda_pop_context();
|
||||
}
|
||||
|
||||
CUdeviceptr map_pixels(device_ptr mem)
|
||||
{
|
||||
if(!background) {
|
||||
PixelMem pmem = pixel_mem_map[mem];
|
||||
CUdeviceptr buffer;
|
||||
|
||||
size_t bytes;
|
||||
cuda_assert(cuGraphicsMapResources(1, &pmem.cuPBOresource, 0))
|
||||
cuda_assert(cuGraphicsResourceGetMappedPointer(&buffer, &bytes, pmem.cuPBOresource))
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return cuda_device_ptr(mem);
|
||||
}
|
||||
|
||||
void unmap_pixels(device_ptr mem)
|
||||
{
|
||||
if(!background) {
|
||||
PixelMem pmem = pixel_mem_map[mem];
|
||||
|
||||
cuda_assert(cuGraphicsUnmapResources(1, &pmem.cuPBOresource, 0))
|
||||
}
|
||||
}
|
||||
|
||||
void pixels_alloc(device_memory& mem)
|
||||
{
|
||||
if(!background) {
|
||||
PixelMem pmem;
|
||||
|
||||
pmem.w = mem.data_width;
|
||||
pmem.h = mem.data_height;
|
||||
|
||||
cuda_push_context();
|
||||
|
||||
glGenBuffers(1, &pmem.cuPBO);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, pmem.w*pmem.h*sizeof(GLfloat)*3, NULL, GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
|
||||
glGenTextures(1, &pmem.cuTexId);
|
||||
glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pmem.w, pmem.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
cuda_assert(cuGraphicsGLRegisterBuffer(&pmem.cuPBOresource, pmem.cuPBO, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE))
|
||||
|
||||
cuda_pop_context();
|
||||
|
||||
mem.device_pointer = pmem.cuTexId;
|
||||
pixel_mem_map[mem.device_pointer] = pmem;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Device::pixels_alloc(mem);
|
||||
}
|
||||
|
||||
void pixels_copy_from(device_memory& mem, int y, int w, int h)
|
||||
{
|
||||
if(!background) {
|
||||
PixelMem pmem = pixel_mem_map[mem.device_pointer];
|
||||
|
||||
cuda_push_context();
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO);
|
||||
uchar *pixels = (uchar*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_ONLY);
|
||||
size_t offset = sizeof(uchar)*4*y*w;
|
||||
memcpy((uchar*)mem.data_pointer + offset, pixels + offset, sizeof(uchar)*4*w*h);
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
|
||||
cuda_pop_context();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Device::pixels_copy_from(mem, y, w, h);
|
||||
}
|
||||
|
||||
void pixels_free(device_memory& mem)
|
||||
{
|
||||
if(mem.device_pointer) {
|
||||
if(!background) {
|
||||
PixelMem pmem = pixel_mem_map[mem.device_pointer];
|
||||
|
||||
cuda_push_context();
|
||||
|
||||
cuda_assert(cuGraphicsUnregisterResource(pmem.cuPBOresource))
|
||||
glDeleteBuffers(1, &pmem.cuPBO);
|
||||
glDeleteTextures(1, &pmem.cuTexId);
|
||||
|
||||
cuda_pop_context();
|
||||
|
||||
pixel_mem_map.erase(pixel_mem_map.find(mem.device_pointer));
|
||||
mem.device_pointer = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Device::pixels_free(mem);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_pixels(device_memory& mem, int y, int w, int h, int width, int height)
|
||||
{
|
||||
if(!background) {
|
||||
PixelMem pmem = pixel_mem_map[mem.device_pointer];
|
||||
|
||||
cuda_push_context();
|
||||
|
||||
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pmem.cuPBO);
|
||||
glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(0, y, 0.0f);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(0, 0);
|
||||
glTexCoord2f((float)w/(float)width, 0);
|
||||
glVertex2f(width, 0);
|
||||
glTexCoord2f((float)w/(float)width, (float)h/(float)height);
|
||||
glVertex2f(width, height);
|
||||
glTexCoord2f(0, (float)h/(float)height);
|
||||
glVertex2f(0, height);
|
||||
|
||||
glEnd();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
cuda_pop_context();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Device::draw_pixels(mem, y, w, h, width, height);
|
||||
}
|
||||
|
||||
void task_add(DeviceTask& task)
|
||||
{
|
||||
if(task.type == DeviceTask::TONEMAP)
|
||||
tonemap(task);
|
||||
else if(task.type == DeviceTask::PATH_TRACE)
|
||||
path_trace(task);
|
||||
else if(task.type == DeviceTask::DISPLACE)
|
||||
displace(task);
|
||||
}
|
||||
|
||||
void task_wait()
|
||||
{
|
||||
cuda_push_context();
|
||||
|
||||
cuda_assert(cuCtxSynchronize())
|
||||
|
||||
cuda_pop_context();
|
||||
}
|
||||
|
||||
void task_cancel()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Device *device_cuda_create(bool background)
|
||||
{
|
||||
return new CUDADevice(background);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
35
intern/cycles/device/device_intern.h
Normal file
35
intern/cycles/device/device_intern.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __DEVICE_INTERN_H__
|
||||
#define __DEVICE_INTERN_H__
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Device;
|
||||
|
||||
Device *device_cpu_create();
|
||||
Device *device_opencl_create(bool background);
|
||||
Device *device_cuda_create(bool background);
|
||||
Device *device_network_create(const char *address);
|
||||
Device *device_multi_create(bool background);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __DEVICE_INTERN_H__ */
|
||||
|
244
intern/cycles/device/device_memory.h
Normal file
244
intern/cycles/device/device_memory.h
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __DEVICE_MEMORY_H__
|
||||
#define __DEVICE_MEMORY_H__
|
||||
|
||||
/* Device Memory
|
||||
*
|
||||
* This file defines data types that can be used in device memory arrays, and
|
||||
* a device_vector<T> type to store such arrays.
|
||||
*
|
||||
* device_vector<T> contains an STL vector, metadata about the data type,
|
||||
* dimensions, elements, and a device pointer. For the CPU device this is just
|
||||
* a pointer to the STL vector data, as no copying needs to take place. For
|
||||
* other devices this is a pointer to device memory, where we will copy memory
|
||||
* to and from. */
|
||||
|
||||
#include "util_debug.h"
|
||||
#include "util_types.h"
|
||||
#include "util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Supported Data Types */
|
||||
|
||||
enum DataType {
|
||||
TYPE_UCHAR,
|
||||
TYPE_UINT,
|
||||
TYPE_INT,
|
||||
TYPE_FLOAT
|
||||
};
|
||||
|
||||
static inline size_t datatype_size(DataType datatype)
|
||||
{
|
||||
switch(datatype) {
|
||||
case TYPE_UCHAR: return sizeof(uchar);
|
||||
case TYPE_FLOAT: return sizeof(float);
|
||||
case TYPE_UINT: return sizeof(uint);
|
||||
case TYPE_INT: return sizeof(int);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Traits for data types */
|
||||
|
||||
template<typename T> struct device_type_traits {
|
||||
static const DataType data_type = TYPE_UCHAR;
|
||||
static const int num_elements = 0;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<uchar> {
|
||||
static const DataType data_type = TYPE_UCHAR;
|
||||
static const int num_elements = 1;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<uchar2> {
|
||||
static const DataType data_type = TYPE_UCHAR;
|
||||
static const int num_elements = 2;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<uchar3> {
|
||||
static const DataType data_type = TYPE_UCHAR;
|
||||
static const int num_elements = 3;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<uchar4> {
|
||||
static const DataType data_type = TYPE_UCHAR;
|
||||
static const int num_elements = 4;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<uint> {
|
||||
static const DataType data_type = TYPE_UINT;
|
||||
static const int num_elements = 1;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<uint2> {
|
||||
static const DataType data_type = TYPE_UINT;
|
||||
static const int num_elements = 2;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<uint3> {
|
||||
static const DataType data_type = TYPE_UINT;
|
||||
static const int num_elements = 3;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<uint4> {
|
||||
static const DataType data_type = TYPE_UINT;
|
||||
static const int num_elements = 4;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<int> {
|
||||
static const DataType data_type = TYPE_INT;
|
||||
static const int num_elements = 1;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<int2> {
|
||||
static const DataType data_type = TYPE_INT;
|
||||
static const int num_elements = 2;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<int3> {
|
||||
static const DataType data_type = TYPE_INT;
|
||||
static const int num_elements = 3;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<int4> {
|
||||
static const DataType data_type = TYPE_INT;
|
||||
static const int num_elements = 4;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<float> {
|
||||
static const DataType data_type = TYPE_FLOAT;
|
||||
static const int num_elements = 1;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<float2> {
|
||||
static const DataType data_type = TYPE_FLOAT;
|
||||
static const int num_elements = 2;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<float3> {
|
||||
static const DataType data_type = TYPE_FLOAT;
|
||||
static const int num_elements = 3;
|
||||
};
|
||||
|
||||
template<> struct device_type_traits<float4> {
|
||||
static const DataType data_type = TYPE_FLOAT;
|
||||
static const int num_elements = 4;
|
||||
};
|
||||
|
||||
/* Device Memory */
|
||||
|
||||
class device_memory
|
||||
{
|
||||
public:
|
||||
size_t memory_size() { return data_size*data_elements*datatype_size(data_type); }
|
||||
|
||||
/* data information */
|
||||
DataType data_type;
|
||||
int data_elements;
|
||||
device_ptr data_pointer;
|
||||
size_t data_size;
|
||||
size_t data_width;
|
||||
size_t data_height;
|
||||
|
||||
/* device pointer */
|
||||
device_ptr device_pointer;
|
||||
|
||||
protected:
|
||||
device_memory() {}
|
||||
virtual ~device_memory() { assert(!device_pointer); }
|
||||
|
||||
/* no copying */
|
||||
device_memory(const device_memory&);
|
||||
device_memory& operator = (const device_memory&);
|
||||
};
|
||||
|
||||
/* Device Vector */
|
||||
|
||||
template<typename T> class device_vector : public device_memory
|
||||
{
|
||||
public:
|
||||
device_vector()
|
||||
{
|
||||
data_type = device_type_traits<T>::data_type;
|
||||
data_elements = device_type_traits<T>::num_elements;
|
||||
data_pointer = 0;
|
||||
data_size = 0;
|
||||
data_width = 0;
|
||||
data_height = 0;
|
||||
|
||||
assert(data_elements > 0);
|
||||
|
||||
device_pointer = 0;
|
||||
}
|
||||
|
||||
virtual ~device_vector() {}
|
||||
|
||||
/* vector functions */
|
||||
T *resize(size_t width, size_t height = 0)
|
||||
{
|
||||
data_size = (height == 0)? width: width*height;
|
||||
data.resize(data_size);
|
||||
data_pointer = (device_ptr)&data[0];
|
||||
data_width = width;
|
||||
data_height = height;
|
||||
|
||||
return &data[0];
|
||||
}
|
||||
|
||||
T *copy(T *ptr, size_t width, size_t height = 0)
|
||||
{
|
||||
T *mem = resize(width, height);
|
||||
memcpy(mem, ptr, memory_size());
|
||||
return mem;
|
||||
}
|
||||
|
||||
void reference(T *ptr, size_t width, size_t height = 0)
|
||||
{
|
||||
data.clear();
|
||||
data_size = (height == 0)? width: width*height;
|
||||
data_pointer = (device_ptr)ptr;
|
||||
data_width = width;
|
||||
data_height = height;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
data.clear();
|
||||
data_pointer = 0;
|
||||
data_width = 0;
|
||||
data_height = 0;
|
||||
data_size = 0;
|
||||
}
|
||||
|
||||
size_t size()
|
||||
{
|
||||
return data.size();
|
||||
}
|
||||
|
||||
private:
|
||||
array<T> data;
|
||||
bool referenced;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __DEVICE_MEMORY_H__ */
|
||||
|
304
intern/cycles/device/device_multi.cpp
Normal file
304
intern/cycles/device/device_multi.cpp
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "device.h"
|
||||
#include "device_intern.h"
|
||||
#include "device_network.h"
|
||||
|
||||
#include "util_foreach.h"
|
||||
#include "util_list.h"
|
||||
#include "util_map.h"
|
||||
#include "util_time.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class MultiDevice : public Device
|
||||
{
|
||||
public:
|
||||
struct SubDevice {
|
||||
SubDevice(Device *device_)
|
||||
: device(device_) {}
|
||||
|
||||
Device *device;
|
||||
map<device_ptr, device_ptr> ptr_map;
|
||||
};
|
||||
|
||||
list<SubDevice> devices;
|
||||
device_ptr unique_ptr;
|
||||
|
||||
MultiDevice(bool background_)
|
||||
: unique_ptr(1)
|
||||
{
|
||||
/* enforce background for now */
|
||||
background = true;
|
||||
|
||||
Device *device;
|
||||
|
||||
/* add CPU device */
|
||||
device = Device::create(DEVICE_CPU, background);
|
||||
devices.push_back(SubDevice(device));
|
||||
|
||||
#ifdef WITH_CUDA
|
||||
/* try to add GPU device */
|
||||
device = Device::create(DEVICE_CUDA, background);
|
||||
if(device) {
|
||||
devices.push_back(SubDevice(device));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef WITH_OPENCL
|
||||
device = Device::create(DEVICE_OPENCL, background);
|
||||
if(device)
|
||||
devices.push_back(SubDevice(device));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WITH_NETWORK
|
||||
/* try to add network devices */
|
||||
ServerDiscovery discovery(true);
|
||||
time_sleep(1.0);
|
||||
|
||||
list<string> servers = discovery.get_server_list();
|
||||
|
||||
foreach(string& server, servers) {
|
||||
device = device_network_create(server.c_str());
|
||||
if(device)
|
||||
devices.push_back(SubDevice(device));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
~MultiDevice()
|
||||
{
|
||||
foreach(SubDevice& sub, devices)
|
||||
delete sub.device;
|
||||
}
|
||||
|
||||
string description()
|
||||
{
|
||||
/* create map to find duplicate descriptions */
|
||||
map<string, int> dupli_map;
|
||||
map<string, int>::iterator dt;
|
||||
|
||||
foreach(SubDevice& sub, devices) {
|
||||
string key = sub.device->description();
|
||||
|
||||
if(dupli_map.find(key) == dupli_map.end())
|
||||
dupli_map[key] = 1;
|
||||
else
|
||||
dupli_map[key]++;
|
||||
}
|
||||
|
||||
/* generate string */
|
||||
stringstream desc;
|
||||
bool first = true;
|
||||
|
||||
for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) {
|
||||
if(!first) desc << ", ";
|
||||
first = false;
|
||||
|
||||
if(dt->second > 1)
|
||||
desc << dt->second << "x " << dt->first;
|
||||
else
|
||||
desc << dt->first;
|
||||
}
|
||||
|
||||
return desc.str();
|
||||
}
|
||||
|
||||
void mem_alloc(device_memory& mem, MemoryType type)
|
||||
{
|
||||
foreach(SubDevice& sub, devices) {
|
||||
mem.device_pointer = 0;
|
||||
sub.device->mem_alloc(mem, type);
|
||||
sub.ptr_map[unique_ptr] = mem.device_pointer;
|
||||
}
|
||||
|
||||
mem.device_pointer = unique_ptr++;
|
||||
}
|
||||
|
||||
void mem_copy_to(device_memory& mem)
|
||||
{
|
||||
device_ptr tmp = mem.device_pointer;
|
||||
|
||||
foreach(SubDevice& sub, devices) {
|
||||
mem.device_pointer = sub.ptr_map[tmp];
|
||||
sub.device->mem_copy_to(mem);
|
||||
}
|
||||
|
||||
mem.device_pointer = tmp;
|
||||
}
|
||||
|
||||
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
|
||||
{
|
||||
device_ptr tmp = mem.device_pointer;
|
||||
|
||||
/* todo: how does this work? */
|
||||
foreach(SubDevice& sub, devices) {
|
||||
mem.device_pointer = sub.ptr_map[tmp];
|
||||
sub.device->mem_copy_from(mem, offset, size);
|
||||
break;
|
||||
}
|
||||
|
||||
mem.device_pointer = tmp;
|
||||
}
|
||||
|
||||
void mem_zero(device_memory& mem)
|
||||
{
|
||||
device_ptr tmp = mem.device_pointer;
|
||||
|
||||
foreach(SubDevice& sub, devices) {
|
||||
mem.device_pointer = sub.ptr_map[tmp];
|
||||
sub.device->mem_zero(mem);
|
||||
}
|
||||
|
||||
mem.device_pointer = tmp;
|
||||
}
|
||||
|
||||
void mem_free(device_memory& mem)
|
||||
{
|
||||
device_ptr tmp = mem.device_pointer;
|
||||
|
||||
foreach(SubDevice& sub, devices) {
|
||||
mem.device_pointer = sub.ptr_map[tmp];
|
||||
sub.device->mem_free(mem);
|
||||
sub.ptr_map.erase(sub.ptr_map.find(tmp));
|
||||
}
|
||||
|
||||
mem.device_pointer = 0;
|
||||
}
|
||||
|
||||
void const_copy_to(const char *name, void *host, size_t size)
|
||||
{
|
||||
foreach(SubDevice& sub, devices)
|
||||
sub.device->const_copy_to(name, host, size);
|
||||
}
|
||||
|
||||
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
|
||||
{
|
||||
foreach(SubDevice& sub, devices) {
|
||||
mem.device_pointer = 0;
|
||||
sub.device->tex_alloc(name, mem, interpolation, periodic);
|
||||
sub.ptr_map[unique_ptr] = mem.device_pointer;
|
||||
}
|
||||
|
||||
mem.device_pointer = unique_ptr++;
|
||||
}
|
||||
|
||||
void tex_free(device_memory& mem)
|
||||
{
|
||||
device_ptr tmp = mem.device_pointer;
|
||||
|
||||
foreach(SubDevice& sub, devices) {
|
||||
mem.device_pointer = sub.ptr_map[tmp];
|
||||
sub.device->tex_free(mem);
|
||||
sub.ptr_map.erase(sub.ptr_map.find(tmp));
|
||||
}
|
||||
|
||||
mem.device_pointer = 0;
|
||||
}
|
||||
|
||||
void pixels_alloc(device_memory& mem)
|
||||
{
|
||||
Device::pixels_alloc(mem);
|
||||
}
|
||||
|
||||
void pixels_free(device_memory& mem)
|
||||
{
|
||||
Device::pixels_free(mem);
|
||||
}
|
||||
|
||||
void pixels_copy_from(device_memory& mem, int y, int w, int h)
|
||||
{
|
||||
device_ptr tmp = mem.device_pointer;
|
||||
int i = 0, sub_h = h/devices.size();
|
||||
|
||||
foreach(SubDevice& sub, devices) {
|
||||
int sy = y + i*sub_h;
|
||||
int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
|
||||
|
||||
mem.device_pointer = sub.ptr_map[tmp];
|
||||
sub.device->pixels_copy_from(mem, sy, w, sh);
|
||||
i++;
|
||||
}
|
||||
|
||||
mem.device_pointer = tmp;
|
||||
}
|
||||
|
||||
void draw_pixels(device_memory& rgba, int x, int y, int w, int h, int width, int height)
|
||||
{
|
||||
device_ptr tmp = rgba.device_pointer;
|
||||
int i = 0, sub_h = h/devices.size();
|
||||
|
||||
foreach(SubDevice& sub, devices) {
|
||||
int sy = y + i*sub_h;
|
||||
int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
|
||||
/* adjust math for w/width */
|
||||
|
||||
rgba.device_pointer = sub.ptr_map[tmp];
|
||||
sub.device->draw_pixels(rgba, sy, w, sh, width, height);
|
||||
i++;
|
||||
}
|
||||
|
||||
rgba.device_pointer = tmp;
|
||||
}
|
||||
|
||||
void task_add(DeviceTask& task)
|
||||
{
|
||||
ThreadQueue<DeviceTask> tasks;
|
||||
task.split(tasks, devices.size());
|
||||
|
||||
foreach(SubDevice& sub, devices) {
|
||||
DeviceTask subtask;
|
||||
|
||||
if(tasks.worker_wait_pop(subtask)) {
|
||||
if(task.buffer) subtask.buffer = sub.ptr_map[task.buffer];
|
||||
if(task.rng_state) subtask.rng_state = sub.ptr_map[task.rng_state];
|
||||
if(task.rgba) subtask.rgba = sub.ptr_map[task.rgba];
|
||||
if(task.displace_input) subtask.displace_input = sub.ptr_map[task.displace_input];
|
||||
if(task.displace_offset) subtask.displace_offset = sub.ptr_map[task.displace_offset];
|
||||
|
||||
sub.device->task_add(subtask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void task_wait()
|
||||
{
|
||||
foreach(SubDevice& sub, devices)
|
||||
sub.device->task_wait();
|
||||
}
|
||||
|
||||
void task_cancel()
|
||||
{
|
||||
foreach(SubDevice& sub, devices)
|
||||
sub.device->task_cancel();
|
||||
}
|
||||
};
|
||||
|
||||
Device *device_multi_create(bool background)
|
||||
{
|
||||
return new MultiDevice(background);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
382
intern/cycles/device/device_network.cpp
Normal file
382
intern/cycles/device/device_network.cpp
Normal file
@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
#include "device_intern.h"
|
||||
#include "device_network.h"
|
||||
|
||||
#include "util_foreach.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class NetworkDevice : public Device
|
||||
{
|
||||
public:
|
||||
boost::asio::io_service io_service;
|
||||
tcp::socket socket;
|
||||
|
||||
NetworkDevice(const char *address)
|
||||
: socket(io_service)
|
||||
{
|
||||
stringstream portstr;
|
||||
portstr << SERVER_PORT;
|
||||
|
||||
tcp::resolver resolver(io_service);
|
||||
tcp::resolver::query query(address, portstr.str());
|
||||
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
|
||||
tcp::resolver::iterator end;
|
||||
|
||||
boost::system::error_code error = boost::asio::error::host_not_found;
|
||||
while(error && endpoint_iterator != end)
|
||||
{
|
||||
socket.close();
|
||||
socket.connect(*endpoint_iterator++, error);
|
||||
}
|
||||
if(error)
|
||||
throw boost::system::system_error(error);
|
||||
}
|
||||
|
||||
~NetworkDevice()
|
||||
{
|
||||
}
|
||||
|
||||
string description()
|
||||
{
|
||||
RPCSend snd(socket, "description");
|
||||
snd.write();
|
||||
|
||||
RPCReceive rcv(socket);
|
||||
string desc_string;
|
||||
|
||||
*rcv.archive & desc_string;
|
||||
|
||||
return desc_string + " (remote)";
|
||||
}
|
||||
|
||||
void mem_alloc(device_memory& mem, MemoryType type)
|
||||
{
|
||||
#if 0
|
||||
RPCSend snd(socket, "mem_alloc");
|
||||
|
||||
snd.archive & size & type;
|
||||
snd.write();
|
||||
|
||||
RPCReceive rcv(socket);
|
||||
|
||||
device_ptr mem;
|
||||
*rcv.archive & mem;
|
||||
|
||||
return mem;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mem_copy_to(device_memory& mem)
|
||||
{
|
||||
#if 0
|
||||
RPCSend snd(socket, "mem_copy_to");
|
||||
|
||||
snd.archive & mem & size;
|
||||
snd.write();
|
||||
snd.write_buffer(host, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
|
||||
{
|
||||
#if 0
|
||||
RPCSend snd(socket, "mem_copy_from");
|
||||
|
||||
snd.archive & mem & offset & size;
|
||||
snd.write();
|
||||
|
||||
RPCReceive rcv(socket);
|
||||
rcv.read_buffer(host, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mem_zero(device_memory& mem)
|
||||
{
|
||||
#if 0
|
||||
RPCSend snd(socket, "mem_zero");
|
||||
|
||||
snd.archive & mem & size;
|
||||
snd.write();
|
||||
#endif
|
||||
}
|
||||
|
||||
void mem_free(device_memory& mem)
|
||||
{
|
||||
#if 0
|
||||
if(mem) {
|
||||
RPCSend snd(socket, "mem_free");
|
||||
|
||||
snd.archive & mem;
|
||||
snd.write();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void const_copy_to(const char *name, void *host, size_t size)
|
||||
{
|
||||
RPCSend snd(socket, "const_copy_to");
|
||||
|
||||
string name_string(name);
|
||||
|
||||
snd.archive & name_string & size;
|
||||
snd.write();
|
||||
snd.write_buffer(host, size);
|
||||
}
|
||||
|
||||
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
|
||||
{
|
||||
#if 0
|
||||
RPCSend snd(socket, "tex_alloc");
|
||||
|
||||
string name_string(name);
|
||||
|
||||
snd.archive & name_string & width & height & datatype & components & interpolation;
|
||||
snd.write();
|
||||
|
||||
size_t size = width*height*components*datatype_size(datatype);
|
||||
snd.write_buffer(host, size);
|
||||
|
||||
RPCReceive rcv(socket);
|
||||
|
||||
device_ptr mem;
|
||||
*rcv.archive & mem;
|
||||
|
||||
return mem;
|
||||
#endif
|
||||
}
|
||||
|
||||
void tex_free(device_memory& mem)
|
||||
{
|
||||
#if 0
|
||||
if(mem) {
|
||||
RPCSend snd(socket, "tex_free");
|
||||
|
||||
snd.archive & mem;
|
||||
snd.write();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void path_trace(int x, int y, int w, int h, device_ptr buffer, device_ptr rng_state, int pass)
|
||||
{
|
||||
#if 0
|
||||
RPCSend snd(socket, "path_trace");
|
||||
|
||||
snd.archive & x & y & w & h & buffer & rng_state & pass;
|
||||
snd.write();
|
||||
#endif
|
||||
}
|
||||
|
||||
void tonemap(int x, int y, int w, int h, device_ptr rgba, device_ptr buffer, int pass, int resolution)
|
||||
{
|
||||
#if 0
|
||||
RPCSend snd(socket, "tonemap");
|
||||
|
||||
snd.archive & x & y & w & h & rgba & buffer & pass & resolution;
|
||||
snd.write();
|
||||
#endif
|
||||
}
|
||||
|
||||
void task_add(DeviceTask& task)
|
||||
{
|
||||
if(task.type == DeviceTask::TONEMAP)
|
||||
tonemap(task.x, task.y, task.w, task.h, task.rgba, task.buffer, task.pass, task.resolution);
|
||||
else if(task.type == DeviceTask::PATH_TRACE)
|
||||
path_trace(task.x, task.y, task.w, task.h, task.buffer, task.rng_state, task.pass);
|
||||
}
|
||||
|
||||
void task_wait()
|
||||
{
|
||||
}
|
||||
|
||||
void task_cancel()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Device *device_network_create(const char *address)
|
||||
{
|
||||
return new NetworkDevice(address);
|
||||
}
|
||||
|
||||
|
||||
void Device::server_run()
|
||||
{
|
||||
try
|
||||
{
|
||||
/* starts thread that responds to discovery requests */
|
||||
ServerDiscovery discovery;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
||||
/* accept connection */
|
||||
boost::asio::io_service io_service;
|
||||
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), SERVER_PORT));
|
||||
|
||||
tcp::socket socket(io_service);
|
||||
acceptor.accept(socket);
|
||||
|
||||
/* receive remote function calls */
|
||||
for(;;) {
|
||||
RPCReceive rcv(socket);
|
||||
|
||||
if(rcv.name == "description") {
|
||||
string desc = description();
|
||||
|
||||
RPCSend snd(socket);
|
||||
snd.archive & desc;
|
||||
snd.write();
|
||||
}
|
||||
else if(rcv.name == "mem_alloc") {
|
||||
#if 0
|
||||
MemoryType type;
|
||||
size_t size;
|
||||
device_ptr mem;
|
||||
|
||||
*rcv.archive & size & type;
|
||||
mem = mem_alloc(size, type);
|
||||
|
||||
RPCSend snd(socket);
|
||||
snd.archive & mem;
|
||||
snd.write();
|
||||
#endif
|
||||
}
|
||||
else if(rcv.name == "mem_copy_to") {
|
||||
#if 0
|
||||
device_ptr mem;
|
||||
size_t size;
|
||||
|
||||
*rcv.archive & mem & size;
|
||||
|
||||
vector<char> host_vector(size);
|
||||
rcv.read_buffer(&host_vector[0], size);
|
||||
|
||||
mem_copy_to(mem, &host_vector[0], size);
|
||||
#endif
|
||||
}
|
||||
else if(rcv.name == "mem_copy_from") {
|
||||
#if 0
|
||||
device_ptr mem;
|
||||
size_t offset, size;
|
||||
|
||||
*rcv.archive & mem & offset & size;
|
||||
|
||||
vector<char> host_vector(size);
|
||||
|
||||
mem_copy_from(&host_vector[0], mem, offset, size);
|
||||
|
||||
RPCSend snd(socket);
|
||||
snd.write();
|
||||
snd.write_buffer(&host_vector[0], size);
|
||||
#endif
|
||||
}
|
||||
else if(rcv.name == "mem_zero") {
|
||||
#if 0
|
||||
device_ptr mem;
|
||||
size_t size;
|
||||
|
||||
*rcv.archive & mem & size;
|
||||
mem_zero(mem, size);
|
||||
#endif
|
||||
}
|
||||
else if(rcv.name == "mem_free") {
|
||||
#if 0
|
||||
device_ptr mem;
|
||||
|
||||
*rcv.archive & mem;
|
||||
mem_free(mem);
|
||||
#endif
|
||||
}
|
||||
else if(rcv.name == "const_copy_to") {
|
||||
string name_string;
|
||||
size_t size;
|
||||
|
||||
*rcv.archive & name_string & size;
|
||||
|
||||
vector<char> host_vector(size);
|
||||
rcv.read_buffer(&host_vector[0], size);
|
||||
|
||||
const_copy_to(name_string.c_str(), &host_vector[0], size);
|
||||
}
|
||||
else if(rcv.name == "tex_alloc") {
|
||||
#if 0
|
||||
string name_string;
|
||||
DataType datatype;
|
||||
device_ptr mem;
|
||||
size_t width, height;
|
||||
int components;
|
||||
bool interpolation;
|
||||
|
||||
*rcv.archive & name_string & width & height & datatype & components & interpolation;
|
||||
|
||||
size_t size = width*height*components*datatype_size(datatype);
|
||||
|
||||
vector<char> host_vector(size);
|
||||
rcv.read_buffer(&host_vector[0], size);
|
||||
|
||||
mem = tex_alloc(name_string.c_str(), &host_vector[0], width, height, datatype, components, interpolation);
|
||||
|
||||
RPCSend snd(socket);
|
||||
snd.archive & mem;
|
||||
snd.write();
|
||||
#endif
|
||||
}
|
||||
else if(rcv.name == "tex_free") {
|
||||
#if 0
|
||||
device_ptr mem;
|
||||
|
||||
*rcv.archive & mem;
|
||||
tex_free(mem);
|
||||
#endif
|
||||
}
|
||||
else if(rcv.name == "path_trace") {
|
||||
#if 0
|
||||
device_ptr buffer, rng_state;
|
||||
int x, y, w, h;
|
||||
int pass;
|
||||
|
||||
*rcv.archive & x & y & w & h & buffer & rng_state & pass;
|
||||
path_trace(x, y, w, h, buffer, rng_state, pass);
|
||||
#endif
|
||||
}
|
||||
else if(rcv.name == "tonemap") {
|
||||
#if 0
|
||||
device_ptr rgba, buffer;
|
||||
int x, y, w, h;
|
||||
int pass, resolution;
|
||||
|
||||
*rcv.archive & x & y & w & h & rgba & buffer & pass & resolution;
|
||||
tonemap(x, y, w, h, rgba, buffer, pass, resolution);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(exception& e)
|
||||
{
|
||||
cerr << "Network server exception: " << e.what() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
304
intern/cycles/device/device_network.h
Normal file
304
intern/cycles/device/device_network.h
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __DEVICE_NETWORK_H__
|
||||
#define __DEVICE_NETWORK_H__
|
||||
|
||||
#include <boost/archive/text_iarchive.hpp>
|
||||
#include <boost/archive/text_oarchive.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "util_foreach.h"
|
||||
#include "util_list.h"
|
||||
#include "util_string.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::hex;
|
||||
using std::setw;
|
||||
using std::exception;
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
static const int SERVER_PORT = 5120;
|
||||
static const int DISCOVER_PORT = 5121;
|
||||
static const string DISCOVER_REQUEST_MSG = "REQUEST_RENDER_SERVER_IP";
|
||||
static const string DISCOVER_REPLY_MSG = "REPLY_RENDER_SERVER_IP";
|
||||
|
||||
typedef struct RPCSend {
|
||||
RPCSend(tcp::socket& socket_, const string& name_ = "")
|
||||
: name(name_), socket(socket_), archive(archive_stream)
|
||||
{
|
||||
archive & name_;
|
||||
}
|
||||
|
||||
void write()
|
||||
{
|
||||
boost::system::error_code error;
|
||||
|
||||
/* get string from stream */
|
||||
string archive_str = archive_stream.str();
|
||||
|
||||
/* first send fixed size header with size of following data */
|
||||
ostringstream header_stream;
|
||||
header_stream << setw(8) << hex << archive_str.size();
|
||||
string header_str = header_stream.str();
|
||||
|
||||
boost::asio::write(socket,
|
||||
boost::asio::buffer(header_str),
|
||||
boost::asio::transfer_all(), error);
|
||||
|
||||
if(error.value())
|
||||
cout << "Network send error: " << error.message() << "\n";
|
||||
|
||||
/* then send actual data */
|
||||
boost::asio::write(socket,
|
||||
boost::asio::buffer(archive_str),
|
||||
boost::asio::transfer_all(), error);
|
||||
|
||||
if(error.value())
|
||||
cout << "Network send error: " << error.message() << "\n";
|
||||
}
|
||||
|
||||
void write_buffer(void *buffer, size_t size)
|
||||
{
|
||||
boost::system::error_code error;
|
||||
|
||||
boost::asio::write(socket,
|
||||
boost::asio::buffer(buffer, size),
|
||||
boost::asio::transfer_all(), error);
|
||||
|
||||
if(error.value())
|
||||
cout << "Network send error: " << error.message() << "\n";
|
||||
}
|
||||
|
||||
string name;
|
||||
tcp::socket& socket;
|
||||
ostringstream archive_stream;
|
||||
boost::archive::text_oarchive archive;
|
||||
} RPCSend;
|
||||
|
||||
typedef struct RPCReceive {
|
||||
RPCReceive(tcp::socket& socket_)
|
||||
: socket(socket_), archive_stream(NULL), archive(NULL)
|
||||
{
|
||||
/* read head with fixed size */
|
||||
vector<char> header(8);
|
||||
size_t len = boost::asio::read(socket, boost::asio::buffer(header));
|
||||
|
||||
/* verify if we got something */
|
||||
if(len == header.size()) {
|
||||
/* decode header */
|
||||
string header_str(&header[0], header.size());
|
||||
istringstream header_stream(header_str);
|
||||
|
||||
size_t data_size;
|
||||
|
||||
if((header_stream >> hex >> data_size)) {
|
||||
vector<char> data(data_size);
|
||||
size_t len = boost::asio::read(socket, boost::asio::buffer(data));
|
||||
|
||||
if(len == data_size) {
|
||||
archive_str = string(&data[0], data.size());
|
||||
/*istringstream archive_stream(archive_str);
|
||||
boost::archive::text_iarchive archive(archive_stream);*/
|
||||
archive_stream = new istringstream(archive_str);
|
||||
archive = new boost::archive::text_iarchive(*archive_stream);
|
||||
|
||||
*archive & name;
|
||||
}
|
||||
else
|
||||
cout << "Network receive error: data size doens't match header\n";
|
||||
}
|
||||
else
|
||||
cout << "Network receive error: can't decode data size from header\n";
|
||||
}
|
||||
else
|
||||
cout << "Network receive error: invalid header size\n";
|
||||
}
|
||||
|
||||
~RPCReceive()
|
||||
{
|
||||
delete archive;
|
||||
delete archive_stream;
|
||||
}
|
||||
|
||||
void read_buffer(void *buffer, size_t size)
|
||||
{
|
||||
size_t len = boost::asio::read(socket, boost::asio::buffer(buffer, size));
|
||||
|
||||
if(len != size)
|
||||
cout << "Network receive error: buffer size doesn't match expected size\n";
|
||||
}
|
||||
|
||||
string name;
|
||||
tcp::socket& socket;
|
||||
string archive_str;
|
||||
istringstream *archive_stream;
|
||||
boost::archive::text_iarchive *archive;
|
||||
} RPCReceive;
|
||||
|
||||
class ServerDiscovery {
|
||||
public:
|
||||
ServerDiscovery(bool discover = false)
|
||||
: listen_socket(io_service), collect_servers(false)
|
||||
{
|
||||
/* setup listen socket */
|
||||
listen_endpoint.address(boost::asio::ip::address_v4::any());
|
||||
listen_endpoint.port(DISCOVER_PORT);
|
||||
|
||||
listen_socket.open(listen_endpoint.protocol());
|
||||
|
||||
boost::asio::socket_base::reuse_address option(true);
|
||||
listen_socket.set_option(option);
|
||||
|
||||
listen_socket.bind(listen_endpoint);
|
||||
|
||||
/* setup receive callback */
|
||||
async_receive();
|
||||
|
||||
/* start server discovery */
|
||||
if(discover) {
|
||||
collect_servers = true;
|
||||
servers.clear();
|
||||
|
||||
broadcast_message(DISCOVER_REQUEST_MSG);
|
||||
}
|
||||
|
||||
/* start thread */
|
||||
work = new boost::asio::io_service::work(io_service);
|
||||
thread = new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service));
|
||||
}
|
||||
|
||||
~ServerDiscovery()
|
||||
{
|
||||
io_service.stop();
|
||||
thread->join();
|
||||
delete thread;
|
||||
delete work;
|
||||
}
|
||||
|
||||
list<string> get_server_list()
|
||||
{
|
||||
list<string> result;
|
||||
|
||||
mutex.lock();
|
||||
result = servers;
|
||||
mutex.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_receive_from(const boost::system::error_code& error, size_t size)
|
||||
{
|
||||
if(error) {
|
||||
cout << "Server discovery receive error: " << error.message() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if(size > 0) {
|
||||
string msg = string(receive_buffer, size);
|
||||
|
||||
/* handle incoming message */
|
||||
if(collect_servers) {
|
||||
if(msg == DISCOVER_REPLY_MSG) {
|
||||
string address = receive_endpoint.address().to_string();
|
||||
|
||||
mutex.lock();
|
||||
|
||||
/* add address if it's not already in the list */
|
||||
bool found = false;
|
||||
|
||||
foreach(string& server, servers)
|
||||
if(server == address)
|
||||
found = true;
|
||||
|
||||
if(!found)
|
||||
servers.push_back(address);
|
||||
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* reply to request */
|
||||
if(msg == DISCOVER_REQUEST_MSG)
|
||||
broadcast_message(DISCOVER_REPLY_MSG);
|
||||
}
|
||||
}
|
||||
|
||||
async_receive();
|
||||
}
|
||||
|
||||
void async_receive()
|
||||
{
|
||||
listen_socket.async_receive_from(
|
||||
boost::asio::buffer(receive_buffer), receive_endpoint,
|
||||
boost::bind(&ServerDiscovery::handle_receive_from, this,
|
||||
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void broadcast_message(const string& msg)
|
||||
{
|
||||
/* setup broadcast socket */
|
||||
boost::asio::ip::udp::socket socket(io_service);
|
||||
|
||||
socket.open(boost::asio::ip::udp::v4());
|
||||
|
||||
boost::asio::socket_base::broadcast option(true);
|
||||
socket.set_option(option);
|
||||
|
||||
boost::asio::ip::udp::endpoint broadcast_endpoint(
|
||||
boost::asio::ip::address::from_string("255.255.255.255"), DISCOVER_PORT);
|
||||
|
||||
/* broadcast message */
|
||||
socket.send_to(boost::asio::buffer(msg), broadcast_endpoint);
|
||||
}
|
||||
|
||||
/* network service and socket */
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::ip::udp::endpoint listen_endpoint;
|
||||
boost::asio::ip::udp::socket listen_socket;
|
||||
|
||||
/* threading */
|
||||
boost::thread *thread;
|
||||
boost::asio::io_service::work *work;
|
||||
boost::mutex mutex;
|
||||
|
||||
/* buffer and endpoint for receiving messages */
|
||||
char receive_buffer[256];
|
||||
boost::asio::ip::udp::endpoint receive_endpoint;
|
||||
|
||||
/* collection of server addresses in list */
|
||||
bool collect_servers;
|
||||
list<string> servers;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __DEVICE_NETWORK_H__ */
|
||||
|
396
intern/cycles/device/device_opencl.cpp
Normal file
396
intern/cycles/device/device_opencl.cpp
Normal file
@ -0,0 +1,396 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef WITH_OPENCL
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <cl.h>
|
||||
#include <cl_ext.h>
|
||||
#else
|
||||
#include <CL/cl.h>
|
||||
#include <CL/cl_ext.h>
|
||||
#endif
|
||||
|
||||
#include "device.h"
|
||||
#include "device_intern.h"
|
||||
|
||||
#include "util_map.h"
|
||||
#include "util_opengl.h"
|
||||
#include "util_path.h"
|
||||
#include "util_time.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#define CL_MEM_PTR(p) ((cl_mem)(unsigned long)(p))
|
||||
|
||||
class OpenCLDevice : public Device
|
||||
{
|
||||
public:
|
||||
cl_context cxGPUContext;
|
||||
cl_command_queue cqCommandQueue;
|
||||
cl_platform_id cpPlatform;
|
||||
cl_device_id cdDevice;
|
||||
cl_program cpProgram;
|
||||
cl_kernel ckPathTraceKernel;
|
||||
cl_kernel ckFilmConvertKernel;
|
||||
cl_int ciErr;
|
||||
map<string, device_vector<uchar>*> const_mem_map;
|
||||
map<string, device_memory*> mem_map;
|
||||
|
||||
const char *opencl_error_string(cl_int err)
|
||||
{
|
||||
switch (err) {
|
||||
case CL_SUCCESS: return "Success!";
|
||||
case CL_DEVICE_NOT_FOUND: return "Device not found.";
|
||||
case CL_DEVICE_NOT_AVAILABLE: return "Device not available";
|
||||
case CL_COMPILER_NOT_AVAILABLE: return "Compiler not available";
|
||||
case CL_MEM_OBJECT_ALLOCATION_FAILURE: return "Memory object allocation failure";
|
||||
case CL_OUT_OF_RESOURCES: return "Out of resources";
|
||||
case CL_OUT_OF_HOST_MEMORY: return "Out of host memory";
|
||||
case CL_PROFILING_INFO_NOT_AVAILABLE: return "Profiling information not available";
|
||||
case CL_MEM_COPY_OVERLAP: return "Memory copy overlap";
|
||||
case CL_IMAGE_FORMAT_MISMATCH: return "Image format mismatch";
|
||||
case CL_IMAGE_FORMAT_NOT_SUPPORTED: return "Image format not supported";
|
||||
case CL_BUILD_PROGRAM_FAILURE: return "Program build failure";
|
||||
case CL_MAP_FAILURE: return "Map failure";
|
||||
case CL_INVALID_VALUE: return "Invalid value";
|
||||
case CL_INVALID_DEVICE_TYPE: return "Invalid device type";
|
||||
case CL_INVALID_PLATFORM: return "Invalid platform";
|
||||
case CL_INVALID_DEVICE: return "Invalid device";
|
||||
case CL_INVALID_CONTEXT: return "Invalid context";
|
||||
case CL_INVALID_QUEUE_PROPERTIES: return "Invalid queue properties";
|
||||
case CL_INVALID_COMMAND_QUEUE: return "Invalid command queue";
|
||||
case CL_INVALID_HOST_PTR: return "Invalid host pointer";
|
||||
case CL_INVALID_MEM_OBJECT: return "Invalid memory object";
|
||||
case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: return "Invalid image format descriptor";
|
||||
case CL_INVALID_IMAGE_SIZE: return "Invalid image size";
|
||||
case CL_INVALID_SAMPLER: return "Invalid sampler";
|
||||
case CL_INVALID_BINARY: return "Invalid binary";
|
||||
case CL_INVALID_BUILD_OPTIONS: return "Invalid build options";
|
||||
case CL_INVALID_PROGRAM: return "Invalid program";
|
||||
case CL_INVALID_PROGRAM_EXECUTABLE: return "Invalid program executable";
|
||||
case CL_INVALID_KERNEL_NAME: return "Invalid kernel name";
|
||||
case CL_INVALID_KERNEL_DEFINITION: return "Invalid kernel definition";
|
||||
case CL_INVALID_KERNEL: return "Invalid kernel";
|
||||
case CL_INVALID_ARG_INDEX: return "Invalid argument index";
|
||||
case CL_INVALID_ARG_VALUE: return "Invalid argument value";
|
||||
case CL_INVALID_ARG_SIZE: return "Invalid argument size";
|
||||
case CL_INVALID_KERNEL_ARGS: return "Invalid kernel arguments";
|
||||
case CL_INVALID_WORK_DIMENSION: return "Invalid work dimension";
|
||||
case CL_INVALID_WORK_GROUP_SIZE: return "Invalid work group size";
|
||||
case CL_INVALID_WORK_ITEM_SIZE: return "Invalid work item size";
|
||||
case CL_INVALID_GLOBAL_OFFSET: return "Invalid global offset";
|
||||
case CL_INVALID_EVENT_WAIT_LIST: return "Invalid event wait list";
|
||||
case CL_INVALID_EVENT: return "Invalid event";
|
||||
case CL_INVALID_OPERATION: return "Invalid operation";
|
||||
case CL_INVALID_GL_OBJECT: return "Invalid OpenGL object";
|
||||
case CL_INVALID_BUFFER_SIZE: return "Invalid buffer size";
|
||||
case CL_INVALID_MIP_LEVEL: return "Invalid mip-map level";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void opencl_assert(cl_int err)
|
||||
{
|
||||
if(err != CL_SUCCESS) {
|
||||
printf("error (%d): %s\n", err, opencl_error_string(err));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
OpenCLDevice(bool background_)
|
||||
{
|
||||
background = background_;
|
||||
|
||||
/* setup device */
|
||||
ciErr = clGetPlatformIDs(1, &cpPlatform, NULL);
|
||||
opencl_assert(ciErr);
|
||||
|
||||
ciErr = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 1, &cdDevice, NULL);
|
||||
opencl_assert(ciErr);
|
||||
|
||||
cxGPUContext = clCreateContext(0, 1, &cdDevice, NULL /*clLogMessagesToStdoutAPPLE */, NULL, &ciErr);
|
||||
opencl_assert(ciErr);
|
||||
|
||||
cqCommandQueue = clCreateCommandQueue(cxGPUContext, cdDevice, 0, &ciErr);
|
||||
opencl_assert(ciErr);
|
||||
|
||||
/* compile kernel */
|
||||
string source = string_printf("#include \"kernel.cl\" // %lf\n", time_dt());
|
||||
size_t source_len = source.size();
|
||||
string build_options = "-I ../kernel -I ../util -Werror -DCCL_NAMESPACE_BEGIN= -DCCL_NAMESPACE_END="; //" + path_get("kernel") + " -Werror";
|
||||
//printf("path %s\n", path_get("kernel").c_str());
|
||||
|
||||
//clUnloadCompiler();
|
||||
|
||||
cpProgram = clCreateProgramWithSource(cxGPUContext, 1, (const char **)&source, &source_len, &ciErr);
|
||||
|
||||
opencl_assert(ciErr);
|
||||
|
||||
ciErr = clBuildProgram(cpProgram, 0, NULL, build_options.c_str(), NULL, NULL);
|
||||
if(ciErr != CL_SUCCESS) {
|
||||
char *build_log;
|
||||
size_t ret_val_size;
|
||||
|
||||
clGetProgramBuildInfo(cpProgram, cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
|
||||
|
||||
build_log = new char[ret_val_size+1];
|
||||
clGetProgramBuildInfo(cpProgram, cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
|
||||
|
||||
build_log[ret_val_size] = '\0';
|
||||
printf("OpenCL build failed:\n %s\n", build_log);
|
||||
|
||||
delete[] build_log;
|
||||
|
||||
opencl_assert(ciErr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ckPathTraceKernel = clCreateKernel(cpProgram, "kernel_ocl_path_trace", &ciErr);
|
||||
opencl_assert(ciErr);
|
||||
ckFilmConvertKernel = clCreateKernel(cpProgram, "kernel_ocl_tonemap", &ciErr);
|
||||
opencl_assert(ciErr);
|
||||
}
|
||||
|
||||
~OpenCLDevice()
|
||||
{
|
||||
map<string, device_vector<uchar>*>::iterator mt;
|
||||
for(mt = const_mem_map.begin(); mt != const_mem_map.end(); mt++) {
|
||||
mem_free(*(mt->second));
|
||||
delete mt->second;
|
||||
}
|
||||
|
||||
clReleaseKernel(ckPathTraceKernel);
|
||||
clReleaseKernel(ckFilmConvertKernel);
|
||||
clReleaseProgram(cpProgram);
|
||||
clReleaseCommandQueue(cqCommandQueue);
|
||||
clReleaseContext(cxGPUContext);
|
||||
}
|
||||
|
||||
string description()
|
||||
{
|
||||
char name[1024];
|
||||
|
||||
clGetDeviceInfo(cdDevice, CL_DEVICE_NAME, sizeof(name), &name, NULL);
|
||||
|
||||
return string("OpenCL ") + name;
|
||||
}
|
||||
|
||||
void mem_alloc(device_memory& mem, MemoryType type)
|
||||
{
|
||||
size_t size = mem.memory_size();
|
||||
|
||||
if(type == MEM_READ_ONLY)
|
||||
mem.device_pointer = (device_ptr)clCreateBuffer(cxGPUContext, CL_MEM_READ_ONLY, size, NULL, &ciErr);
|
||||
else if(type == MEM_WRITE_ONLY)
|
||||
mem.device_pointer = (device_ptr)clCreateBuffer(cxGPUContext, CL_MEM_WRITE_ONLY, size, NULL, &ciErr);
|
||||
else
|
||||
mem.device_pointer = (device_ptr)clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE, size, NULL, &ciErr);
|
||||
|
||||
opencl_assert(ciErr);
|
||||
}
|
||||
|
||||
void mem_copy_to(device_memory& mem)
|
||||
{
|
||||
/* this is blocking */
|
||||
size_t size = mem.memory_size();
|
||||
ciErr = clEnqueueWriteBuffer(cqCommandQueue, CL_MEM_PTR(mem.device_pointer), CL_TRUE, 0, size, (void*)mem.data_pointer, 0, NULL, NULL);
|
||||
opencl_assert(ciErr);
|
||||
}
|
||||
|
||||
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
|
||||
{
|
||||
ciErr = clEnqueueReadBuffer(cqCommandQueue, CL_MEM_PTR(mem.device_pointer), CL_TRUE, offset, size, (uchar*)mem.data_pointer + offset, 0, NULL, NULL);
|
||||
opencl_assert(ciErr);
|
||||
}
|
||||
|
||||
void mem_zero(device_memory& mem)
|
||||
{
|
||||
if(mem.device_pointer) {
|
||||
memset((void*)mem.data_pointer, 0, mem.memory_size());
|
||||
mem_copy_to(mem);
|
||||
}
|
||||
}
|
||||
|
||||
void mem_free(device_memory& mem)
|
||||
{
|
||||
if(mem.device_pointer) {
|
||||
ciErr = clReleaseMemObject(CL_MEM_PTR(mem.device_pointer));
|
||||
mem.device_pointer = 0;
|
||||
opencl_assert(ciErr);
|
||||
}
|
||||
}
|
||||
|
||||
void const_copy_to(const char *name, void *host, size_t size)
|
||||
{
|
||||
if(const_mem_map.find(name) == const_mem_map.end()) {
|
||||
device_vector<uchar> *data = new device_vector<uchar>();
|
||||
data->copy((uchar*)host, size);
|
||||
|
||||
mem_alloc(*data, MEM_READ_ONLY);
|
||||
const_mem_map[name] = data;
|
||||
}
|
||||
else {
|
||||
device_vector<uchar> *data = const_mem_map[name];
|
||||
data->copy((uchar*)host, size);
|
||||
}
|
||||
|
||||
mem_copy_to(*const_mem_map[name]);
|
||||
}
|
||||
|
||||
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
|
||||
{
|
||||
mem_alloc(mem, MEM_READ_ONLY);
|
||||
mem_map[name] = &mem;
|
||||
}
|
||||
|
||||
void tex_free(device_memory& mem)
|
||||
{
|
||||
if(mem.data_pointer)
|
||||
mem_free(mem);
|
||||
}
|
||||
|
||||
size_t global_size_round_up(int group_size, int global_size)
|
||||
{
|
||||
int r = global_size % group_size;
|
||||
return global_size + ((r == 0)? 0: group_size - r);
|
||||
}
|
||||
|
||||
void path_trace(DeviceTask& task)
|
||||
{
|
||||
/* cast arguments to cl types */
|
||||
cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
|
||||
cl_mem d_buffer = CL_MEM_PTR(task.buffer);
|
||||
cl_mem d_rng_state = CL_MEM_PTR(task.rng_state);
|
||||
cl_int d_x = task.x;
|
||||
cl_int d_y = task.y;
|
||||
cl_int d_w = task.w;
|
||||
cl_int d_h = task.h;
|
||||
cl_int d_pass = task.pass;
|
||||
|
||||
/* pass arguments */
|
||||
int narg = 0;
|
||||
ciErr = 0;
|
||||
|
||||
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_data), (void*)&d_data);
|
||||
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_buffer), (void*)&d_buffer);
|
||||
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_rng_state), (void*)&d_rng_state);
|
||||
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_pass), (void*)&d_pass);
|
||||
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_x), (void*)&d_x);
|
||||
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_y), (void*)&d_y);
|
||||
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_w), (void*)&d_w);
|
||||
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_h), (void*)&d_h);
|
||||
|
||||
opencl_assert(ciErr);
|
||||
|
||||
size_t local_size[2] = {1, 1};
|
||||
size_t global_size[2] = {global_size_round_up(local_size[0], d_w), global_size_round_up(local_size[1], d_h)};
|
||||
|
||||
/* run kernel */
|
||||
ciErr = clEnqueueNDRangeKernel(cqCommandQueue, ckPathTraceKernel, 2, NULL, global_size, local_size, 0, NULL, NULL);
|
||||
opencl_assert(ciErr);
|
||||
opencl_assert(clFinish(cqCommandQueue));
|
||||
}
|
||||
|
||||
cl_int set_kernel_arg_mem(cl_kernel kernel, int *narg, const char *name)
|
||||
{
|
||||
device_memory *mem = mem_map[name];
|
||||
cl_mem ptr = CL_MEM_PTR(mem->device_pointer);
|
||||
cl_int size = mem->data_width;
|
||||
cl_int err = 0;
|
||||
|
||||
err |= clSetKernelArg(kernel, (*narg)++, sizeof(ptr), (void*)&ptr);
|
||||
opencl_assert(err);
|
||||
err |= clSetKernelArg(kernel, (*narg)++, sizeof(size), (void*)&size);
|
||||
opencl_assert(err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void tonemap(DeviceTask& task)
|
||||
{
|
||||
/* cast arguments to cl types */
|
||||
cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
|
||||
cl_mem d_rgba = CL_MEM_PTR(task.rgba);
|
||||
cl_mem d_buffer = CL_MEM_PTR(task.buffer);
|
||||
cl_int d_x = task.x;
|
||||
cl_int d_y = task.y;
|
||||
cl_int d_w = task.w;
|
||||
cl_int d_h = task.h;
|
||||
cl_int d_pass = task.pass;
|
||||
cl_int d_resolution = task.resolution;
|
||||
|
||||
/* pass arguments */
|
||||
int narg = 0;
|
||||
ciErr = 0;
|
||||
|
||||
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_data), (void*)&d_data);
|
||||
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_rgba), (void*)&d_rgba);
|
||||
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_buffer), (void*)&d_buffer);
|
||||
ciErr |= set_kernel_arg_mem(ckFilmConvertKernel, &narg, "__response_curve_R");
|
||||
ciErr |= set_kernel_arg_mem(ckFilmConvertKernel, &narg, "__response_curve_G");
|
||||
ciErr |= set_kernel_arg_mem(ckFilmConvertKernel, &narg, "__response_curve_B");
|
||||
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_pass), (void*)&d_pass);
|
||||
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_resolution), (void*)&d_resolution);
|
||||
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_x), (void*)&d_x);
|
||||
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_y), (void*)&d_y);
|
||||
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_w), (void*)&d_w);
|
||||
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_h), (void*)&d_h);
|
||||
|
||||
opencl_assert(ciErr);
|
||||
|
||||
size_t local_size[2] = {1, 1};
|
||||
size_t global_size[2] = {global_size_round_up(local_size[0], d_w), global_size_round_up(local_size[1], d_h)};
|
||||
|
||||
/* run kernel */
|
||||
ciErr = clEnqueueNDRangeKernel(cqCommandQueue, ckFilmConvertKernel, 2, NULL, global_size, local_size, 0, NULL, NULL);
|
||||
opencl_assert(ciErr);
|
||||
opencl_assert(clFinish(cqCommandQueue));
|
||||
}
|
||||
|
||||
void task_add(DeviceTask& task)
|
||||
{
|
||||
if(task.type == DeviceTask::TONEMAP)
|
||||
tonemap(task);
|
||||
else if(task.type == DeviceTask::PATH_TRACE)
|
||||
path_trace(task);
|
||||
}
|
||||
|
||||
void task_wait()
|
||||
{
|
||||
}
|
||||
|
||||
void task_cancel()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Device *device_opencl_create(bool background)
|
||||
{
|
||||
return new OpenCLDevice(background);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* WITH_OPENCL */
|
||||
|
105
intern/cycles/doc/CMakeLists.txt
Normal file
105
intern/cycles/doc/CMakeLists.txt
Normal file
@ -0,0 +1,105 @@
|
||||
|
||||
INSTALL(DIRECTORY license DESTINATION ${INSTALL_PATH}/cycles)
|
||||
|
||||
SET(doc_sources
|
||||
index.html
|
||||
|
||||
development/build.html
|
||||
development/bvh.html
|
||||
development/design.html
|
||||
development/device_abstraction.html
|
||||
development/displacement.html
|
||||
development/feature_todo.html
|
||||
development/known_issues.html
|
||||
development/geometric_issues.html
|
||||
development/ideas.html
|
||||
development/index.html
|
||||
development/kernel.html
|
||||
development/license.html
|
||||
development/node_guidelines.html
|
||||
development/optimization.html
|
||||
development/osl_gpu.html
|
||||
development/papers.html
|
||||
development/sobol.html
|
||||
development/source.html
|
||||
development/subdivision.html
|
||||
development/threads.html
|
||||
development/units_colors.html
|
||||
|
||||
reference/camera.html
|
||||
reference/curve.html
|
||||
reference/devices.html
|
||||
reference/film.html
|
||||
reference/index.html
|
||||
reference/integrator.html
|
||||
reference/interactive.html
|
||||
reference/lamp.html
|
||||
reference/mesh.html
|
||||
reference/motion_blur.html
|
||||
reference/particle.html
|
||||
reference/subdivision.html
|
||||
reference/world.html
|
||||
|
||||
reference/material/displacement.html
|
||||
reference/material/index.html
|
||||
reference/material/surface.html
|
||||
reference/material/volume.html
|
||||
|
||||
reference/shader/background.html
|
||||
reference/shader/bsdf.html
|
||||
reference/shader/color_operations.html
|
||||
reference/shader/custom.html
|
||||
reference/shader/emission.html
|
||||
reference/shader/image_textures.html
|
||||
reference/shader/index.html
|
||||
reference/shader/input.html
|
||||
reference/shader/output.html
|
||||
reference/shader/procedural_textures.html
|
||||
reference/shader/vector_operations.html
|
||||
reference/shader/volume.html
|
||||
reference/shader/volume_textures.html)
|
||||
|
||||
SET(doc_extra
|
||||
development/images/rng_lcg_50_pass.png
|
||||
development/images/rng_sobol_50_pass.png
|
||||
development/threads.svg
|
||||
reference/camera_ortho.svg
|
||||
reference/camera_persp.svg
|
||||
reference/material/material.svg
|
||||
reference/shader/bsdf.svg
|
||||
style/style.css)
|
||||
|
||||
SET(doc_templates
|
||||
templates/development.html
|
||||
templates/footer.html
|
||||
templates/header.html
|
||||
templates/nodes.html
|
||||
templates/reference.html)
|
||||
|
||||
IF(WITH_DOCS)
|
||||
MACRO(install_doc_file source_file html_file)
|
||||
GET_FILENAME_COMPONENT(subdir ${source_file} PATH)
|
||||
INSTALL(
|
||||
FILES ${html_file}
|
||||
DESTINATION ${INSTALL_PATH}/cycles/doc/${subdir})
|
||||
ENDMACRO()
|
||||
|
||||
FOREACH(_file ${doc_sources})
|
||||
SET(source_file ${_file})
|
||||
SET(html_file ${CMAKE_CURRENT_BINARY_DIR}/${_file})
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${html_file}
|
||||
COMMAND python generate.py ${source_file} ${html_file} ${CYCLES_VERSION}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${source_file} ${doc_templates} generate.py)
|
||||
LIST(APPEND html_files ${html_file})
|
||||
install_doc_file(${source_file} ${html_file})
|
||||
ENDFOREACH()
|
||||
|
||||
FOREACH(_file ${doc_extra})
|
||||
install_doc_file(${_file} ${_file})
|
||||
ENDFOREACH()
|
||||
|
||||
ADD_CUSTOM_TARGET(doc ALL DEPENDS ${html_files})
|
||||
ENDIF()
|
||||
|
203
intern/cycles/doc/license/Apache_2.0.txt
Normal file
203
intern/cycles/doc/license/Apache_2.0.txt
Normal file
@ -0,0 +1,203 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
17
intern/cycles/doc/license/Blender.txt
Normal file
17
intern/cycles/doc/license/Blender.txt
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Contributor(s): Alfredo de Greef, Blender Foundation
|
||||
|
342
intern/cycles/doc/license/GPL.txt
Normal file
342
intern/cycles/doc/license/GPL.txt
Normal file
@ -0,0 +1,342 @@
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
|
29
intern/cycles/doc/license/ILM.txt
Normal file
29
intern/cycles/doc/license/ILM.txt
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
|
||||
Digital Ltd. LLC. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Industrial Light & Magic nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
36
intern/cycles/doc/license/NVidia.txt
Normal file
36
intern/cycles/doc/license/NVidia.txt
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
Copyright 2006, NVIDIA Corporation Ignacio Castano <icastano@nvidia.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
Copyright 2009-2010 NVIDIA Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
28
intern/cycles/doc/license/OSL.txt
Normal file
28
intern/cycles/doc/license/OSL.txt
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
29
intern/cycles/doc/license/Sobol.txt
Normal file
29
intern/cycles/doc/license/Sobol.txt
Normal file
@ -0,0 +1,29 @@
|
||||
Copyright (c) 2008, Frances Y. Kuo and Stephen Joe
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the copyright holders nor the names of the
|
||||
University of New South Wales and the University of Waikato
|
||||
and its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
11
intern/cycles/doc/license/readme.txt
Normal file
11
intern/cycles/doc/license/readme.txt
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
This program uses code from various sources. These are the licenses:
|
||||
|
||||
* New code is licensed under the GPL license v2 or later.
|
||||
* BVH building and traversal code is licensed under Apache License v2.
|
||||
* Approximate Catmull Clark subdivision code is licensed under the MIT license.
|
||||
* Open Shading Language code on GPU is licensed under the Modified BSD license.
|
||||
* Sobol direction vectors are licensed under the Modified BSD license.
|
||||
* Matrix code adapted from OpenEXR under the Modified BSD license.
|
||||
* Procedural texture functions from Blender are licensed under GPL v2 or later.
|
||||
|
104
intern/cycles/kernel/CMakeLists.txt
Normal file
104
intern/cycles/kernel/CMakeLists.txt
Normal file
@ -0,0 +1,104 @@
|
||||
|
||||
SET(sources
|
||||
kernel.cpp
|
||||
kernel.cl
|
||||
kernel.cu)
|
||||
|
||||
SET(headers
|
||||
kernel.h
|
||||
kernel_bvh.h
|
||||
kernel_camera.h
|
||||
kernel_compat_cpu.h
|
||||
kernel_compat_cuda.h
|
||||
kernel_compat_opencl.h
|
||||
kernel_differential.h
|
||||
kernel_displace.h
|
||||
kernel_emission.h
|
||||
kernel_film.h
|
||||
kernel_globals.h
|
||||
kernel_light.h
|
||||
kernel_math.h
|
||||
kernel_mbvh.h
|
||||
kernel_montecarlo.h
|
||||
kernel_object.h
|
||||
kernel_path.h
|
||||
kernel_qbvh.h
|
||||
kernel_random.h
|
||||
kernel_shader.h
|
||||
kernel_triangle.h
|
||||
kernel_types.h
|
||||
svm/bsdf.h
|
||||
svm/bsdf_ashikhmin_velvet.h
|
||||
svm/bsdf_diffuse.h
|
||||
svm/bsdf_microfacet.h
|
||||
svm/bsdf_reflection.h
|
||||
svm/bsdf_refraction.h
|
||||
svm/bsdf_transparent.h
|
||||
svm/bsdf_ward.h
|
||||
svm/bsdf_westin.h
|
||||
svm/emissive.h
|
||||
svm/svm.h
|
||||
svm/svm_attribute.h
|
||||
svm/svm_blend.h
|
||||
svm/svm_bsdf.h
|
||||
svm/svm_closure.h
|
||||
svm/svm_clouds.h
|
||||
svm/svm_convert.h
|
||||
svm/svm_displace.h
|
||||
svm/svm_distorted_noise.h
|
||||
svm/svm_fresnel.h
|
||||
svm/svm_geometry.h
|
||||
svm/svm_image.h
|
||||
svm/svm_light_path.h
|
||||
svm/svm_magic.h
|
||||
svm/svm_mapping.h
|
||||
svm/svm_marble.h
|
||||
svm/svm_math.h
|
||||
svm/svm_mix.h
|
||||
svm/svm_musgrave.h
|
||||
svm/svm_noise.h
|
||||
svm/svm_noisetex.h
|
||||
svm/svm_sky.h
|
||||
svm/svm_stucci.h
|
||||
svm/svm_tex_coord.h
|
||||
svm/svm_texture.h
|
||||
svm/svm_types.h
|
||||
svm/svm_value.h
|
||||
svm/svm_voronoi.h
|
||||
svm/svm_wood.h
|
||||
svm/volume.h
|
||||
)
|
||||
|
||||
# CUDA module
|
||||
|
||||
IF(WITH_CUDA)
|
||||
SET(cuda_sources kernel.cu ${headers})
|
||||
SET(cuda_cubins)
|
||||
|
||||
FOREACH(arch ${CUDA_ARCH})
|
||||
SET(cuda_cubin kernel_${arch}.cubin)
|
||||
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${cuda_cubin}
|
||||
COMMAND ${CUDA_NVCC} -arch=${arch} -m64 --cubin ${CMAKE_CURRENT_SOURCE_DIR}/kernel.cu --use_fast_math -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin} --ptxas-options="-v" --maxrregcount=${CUDA_MAXREG} --opencc-options -OPT:Olimit=0 -I${CMAKE_CURRENT_SOURCE_DIR}/../util -I${CMAKE_CURRENT_SOURCE_DIR}/svm -DCCL_NAMESPACE_BEGIN= -DCCL_NAMESPACE_END=
|
||||
DEPENDS ${cuda_sources})
|
||||
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin} DESTINATION ${INSTALL_PATH}/cycles/lib)
|
||||
LIST(APPEND cuda_cubins ${cuda_cubin})
|
||||
ENDFOREACH()
|
||||
|
||||
ADD_CUSTOM_TARGET(kernel_cuda ALL DEPENDS ${cuda_cubins})
|
||||
ENDIF(WITH_CUDA)
|
||||
|
||||
# OSL module
|
||||
|
||||
IF(WITH_OSL)
|
||||
ADD_SUBDIRECTORY(osl)
|
||||
ENDIF(WITH_OSL)
|
||||
|
||||
# CPU module
|
||||
|
||||
INCLUDE_DIRECTORIES(. ../util osl svm)
|
||||
|
||||
ADD_LIBRARY(kernel ${sources} ${headers})
|
||||
|
105
intern/cycles/kernel/kernel.cl
Normal file
105
intern/cycles/kernel/kernel.cl
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* OpenCL kernel entry points - unfinished */
|
||||
|
||||
#include "kernel_compat_opencl.h"
|
||||
#include "kernel_math.h"
|
||||
#include "kernel_types.h"
|
||||
#include "kernel_globals.h"
|
||||
|
||||
typedef struct KernelGlobals {
|
||||
__constant KernelData *data;
|
||||
|
||||
__global float *__response_curve_R;
|
||||
int __response_curve_R_width;
|
||||
|
||||
__global float *__response_curve_G;
|
||||
int __response_curve_G_width;
|
||||
|
||||
__global float *__response_curve_B;
|
||||
int __response_curve_B_width;
|
||||
} KernelGlobals;
|
||||
|
||||
#include "kernel_film.h"
|
||||
//#include "kernel_path.h"
|
||||
//#include "kernel_displace.h"
|
||||
|
||||
__kernel void kernel_ocl_path_trace(__constant KernelData *data, __global float4 *buffer, __global uint *rng_state, int pass, int sx, int sy, int sw, int sh)
|
||||
{
|
||||
KernelGlobals kglobals, *kg = &kglobals;
|
||||
kg->data = data;
|
||||
|
||||
int x = get_global_id(0);
|
||||
int y = get_global_id(1);
|
||||
int w = kernel_data.cam.width;
|
||||
|
||||
if(x < sx + sw && y < sy + sh) {
|
||||
if(pass == 0) {
|
||||
buffer[x + w*y].x = 0.5f;
|
||||
buffer[x + w*y].y = 0.5f;
|
||||
buffer[x + w*y].z = 0.5f;
|
||||
}
|
||||
else {
|
||||
buffer[x + w*y].x += 0.5f;
|
||||
buffer[x + w*y].y += 0.5f;
|
||||
buffer[x + w*y].z += 0.5f;
|
||||
}
|
||||
|
||||
//= make_float3(1.0f, 0.9f, 0.0f);
|
||||
//kernel_path_trace(buffer, rng_state, pass, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
__kernel void kernel_ocl_tonemap(
|
||||
__constant KernelData *data,
|
||||
__global uchar4 *rgba,
|
||||
__global float4 *buffer,
|
||||
__global float *__response_curve_R,
|
||||
int __response_curve_R_width,
|
||||
__global float *__response_curve_G,
|
||||
int __response_curve_G_width,
|
||||
__global float *__response_curve_B,
|
||||
int __response_curve_B_width,
|
||||
int pass, int resolution,
|
||||
int sx, int sy, int sw, int sh)
|
||||
{
|
||||
KernelGlobals kglobals, *kg = &kglobals;
|
||||
|
||||
kg->data = data;
|
||||
kg->__response_curve_R = __response_curve_R;
|
||||
kg->__response_curve_R_width = __response_curve_R_width;
|
||||
kg->__response_curve_G = __response_curve_G;
|
||||
kg->__response_curve_G_width = __response_curve_G_width;
|
||||
kg->__response_curve_B = __response_curve_B;
|
||||
kg->__response_curve_B_width = __response_curve_B_width;
|
||||
|
||||
int x = sx + get_global_id(0);
|
||||
int y = sy + get_global_id(1);
|
||||
|
||||
if(x < sx + sw && y < sy + sh)
|
||||
kernel_film_tonemap(kg, rgba, buffer, pass, resolution, x, y);
|
||||
}
|
||||
|
||||
__kernel void kernel_ocl_displace(__global uint4 *input, __global float3 *offset, int sx)
|
||||
{
|
||||
int x = sx + get_global_id(0);
|
||||
|
||||
kernel_displace(input, offset, x);
|
||||
}
|
||||
|
300
intern/cycles/kernel/kernel.cpp
Normal file
300
intern/cycles/kernel/kernel.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* CPU kernel entry points */
|
||||
|
||||
#include "kernel.h"
|
||||
#include "kernel_compat_cpu.h"
|
||||
#include "kernel_math.h"
|
||||
#include "kernel_types.h"
|
||||
#include "kernel_globals.h"
|
||||
#include "kernel_film.h"
|
||||
#include "kernel_path.h"
|
||||
#include "kernel_displace.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Globals */
|
||||
|
||||
KernelGlobals *kernel_globals_create()
|
||||
{
|
||||
KernelGlobals *kg = new KernelGlobals();
|
||||
#ifdef WITH_OSL
|
||||
kg->osl.use = false;
|
||||
#endif
|
||||
return kg;
|
||||
}
|
||||
|
||||
void kernel_globals_free(KernelGlobals *kg)
|
||||
{
|
||||
delete kg;
|
||||
}
|
||||
|
||||
/* OSL */
|
||||
|
||||
#ifdef WITH_OSL
|
||||
|
||||
void *kernel_osl_memory(KernelGlobals *kg)
|
||||
{
|
||||
return (void*)&kg->osl;
|
||||
}
|
||||
|
||||
bool kernel_osl_use(KernelGlobals *kg)
|
||||
{
|
||||
return kg->osl.use;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Memory Copy */
|
||||
|
||||
void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size)
|
||||
{
|
||||
if(strcmp(name, "__data") == 0)
|
||||
memcpy(&kg->__data, host, size);
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height)
|
||||
{
|
||||
if(strcmp(name, "__bvh_nodes") == 0) {
|
||||
kg->__bvh_nodes.data = (float4*)mem;
|
||||
kg->__bvh_nodes.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__objects") == 0) {
|
||||
kg->__objects.data = (float4*)mem;
|
||||
kg->__objects.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__tri_normal") == 0) {
|
||||
kg->__tri_normal.data = (float4*)mem;
|
||||
kg->__tri_normal.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__tri_woop") == 0) {
|
||||
kg->__tri_woop.data = (float4*)mem;
|
||||
kg->__tri_woop.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__prim_index") == 0) {
|
||||
kg->__prim_index.data = (uint*)mem;
|
||||
kg->__prim_index.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__prim_object") == 0) {
|
||||
kg->__prim_object.data = (uint*)mem;
|
||||
kg->__prim_object.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__object_node") == 0) {
|
||||
kg->__object_node.data = (uint*)mem;
|
||||
kg->__object_node.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__tri_vnormal") == 0) {
|
||||
kg->__tri_vnormal.data = (float4*)mem;
|
||||
kg->__tri_vnormal.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__tri_vindex") == 0) {
|
||||
kg->__tri_vindex.data = (float4*)mem;
|
||||
kg->__tri_vindex.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__tri_verts") == 0) {
|
||||
kg->__tri_verts.data = (float4*)mem;
|
||||
kg->__tri_verts.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__light_distribution") == 0) {
|
||||
kg->__light_distribution.data = (float4*)mem;
|
||||
kg->__light_distribution.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__light_point") == 0) {
|
||||
kg->__light_point.data = (float4*)mem;
|
||||
kg->__light_point.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__svm_nodes") == 0) {
|
||||
kg->__svm_nodes.data = (uint4*)mem;
|
||||
kg->__svm_nodes.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__filter_table") == 0) {
|
||||
kg->__filter_table.data = (float*)mem;
|
||||
kg->__filter_table.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__response_curve_R") == 0) {
|
||||
kg->__response_curve_R.data = (float*)mem;
|
||||
kg->__response_curve_R.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__response_curve_B") == 0) {
|
||||
kg->__response_curve_B.data = (float*)mem;
|
||||
kg->__response_curve_B.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__response_curve_G") == 0) {
|
||||
kg->__response_curve_G.data = (float*)mem;
|
||||
kg->__response_curve_G.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__sobol_directions") == 0) {
|
||||
kg->__sobol_directions.data = (uint*)mem;
|
||||
kg->__sobol_directions.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__attributes_map") == 0) {
|
||||
kg->__attributes_map.data = (uint4*)mem;
|
||||
kg->__attributes_map.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__attributes_float") == 0) {
|
||||
kg->__attributes_float.data = (float*)mem;
|
||||
kg->__attributes_float.width = width;
|
||||
}
|
||||
else if(strcmp(name, "__attributes_float3") == 0) {
|
||||
kg->__attributes_float3.data = (float4*)mem;
|
||||
kg->__attributes_float3.width = width;
|
||||
}
|
||||
else if(strstr(name, "__tex_image")) {
|
||||
texture_image_uchar4 *tex = NULL;
|
||||
int id = atoi(name + strlen("__tex_image_"));
|
||||
|
||||
switch(id) {
|
||||
case 0: tex = &kg->__tex_image_000; break;
|
||||
case 1: tex = &kg->__tex_image_001; break;
|
||||
case 2: tex = &kg->__tex_image_002; break;
|
||||
case 3: tex = &kg->__tex_image_003; break;
|
||||
case 4: tex = &kg->__tex_image_004; break;
|
||||
case 5: tex = &kg->__tex_image_005; break;
|
||||
case 6: tex = &kg->__tex_image_006; break;
|
||||
case 7: tex = &kg->__tex_image_007; break;
|
||||
case 8: tex = &kg->__tex_image_008; break;
|
||||
case 9: tex = &kg->__tex_image_009; break;
|
||||
case 10: tex = &kg->__tex_image_010; break;
|
||||
case 11: tex = &kg->__tex_image_011; break;
|
||||
case 12: tex = &kg->__tex_image_012; break;
|
||||
case 13: tex = &kg->__tex_image_013; break;
|
||||
case 14: tex = &kg->__tex_image_014; break;
|
||||
case 15: tex = &kg->__tex_image_015; break;
|
||||
case 16: tex = &kg->__tex_image_016; break;
|
||||
case 17: tex = &kg->__tex_image_017; break;
|
||||
case 18: tex = &kg->__tex_image_018; break;
|
||||
case 19: tex = &kg->__tex_image_019; break;
|
||||
case 20: tex = &kg->__tex_image_020; break;
|
||||
case 21: tex = &kg->__tex_image_021; break;
|
||||
case 22: tex = &kg->__tex_image_022; break;
|
||||
case 23: tex = &kg->__tex_image_023; break;
|
||||
case 24: tex = &kg->__tex_image_024; break;
|
||||
case 25: tex = &kg->__tex_image_025; break;
|
||||
case 26: tex = &kg->__tex_image_026; break;
|
||||
case 27: tex = &kg->__tex_image_027; break;
|
||||
case 28: tex = &kg->__tex_image_028; break;
|
||||
case 29: tex = &kg->__tex_image_029; break;
|
||||
case 30: tex = &kg->__tex_image_030; break;
|
||||
case 31: tex = &kg->__tex_image_031; break;
|
||||
case 32: tex = &kg->__tex_image_032; break;
|
||||
case 33: tex = &kg->__tex_image_033; break;
|
||||
case 34: tex = &kg->__tex_image_034; break;
|
||||
case 35: tex = &kg->__tex_image_035; break;
|
||||
case 36: tex = &kg->__tex_image_036; break;
|
||||
case 37: tex = &kg->__tex_image_037; break;
|
||||
case 38: tex = &kg->__tex_image_038; break;
|
||||
case 39: tex = &kg->__tex_image_039; break;
|
||||
case 40: tex = &kg->__tex_image_040; break;
|
||||
case 41: tex = &kg->__tex_image_041; break;
|
||||
case 42: tex = &kg->__tex_image_042; break;
|
||||
case 43: tex = &kg->__tex_image_043; break;
|
||||
case 44: tex = &kg->__tex_image_044; break;
|
||||
case 45: tex = &kg->__tex_image_045; break;
|
||||
case 46: tex = &kg->__tex_image_046; break;
|
||||
case 47: tex = &kg->__tex_image_047; break;
|
||||
case 48: tex = &kg->__tex_image_048; break;
|
||||
case 49: tex = &kg->__tex_image_049; break;
|
||||
case 50: tex = &kg->__tex_image_050; break;
|
||||
case 51: tex = &kg->__tex_image_051; break;
|
||||
case 52: tex = &kg->__tex_image_052; break;
|
||||
case 53: tex = &kg->__tex_image_053; break;
|
||||
case 54: tex = &kg->__tex_image_054; break;
|
||||
case 55: tex = &kg->__tex_image_055; break;
|
||||
case 56: tex = &kg->__tex_image_056; break;
|
||||
case 57: tex = &kg->__tex_image_057; break;
|
||||
case 58: tex = &kg->__tex_image_058; break;
|
||||
case 59: tex = &kg->__tex_image_059; break;
|
||||
case 60: tex = &kg->__tex_image_060; break;
|
||||
case 61: tex = &kg->__tex_image_061; break;
|
||||
case 62: tex = &kg->__tex_image_062; break;
|
||||
case 63: tex = &kg->__tex_image_063; break;
|
||||
case 64: tex = &kg->__tex_image_064; break;
|
||||
case 65: tex = &kg->__tex_image_065; break;
|
||||
case 66: tex = &kg->__tex_image_066; break;
|
||||
case 67: tex = &kg->__tex_image_067; break;
|
||||
case 68: tex = &kg->__tex_image_068; break;
|
||||
case 69: tex = &kg->__tex_image_069; break;
|
||||
case 70: tex = &kg->__tex_image_070; break;
|
||||
case 71: tex = &kg->__tex_image_071; break;
|
||||
case 72: tex = &kg->__tex_image_072; break;
|
||||
case 73: tex = &kg->__tex_image_073; break;
|
||||
case 74: tex = &kg->__tex_image_074; break;
|
||||
case 75: tex = &kg->__tex_image_075; break;
|
||||
case 76: tex = &kg->__tex_image_076; break;
|
||||
case 77: tex = &kg->__tex_image_077; break;
|
||||
case 78: tex = &kg->__tex_image_078; break;
|
||||
case 79: tex = &kg->__tex_image_079; break;
|
||||
case 80: tex = &kg->__tex_image_080; break;
|
||||
case 81: tex = &kg->__tex_image_081; break;
|
||||
case 82: tex = &kg->__tex_image_082; break;
|
||||
case 83: tex = &kg->__tex_image_083; break;
|
||||
case 84: tex = &kg->__tex_image_084; break;
|
||||
case 85: tex = &kg->__tex_image_085; break;
|
||||
case 86: tex = &kg->__tex_image_086; break;
|
||||
case 87: tex = &kg->__tex_image_087; break;
|
||||
case 88: tex = &kg->__tex_image_088; break;
|
||||
case 89: tex = &kg->__tex_image_089; break;
|
||||
case 90: tex = &kg->__tex_image_090; break;
|
||||
case 91: tex = &kg->__tex_image_091; break;
|
||||
case 92: tex = &kg->__tex_image_092; break;
|
||||
case 93: tex = &kg->__tex_image_093; break;
|
||||
case 94: tex = &kg->__tex_image_094; break;
|
||||
case 95: tex = &kg->__tex_image_095; break;
|
||||
case 96: tex = &kg->__tex_image_096; break;
|
||||
case 97: tex = &kg->__tex_image_097; break;
|
||||
case 98: tex = &kg->__tex_image_098; break;
|
||||
case 99: tex = &kg->__tex_image_099; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(tex) {
|
||||
tex->data = (uchar4*)mem;
|
||||
tex->width = width;
|
||||
tex->height = height;
|
||||
}
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* Path Tracing */
|
||||
|
||||
void kernel_cpu_path_trace(KernelGlobals *kg, float4 *buffer, unsigned int *rng_state, int pass, int x, int y)
|
||||
{
|
||||
kernel_path_trace(kg, buffer, rng_state, pass, x, y);
|
||||
}
|
||||
|
||||
/* Tonemapping */
|
||||
|
||||
void kernel_cpu_tonemap(KernelGlobals *kg, uchar4 *rgba, float4 *buffer, int pass, int resolution, int x, int y)
|
||||
{
|
||||
kernel_film_tonemap(kg, rgba, buffer, pass, resolution, x, y);
|
||||
}
|
||||
|
||||
/* Displacement */
|
||||
|
||||
void kernel_cpu_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i)
|
||||
{
|
||||
kernel_displace(kg, input, offset, i);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
53
intern/cycles/kernel/kernel.cu
Normal file
53
intern/cycles/kernel/kernel.cu
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* CUDA kernel entry points */
|
||||
|
||||
#include "kernel_compat_cuda.h"
|
||||
#include "kernel_math.h"
|
||||
#include "kernel_types.h"
|
||||
#include "kernel_globals.h"
|
||||
#include "kernel_film.h"
|
||||
#include "kernel_path.h"
|
||||
#include "kernel_displace.h"
|
||||
|
||||
extern "C" __global__ void kernel_cuda_path_trace(float4 *buffer, uint *rng_state, int pass, int sx, int sy, int sw, int sh)
|
||||
{
|
||||
int x = sx + blockDim.x*blockIdx.x + threadIdx.x;
|
||||
int y = sy + blockDim.y*blockIdx.y + threadIdx.y;
|
||||
|
||||
if(x < sx + sw && y < sy + sh)
|
||||
kernel_path_trace(NULL, buffer, rng_state, pass, x, y);
|
||||
}
|
||||
|
||||
extern "C" __global__ void kernel_cuda_tonemap(uchar4 *rgba, float4 *buffer, int pass, int resolution, int sx, int sy, int sw, int sh)
|
||||
{
|
||||
int x = sx + blockDim.x*blockIdx.x + threadIdx.x;
|
||||
int y = sy + blockDim.y*blockIdx.y + threadIdx.y;
|
||||
|
||||
if(x < sx + sw && y < sy + sh)
|
||||
kernel_film_tonemap(NULL, rgba, buffer, pass, resolution, x, y);
|
||||
}
|
||||
|
||||
extern "C" __global__ void kernel_cuda_displace(uint4 *input, float3 *offset, int sx)
|
||||
{
|
||||
int x = sx + blockDim.x*blockIdx.x + threadIdx.x;
|
||||
|
||||
kernel_displace(NULL, input, offset, x);
|
||||
}
|
||||
|
47
intern/cycles/kernel/kernel.h
Normal file
47
intern/cycles/kernel/kernel.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_H__
|
||||
#define __KERNEL_H__
|
||||
|
||||
/* CPU Kernel Interfae */
|
||||
|
||||
#include "util_types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
struct KernelGlobals;
|
||||
|
||||
KernelGlobals *kernel_globals_create();
|
||||
void kernel_globals_free(KernelGlobals *kg);
|
||||
|
||||
void *kernel_osl_memory(KernelGlobals *kg);
|
||||
bool kernel_osl_use(KernelGlobals *kg);
|
||||
|
||||
void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size);
|
||||
void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height);
|
||||
|
||||
void kernel_cpu_path_trace(KernelGlobals *kg, float4 *buffer, unsigned int *rng_state, int pass, int x, int y);
|
||||
void kernel_cpu_tonemap(KernelGlobals *kg, uchar4 *rgba, float4 *buffer, int pass, int resolution, int x, int y);
|
||||
|
||||
void kernel_cpu_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __KERNEL_H__ */
|
||||
|
361
intern/cycles/kernel/kernel_bvh.h
Normal file
361
intern/cycles/kernel/kernel_bvh.h
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Adapted from code Copyright 2009-2010 NVIDIA Corporation
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/*
|
||||
* "Persistent while-while kernel" used in:
|
||||
*
|
||||
* "Understanding the Efficiency of Ray Traversal on GPUs",
|
||||
* Timo Aila and Samuli Laine,
|
||||
* Proc. High-Performance Graphics 2009
|
||||
*/
|
||||
|
||||
/* bottom-most stack entry, indicating the end of traversal */
|
||||
|
||||
#define ENTRYPOINT_SENTINEL 0x76543210
|
||||
/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
|
||||
#define BVH_STACK_SIZE 192
|
||||
#define BVH_NODE_SIZE 4
|
||||
#define TRI_NODE_SIZE 3
|
||||
|
||||
__device_inline float3 bvh_inverse_direction(float3 dir)
|
||||
{
|
||||
/* avoid divide by zero (ooeps = exp2f(-80.0f)) */
|
||||
float ooeps = 0.00000000000000000000000082718061255302767487140869206996285356581211090087890625f;
|
||||
float3 idir;
|
||||
|
||||
idir.x = 1.0f/((fabsf(dir.x) > ooeps)? dir.x: copysignf(ooeps, dir.x));
|
||||
idir.y = 1.0f/((fabsf(dir.y) > ooeps)? dir.y: copysignf(ooeps, dir.y));
|
||||
idir.z = 1.0f/((fabsf(dir.z) > ooeps)? dir.z: copysignf(ooeps, dir.z));
|
||||
|
||||
return idir;
|
||||
}
|
||||
|
||||
__device_inline void bvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
|
||||
{
|
||||
Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
|
||||
|
||||
*P = transform(&tfm, ray->P);
|
||||
|
||||
float3 dir = transform_direction(&tfm, ray->D);
|
||||
|
||||
float len;
|
||||
dir = normalize_len(dir, &len);
|
||||
|
||||
*idir = bvh_inverse_direction(dir);
|
||||
|
||||
if(*t != FLT_MAX)
|
||||
*t *= len;
|
||||
}
|
||||
|
||||
__device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
|
||||
{
|
||||
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
|
||||
|
||||
if(*t != FLT_MAX)
|
||||
*t *= len(transform_direction(&tfm, 1.0f/(*idir)));
|
||||
|
||||
*P = ray->P;
|
||||
*idir = bvh_inverse_direction(ray->D);
|
||||
}
|
||||
|
||||
/* intersect two bounding boxes */
|
||||
__device_inline void bvh_node_intersect(KernelGlobals *kg,
|
||||
bool *traverseChild0, bool *traverseChild1,
|
||||
bool *closestChild1, int *nodeAddr0, int *nodeAddr1,
|
||||
float3 P, float3 idir, float t, int nodeAddr)
|
||||
{
|
||||
/* fetch node data */
|
||||
float4 n0xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
|
||||
float4 n1xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
|
||||
float4 nz = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
|
||||
float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
|
||||
|
||||
/* intersect ray against child nodes */
|
||||
float3 ood = P * idir;
|
||||
float c0lox = n0xy.x * idir.x - ood.x;
|
||||
float c0hix = n0xy.y * idir.x - ood.x;
|
||||
float c0loy = n0xy.z * idir.y - ood.y;
|
||||
float c0hiy = n0xy.w * idir.y - ood.y;
|
||||
float c0loz = nz.x * idir.z - ood.z;
|
||||
float c0hiz = nz.y * idir.z - ood.z;
|
||||
float c1loz = nz.z * idir.z - ood.z;
|
||||
float c1hiz = nz.w * idir.z - ood.z;
|
||||
|
||||
float c0min_x = min(c0lox, c0hix);
|
||||
float c0min_y = min(c0loy, c0hiy);
|
||||
float c0min_z = min(c0loz, c0hiz);
|
||||
|
||||
float c0min = max4(c0min_x, c0min_y, c0min_z, 0.0f);
|
||||
float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
|
||||
float c1lox = n1xy.x * idir.x - ood.x;
|
||||
float c1hix = n1xy.y * idir.x - ood.x;
|
||||
float c1loy = n1xy.z * idir.y - ood.y;
|
||||
float c1hiy = n1xy.w * idir.y - ood.y;
|
||||
float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
|
||||
float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
|
||||
|
||||
/* decide which nodes to traverse next */
|
||||
*traverseChild0 = (c0max >= c0min);
|
||||
*traverseChild1 = (c1max >= c1min);
|
||||
|
||||
*nodeAddr0 = __float_as_int(cnodes.x);
|
||||
*nodeAddr1 = __float_as_int(cnodes.y);
|
||||
|
||||
*closestChild1 = (c1min < c0min);
|
||||
}
|
||||
|
||||
/* Sven Woop's algorithm */
|
||||
__device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *isect, float3 P, float3 idir, int object, int triAddr)
|
||||
{
|
||||
/* compute and check intersection t-value */
|
||||
float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
|
||||
float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
|
||||
float3 dir = 1.0f/idir;
|
||||
|
||||
float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
|
||||
float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z);
|
||||
float t = Oz * invDz;
|
||||
|
||||
if(t > 0.0f && t < isect->t) {
|
||||
/* compute and check barycentric u */
|
||||
float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z;
|
||||
float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z;
|
||||
float u = Ox + t*Dx;
|
||||
|
||||
if(u >= 0.0f) {
|
||||
/* compute and check barycentric v */
|
||||
float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
|
||||
float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z;
|
||||
float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z;
|
||||
float v = Oy + t*Dy;
|
||||
|
||||
if(v >= 0.0f && u + v <= 1.0f) {
|
||||
/* record intersection */
|
||||
isect->prim = triAddr;
|
||||
isect->object = object;
|
||||
isect->u = u;
|
||||
isect->v = v;
|
||||
isect->t = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const bool isshadowray, Intersection *isect)
|
||||
{
|
||||
/* traversal stack in CUDA thread-local memory */
|
||||
int traversalStack[BVH_STACK_SIZE];
|
||||
traversalStack[0] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
/* traversal variables in registers */
|
||||
int stackPtr = 0;
|
||||
int nodeAddr = kernel_data.bvh.root;
|
||||
|
||||
/* ray parameters in registers */
|
||||
const float tmax = ray->t;
|
||||
float3 P = ray->P;
|
||||
float3 idir = bvh_inverse_direction(ray->D);
|
||||
int object = ~0;
|
||||
|
||||
isect->t = tmax;
|
||||
isect->object = ~0;
|
||||
isect->prim = ~0;
|
||||
isect->u = 0.0f;
|
||||
isect->v = 0.0f;
|
||||
|
||||
/* traversal loop */
|
||||
do {
|
||||
do
|
||||
{
|
||||
/* traverse internal nodes */
|
||||
while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL)
|
||||
{
|
||||
bool traverseChild0, traverseChild1, closestChild1;
|
||||
int nodeAddrChild1;
|
||||
|
||||
bvh_node_intersect(kg, &traverseChild0, &traverseChild1,
|
||||
&closestChild1, &nodeAddr, &nodeAddrChild1,
|
||||
P, idir, isect->t, nodeAddr);
|
||||
|
||||
if(traverseChild0 != traverseChild1) {
|
||||
/* one child was intersected */
|
||||
if(traverseChild1) {
|
||||
nodeAddr = nodeAddrChild1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!traverseChild0) {
|
||||
/* neither child was intersected */
|
||||
nodeAddr = traversalStack[stackPtr];
|
||||
--stackPtr;
|
||||
}
|
||||
else {
|
||||
/* both children were intersected, push the farther one */
|
||||
if(closestChild1) {
|
||||
int tmp = nodeAddr;
|
||||
nodeAddr = nodeAddrChild1;
|
||||
nodeAddrChild1 = tmp;
|
||||
}
|
||||
|
||||
++stackPtr;
|
||||
traversalStack[stackPtr] = nodeAddrChild1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if node is leaf, fetch triangle list */
|
||||
if(nodeAddr < 0) {
|
||||
float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1));
|
||||
int primAddr = __float_as_int(leaf.x);
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
if(primAddr >= 0) {
|
||||
#endif
|
||||
int primAddr2 = __float_as_int(leaf.y);
|
||||
|
||||
/* pop */
|
||||
nodeAddr = traversalStack[stackPtr];
|
||||
--stackPtr;
|
||||
|
||||
/* triangle intersection */
|
||||
while(primAddr < primAddr2) {
|
||||
/* intersect ray against triangle */
|
||||
bvh_triangle_intersect(kg, isect, P, idir, object, primAddr);
|
||||
|
||||
/* shadow ray early termination */
|
||||
if(isshadowray && isect->prim != ~0)
|
||||
return true;
|
||||
|
||||
primAddr++;
|
||||
}
|
||||
#ifdef __INSTANCING__
|
||||
}
|
||||
else {
|
||||
/* instance push */
|
||||
object = kernel_tex_fetch(__prim_object, -primAddr-1);
|
||||
|
||||
bvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax);
|
||||
|
||||
++stackPtr;
|
||||
traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
nodeAddr = kernel_tex_fetch(__object_node, object);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
if(stackPtr >= 0) {
|
||||
kernel_assert(object != ~0);
|
||||
|
||||
/* instance pop */
|
||||
bvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax);
|
||||
object = ~0;
|
||||
nodeAddr = traversalStack[stackPtr];
|
||||
--stackPtr;
|
||||
}
|
||||
#endif
|
||||
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
return (isect->prim != ~0);
|
||||
}
|
||||
|
||||
__device_inline float3 ray_offset(float3 P, float3 Ng)
|
||||
{
|
||||
#ifdef __INTERSECTION_REFINE__
|
||||
const float epsilon_f = 1e-5f;
|
||||
const int epsilon_i = 32;
|
||||
|
||||
float3 res;
|
||||
|
||||
/* x component */
|
||||
if(fabsf(P.x) < epsilon_f) {
|
||||
res.x = P.x + Ng.x*epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint ix = __float_as_uint(P.x);
|
||||
ix += ((ix ^ __float_as_uint(Ng.x)) >> 31)? -epsilon_i: epsilon_i;
|
||||
res.x = __uint_as_float(ix);
|
||||
}
|
||||
|
||||
/* y component */
|
||||
if(fabsf(P.y) < epsilon_f) {
|
||||
res.y = P.y + Ng.y*epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint iy = __float_as_uint(P.y);
|
||||
iy += ((iy ^ __float_as_uint(Ng.y)) >> 31)? -epsilon_i: epsilon_i;
|
||||
res.y = __uint_as_float(iy);
|
||||
}
|
||||
|
||||
/* z component */
|
||||
if(fabsf(P.z) < epsilon_f) {
|
||||
res.z = P.z + Ng.z*epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint iz = __float_as_uint(P.z);
|
||||
iz += ((iz ^ __float_as_uint(Ng.z)) >> 31)? -epsilon_i: epsilon_i;
|
||||
res.z = __uint_as_float(iz);
|
||||
}
|
||||
|
||||
return res;
|
||||
#else
|
||||
const float epsilon_f = 1e-4f;
|
||||
return P + epsilon_f*Ng;
|
||||
#endif
|
||||
}
|
||||
|
||||
__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection *isect, const Ray *ray)
|
||||
{
|
||||
float3 P = ray->P;
|
||||
float3 D = ray->D;
|
||||
float t = isect->t;
|
||||
|
||||
#ifdef __INTERSECTION_REFINE__
|
||||
if(isect->object != ~0) {
|
||||
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
|
||||
|
||||
P = transform(&tfm, P);
|
||||
D = transform_direction(&tfm, D*t);
|
||||
D = normalize_len(D, &t);
|
||||
}
|
||||
|
||||
P = P + D*t;
|
||||
|
||||
float4 v00 = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0);
|
||||
float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
|
||||
float invDz = 1.0f/(D.x*v00.x + D.y*v00.y + D.z*v00.z);
|
||||
float rt = Oz * invDz;
|
||||
|
||||
P = P + D*rt;
|
||||
|
||||
if(isect->object != ~0) {
|
||||
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
|
||||
P = transform(&tfm, P);
|
||||
}
|
||||
|
||||
return P;
|
||||
#else
|
||||
return P + D*t;
|
||||
#endif
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
132
intern/cycles/kernel/kernel_camera.h
Normal file
132
intern/cycles/kernel/kernel_camera.h
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Perspective Camera */
|
||||
|
||||
__device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, Ray *ray)
|
||||
{
|
||||
/* create ray form raster position */
|
||||
Transform rastertocamera = kernel_data.cam.rastertocamera;
|
||||
float3 Pcamera = transform(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
|
||||
|
||||
ray->P = make_float3(0.0f, 0.0f, 0.0f);
|
||||
ray->D = Pcamera;
|
||||
|
||||
/* modify ray for depth of field */
|
||||
float lensradius = kernel_data.cam.lensradius;
|
||||
|
||||
if(lensradius > 0.0f) {
|
||||
/* sample point on lens */
|
||||
float2 lensuv;
|
||||
|
||||
lensuv = concentric_sample_disk(lens_u, lens_v);
|
||||
lensuv *= lensradius;
|
||||
|
||||
/* compute point on plane of focus */
|
||||
float ft = kernel_data.cam.focaldistance/ray->D.z;
|
||||
float3 Pfocus = ray->P + ray->D*ft;
|
||||
|
||||
/* update ray for effect of lens */
|
||||
ray->P = make_float3(lensuv.x, lensuv.y, 0.0f);
|
||||
ray->D = normalize(Pfocus - ray->P);
|
||||
}
|
||||
|
||||
/* transform ray from camera to world */
|
||||
Transform cameratoworld = kernel_data.cam.cameratoworld;
|
||||
|
||||
ray->P = transform(&cameratoworld, ray->P);
|
||||
ray->D = transform_direction(&cameratoworld, ray->D);
|
||||
ray->D = normalize(ray->D);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
/* ray differential */
|
||||
float3 Ddiff = transform_direction(&cameratoworld, Pcamera);
|
||||
|
||||
ray->dP.dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
ray->dP.dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
ray->dD.dx = normalize(Ddiff + kernel_data.cam.dx) - normalize(Ddiff);
|
||||
ray->dD.dy = normalize(Ddiff + kernel_data.cam.dy) - normalize(Ddiff);
|
||||
#endif
|
||||
|
||||
#ifdef __CAMERA_CLIPPING__
|
||||
/* clipping */
|
||||
ray->P += kernel_data.cam.nearclip*ray->D;
|
||||
ray->t = kernel_data.cam.cliplength;
|
||||
#else
|
||||
ray->t = FLT_MAX;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Orthographic Camera */
|
||||
|
||||
__device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, float raster_y, Ray *ray)
|
||||
{
|
||||
/* create ray form raster position */
|
||||
Transform rastertocamera = kernel_data.cam.rastertocamera;
|
||||
float3 Pcamera = transform(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
|
||||
|
||||
ray->P = Pcamera;
|
||||
ray->D = make_float3(0.0f, 0.0f, 1.0f);
|
||||
|
||||
/* transform ray from camera to world */
|
||||
Transform cameratoworld = kernel_data.cam.cameratoworld;
|
||||
|
||||
ray->P = transform(&cameratoworld, ray->P);
|
||||
ray->D = transform_direction(&cameratoworld, ray->D);
|
||||
ray->D = normalize(ray->D);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
/* ray differential */
|
||||
ray->dP.dx = kernel_data.cam.dx;
|
||||
ray->dP.dy = kernel_data.cam.dy;
|
||||
|
||||
ray->dD.dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
ray->dD.dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
#endif
|
||||
|
||||
#ifdef __CAMERA_CLIPPING__
|
||||
/* clipping */
|
||||
ray->t = kernel_data.cam.cliplength;
|
||||
#else
|
||||
ray->t = FLT_MAX;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Common */
|
||||
|
||||
__device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, float filter_v, float lens_u, float lens_v, Ray *ray)
|
||||
{
|
||||
/* pixel filter */
|
||||
float raster_x = x + kernel_tex_interp(__filter_table, filter_u);
|
||||
float raster_y = y + kernel_tex_interp(__filter_table, filter_v);
|
||||
|
||||
/* motion blur */
|
||||
//ray->time = lerp(time_t, kernel_data.cam.shutter_open, kernel_data.cam.shutter_close);
|
||||
|
||||
/* sample */
|
||||
if(kernel_data.cam.ortho)
|
||||
camera_sample_orthographic(kg, raster_x, raster_y, ray);
|
||||
else
|
||||
camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
162
intern/cycles/kernel/kernel_compat_cpu.h
Normal file
162
intern/cycles/kernel/kernel_compat_cpu.h
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_COMPAT_CPU_H__
|
||||
#define __KERNEL_COMPAT_CPU_H__
|
||||
|
||||
#define __KERNEL_CPU__
|
||||
|
||||
#include "util_debug.h"
|
||||
#include "util_math.h"
|
||||
#include "util_types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Assertions inside the kernel only work for the CPU device, so we wrap it in
|
||||
a macro which is empty for other devices */
|
||||
|
||||
#define kernel_assert(cond) assert(cond)
|
||||
|
||||
/* Texture types to be compatible with CUDA textures. These are really just
|
||||
simple arrays and after inlining fetch hopefully revert to being a simple
|
||||
pointer lookup. */
|
||||
|
||||
template<typename T> struct texture {
|
||||
T fetch(int index)
|
||||
{
|
||||
kernel_assert(index >= 0 && index < width);
|
||||
return data[index];
|
||||
}
|
||||
|
||||
__m128 fetch_m128(int index)
|
||||
{
|
||||
kernel_assert(index >= 0 && index < width);
|
||||
return ((__m128*)data)[index];
|
||||
}
|
||||
|
||||
__m128i fetch_m128i(int index)
|
||||
{
|
||||
kernel_assert(index >= 0 && index < width);
|
||||
return ((__m128i*)data)[index];
|
||||
}
|
||||
|
||||
float interp(float x)
|
||||
{
|
||||
x = clamp(x, 0.0f, 1.0f)*width;
|
||||
|
||||
int index = min((int)x, width-1);
|
||||
int nindex = min(index+1, width-1);
|
||||
float t = x - index;
|
||||
|
||||
return (1.0f - t)*data[index] + t*data[nindex];
|
||||
}
|
||||
|
||||
T *data;
|
||||
int width;
|
||||
};
|
||||
|
||||
template<typename T> struct texture_image {
|
||||
float4 read(float4 r)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
float4 read(uchar4 r)
|
||||
{
|
||||
float f = 1.0f/255.0f;
|
||||
return make_float4(r.x*f, r.y*f, r.z*f, r.w*f);
|
||||
}
|
||||
|
||||
int wrap_periodic(int x, int width)
|
||||
{
|
||||
x %= width;
|
||||
if(x < 0)
|
||||
x += width;
|
||||
return x;
|
||||
}
|
||||
|
||||
int wrap_clamp(int x, int width)
|
||||
{
|
||||
return clamp(x, 0, width-1);
|
||||
}
|
||||
|
||||
float frac(float x, int *ix)
|
||||
{
|
||||
int i = (int)x - ((x < 0.0f)? 1: 0);
|
||||
*ix = i;
|
||||
return x - (float)i;
|
||||
}
|
||||
|
||||
float4 interp(float x, float y, bool periodic = true)
|
||||
{
|
||||
if(!data)
|
||||
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
int ix, iy, nix, niy;
|
||||
float tx = frac(x*width, &ix);
|
||||
float ty = frac(y*height, &iy);
|
||||
|
||||
if(periodic) {
|
||||
ix = wrap_periodic(ix, width);
|
||||
iy = wrap_periodic(iy, height);
|
||||
|
||||
nix = wrap_periodic(ix+1, width);
|
||||
niy = wrap_periodic(iy+1, height);
|
||||
}
|
||||
else {
|
||||
ix = wrap_clamp(ix, width);
|
||||
iy = wrap_clamp(iy, height);
|
||||
|
||||
nix = wrap_clamp(ix+1, width);
|
||||
niy = wrap_clamp(iy+1, height);
|
||||
}
|
||||
|
||||
float4 r = (1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width]);
|
||||
r += (1.0f - ty)*tx*read(data[nix + iy*width]);
|
||||
r += ty*(1.0f - tx)*read(data[ix + niy*width]);
|
||||
r += ty*tx*read(data[nix + niy*width]);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
T *data;
|
||||
int width, height;
|
||||
};
|
||||
|
||||
typedef texture<float4> texture_float4;
|
||||
typedef texture<float> texture_float;
|
||||
typedef texture<uint> texture_uint;
|
||||
typedef texture<int> texture_int;
|
||||
typedef texture<uint4> texture_uint4;
|
||||
typedef texture_image<float4> texture_image_float4;
|
||||
typedef texture_image<uchar4> texture_image_uchar4;
|
||||
|
||||
/* Macros to handle different memory storage on different devices */
|
||||
|
||||
#define kernel_tex_fetch(tex, index) (kg->tex.fetch(index))
|
||||
#define kernel_tex_fetch_m128(tex, index) (kg->tex.fetch_m128(index))
|
||||
#define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index))
|
||||
#define kernel_tex_interp(tex, t) (kg->tex.interp(t))
|
||||
#define kernel_tex_image_interp(tex, x, y) (kg->tex.interp(x, y))
|
||||
|
||||
#define kernel_data (kg->__data)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __KERNEL_COMPAT_CPU_H__ */
|
||||
|
65
intern/cycles/kernel/kernel_compat_cuda.h
Normal file
65
intern/cycles/kernel/kernel_compat_cuda.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_COMPAT_CUDA_H__
|
||||
#define __KERNEL_COMPAT_CUDA_H__
|
||||
|
||||
#define __KERNEL_GPU__
|
||||
#define __KERNEL_CUDA__
|
||||
|
||||
#include <cuda.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "util_types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Qualifier wrappers for different names on different devices */
|
||||
|
||||
#define __device __device__ __inline__
|
||||
#define __device_inline __device__ __inline__
|
||||
#define __global
|
||||
#define __shared __shared__
|
||||
#define __constant __constant__
|
||||
|
||||
/* No assert supported for CUDA */
|
||||
|
||||
#define kernel_assert(cond)
|
||||
|
||||
/* Textures */
|
||||
|
||||
typedef texture<float4, 1> texture_float4;
|
||||
typedef texture<float, 1> texture_float;
|
||||
typedef texture<uint, 1> texture_uint;
|
||||
typedef texture<int, 1> texture_int;
|
||||
typedef texture<uint4, 1> texture_uint4;
|
||||
typedef texture<float4, 2> texture_image_float4;
|
||||
typedef texture<uchar4, 2, cudaReadModeNormalizedFloat> texture_image_uchar4;
|
||||
|
||||
/* Macros to handle different memory storage on different devices */
|
||||
|
||||
#define kernel_tex_fetch(t, index) tex1Dfetch(t, index)
|
||||
#define kernel_tex_interp(t, x) tex1D(t, x)
|
||||
#define kernel_tex_image_interp(t, x, y) tex2D(t, x, y)
|
||||
|
||||
#define kernel_data __data
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __KERNEL_COMPAT_CUDA_H__ */
|
||||
|
50
intern/cycles/kernel/kernel_compat_opencl.h
Normal file
50
intern/cycles/kernel/kernel_compat_opencl.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_COMPAT_OPENCL_H__
|
||||
#define __KERNEL_COMPAT_OPENCL_H__
|
||||
|
||||
#define __KERNEL_GPU__
|
||||
#define __KERNEL_OPENCL__
|
||||
|
||||
#include "util_types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#define __device
|
||||
#define __device_inline
|
||||
|
||||
__device float kernel_tex_interp_(__global float *data, int width, float x)
|
||||
{
|
||||
x = clamp(x, 0.0f, 1.0f)*width;
|
||||
|
||||
int index = min((int)x, width-1);
|
||||
int nindex = min(index+1, width-1);
|
||||
float t = x - index;
|
||||
|
||||
return (1.0f - t)*data[index] + t*data[nindex];
|
||||
}
|
||||
|
||||
#define kernel_data (*kg->data)
|
||||
#define kernel_tex_interp(t, x) \
|
||||
kernel_tex_interp_(kg->t, kg->t##_width, x);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __KERNEL_COMPAT_OPENCL_H__ */
|
||||
|
90
intern/cycles/kernel/kernel_differential.h
Normal file
90
intern/cycles/kernel/kernel_differential.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* See "Tracing Ray Differentials", Homan Igehy, 1999. */
|
||||
|
||||
__device void differential_transfer(differential3 *dP_, const differential3 dP, float3 D, const differential3 dD, float3 Ng, float t)
|
||||
{
|
||||
/* ray differential transfer through homogenous medium, to
|
||||
* compute dPdx/dy at a shading point from the incoming ray */
|
||||
|
||||
float3 tmp = D/dot(D, Ng);
|
||||
float3 tmpx = dP.dx + t*dD.dx;
|
||||
float3 tmpy = dP.dy + t*dD.dy;
|
||||
|
||||
dP_->dx = tmpx - dot(tmpx, Ng)*tmp;
|
||||
dP_->dy = tmpy - dot(tmpy, Ng)*tmp;
|
||||
}
|
||||
|
||||
__device void differential_incoming(differential3 *dI, const differential3 dD)
|
||||
{
|
||||
/* compute dIdx/dy at a shading point, we just need to negate the
|
||||
* differential of the ray direction */
|
||||
|
||||
dI->dx = -dD.dx;
|
||||
dI->dy = -dD.dy;
|
||||
}
|
||||
|
||||
__device void differential_dudv(differential *du, differential *dv, float3 dPdu, float3 dPdv, differential3 dP, float3 Ng)
|
||||
{
|
||||
/* now we have dPdx/dy from the ray differential transfer, and dPdu/dv
|
||||
* from the primitive, we can compute dudx/dy and dvdx/dy. these are
|
||||
* mainly used for differentials of arbitrary mesh attributes. */
|
||||
|
||||
/* find most stable axis to project to 2D */
|
||||
float xn= fabsf(Ng.x);
|
||||
float yn= fabsf(Ng.y);
|
||||
float zn= fabsf(Ng.z);
|
||||
|
||||
if(zn < xn || zn < yn) {
|
||||
if(yn < xn || yn < zn) {
|
||||
dPdu.x = dPdu.y;
|
||||
dPdv.x = dPdv.y;
|
||||
dP.dx.x = dP.dx.y;
|
||||
dP.dy.x = dP.dy.y;
|
||||
}
|
||||
|
||||
dPdu.y = dPdu.z;
|
||||
dPdv.y = dPdv.z;
|
||||
dP.dx.y = dP.dx.z;
|
||||
dP.dy.y = dP.dy.z;
|
||||
}
|
||||
|
||||
/* using Cramer's rule, we solve for dudx and dvdx in a 2x2 linear system,
|
||||
* and the same for dudy and dvdy. the denominator is the same for both
|
||||
* solutions, so we compute it only once.
|
||||
*
|
||||
* dP.dx = dPdu * dudx + dPdv * dvdx;
|
||||
* dP.dy = dPdu * dudy + dPdv * dvdy; */
|
||||
|
||||
float det = (dPdu.x*dPdv.y - dPdv.x*dPdu.y);
|
||||
|
||||
if(det != 0.0f)
|
||||
det = 1.0f/det;
|
||||
|
||||
du->dx = (dP.dx.x*dPdv.y - dP.dx.y*dPdv.x)*det;
|
||||
dv->dx = (dP.dx.y*dPdu.x - dP.dx.x*dPdu.y)*det;
|
||||
|
||||
du->dy = (dP.dy.x*dPdv.y - dP.dy.y*dPdv.x)*det;
|
||||
dv->dy = (dP.dy.y*dPdu.x - dP.dy.x*dPdu.y)*det;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
35
intern/cycles/kernel/kernel_displace.h
Normal file
35
intern/cycles/kernel/kernel_displace.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
__device void kernel_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i)
|
||||
{
|
||||
/* setup shader data */
|
||||
ShaderData sd;
|
||||
uint4 in = input[i];
|
||||
shader_setup_from_displace(kg, &sd, in.x, in.y, __int_as_float(in.z), __int_as_float(in.w));
|
||||
|
||||
/* evaluate */
|
||||
float3 P = sd.P;
|
||||
shader_eval_displacement(kg, &sd);
|
||||
offset[i] = sd.P - P;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
118
intern/cycles/kernel/kernel_emission.h
Normal file
118
intern/cycles/kernel/kernel_emission.h
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Direction Emission */
|
||||
|
||||
__device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
|
||||
LightSample *ls, float u, float v, float3 I)
|
||||
{
|
||||
/* setup shading at emitter */
|
||||
ShaderData sd;
|
||||
|
||||
shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v);
|
||||
ls->Ng = sd.Ng;
|
||||
|
||||
/* no path flag, we're evaluating this for all closures. that's weak but
|
||||
we'd have to do multiple evaluations otherwise */
|
||||
shader_eval_surface(kg, &sd, rando, 0);
|
||||
|
||||
float3 eval;
|
||||
|
||||
/* evaluate emissive closure */
|
||||
if(sd.flag & SD_EMISSION)
|
||||
eval = shader_emissive_eval(kg, &sd);
|
||||
else
|
||||
eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
shader_release(kg, &sd);
|
||||
|
||||
return eval;
|
||||
}
|
||||
|
||||
__device bool direct_emission(KernelGlobals *kg, ShaderData *sd, float randt, float rando,
|
||||
float randu, float randv, Ray *ray, float3 *eval)
|
||||
{
|
||||
/* sample a position on a light */
|
||||
LightSample ls;
|
||||
|
||||
light_sample(kg, randt, randu, randv, sd->P, &ls);
|
||||
|
||||
/* compute incoming direction and distance */
|
||||
float t;
|
||||
float3 omega_in = normalize_len(ls.P - sd->P, &t);
|
||||
|
||||
/* compute pdf */
|
||||
float pdf = light_pdf(kg, &ls, -omega_in, t);
|
||||
|
||||
/* evaluate closure */
|
||||
*eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -omega_in);
|
||||
|
||||
if(is_zero(*eval) || pdf == 0.0f)
|
||||
return false;
|
||||
|
||||
/* evaluate BSDF at shading point */
|
||||
float bsdf_pdf;
|
||||
float3 bsdf_eval = shader_bsdf_eval(kg, sd, omega_in, &bsdf_pdf);
|
||||
|
||||
*eval *= bsdf_eval/pdf;
|
||||
|
||||
if(is_zero(*eval))
|
||||
return false;
|
||||
|
||||
if(ls.prim != ~0) {
|
||||
/* multiple importance sampling */
|
||||
float mis_weight = power_heuristic(pdf, bsdf_pdf);
|
||||
*eval *= mis_weight;
|
||||
}
|
||||
else {
|
||||
/* ensure point light works in Watts, this should be handled
|
||||
* elsewhere but for now together with the diffuse emission
|
||||
* closure it works out to the right value */
|
||||
*eval *= 0.25f;
|
||||
}
|
||||
|
||||
/* setup ray */
|
||||
ray->P = ray_offset(sd->P, sd->Ng);
|
||||
ray->D = ray_offset(ls.P, ls.Ng) - ray->P;
|
||||
ray->D = normalize_len(ray->D, &ray->t);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Indirect Emission */
|
||||
|
||||
__device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, int path_flag, float bsdf_pdf)
|
||||
{
|
||||
/* evaluate emissive closure */
|
||||
float3 L = shader_emissive_eval(kg, sd);
|
||||
|
||||
if(!(path_flag & PATH_RAY_SINGULAR)) {
|
||||
/* multiple importance sampling */
|
||||
float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t);
|
||||
float mis_weight = power_heuristic(bsdf_pdf, pdf);
|
||||
|
||||
return L*mis_weight;
|
||||
}
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
68
intern/cycles/kernel/kernel_film.h
Normal file
68
intern/cycles/kernel/kernel_film.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
__device float4 film_map(KernelGlobals *kg, float4 irradiance, int pass)
|
||||
{
|
||||
float scale = kernel_data.film.exposure*(1.0f/(pass+1));
|
||||
float4 result = irradiance*scale;
|
||||
|
||||
if(kernel_data.film.use_response_curve) {
|
||||
/* camera response curve */
|
||||
result.x = kernel_tex_interp(__response_curve_R, result.x);
|
||||
result.y = kernel_tex_interp(__response_curve_G, result.y);
|
||||
result.z = kernel_tex_interp(__response_curve_B, result.z);
|
||||
}
|
||||
else {
|
||||
/* conversion to srgb */
|
||||
result.x = color_scene_linear_to_srgb(result.x);
|
||||
result.y = color_scene_linear_to_srgb(result.y);
|
||||
result.z = color_scene_linear_to_srgb(result.z);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
__device uchar4 film_float_to_byte(float4 color)
|
||||
{
|
||||
uchar4 result;
|
||||
|
||||
/* simple float to byte conversion */
|
||||
result.x = clamp(color.x*255.0f, 0.0f, 255.0f);
|
||||
result.y = clamp(color.y*255.0f, 0.0f, 255.0f);
|
||||
result.z = clamp(color.z*255.0f, 0.0f, 255.0f);
|
||||
result.w = 255;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
__device void kernel_film_tonemap(KernelGlobals *kg, __global uchar4 *rgba, __global float4 *buffer, int pass, int resolution, int x, int y)
|
||||
{
|
||||
int w = kernel_data.cam.width;
|
||||
int index = x + y*w;
|
||||
float4 irradiance = buffer[index];
|
||||
|
||||
float4 float_result = film_map(kg, irradiance, pass);
|
||||
uchar4 byte_result = film_float_to_byte(float_result);
|
||||
|
||||
rgba[index] = byte_result;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
208
intern/cycles/kernel/kernel_globals.h
Normal file
208
intern/cycles/kernel/kernel_globals.h
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* Constant Globals */
|
||||
|
||||
#ifdef __KERNEL_CPU__
|
||||
|
||||
#ifdef WITH_OSL
|
||||
#include "osl_globals.h"
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* On the CPU, we pass along the struct KernelGlobals to nearly everywhere in
|
||||
the kernel, to access constant data. These are all stored as "textures", but
|
||||
these are really just standard arrays. We can't use actually globals because
|
||||
multiple renders may be running inside the same process. */
|
||||
typedef struct KernelGlobals {
|
||||
|
||||
#else
|
||||
|
||||
/* On the GPU, constant memory textures must be globals, so we can't put them
|
||||
into a struct. As a result we don't actually use this struct and use actual
|
||||
globals and simply pass along a NULL pointer everywhere, which we hope gets
|
||||
optimized out. */
|
||||
#ifdef __KERNEL_CUDA__
|
||||
typedef struct KernelGlobals {} KernelGlobals;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* globals */
|
||||
__constant KernelData __data;
|
||||
|
||||
#ifndef __KERNEL_OPENCL__
|
||||
|
||||
/* bvh */
|
||||
texture_float4 __bvh_nodes;
|
||||
texture_float4 __tri_woop;
|
||||
texture_uint __prim_index;
|
||||
texture_uint __prim_object;
|
||||
texture_uint __object_node;
|
||||
|
||||
/* objects */
|
||||
texture_float4 __objects;
|
||||
|
||||
/* triangles */
|
||||
texture_float4 __tri_normal;
|
||||
texture_float4 __tri_vnormal;
|
||||
texture_float4 __tri_vindex;
|
||||
texture_float4 __tri_verts;
|
||||
|
||||
/* attributes */
|
||||
texture_uint4 __attributes_map;
|
||||
texture_float __attributes_float;
|
||||
texture_float4 __attributes_float3;
|
||||
|
||||
/* lights */
|
||||
texture_float4 __light_distribution;
|
||||
texture_float4 __light_point;
|
||||
|
||||
/* shaders */
|
||||
texture_uint4 __svm_nodes;
|
||||
|
||||
/* camera/film */
|
||||
texture_float __filter_table;
|
||||
texture_float __response_curve_R;
|
||||
texture_float __response_curve_G;
|
||||
texture_float __response_curve_B;
|
||||
|
||||
/* sobol */
|
||||
texture_uint __sobol_directions;
|
||||
|
||||
/* image */
|
||||
texture_image_uchar4 __tex_image_000;
|
||||
texture_image_uchar4 __tex_image_001;
|
||||
texture_image_uchar4 __tex_image_002;
|
||||
texture_image_uchar4 __tex_image_003;
|
||||
texture_image_uchar4 __tex_image_004;
|
||||
texture_image_uchar4 __tex_image_005;
|
||||
texture_image_uchar4 __tex_image_006;
|
||||
texture_image_uchar4 __tex_image_007;
|
||||
texture_image_uchar4 __tex_image_008;
|
||||
texture_image_uchar4 __tex_image_009;
|
||||
texture_image_uchar4 __tex_image_010;
|
||||
texture_image_uchar4 __tex_image_011;
|
||||
texture_image_uchar4 __tex_image_012;
|
||||
texture_image_uchar4 __tex_image_013;
|
||||
texture_image_uchar4 __tex_image_014;
|
||||
texture_image_uchar4 __tex_image_015;
|
||||
texture_image_uchar4 __tex_image_016;
|
||||
texture_image_uchar4 __tex_image_017;
|
||||
texture_image_uchar4 __tex_image_018;
|
||||
texture_image_uchar4 __tex_image_019;
|
||||
texture_image_uchar4 __tex_image_020;
|
||||
texture_image_uchar4 __tex_image_021;
|
||||
texture_image_uchar4 __tex_image_022;
|
||||
texture_image_uchar4 __tex_image_023;
|
||||
texture_image_uchar4 __tex_image_024;
|
||||
texture_image_uchar4 __tex_image_025;
|
||||
texture_image_uchar4 __tex_image_026;
|
||||
texture_image_uchar4 __tex_image_027;
|
||||
texture_image_uchar4 __tex_image_028;
|
||||
texture_image_uchar4 __tex_image_029;
|
||||
texture_image_uchar4 __tex_image_030;
|
||||
texture_image_uchar4 __tex_image_031;
|
||||
texture_image_uchar4 __tex_image_032;
|
||||
texture_image_uchar4 __tex_image_033;
|
||||
texture_image_uchar4 __tex_image_034;
|
||||
texture_image_uchar4 __tex_image_035;
|
||||
texture_image_uchar4 __tex_image_036;
|
||||
texture_image_uchar4 __tex_image_037;
|
||||
texture_image_uchar4 __tex_image_038;
|
||||
texture_image_uchar4 __tex_image_039;
|
||||
texture_image_uchar4 __tex_image_040;
|
||||
texture_image_uchar4 __tex_image_041;
|
||||
texture_image_uchar4 __tex_image_042;
|
||||
texture_image_uchar4 __tex_image_043;
|
||||
texture_image_uchar4 __tex_image_044;
|
||||
texture_image_uchar4 __tex_image_045;
|
||||
texture_image_uchar4 __tex_image_046;
|
||||
texture_image_uchar4 __tex_image_047;
|
||||
texture_image_uchar4 __tex_image_048;
|
||||
texture_image_uchar4 __tex_image_049;
|
||||
texture_image_uchar4 __tex_image_050;
|
||||
texture_image_uchar4 __tex_image_051;
|
||||
texture_image_uchar4 __tex_image_052;
|
||||
texture_image_uchar4 __tex_image_053;
|
||||
texture_image_uchar4 __tex_image_054;
|
||||
texture_image_uchar4 __tex_image_055;
|
||||
texture_image_uchar4 __tex_image_056;
|
||||
texture_image_uchar4 __tex_image_057;
|
||||
texture_image_uchar4 __tex_image_058;
|
||||
texture_image_uchar4 __tex_image_059;
|
||||
texture_image_uchar4 __tex_image_060;
|
||||
texture_image_uchar4 __tex_image_061;
|
||||
texture_image_uchar4 __tex_image_062;
|
||||
texture_image_uchar4 __tex_image_063;
|
||||
texture_image_uchar4 __tex_image_064;
|
||||
texture_image_uchar4 __tex_image_065;
|
||||
texture_image_uchar4 __tex_image_066;
|
||||
texture_image_uchar4 __tex_image_067;
|
||||
texture_image_uchar4 __tex_image_068;
|
||||
texture_image_uchar4 __tex_image_069;
|
||||
texture_image_uchar4 __tex_image_070;
|
||||
texture_image_uchar4 __tex_image_071;
|
||||
texture_image_uchar4 __tex_image_072;
|
||||
texture_image_uchar4 __tex_image_073;
|
||||
texture_image_uchar4 __tex_image_074;
|
||||
texture_image_uchar4 __tex_image_075;
|
||||
texture_image_uchar4 __tex_image_076;
|
||||
texture_image_uchar4 __tex_image_077;
|
||||
texture_image_uchar4 __tex_image_078;
|
||||
texture_image_uchar4 __tex_image_079;
|
||||
texture_image_uchar4 __tex_image_080;
|
||||
texture_image_uchar4 __tex_image_081;
|
||||
texture_image_uchar4 __tex_image_082;
|
||||
texture_image_uchar4 __tex_image_083;
|
||||
texture_image_uchar4 __tex_image_084;
|
||||
texture_image_uchar4 __tex_image_085;
|
||||
texture_image_uchar4 __tex_image_086;
|
||||
texture_image_uchar4 __tex_image_087;
|
||||
texture_image_uchar4 __tex_image_088;
|
||||
texture_image_uchar4 __tex_image_089;
|
||||
texture_image_uchar4 __tex_image_090;
|
||||
texture_image_uchar4 __tex_image_091;
|
||||
texture_image_uchar4 __tex_image_092;
|
||||
texture_image_uchar4 __tex_image_093;
|
||||
texture_image_uchar4 __tex_image_094;
|
||||
texture_image_uchar4 __tex_image_095;
|
||||
texture_image_uchar4 __tex_image_096;
|
||||
texture_image_uchar4 __tex_image_097;
|
||||
texture_image_uchar4 __tex_image_098;
|
||||
texture_image_uchar4 __tex_image_099;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __KERNEL_CPU__
|
||||
|
||||
#ifdef WITH_OSL
|
||||
|
||||
/* On the CPU, we also have the OSL globals here. Most data structures are shared
|
||||
with SVM, the difference is in the shaders and object/mesh attributes. */
|
||||
|
||||
OSLGlobals osl;
|
||||
|
||||
#endif
|
||||
|
||||
} KernelGlobals;
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
145
intern/cycles/kernel/kernel_light.h
Normal file
145
intern/cycles/kernel/kernel_light.h
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
struct LightSample {
|
||||
float3 P;
|
||||
float3 Ng;
|
||||
int object;
|
||||
int prim;
|
||||
int shader;
|
||||
float weight;
|
||||
};
|
||||
|
||||
/* Point Light */
|
||||
|
||||
__device void point_light_sample(KernelGlobals *kg, int point,
|
||||
float randu, float randv, float3 P, LightSample *ls)
|
||||
{
|
||||
float4 f = kernel_tex_fetch(__light_point, point);
|
||||
|
||||
ls->P = make_float3(f.x, f.y, f.z);
|
||||
ls->Ng = normalize(ls->P - P);
|
||||
ls->shader = __float_as_int(f.w);
|
||||
ls->object = ~0;
|
||||
ls->prim = ~0;
|
||||
}
|
||||
|
||||
__device float point_light_pdf(KernelGlobals *kg, float t)
|
||||
{
|
||||
return t*t*kernel_data.integrator.pdf_lights;
|
||||
}
|
||||
|
||||
/* Triangle Light */
|
||||
|
||||
__device void triangle_light_sample(KernelGlobals *kg, int prim, int object,
|
||||
float randu, float randv, LightSample *ls)
|
||||
{
|
||||
/* triangle, so get position, normal, shader */
|
||||
ls->P = triangle_sample_MT(kg, prim, randu, randv);
|
||||
ls->Ng = triangle_normal_MT(kg, prim, &ls->shader);
|
||||
ls->object = object;
|
||||
ls->prim = prim;
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
/* instance transform */
|
||||
if(ls->object >= 0) {
|
||||
object_position_transform(kg, ls->object, &ls->P);
|
||||
object_normal_transform(kg, ls->object, &ls->Ng);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__device float triangle_light_pdf(KernelGlobals *kg,
|
||||
const float3 Ng, const float3 I, float t)
|
||||
{
|
||||
float cos_pi = fabsf(dot(Ng, I));
|
||||
|
||||
if(cos_pi == 0.0f)
|
||||
return 0.0f;
|
||||
|
||||
return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi;
|
||||
}
|
||||
|
||||
/* Light Distribution */
|
||||
|
||||
__device int light_distribution_sample(KernelGlobals *kg, float randt)
|
||||
{
|
||||
/* this is basically std::upper_bound as used by pbrt, to find a point light or
|
||||
triangle to emit from, proportional to area. a good improvement would be to
|
||||
also sample proportional to power, though it's not so well defined with
|
||||
OSL shaders. */
|
||||
int first = 0;
|
||||
int len = kernel_data.integrator.num_distribution + 1;
|
||||
|
||||
while(len > 0) {
|
||||
int half_len = len >> 1;
|
||||
int middle = first + half_len;
|
||||
|
||||
if(randt < kernel_tex_fetch(__light_distribution, middle).x) {
|
||||
len = half_len;
|
||||
}
|
||||
else {
|
||||
first = middle + 1;
|
||||
len = len - half_len - 1;
|
||||
}
|
||||
}
|
||||
|
||||
first = max(0, first-1);
|
||||
kernel_assert(first >= 0 && first < kernel_data.integrator.num_distribution);
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
/* Generic Light */
|
||||
|
||||
__device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float3 P, LightSample *ls)
|
||||
{
|
||||
/* sample index */
|
||||
int index = light_distribution_sample(kg, randt);
|
||||
|
||||
/* fetch light data */
|
||||
float4 l = kernel_tex_fetch(__light_distribution, index);
|
||||
int prim = __float_as_int(l.y);
|
||||
ls->weight = l.z;
|
||||
|
||||
if(prim >= 0) {
|
||||
int object = __float_as_int(l.w);
|
||||
triangle_light_sample(kg, prim, object, randu, randv, ls);
|
||||
}
|
||||
else {
|
||||
int point = -prim-1;
|
||||
point_light_sample(kg, point, randu, randv, P, ls);
|
||||
}
|
||||
}
|
||||
|
||||
__device float light_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
|
||||
{
|
||||
float pdf;
|
||||
|
||||
if(ls->prim != ~0)
|
||||
pdf = triangle_light_pdf(kg, ls->Ng, I, t);
|
||||
else
|
||||
pdf = point_light_pdf(kg, t);
|
||||
|
||||
return pdf;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
27
intern/cycles/kernel/kernel_math.h
Normal file
27
intern/cycles/kernel/kernel_math.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_MATH_H__
|
||||
#define __KERNEL_MATH_H__
|
||||
|
||||
#include "util_color.h"
|
||||
#include "util_math.h"
|
||||
#include "util_transform.h"
|
||||
|
||||
#endif /* __KERNEL_MATH_H__ */
|
||||
|
394
intern/cycles/kernel/kernel_mbvh.h
Normal file
394
intern/cycles/kernel/kernel_mbvh.h
Normal file
@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#define MBVH_OBJECT_SENTINEL 0x76543210
|
||||
#define MBVH_NODE_SIZE 8
|
||||
#define MBVH_STACK_SIZE 1024
|
||||
#define MBVH_RAY_STACK_SIZE 10000
|
||||
|
||||
typedef struct MBVHTask {
|
||||
int node;
|
||||
int index;
|
||||
int num;
|
||||
int object;
|
||||
} MBVHTask;
|
||||
|
||||
typedef struct MVBHRay {
|
||||
float3 P;
|
||||
float u;
|
||||
float3 idir;
|
||||
float v;
|
||||
float t;
|
||||
int index;
|
||||
int object;
|
||||
|
||||
float3 origP;
|
||||
float3 origD;
|
||||
float tmax;
|
||||
} MBVHRay;
|
||||
|
||||
__device float3 mbvh_inverse_direction(float3 dir)
|
||||
{
|
||||
// Avoid divide by zero (ooeps = exp2f(-80.0f))
|
||||
float ooeps = 0.00000000000000000000000082718061255302767487140869206996285356581211090087890625f;
|
||||
float3 idir;
|
||||
|
||||
idir.x = 1.0f / (fabsf(dir.x) > ooeps ? dir.x : copysignf(ooeps, dir.x));
|
||||
idir.y = 1.0f / (fabsf(dir.y) > ooeps ? dir.y : copysignf(ooeps, dir.y));
|
||||
idir.z = 1.0f / (fabsf(dir.z) > ooeps ? dir.z : copysignf(ooeps, dir.z));
|
||||
|
||||
return idir;
|
||||
}
|
||||
|
||||
__device void mbvh_instance_push(KernelGlobals *kg, int object, MBVHRay *ray)
|
||||
{
|
||||
Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
|
||||
|
||||
ray->P = transform(&tfm, ray->origP);
|
||||
|
||||
float3 dir = ray->origD;
|
||||
|
||||
if(ray->t != ray->tmax) dir *= ray->t;
|
||||
|
||||
dir = transform_direction(&tfm, dir);
|
||||
ray->idir = mbvh_inverse_direction(normalize(dir));
|
||||
|
||||
if(ray->t != ray->tmax) ray->t = len(dir);
|
||||
}
|
||||
|
||||
__device void mbvh_instance_pop(KernelGlobals *kg, int object, MBVHRay *ray)
|
||||
{
|
||||
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
|
||||
|
||||
if(ray->t != ray->tmax)
|
||||
ray->t = len(transform_direction(&tfm, (1.0f/(ray->idir)) * (ray->t)));
|
||||
|
||||
ray->P = ray->origP;
|
||||
ray->idir = mbvh_inverse_direction(ray->origD);
|
||||
}
|
||||
|
||||
/* Sven Woop's algorithm */
|
||||
__device void mbvh_triangle_intersect(KernelGlobals *kg, MBVHRay *ray, int object, int triAddr)
|
||||
{
|
||||
float3 P = ray->P;
|
||||
float3 idir = ray->idir;
|
||||
|
||||
/* compute and check intersection t-value */
|
||||
float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+0);
|
||||
float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+1);
|
||||
float3 dir = 1.0f/idir;
|
||||
|
||||
float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
|
||||
float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z);
|
||||
float t = Oz * invDz;
|
||||
|
||||
if(t > 0.0f && t < ray->t) {
|
||||
/* compute and check barycentric u */
|
||||
float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z;
|
||||
float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z;
|
||||
float u = Ox + t*Dx;
|
||||
|
||||
if(u >= 0.0f) {
|
||||
/* compute and check barycentric v */
|
||||
float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+2);
|
||||
float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z;
|
||||
float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z;
|
||||
float v = Oy + t*Dy;
|
||||
|
||||
if(v >= 0.0f && u + v <= 1.0f) {
|
||||
/* record intersection */
|
||||
ray->index = triAddr;
|
||||
ray->object = object;
|
||||
ray->u = u;
|
||||
ray->v = v;
|
||||
ray->t = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__device void mbvh_node_intersect(KernelGlobals *kg, __m128 *traverseChild,
|
||||
__m128 *tHit, float3 P, float3 idir, float t, int nodeAddr)
|
||||
{
|
||||
/* X axis */
|
||||
const __m128 bminx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+0);
|
||||
const __m128 t0x = _mm_mul_ps(_mm_sub_ps(bminx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x));
|
||||
const __m128 bmaxx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+1);
|
||||
const __m128 t1x = _mm_mul_ps(_mm_sub_ps(bmaxx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x));
|
||||
|
||||
__m128 tmin = _mm_max_ps(_mm_min_ps(t0x, t1x), _mm_setzero_ps());
|
||||
__m128 tmax = _mm_min_ps(_mm_max_ps(t0x, t1x), _mm_set_ps1(t));
|
||||
|
||||
/* Y axis */
|
||||
const __m128 bminy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+2);
|
||||
const __m128 t0y = _mm_mul_ps(_mm_sub_ps(bminy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y));
|
||||
const __m128 bmaxy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+3);
|
||||
const __m128 t1y = _mm_mul_ps(_mm_sub_ps(bmaxy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y));
|
||||
|
||||
tmin = _mm_max_ps(_mm_min_ps(t0y, t1y), tmin);
|
||||
tmax = _mm_min_ps(_mm_max_ps(t0y, t1y), tmax);
|
||||
|
||||
/* Z axis */
|
||||
const __m128 bminz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+4);
|
||||
const __m128 t0z = _mm_mul_ps(_mm_sub_ps(bminz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z));
|
||||
const __m128 bmaxz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+5);
|
||||
const __m128 t1z = _mm_mul_ps(_mm_sub_ps(bmaxz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z));
|
||||
|
||||
tmin = _mm_max_ps(_mm_min_ps(t0z, t1z), tmin);
|
||||
tmax = _mm_min_ps(_mm_max_ps(t0z, t1z), tmax);
|
||||
|
||||
/* compare and get mask */
|
||||
*traverseChild = _mm_cmple_ps(tmin, tmax);
|
||||
|
||||
/* get distance XXX probably wrong */
|
||||
*tHit = tmin;
|
||||
}
|
||||
|
||||
static void mbvh_sort_by_length(int id[4], float len[4])
|
||||
{
|
||||
for(int i = 1; i < 4; i++) {
|
||||
int j = i - 1;
|
||||
|
||||
while(j >= 0 && len[j] > len[j+1]) {
|
||||
swap(len[j], len[j+1]);
|
||||
swap(id[j], id[j+1]);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__device void scene_intersect(KernelGlobals *kg, MBVHRay *rays, int numrays)
|
||||
{
|
||||
/* traversal stacks */
|
||||
MBVHTask task_stack[MBVH_STACK_SIZE];
|
||||
int active_ray_stacks[4][MBVH_RAY_STACK_SIZE];
|
||||
int num_task, num_active[4] = {0, 0, 0, 0};
|
||||
__m128i one_mm = _mm_set1_epi32(1);
|
||||
|
||||
/* push root node task on stack */
|
||||
task_stack[0].node = kernel_data.bvh.root;
|
||||
task_stack[0].index = 0;
|
||||
task_stack[0].num = numrays;
|
||||
task_stack[0].object = ~0;
|
||||
num_task = 1;
|
||||
|
||||
/* push all rays in first SIMD lane */
|
||||
for(int i = 0; i < numrays; i++)
|
||||
active_ray_stacks[0][i] = i;
|
||||
num_active[0] = numrays;
|
||||
|
||||
while(num_task >= 1) {
|
||||
/* pop task */
|
||||
MBVHTask task = task_stack[--num_task];
|
||||
|
||||
if(task.node == MBVH_OBJECT_SENTINEL) {
|
||||
/* instance pop */
|
||||
|
||||
/* pop rays from stack */
|
||||
num_active[task.index] -= task.num;
|
||||
int ray_offset = num_active[task.index];
|
||||
|
||||
/* transform rays */
|
||||
for(int i = 0; i < task.num; i++) {
|
||||
MBVHRay *ray = &rays[active_ray_stacks[task.index][ray_offset + i]];
|
||||
mbvh_instance_pop(kg, task.object, ray);
|
||||
}
|
||||
}
|
||||
else if(task.node >= 0) {
|
||||
/* inner node? */
|
||||
|
||||
/* pop rays from stack*/
|
||||
num_active[task.index] -= task.num;
|
||||
int ray_offset = num_active[task.index];
|
||||
|
||||
/* initialze simd values */
|
||||
__m128i num_active_mm = _mm_load_si128((__m128i*)num_active);
|
||||
__m128 len_mm = _mm_set_ps1(0.0f);
|
||||
|
||||
for(int i = 0; i < task.num; i++) {
|
||||
int rayid = active_ray_stacks[task.index][ray_offset + i];
|
||||
MVBHRay *ray = rays + rayid;
|
||||
|
||||
/* intersect 4 QBVH node children */
|
||||
__m128 result;
|
||||
__m128 thit;
|
||||
|
||||
mbvh_node_intersect(kg, &result, &thit, ray->P, ray->idir, ray->t, task.node);
|
||||
|
||||
/* update length for sorting */
|
||||
len_mm = _mm_add_ps(len_mm, _mm_and_ps(thit, result));
|
||||
|
||||
/* push rays on stack */
|
||||
for(int j = 0; j < 4; j++)
|
||||
active_ray_stacks[j][num_active[j]] = rayid;
|
||||
|
||||
/* update num active */
|
||||
__m128i resulti = _mm_and_si128(*((__m128i*)&result), one_mm);
|
||||
num_active_mm = _mm_add_epi32(resulti, num_active_mm);
|
||||
_mm_store_si128((__m128i*)num_active, num_active_mm);
|
||||
}
|
||||
|
||||
if(num_active[0] || num_active[1] || num_active[2] || num_active[3]) {
|
||||
/* load child node addresses */
|
||||
float4 cnodes = kernel_tex_fetch(__bvh_nodes, task.node);
|
||||
int child[4] = {
|
||||
__float_as_int(cnodes.x),
|
||||
__float_as_int(cnodes.y),
|
||||
__float_as_int(cnodes.z),
|
||||
__float_as_int(cnodes.w)};
|
||||
|
||||
/* sort nodes by average intersection distance */
|
||||
int ids[4] = {0, 1, 2, 3};
|
||||
float len[4];
|
||||
|
||||
_mm_store_ps(len, len_mm);
|
||||
mbvh_sort_by_length(ids, len);
|
||||
|
||||
/* push new tasks on stack */
|
||||
for(int j = 0; j < 4; j++) {
|
||||
if(num_active[j]) {
|
||||
int id = ids[j];
|
||||
|
||||
task_stack[num_task].node = child[id];
|
||||
task_stack[num_task].index = id;
|
||||
task_stack[num_task].num = num_active[id];
|
||||
task_stack[num_task].object = task.object;
|
||||
num_task++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* fetch leaf node data */
|
||||
float4 leaf = kernel_tex_fetch(__bvh_nodes, (-task.node-1)*MBVH_NODE_SIZE+(MBVH_NODE_SIZE-2));
|
||||
int triAddr = __float_as_int(leaf.x);
|
||||
int triAddr2 = __float_as_int(leaf.y);
|
||||
|
||||
/* pop rays from stack*/
|
||||
num_active[task.index] -= task.num;
|
||||
int ray_offset = num_active[task.index];
|
||||
|
||||
/* triangles */
|
||||
if(triAddr >= 0) {
|
||||
int i, numq = (task.num >> 2) << 2;
|
||||
|
||||
/* SIMD ray leaf intersection */
|
||||
for(i = 0; i < numq; i += 4) {
|
||||
MBVHRay *ray4[4] = {
|
||||
&rays[active_ray_stacks[task.index][ray_offset + i + 0]],
|
||||
&rays[active_ray_stacks[task.index][ray_offset + i + 1]],
|
||||
&rays[active_ray_stacks[task.index][ray_offset + i + 2]],
|
||||
&rays[active_ray_stacks[task.index][ray_offset + i + 3]]};
|
||||
|
||||
/* load SoA */
|
||||
|
||||
while(triAddr < triAddr2) {
|
||||
mbvh_triangle_intersect(ray4[0], task.object, task.node);
|
||||
mbvh_triangle_intersect(ray4[1], task.object, task.node);
|
||||
mbvh_triangle_intersect(ray4[2], task.object, task.node);
|
||||
mbvh_triangle_intersect(ray4[3], task.object, task.node);
|
||||
triAddr++;
|
||||
|
||||
/* some shadow ray optim could be done by setting t=0 */
|
||||
}
|
||||
|
||||
/* store AoS */
|
||||
}
|
||||
|
||||
/* mono ray leaf intersection */
|
||||
for(; i < task.num; i++) {
|
||||
MBVHRay *ray = &rays[active_ray_stacks[task.index][ray_offset + i]];
|
||||
|
||||
while(triAddr < triAddr2) {
|
||||
mbvh_triangle_intersect(kg, ray, task.object, task.node);
|
||||
triAddr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* instance push */
|
||||
int object = -triAddr-1;
|
||||
int node = triAddr;
|
||||
|
||||
/* push instance pop task */
|
||||
task_stack[num_task].node = MBVH_OBJECT_SENTINEL;
|
||||
task_stack[num_task].index = task.index;
|
||||
task_stack[num_task].num = task.num;
|
||||
task_stack[num_task].object = object;
|
||||
num_task++;
|
||||
|
||||
num_active[task.index] += task.num;
|
||||
|
||||
/* push node task */
|
||||
task_stack[num_task].node = node;
|
||||
task_stack[num_task].index = task.index;
|
||||
task_stack[num_task].num = task.num;
|
||||
task_stack[num_task].object = object;
|
||||
num_task++;
|
||||
|
||||
for(int i = 0; i < task.num; i++) {
|
||||
int rayid = active_ray_stacks[task.index][ray_offset + i];
|
||||
|
||||
/* push on stack for last task */
|
||||
active_ray_stacks[task.index][num_active[task.index]] = rayid;
|
||||
num_active[task.index]++;
|
||||
|
||||
/* transform ray */
|
||||
MBVHRay *ray = &rays[rayid];
|
||||
mbvh_instance_push(kg, object, ray);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__device void mbvh_set_ray(MBVHRay *rays, int i, Ray *ray, float tmax)
|
||||
{
|
||||
MBVHRay *mray = &rays[i];
|
||||
|
||||
/* ray parameters in registers */
|
||||
mray->P = ray->P;
|
||||
mray->idir = mbvh_inverse_direction(ray->D);
|
||||
mray->t = tmax;
|
||||
}
|
||||
|
||||
__device bool mbvh_get_intersection(MVBHRay *rays, int i, Intersection *isect, float tmax)
|
||||
{
|
||||
MBVHRay *mray = &rays[i];
|
||||
|
||||
if(mray->t == tmax)
|
||||
return false;
|
||||
|
||||
isect->t = mray->t;
|
||||
isect->u = mray->u;
|
||||
isect->v = mray->v;
|
||||
isect->index = mray->index;
|
||||
isect->object = mray->object;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
__device bool mbvh_get_shadow(MBVHRay *rays, int i, float tmax)
|
||||
{
|
||||
return (rays[i].t == tmax);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
196
intern/cycles/kernel/kernel_montecarlo.h
Normal file
196
intern/cycles/kernel/kernel_montecarlo.h
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Parts adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_MONTECARLO_CL__
|
||||
#define __KERNEL_MONTECARLO_CL__
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/// Given values x and y on [0,1], convert them in place to values on
|
||||
/// [-1,1] uniformly distributed over a unit sphere. This code is
|
||||
/// derived from Peter Shirley, "Realistic Ray Tracing", p. 103.
|
||||
__device void to_unit_disk(float *x, float *y)
|
||||
{
|
||||
float r, phi;
|
||||
float a = 2.0f * (*x) - 1.0f;
|
||||
float b = 2.0f * (*y) - 1.0f;
|
||||
if(a > -b) {
|
||||
if(a > b) {
|
||||
r = a;
|
||||
phi = M_PI_4_F *(b/a);
|
||||
} else {
|
||||
r = b;
|
||||
phi = M_PI_4_F *(2.0f - a/b);
|
||||
}
|
||||
} else {
|
||||
if(a < b) {
|
||||
r = -a;
|
||||
phi = M_PI_4_F *(4.0f + b/a);
|
||||
} else {
|
||||
r = -b;
|
||||
if(b != 0.0f)
|
||||
phi = M_PI_4_F *(6.0f - a/b);
|
||||
else
|
||||
phi = 0.0f;
|
||||
}
|
||||
}
|
||||
*x = r * cosf(phi);
|
||||
*y = r * sinf(phi);
|
||||
}
|
||||
|
||||
__device_inline void make_orthonormals(const float3 N, float3 *a, float3 *b)
|
||||
{
|
||||
if(N.x != N.y || N.x != N.z)
|
||||
*a = make_float3(N.z-N.y, N.x-N.z, N.y-N.x); //(1,1,1)x N
|
||||
else
|
||||
*a = make_float3(N.z-N.y, N.x+N.z, -N.y-N.x); //(-1,1,1)x N
|
||||
|
||||
*a = normalize(*a);
|
||||
*b = cross(N, *a);
|
||||
}
|
||||
|
||||
__device void make_orthonormals_tangent(const float3 N, const float3 T, float3 *a, float3 *b)
|
||||
{
|
||||
*b = cross(N, T);
|
||||
*a = cross(*b, N);
|
||||
}
|
||||
|
||||
__device_inline void sample_cos_hemisphere(const float3 N,
|
||||
float randu, float randv, float3 *omega_in, float *pdf)
|
||||
{
|
||||
// Default closure BSDF implementation: uniformly sample
|
||||
// cosine-weighted hemisphere above the point.
|
||||
to_unit_disk(&randu, &randv);
|
||||
float costheta = sqrtf(max(1.0f - randu * randu - randv * randv, 0.0f));
|
||||
float3 T, B;
|
||||
make_orthonormals(N, &T, &B);
|
||||
*omega_in = randu * T + randv * B + costheta * N;
|
||||
*pdf = costheta *M_1_PI_F;
|
||||
}
|
||||
|
||||
__device_inline void sample_uniform_hemisphere(const float3 N,
|
||||
float randu, float randv,
|
||||
float3 *omega_in, float *pdf)
|
||||
{
|
||||
float z = randu;
|
||||
float r = sqrtf(max(0.f, 1.f - z*z));
|
||||
float phi = 2.f * M_PI_F * randv;
|
||||
float x = r * cosf(phi);
|
||||
float y = r * sinf(phi);
|
||||
|
||||
float3 T, B;
|
||||
make_orthonormals (N, &T, &B);
|
||||
*omega_in = x * T + y * B + z * N;
|
||||
*pdf = 0.5f * M_1_PI_F;
|
||||
}
|
||||
|
||||
__device float3 sample_uniform_sphere(float u1, float u2)
|
||||
{
|
||||
float z = 1.0f - 2.0f*u1;
|
||||
float r = sqrtf(fmaxf(0.0f, 1.0f - z*z));
|
||||
float phi = 2.0f*M_PI_F*u2;
|
||||
float x = r*cosf(phi);
|
||||
float y = r*sinf(phi);
|
||||
|
||||
return make_float3(x, y, z);
|
||||
}
|
||||
|
||||
__device float power_heuristic(float a, float b)
|
||||
{
|
||||
return (a*a)/(a*a + b*b);
|
||||
}
|
||||
|
||||
__device float2 concentric_sample_disk(float u1, float u2)
|
||||
{
|
||||
float r, theta;
|
||||
// Map uniform random numbers to $[-1,1]^2$
|
||||
float sx = 2 * u1 - 1;
|
||||
float sy = 2 * u2 - 1;
|
||||
|
||||
// Map square to $(r,\theta)$
|
||||
|
||||
// Handle degeneracy at the origin
|
||||
if(sx == 0.0f && sy == 0.0f) {
|
||||
return make_float2(0.0f, 0.0f);
|
||||
}
|
||||
if(sx >= -sy) {
|
||||
if(sx > sy) {
|
||||
// Handle first region of disk
|
||||
r = sx;
|
||||
if(sy > 0.0f) theta = sy/r;
|
||||
else theta = 8.0f + sy/r;
|
||||
}
|
||||
else {
|
||||
// Handle second region of disk
|
||||
r = sy;
|
||||
theta = 2.0f - sx/r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(sx <= sy) {
|
||||
// Handle third region of disk
|
||||
r = -sx;
|
||||
theta = 4.0f - sy/r;
|
||||
}
|
||||
else {
|
||||
// Handle fourth region of disk
|
||||
r = -sy;
|
||||
theta = 6.0f + sx/r;
|
||||
}
|
||||
}
|
||||
|
||||
theta *= M_PI_4_F;
|
||||
return make_float2(r * cosf(theta), r * sinf(theta));
|
||||
}
|
||||
|
||||
/* Spherical coordinates <-> Cartesion direction */
|
||||
|
||||
__device float2 direction_to_spherical(float3 dir)
|
||||
{
|
||||
float theta = acosf(dir.z);
|
||||
float phi = atan2f(dir.x, dir.y);
|
||||
|
||||
return make_float2(theta, phi);
|
||||
}
|
||||
|
||||
__device float3 spherical_to_direction(float theta, float phi)
|
||||
{
|
||||
return make_float3(
|
||||
sinf(theta)*cosf(phi),
|
||||
sinf(theta)*sinf(phi),
|
||||
cosf(theta));
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __KERNEL_MONTECARLO_CL__ */
|
||||
|
68
intern/cycles/kernel/kernel_object.h
Normal file
68
intern/cycles/kernel/kernel_object.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
enum ObjectTransform {
|
||||
OBJECT_TRANSFORM = 0,
|
||||
OBJECT_INVERSE_TRANSFORM = 4,
|
||||
OBJECT_NORMAL_TRANSFORM = 8,
|
||||
OBJECT_PROPERTIES = 12
|
||||
};
|
||||
|
||||
__device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type)
|
||||
{
|
||||
Transform tfm;
|
||||
|
||||
int offset = object*OBJECT_SIZE + (int)type;
|
||||
|
||||
tfm.x = kernel_tex_fetch(__objects, offset + 0);
|
||||
tfm.y = kernel_tex_fetch(__objects, offset + 1);
|
||||
tfm.z = kernel_tex_fetch(__objects, offset + 2);
|
||||
tfm.w = kernel_tex_fetch(__objects, offset + 3);
|
||||
|
||||
return tfm;
|
||||
}
|
||||
|
||||
__device_inline void object_position_transform(KernelGlobals *kg, int object, float3 *P)
|
||||
{
|
||||
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
|
||||
*P = transform(&tfm, *P);
|
||||
}
|
||||
|
||||
__device_inline void object_normal_transform(KernelGlobals *kg, int object, float3 *N)
|
||||
{
|
||||
Transform tfm = object_fetch_transform(kg, object, OBJECT_NORMAL_TRANSFORM);
|
||||
*N = normalize(transform_direction(&tfm, *N));
|
||||
}
|
||||
|
||||
__device_inline void object_dir_transform(KernelGlobals *kg, int object, float3 *D)
|
||||
{
|
||||
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
|
||||
*D = transform_direction(&tfm, *D);
|
||||
}
|
||||
|
||||
__device_inline float object_surface_area(KernelGlobals *kg, int object)
|
||||
{
|
||||
int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
|
||||
float4 f = kernel_tex_fetch(__objects, offset);
|
||||
return f.x;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
263
intern/cycles/kernel/kernel_path.h
Normal file
263
intern/cycles/kernel/kernel_path.h
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "kernel_differential.h"
|
||||
#include "kernel_montecarlo.h"
|
||||
#include "kernel_triangle.h"
|
||||
#include "kernel_object.h"
|
||||
#ifdef __QBVH__
|
||||
#include "kernel_qbvh.h"
|
||||
#else
|
||||
#include "kernel_bvh.h"
|
||||
#endif
|
||||
#include "kernel_camera.h"
|
||||
#include "kernel_shader.h"
|
||||
#include "kernel_light.h"
|
||||
#include "kernel_emission.h"
|
||||
#include "kernel_random.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef __MODIFY_TP__
|
||||
__device float3 path_terminate_modified_throughput(KernelGlobals *kg, __global float3 *buffer, int x, int y, int pass)
|
||||
{
|
||||
/* modify throughput to influence path termination probability, to avoid
|
||||
darker regions receiving fewer samples than lighter regions. also RGB
|
||||
are weighted differently. proper validation still remains to be done. */
|
||||
const float3 weights = make_float3(1.0f, 1.33f, 0.66f);
|
||||
const float3 one = make_float3(1.0f, 1.0f, 1.0f);
|
||||
const int minpass = 5;
|
||||
const float minL = 0.1f;
|
||||
|
||||
if(pass >= minpass) {
|
||||
float3 L = buffer[x + y*kernel_data.cam.width];
|
||||
float3 Lmin = make_float3(minL, minL, minL);
|
||||
float correct = (float)(pass+1)/(float)pass;
|
||||
|
||||
L = film_map(L*correct, pass);
|
||||
|
||||
return weights/clamp(L, Lmin, one);
|
||||
}
|
||||
|
||||
return weights;
|
||||
}
|
||||
#endif
|
||||
|
||||
__device float path_terminate_probability(KernelGlobals *kg, int bounce, const float3 throughput)
|
||||
{
|
||||
if(bounce >= kernel_data.integrator.maxbounce)
|
||||
return 0.0f;
|
||||
else if(bounce <= kernel_data.integrator.minbounce)
|
||||
return 1.0f;
|
||||
|
||||
return average(throughput);
|
||||
}
|
||||
|
||||
__device int path_flag_from_label(int path_flag, int label)
|
||||
{
|
||||
/* reflect/transmit */
|
||||
if(label & LABEL_REFLECT) {
|
||||
path_flag |= PATH_RAY_REFLECT;
|
||||
path_flag &= ~PATH_RAY_TRANSMIT;
|
||||
}
|
||||
else {
|
||||
kernel_assert(label & LABEL_TRANSMIT);
|
||||
|
||||
path_flag |= PATH_RAY_TRANSMIT;
|
||||
path_flag &= ~PATH_RAY_REFLECT;
|
||||
}
|
||||
|
||||
/* diffuse/glossy/singular */
|
||||
if(label & LABEL_DIFFUSE) {
|
||||
path_flag |= PATH_RAY_DIFFUSE;
|
||||
path_flag &= ~(PATH_RAY_GLOSSY|PATH_RAY_SINGULAR);
|
||||
}
|
||||
else if(label & LABEL_GLOSSY) {
|
||||
path_flag |= PATH_RAY_GLOSSY;
|
||||
path_flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_SINGULAR);
|
||||
}
|
||||
else {
|
||||
kernel_assert(label & (LABEL_SINGULAR|LABEL_STRAIGHT));
|
||||
|
||||
path_flag |= PATH_RAY_SINGULAR;
|
||||
path_flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY);
|
||||
}
|
||||
|
||||
/* ray through transparent is still camera ray */
|
||||
if(!(label & LABEL_STRAIGHT))
|
||||
path_flag &= ~PATH_RAY_CAMERA;
|
||||
|
||||
return path_flag;
|
||||
}
|
||||
|
||||
__device float3 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray ray, float3 throughput)
|
||||
{
|
||||
/* initialize */
|
||||
float3 L = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
#ifdef __EMISSION__
|
||||
float ray_pdf = 0.0f;
|
||||
#endif
|
||||
int path_flag = PATH_RAY_CAMERA|PATH_RAY_SINGULAR;
|
||||
int rng_offset = PRNG_BASE_NUM;
|
||||
|
||||
/* path iteration */
|
||||
for(int bounce = 0; ; bounce++, rng_offset += PRNG_BOUNCE_NUM) {
|
||||
/* intersect scene */
|
||||
Intersection isect;
|
||||
|
||||
if(!scene_intersect(kg, &ray, false, &isect)) {
|
||||
/* eval background shader if nothing hit */
|
||||
#ifdef __BACKGROUND__
|
||||
ShaderData sd;
|
||||
shader_setup_from_background(kg, &sd, &ray);
|
||||
L += throughput*shader_eval_background(kg, &sd, path_flag);
|
||||
shader_release(kg, &sd);
|
||||
#else
|
||||
L += throughputmake_float3(0.8f, 0.8f, 0.8f);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup shading */
|
||||
ShaderData sd;
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray);
|
||||
float rbsdf = path_rng(kg, rng, pass, rng_offset + PRNG_BSDF);
|
||||
shader_eval_surface(kg, &sd, rbsdf, path_flag);
|
||||
|
||||
#ifdef __EMISSION__
|
||||
/* emission */
|
||||
if(kernel_data.integrator.use_emission) {
|
||||
if(sd.flag & SD_EMISSION)
|
||||
L += throughput*indirect_emission(kg, &sd, isect.t, path_flag, ray_pdf);
|
||||
|
||||
/* sample illumination from lights to find path contribution */
|
||||
if((sd.flag & SD_BSDF_HAS_EVAL) &&
|
||||
bounce != kernel_data.integrator.maxbounce) {
|
||||
float light_t = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT);
|
||||
float light_o = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_F);
|
||||
float light_u = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_U);
|
||||
float light_v = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_V);
|
||||
|
||||
Ray light_ray;
|
||||
float3 light_L;
|
||||
|
||||
if(direct_emission(kg, &sd, light_t, light_o, light_u, light_v, &light_ray, &light_L)) {
|
||||
/* trace shadow ray */
|
||||
if(!scene_intersect(kg, &light_ray, true, &isect))
|
||||
L += throughput*light_L;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* sample BSDF */
|
||||
float bsdf_pdf;
|
||||
float3 bsdf_eval;
|
||||
float3 bsdf_omega_in;
|
||||
differential3 bsdf_domega_in;
|
||||
float bsdf_u = path_rng(kg, rng, pass, rng_offset + PRNG_BSDF_U);
|
||||
float bsdf_v = path_rng(kg, rng, pass, rng_offset + PRNG_BSDF_V);
|
||||
int label;
|
||||
|
||||
label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
|
||||
&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
|
||||
|
||||
shader_release(kg, &sd);
|
||||
|
||||
if(bsdf_pdf == 0.0f || is_zero(bsdf_eval))
|
||||
break;
|
||||
|
||||
/* modify throughput */
|
||||
throughput *= bsdf_eval/bsdf_pdf;
|
||||
|
||||
/* set labels */
|
||||
#ifdef __EMISSION__
|
||||
ray_pdf = bsdf_pdf;
|
||||
#endif
|
||||
|
||||
path_flag = path_flag_from_label(path_flag, label);
|
||||
|
||||
/* path termination */
|
||||
float probability = path_terminate_probability(kg, bounce, throughput);
|
||||
float terminate = path_rng(kg, rng, pass, rng_offset + PRNG_TERMINATE);
|
||||
|
||||
if(terminate >= probability)
|
||||
break;
|
||||
|
||||
throughput /= probability;
|
||||
|
||||
/* setup ray */
|
||||
ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);
|
||||
ray.D = bsdf_omega_in;
|
||||
ray.t = FLT_MAX;
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
ray.dP = sd.dP;
|
||||
ray.dD = bsdf_domega_in;
|
||||
#endif
|
||||
}
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
__device void kernel_path_trace(KernelGlobals *kg, __global float4 *buffer, __global uint *rng_state, int pass, int x, int y)
|
||||
{
|
||||
/* initialize random numbers */
|
||||
RNG rng;
|
||||
|
||||
float filter_u;
|
||||
float filter_v;
|
||||
|
||||
path_rng_init(kg, rng_state, pass, &rng, x, y, &filter_u, &filter_v);
|
||||
|
||||
/* sample camera ray */
|
||||
Ray ray;
|
||||
|
||||
float lens_u = path_rng(kg, &rng, pass, PRNG_LENS_U);
|
||||
float lens_v = path_rng(kg, &rng, pass, PRNG_LENS_V);
|
||||
|
||||
camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, &ray);
|
||||
|
||||
/* integrate */
|
||||
#ifdef __MODIFY_TP__
|
||||
float3 throughput = path_terminate_modified_throughput(kg, buffer, x, y, pass);
|
||||
float3 L = kernel_path_integrate(kg, &rng, pass, ray, throughput)/throughput;
|
||||
#else
|
||||
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
|
||||
float3 L = kernel_path_integrate(kg, &rng, pass, ray, throughput);
|
||||
#endif
|
||||
|
||||
/* accumulate result in output buffer */
|
||||
int index = x + y*kernel_data.cam.width;
|
||||
|
||||
float4 result;
|
||||
result.x = L.x;
|
||||
result.y = L.y;
|
||||
result.z = L.z;
|
||||
result.w = 1.0f;
|
||||
|
||||
if(pass == 0)
|
||||
buffer[index] = result;
|
||||
else
|
||||
buffer[index] += result;
|
||||
|
||||
path_rng_end(kg, rng_state, rng, x, y);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
413
intern/cycles/kernel/kernel_qbvh.h
Normal file
413
intern/cycles/kernel/kernel_qbvh.h
Normal file
@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Adapted from code Copyright 2009-2010 NVIDIA Corporation
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/*
|
||||
* "Persistent while-while kernel" used in:
|
||||
*
|
||||
* "Understanding the Efficiency of Ray Traversal on GPUs",
|
||||
* Timo Aila and Samuli Laine,
|
||||
* Proc. High-Performance Graphics 2009
|
||||
*/
|
||||
|
||||
/* bottom-most stack entry, indicating the end of traversal */
|
||||
|
||||
#define ENTRYPOINT_SENTINEL 0x76543210
|
||||
/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
|
||||
#define QBVH_STACK_SIZE 192
|
||||
#define QBVH_NODE_SIZE 8
|
||||
#define TRI_NODE_SIZE 3
|
||||
|
||||
__device_inline float3 qbvh_inverse_direction(float3 dir)
|
||||
{
|
||||
// Avoid divide by zero (ooeps = exp2f(-80.0f))
|
||||
float ooeps = 0.00000000000000000000000082718061255302767487140869206996285356581211090087890625f;
|
||||
float3 idir;
|
||||
|
||||
idir.x = 1.0f/((fabsf(dir.x) > ooeps)? dir.x: copysignf(ooeps, dir.x));
|
||||
idir.y = 1.0f/((fabsf(dir.y) > ooeps)? dir.y: copysignf(ooeps, dir.y));
|
||||
idir.z = 1.0f/((fabsf(dir.z) > ooeps)? dir.z: copysignf(ooeps, dir.z));
|
||||
|
||||
return idir;
|
||||
}
|
||||
|
||||
__device_inline void qbvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
|
||||
{
|
||||
Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
|
||||
|
||||
*P = transform(&tfm, ray->P);
|
||||
|
||||
float3 dir = transform_direction(&tfm, ray->D);
|
||||
|
||||
float len;
|
||||
dir = normalize_len(dir, &len);
|
||||
|
||||
*idir = qbvh_inverse_direction(dir);
|
||||
|
||||
if(*t != FLT_MAX)
|
||||
*t *= len;
|
||||
}
|
||||
|
||||
__device_inline void qbvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
|
||||
{
|
||||
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
|
||||
|
||||
if(*t != FLT_MAX)
|
||||
*t *= len(transform_direction(&tfm, 1.0f/(*idir)));
|
||||
|
||||
*P = ray->P;
|
||||
*idir = qbvh_inverse_direction(ray->D);
|
||||
}
|
||||
|
||||
#ifdef __KERNEL_CPU__
|
||||
|
||||
__device_inline void qbvh_node_intersect(KernelGlobals *kg, int *traverseChild,
|
||||
int nodeAddrChild[4], float3 P, float3 idir, float t, int nodeAddr)
|
||||
{
|
||||
/* X axis */
|
||||
const __m128 bminx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+0);
|
||||
const __m128 t0x = _mm_mul_ps(_mm_sub_ps(bminx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x));
|
||||
const __m128 bmaxx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+1);
|
||||
const __m128 t1x = _mm_mul_ps(_mm_sub_ps(bmaxx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x));
|
||||
|
||||
__m128 tmin = _mm_max_ps(_mm_min_ps(t0x, t1x), _mm_setzero_ps());
|
||||
__m128 tmax = _mm_min_ps(_mm_max_ps(t0x, t1x), _mm_set_ps1(t));
|
||||
|
||||
/* Y axis */
|
||||
const __m128 bminy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+2);
|
||||
const __m128 t0y = _mm_mul_ps(_mm_sub_ps(bminy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y));
|
||||
const __m128 bmaxy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+3);
|
||||
const __m128 t1y = _mm_mul_ps(_mm_sub_ps(bmaxy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y));
|
||||
|
||||
tmin = _mm_max_ps(_mm_min_ps(t0y, t1y), tmin);
|
||||
tmax = _mm_min_ps(_mm_max_ps(t0y, t1y), tmax);
|
||||
|
||||
/* Z axis */
|
||||
const __m128 bminz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+4);
|
||||
const __m128 t0z = _mm_mul_ps(_mm_sub_ps(bminz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z));
|
||||
const __m128 bmaxz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+5);
|
||||
const __m128 t1z = _mm_mul_ps(_mm_sub_ps(bmaxz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z));
|
||||
|
||||
tmin = _mm_max_ps(_mm_min_ps(t0z, t1z), tmin);
|
||||
tmax = _mm_min_ps(_mm_max_ps(t0z, t1z), tmax);
|
||||
|
||||
/* compare and get mask */
|
||||
*traverseChild = _mm_movemask_ps(_mm_cmple_ps(tmin, tmax));
|
||||
|
||||
/* get node addresses */
|
||||
float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+6);
|
||||
|
||||
nodeAddrChild[0] = __float_as_int(cnodes.x);
|
||||
nodeAddrChild[1] = __float_as_int(cnodes.y);
|
||||
nodeAddrChild[2] = __float_as_int(cnodes.z);
|
||||
nodeAddrChild[3] = __float_as_int(cnodes.w);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
__device_inline bool qbvh_bb_intersect(float3 bmin, float3 bmax, float3 P, float3 idir, float t)
|
||||
{
|
||||
float t0x = (bmin.x - P.x)*idir.x;
|
||||
float t1x = (bmax.x - P.x)*idir.x;
|
||||
float t0y = (bmin.y - P.y)*idir.y;
|
||||
float t1y = (bmax.y - P.y)*idir.y;
|
||||
float t0z = (bmin.z - P.z)*idir.z;
|
||||
float t1z = (bmax.z - P.z)*idir.z;
|
||||
|
||||
float minx = min(t0x, t1x);
|
||||
float maxx = max(t0x, t1x);
|
||||
float miny = min(t0y, t1y);
|
||||
float maxy = max(t0y, t1y);
|
||||
float minz = min(t0z, t1z);
|
||||
float maxz = max(t0z, t1z);
|
||||
|
||||
float tmin = max4(0.0f, minx, miny, minz);
|
||||
float tmax = min4(t, maxx, maxy, maxz);
|
||||
|
||||
return (tmin <= tmax);
|
||||
}
|
||||
|
||||
/* intersect four bounding boxes */
|
||||
__device_inline void qbvh_node_intersect(KernelGlobals *kg, int *traverseChild,
|
||||
int nodeAddrChild[4], float3 P, float3 idir, float t, int nodeAddr)
|
||||
{
|
||||
/* fetch node data */
|
||||
float4 minx = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+0);
|
||||
float4 miny = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+2);
|
||||
float4 minz = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+4);
|
||||
float4 maxx = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+1);
|
||||
float4 maxy = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+3);
|
||||
float4 maxz = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+5);
|
||||
|
||||
/* intersect bounding boxes */
|
||||
bool traverseChild0 = qbvh_bb_intersect(make_float3(minx.x, miny.x, minz.x), make_float3(maxx.x, maxy.x, maxz.x), P, idir, t);
|
||||
bool traverseChild1 = qbvh_bb_intersect(make_float3(minx.y, miny.y, minz.y), make_float3(maxx.y, maxy.y, maxz.y), P, idir, t);
|
||||
bool traverseChild2 = qbvh_bb_intersect(make_float3(minx.z, miny.z, minz.z), make_float3(maxx.z, maxy.z, maxz.z), P, idir, t);
|
||||
bool traverseChild3 = qbvh_bb_intersect(make_float3(minx.w, miny.w, minz.w), make_float3(maxx.w, maxy.w, maxz.w), P, idir, t);
|
||||
|
||||
*traverseChild = 0;
|
||||
if(traverseChild0) *traverseChild |= 1;
|
||||
if(traverseChild1) *traverseChild |= 2;
|
||||
if(traverseChild2) *traverseChild |= 4;
|
||||
if(traverseChild3) *traverseChild |= 8;
|
||||
|
||||
/* get node addresses */
|
||||
float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+6);
|
||||
|
||||
nodeAddrChild[0] = __float_as_int(cnodes.x);
|
||||
nodeAddrChild[1] = __float_as_int(cnodes.y);
|
||||
nodeAddrChild[2] = __float_as_int(cnodes.z);
|
||||
nodeAddrChild[3] = __float_as_int(cnodes.w);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Sven Woop's algorithm */
|
||||
__device_inline void qbvh_triangle_intersect(KernelGlobals *kg, Intersection *isect, float3 P, float3 idir, int object, int triAddr)
|
||||
{
|
||||
/* compute and check intersection t-value */
|
||||
float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
|
||||
float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
|
||||
float3 dir = 1.0f/idir;
|
||||
|
||||
float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
|
||||
float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z);
|
||||
float t = Oz * invDz;
|
||||
|
||||
if(t > 0.0f && t < isect->t) {
|
||||
/* compute and check barycentric u */
|
||||
float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z;
|
||||
float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z;
|
||||
float u = Ox + t*Dx;
|
||||
|
||||
if(u >= 0.0f) {
|
||||
/* compute and check barycentric v */
|
||||
float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
|
||||
float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z;
|
||||
float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z;
|
||||
float v = Oy + t*Dy;
|
||||
|
||||
if(v >= 0.0f && u + v <= 1.0f) {
|
||||
/* record intersection */
|
||||
isect->prim = triAddr;
|
||||
isect->object = object;
|
||||
isect->u = u;
|
||||
isect->v = v;
|
||||
isect->t = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const bool isshadowray, Intersection *isect)
|
||||
{
|
||||
/* traversal stack in CUDA thread-local memory */
|
||||
int traversalStack[QBVH_STACK_SIZE];
|
||||
traversalStack[0] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
/* traversal variables in registers */
|
||||
int stackPtr = 0;
|
||||
int nodeAddr = kernel_data.bvh.root;
|
||||
|
||||
/* ray parameters in registers */
|
||||
const float tmax = ray->t;
|
||||
float3 P = ray->P;
|
||||
float3 idir = qbvh_inverse_direction(ray->D);
|
||||
int object = ~0;
|
||||
|
||||
isect->t = tmax;
|
||||
isect->object = ~0;
|
||||
isect->prim = ~0;
|
||||
isect->u = 0.0f;
|
||||
isect->v = 0.0f;
|
||||
|
||||
/* traversal loop */
|
||||
do {
|
||||
do
|
||||
{
|
||||
/* traverse internal nodes */
|
||||
while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL)
|
||||
{
|
||||
int traverseChild, nodeAddrChild[4];
|
||||
|
||||
qbvh_node_intersect(kg, &traverseChild, nodeAddrChild,
|
||||
P, idir, isect->t, nodeAddr);
|
||||
|
||||
if(traverseChild & 1) {
|
||||
++stackPtr;
|
||||
traversalStack[stackPtr] = nodeAddrChild[0];
|
||||
}
|
||||
|
||||
if(traverseChild & 2) {
|
||||
++stackPtr;
|
||||
traversalStack[stackPtr] = nodeAddrChild[1];
|
||||
}
|
||||
if(traverseChild & 4) {
|
||||
++stackPtr;
|
||||
traversalStack[stackPtr] = nodeAddrChild[2];
|
||||
}
|
||||
|
||||
if(traverseChild & 8) {
|
||||
++stackPtr;
|
||||
traversalStack[stackPtr] = nodeAddrChild[3];
|
||||
}
|
||||
|
||||
nodeAddr = traversalStack[stackPtr];
|
||||
--stackPtr;
|
||||
}
|
||||
|
||||
/* if node is leaf, fetch triangle list */
|
||||
if(nodeAddr < 0) {
|
||||
float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*QBVH_NODE_SIZE+(QBVH_NODE_SIZE-2));
|
||||
int primAddr = __float_as_int(leaf.x);
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
if(primAddr >= 0) {
|
||||
#endif
|
||||
int primAddr2 = __float_as_int(leaf.y);
|
||||
|
||||
/* pop */
|
||||
nodeAddr = traversalStack[stackPtr];
|
||||
--stackPtr;
|
||||
|
||||
/* triangle intersection */
|
||||
while(primAddr < primAddr2) {
|
||||
/* intersect ray against triangle */
|
||||
qbvh_triangle_intersect(kg, isect, P, idir, object, primAddr);
|
||||
|
||||
/* shadow ray early termination */
|
||||
if(isshadowray && isect->prim != ~0)
|
||||
return true;
|
||||
|
||||
primAddr++;
|
||||
}
|
||||
#ifdef __INSTANCING__
|
||||
}
|
||||
else {
|
||||
/* instance push */
|
||||
object = kernel_tex_fetch(__prim_object, -primAddr-1);
|
||||
|
||||
qbvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax);
|
||||
|
||||
++stackPtr;
|
||||
traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
nodeAddr = kernel_tex_fetch(__object_node, object);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
if(stackPtr >= 0) {
|
||||
kernel_assert(object != ~0);
|
||||
|
||||
/* instance pop */
|
||||
qbvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax);
|
||||
object = ~0;
|
||||
nodeAddr = traversalStack[stackPtr];
|
||||
--stackPtr;
|
||||
}
|
||||
#endif
|
||||
} while(nodeAddr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
return (isect->prim != ~0);
|
||||
}
|
||||
|
||||
__device_inline float3 ray_offset(float3 P, float3 Ng)
|
||||
{
|
||||
#ifdef __INTERSECTION_REFINE__
|
||||
const float epsilon_f = 1e-5f;
|
||||
const int epsilon_i = 32;
|
||||
|
||||
float3 res;
|
||||
|
||||
/* x component */
|
||||
if(fabsf(P.x) < epsilon_f) {
|
||||
res.x = P.x + Ng.x*epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint ix = __float_as_uint(P.x);
|
||||
ix += ((ix ^ __float_as_uint(Ng.x)) >> 31)? -epsilon_i: epsilon_i;
|
||||
res.x = __uint_as_float(ix);
|
||||
}
|
||||
|
||||
/* y component */
|
||||
if(fabsf(P.y) < epsilon_f) {
|
||||
res.y = P.y + Ng.y*epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint iy = __float_as_uint(P.y);
|
||||
iy += ((iy ^ __float_as_uint(Ng.y)) >> 31)? -epsilon_i: epsilon_i;
|
||||
res.y = __uint_as_float(iy);
|
||||
}
|
||||
|
||||
/* z component */
|
||||
if(fabsf(P.z) < epsilon_f) {
|
||||
res.z = P.z + Ng.z*epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint iz = __float_as_uint(P.z);
|
||||
iz += ((iz ^ __float_as_uint(Ng.z)) >> 31)? -epsilon_i: epsilon_i;
|
||||
res.z = __uint_as_float(iz);
|
||||
}
|
||||
|
||||
return res;
|
||||
#else
|
||||
const float epsilon_f = 1e-4f;
|
||||
return P + epsilon_f*Ng;
|
||||
#endif
|
||||
}
|
||||
|
||||
__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection *isect, const Ray *ray)
|
||||
{
|
||||
float3 P = ray->P;
|
||||
float3 D = ray->D;
|
||||
float t = isect->t;
|
||||
|
||||
#ifdef __INTERSECTION_REFINE__
|
||||
if(isect->object != ~0) {
|
||||
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
|
||||
|
||||
P = transform(&tfm, P);
|
||||
D = transform_direction(&tfm, D*t);
|
||||
D = normalize_len(D, &t);
|
||||
}
|
||||
|
||||
P = P + D*t;
|
||||
|
||||
float4 v00 = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0);
|
||||
float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
|
||||
float invDz = 1.0f/(D.x*v00.x + D.y*v00.y + D.z*v00.z);
|
||||
float rt = Oz * invDz;
|
||||
|
||||
P = P + D*rt;
|
||||
|
||||
if(isect->object != ~0) {
|
||||
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
|
||||
P = transform(&tfm, P);
|
||||
}
|
||||
|
||||
return P;
|
||||
#else
|
||||
return P + D*t;
|
||||
#endif
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
175
intern/cycles/kernel/kernel_random.h
Normal file
175
intern/cycles/kernel/kernel_random.h
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
typedef uint RNG;
|
||||
|
||||
#ifdef __SOBOL__
|
||||
|
||||
/* High Dimensional Sobol */
|
||||
|
||||
/* van der corput radical inverse */
|
||||
__device uint van_der_corput(uint bits)
|
||||
{
|
||||
bits = (bits << 16) | (bits >> 16);
|
||||
bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8);
|
||||
bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4);
|
||||
bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2);
|
||||
bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1);
|
||||
return bits;
|
||||
}
|
||||
|
||||
/* sobol radical inverse */
|
||||
__device uint sobol(uint i)
|
||||
{
|
||||
uint r = 0;
|
||||
|
||||
for(uint v = 1U << 31; i; i >>= 1, v ^= v >> 1)
|
||||
if(i & 1)
|
||||
r ^= v;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* inverse of sobol radical inverse */
|
||||
__device uint sobol_inverse(uint i)
|
||||
{
|
||||
const uint msb = 1U << 31;
|
||||
uint r = 0;
|
||||
|
||||
for(uint v = 1; i; i <<= 1, v ^= v << 1)
|
||||
if(i & msb)
|
||||
r ^= v;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* multidimensional sobol with generator matrices
|
||||
dimension 0 and 1 are equal to van_der_corput() and sobol() respectively */
|
||||
__device uint sobol_dimension(KernelGlobals *kg, int index, int dimension)
|
||||
{
|
||||
uint result = 0;
|
||||
uint i = index;
|
||||
|
||||
for(uint j = 0; i; i >>= 1, j++)
|
||||
if(i & 1)
|
||||
result ^= kernel_tex_fetch(__sobol_directions, 32*dimension + j);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* lookup index and x/y coordinate, assumes m is a power of two */
|
||||
__device uint sobol_lookup(const uint m, const uint frame, const uint ex, const uint ey, uint *x, uint *y)
|
||||
{
|
||||
/* shift is constant per frame */
|
||||
const uint shift = frame << (m << 1);
|
||||
const uint sobol_shift = sobol(shift);
|
||||
/* van der Corput is its own inverse */
|
||||
const uint lower = van_der_corput(ex << (32 - m));
|
||||
/* need to compensate for ey difference and shift */
|
||||
const uint sobol_lower = sobol(lower);
|
||||
const uint mask = ~-(1 << m) << (32 - m); /* only m upper bits */
|
||||
const uint delta = ((ey << (32 - m)) ^ sobol_lower ^ sobol_shift) & mask;
|
||||
/* only use m upper bits for the index (m is a power of two) */
|
||||
const uint sobol_result = delta | (delta >> m);
|
||||
const uint upper = sobol_inverse(sobol_result);
|
||||
const uint index = shift | upper | lower;
|
||||
*x = van_der_corput(index);
|
||||
*y = sobol_shift ^ sobol_result ^ sobol_lower;
|
||||
return index;
|
||||
}
|
||||
|
||||
__device_inline float path_rng(KernelGlobals *kg, RNG *rng, int pass, int dimension)
|
||||
{
|
||||
#ifdef __SOBOL_FULL_SCREEN__
|
||||
uint result = sobol_dimension(kg, *rng, dimension);
|
||||
float r = (float)result * (1.0f/(float)0xFFFFFFFF);
|
||||
return r;
|
||||
#else
|
||||
/* compute sobol sequence value using direction vectors */
|
||||
uint result = sobol_dimension(kg, pass, dimension);
|
||||
float r = (float)result * (1.0f/(float)0xFFFFFFFF);
|
||||
|
||||
/* Cranly-Patterson rotation using rng seed */
|
||||
float shift;
|
||||
|
||||
if(dimension & 1)
|
||||
shift = (*rng >> 16)/((float)0xFFFF);
|
||||
else
|
||||
shift = (*rng & 0xFFFF)/((float)0xFFFF);
|
||||
|
||||
return r + shift - floor(r + shift);
|
||||
#endif
|
||||
}
|
||||
|
||||
__device_inline void path_rng_init(KernelGlobals *kg, __global uint *rng_state, int pass, RNG *rng, int x, int y, float *fx, float *fy)
|
||||
{
|
||||
#ifdef __SOBOL_FULL_SCREEN__
|
||||
uint px, py;
|
||||
uint bits = 16; /* limits us to 65536x65536 and 65536 samples */
|
||||
uint size = 1 << bits;
|
||||
uint frame = pass;
|
||||
|
||||
*rng = sobol_lookup(bits, frame, x, y, &px, &py);
|
||||
|
||||
*fx = size * (float)px * (1.0f/(float)0xFFFFFFFF) - x;
|
||||
*fy = size * (float)py * (1.0f/(float)0xFFFFFFFF) - y;
|
||||
#else
|
||||
*rng = rng_state[x + y*kernel_data.cam.width];
|
||||
|
||||
*fx = path_rng(kg, rng, pass, PRNG_FILTER_U);
|
||||
*fy = path_rng(kg, rng, pass, PRNG_FILTER_V);
|
||||
#endif
|
||||
}
|
||||
|
||||
__device void path_rng_end(KernelGlobals *kg, __global uint *rng_state, RNG rng, int x, int y)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Linear Congruential Generator */
|
||||
|
||||
__device float path_rng(KernelGlobals *kg, RNG *rng, int pass, int dimension)
|
||||
{
|
||||
/* implicit mod 2^32 */
|
||||
*rng = (1103515245*(*rng) + 12345);
|
||||
return (float)*rng * (1.0f/(float)0xFFFFFFFF);
|
||||
}
|
||||
|
||||
__device void path_rng_init(KernelGlobals *kg, __global uint *rng_state, int pass, RNG *rng, int x, int y, float *fx, float *fy)
|
||||
{
|
||||
/* load state */
|
||||
*rng = rng_state[x + y*kernel_data.cam.width];
|
||||
|
||||
*fx = path_rng(kg, rng, pass, PRNG_FILTER_U);
|
||||
*fy = path_rng(kg, rng, pass, PRNG_FILTER_V);
|
||||
}
|
||||
|
||||
__device void path_rng_end(KernelGlobals *kg, __global uint *rng_state, RNG rng, int x, int y)
|
||||
{
|
||||
/* store state for next pass */
|
||||
rng_state[x + y*kernel_data.cam.width] = rng;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
460
intern/cycles/kernel/kernel_shader.h
Normal file
460
intern/cycles/kernel/kernel_shader.h
Normal file
@ -0,0 +1,460 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ShaderData, used in four steps:
|
||||
*
|
||||
* Setup from incoming ray, sampled position and background.
|
||||
* Execute for surface, volume or displacement.
|
||||
* Evaluate one or more closures.
|
||||
* Release.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "svm/bsdf.h"
|
||||
#include "svm/emissive.h"
|
||||
#include "svm/volume.h"
|
||||
#include "svm/svm_bsdf.h"
|
||||
#include "svm/svm.h"
|
||||
|
||||
#ifdef WITH_OSL
|
||||
#include "osl_shader.h"
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* ShaderData setup from incoming ray */
|
||||
|
||||
__device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
|
||||
const Intersection *isect, const Ray *ray)
|
||||
{
|
||||
/* fetch triangle data */
|
||||
int prim = kernel_tex_fetch(__prim_index, isect->prim);
|
||||
float4 Ns = kernel_tex_fetch(__tri_normal, prim);
|
||||
float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
|
||||
int shader = __float_as_int(Ns.w);
|
||||
|
||||
/* vectors */
|
||||
sd->P = bvh_triangle_refine(kg, isect, ray);
|
||||
sd->Ng = Ng;
|
||||
sd->N = Ng;
|
||||
sd->I = -ray->D;
|
||||
sd->shader = shader;
|
||||
sd->flag = 0;
|
||||
|
||||
/* triangle */
|
||||
#ifdef __INSTANCING__
|
||||
sd->object = isect->object;
|
||||
#endif
|
||||
sd->prim = prim;
|
||||
#ifdef __UV__
|
||||
sd->u = isect->u;
|
||||
sd->v = isect->v;
|
||||
#endif
|
||||
|
||||
/* smooth normal */
|
||||
if(sd->shader < 0) {
|
||||
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
|
||||
sd->shader = -sd->shader;
|
||||
}
|
||||
|
||||
#ifdef __DPDU__
|
||||
/* dPdu/dPdv */
|
||||
triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
|
||||
#endif
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
if(sd->object != ~0) {
|
||||
/* instance transform */
|
||||
object_normal_transform(kg, sd->object, &sd->N);
|
||||
object_normal_transform(kg, sd->object, &sd->Ng);
|
||||
#ifdef __DPDU__
|
||||
object_dir_transform(kg, sd->object, &sd->dPdu);
|
||||
object_dir_transform(kg, sd->object, &sd->dPdv);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* non-instanced object index */
|
||||
sd->object = kernel_tex_fetch(__prim_object, isect->prim);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* backfacing test */
|
||||
bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
|
||||
|
||||
if(backfacing) {
|
||||
sd->flag = SD_BACKFACING;
|
||||
sd->Ng = -sd->Ng;
|
||||
sd->N = -sd->N;
|
||||
#ifdef __DPDU__
|
||||
sd->dPdu = -sd->dPdu;
|
||||
sd->dPdv = -sd->dPdv;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
/* differentials */
|
||||
differential_transfer(&sd->dP, ray->dP, ray->D, ray->dD, sd->Ng, isect->t);
|
||||
differential_incoming(&sd->dI, ray->dD);
|
||||
differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ShaderData setup from position sampled on mesh */
|
||||
|
||||
__device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
|
||||
const float3 P, const float3 Ng, const float3 I,
|
||||
int shader, int object, int prim, float u, float v)
|
||||
{
|
||||
/* vectors */
|
||||
sd->P = P;
|
||||
sd->N = Ng;
|
||||
sd->Ng = Ng;
|
||||
sd->I = I;
|
||||
sd->shader = shader;
|
||||
sd->flag = 0;
|
||||
|
||||
/* primitive */
|
||||
#ifdef __INSTANCING__
|
||||
sd->object = object;
|
||||
#endif
|
||||
sd->prim = prim;
|
||||
#ifdef __UV__
|
||||
sd->u = u;
|
||||
sd->v = v;
|
||||
#endif
|
||||
|
||||
/* detect instancing, for non-instanced the object index is -object-1 */
|
||||
bool instanced = false;
|
||||
|
||||
if(sd->prim != ~0) {
|
||||
if(sd->object >= 0)
|
||||
instanced = true;
|
||||
else
|
||||
sd->object = -sd->object-1;
|
||||
}
|
||||
|
||||
/* smooth normal */
|
||||
if(sd->shader < 0) {
|
||||
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
|
||||
sd->shader = -sd->shader;
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
if(instanced)
|
||||
object_normal_transform(kg, sd->object, &sd->N);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __DPDU__
|
||||
/* dPdu/dPdv */
|
||||
if(sd->prim == ~0) {
|
||||
sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
else {
|
||||
triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
if(instanced) {
|
||||
object_dir_transform(kg, sd->object, &sd->dPdu);
|
||||
object_dir_transform(kg, sd->object, &sd->dPdv);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* backfacing test */
|
||||
if(sd->prim != ~0) {
|
||||
bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
|
||||
|
||||
if(backfacing) {
|
||||
sd->flag = SD_BACKFACING;
|
||||
sd->Ng = -sd->Ng;
|
||||
sd->N = -sd->N;
|
||||
#ifdef __DPDU__
|
||||
sd->dPdu = -sd->dPdu;
|
||||
sd->dPdv = -sd->dPdv;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
/* no ray differentials here yet */
|
||||
sd->dP.dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dP.dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dI.dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dI.dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->du.dx = 0.0f;
|
||||
sd->du.dy = 0.0f;
|
||||
sd->dv.dx = 0.0f;
|
||||
sd->dv.dy = 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ShaderData setup for displacement */
|
||||
|
||||
__device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
|
||||
int object, int prim, float u, float v)
|
||||
{
|
||||
float3 P, Ng, I = make_float3(0.0f, 0.0f, 0.0f);
|
||||
int shader;
|
||||
|
||||
P = triangle_point_MT(kg, prim, u, v);
|
||||
Ng = triangle_normal_MT(kg, prim, &shader);
|
||||
|
||||
/* force smooth shading for displacement */
|
||||
if(shader >= 0)
|
||||
shader = -shader;
|
||||
|
||||
/* watch out: no instance transform currently */
|
||||
|
||||
shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v);
|
||||
}
|
||||
|
||||
/* ShaderData setup from ray into background */
|
||||
|
||||
__device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray)
|
||||
{
|
||||
/* vectors */
|
||||
sd->P = ray->D;
|
||||
sd->N = -sd->P;
|
||||
sd->Ng = -sd->P;
|
||||
sd->I = -sd->P;
|
||||
sd->shader = kernel_data.background.shader;
|
||||
sd->flag = 0;
|
||||
|
||||
#ifdef __INSTANCING__
|
||||
sd->object = ~0;
|
||||
#endif
|
||||
sd->prim = ~0;
|
||||
#ifdef __UV__
|
||||
sd->u = 0.0f;
|
||||
sd->v = 0.0f;
|
||||
#endif
|
||||
|
||||
#ifdef __DPDU__
|
||||
/* dPdu/dPdv */
|
||||
sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
|
||||
#endif
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
/* differentials */
|
||||
sd->dP = ray->dD;
|
||||
differential_incoming(&sd->dI, sd->dP);
|
||||
sd->du.dx = 0.0f;
|
||||
sd->du.dy = 0.0f;
|
||||
sd->dv.dx = 0.0f;
|
||||
sd->dv.dy = 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* BSDF */
|
||||
|
||||
__device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
|
||||
float randu, float randv, float3 *eval,
|
||||
float3 *omega_in, differential3 *domega_in, float *pdf)
|
||||
{
|
||||
int label;
|
||||
|
||||
*pdf = 0.0f;
|
||||
|
||||
#ifdef WITH_OSL
|
||||
if(kg->osl.use)
|
||||
label = OSLShader::bsdf_sample(sd, randu, randv, *eval, *omega_in, *domega_in, *pdf);
|
||||
else
|
||||
#endif
|
||||
label = svm_bsdf_sample(sd, randu, randv, eval, omega_in, domega_in, pdf);
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
__device float3 shader_bsdf_eval(KernelGlobals *kg, const ShaderData *sd,
|
||||
const float3 omega_in, float *pdf)
|
||||
{
|
||||
float3 eval;
|
||||
|
||||
*pdf = 0.0f;
|
||||
|
||||
#ifdef WITH_OSL
|
||||
if(kg->osl.use)
|
||||
eval = OSLShader::bsdf_eval(sd, omega_in, *pdf);
|
||||
else
|
||||
#endif
|
||||
eval = svm_bsdf_eval(sd, omega_in, pdf);
|
||||
|
||||
return eval;
|
||||
}
|
||||
|
||||
__device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughness)
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
if(!kg->osl.use)
|
||||
#endif
|
||||
svm_bsdf_blur(sd, roughness);
|
||||
}
|
||||
|
||||
/* Emission */
|
||||
|
||||
__device float3 shader_emissive_eval(KernelGlobals *kg, ShaderData *sd)
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
if(kg->osl.use) {
|
||||
return OSLShader::emissive_eval(sd);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return svm_emissive_eval(sd);
|
||||
}
|
||||
}
|
||||
|
||||
__device void shader_emissive_sample(KernelGlobals *kg, ShaderData *sd,
|
||||
float randu, float randv, float3 *eval, float3 *I, float *pdf)
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
if(kg->osl.use) {
|
||||
OSLShader::emissive_sample(sd, randu, randv, eval, I, pdf);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
svm_emissive_sample(sd, randu, randv, eval, I, pdf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Surface Evaluation */
|
||||
|
||||
__device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
|
||||
float randb, int path_flag)
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
if(kg->osl.use) {
|
||||
OSLShader::eval_surface(kg, sd, randb, path_flag);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef __SVM__
|
||||
svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, randb, path_flag);
|
||||
#else
|
||||
sd->svm_closure = CLOSURE_BSDF_DIFFUSE_ID;
|
||||
sd->svm_closure_weight = make_float3(0.8f, 0.8f, 0.8f);
|
||||
#endif
|
||||
|
||||
#ifdef __CAUSTICS_TRICKS__
|
||||
/* caustic tricks */
|
||||
if((path_flag & PATH_RAY_DIFFUSE) && (sd->flag & SD_BSDF_GLOSSY)) {
|
||||
if(kernel_data.integrator.no_caustics) {
|
||||
sd->flag &= ~(SD_BSDF_GLOSSY|SD_BSDF_HAS_EVAL|SD_EMISSION);
|
||||
sd->svm_closure = NBUILTIN_CLOSURES;
|
||||
sd->svm_closure_weight = make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
else if(kernel_data.integrator.blur_caustics > 0.0f)
|
||||
shader_bsdf_blur(kg, sd, kernel_data.integrator.blur_caustics);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Background Evaluation */
|
||||
|
||||
__device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag)
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
if(kg->osl.use) {
|
||||
return OSLShader::eval_background(kg, sd, path_flag);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef __SVM__
|
||||
svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, 0.0f, path_flag);
|
||||
#else
|
||||
sd->svm_closure_weight = make_float3(0.8f, 0.8f, 0.8f);
|
||||
#endif
|
||||
|
||||
return sd->svm_closure_weight;
|
||||
}
|
||||
}
|
||||
|
||||
/* Volume */
|
||||
|
||||
__device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,
|
||||
float3 omega_in, float3 omega_out)
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
if(kg->osl.use) {
|
||||
OSLShader::volume_eval_phase(sd, omega_in, omega_out);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return volume_eval_phase(sd, omega_in, omega_out);
|
||||
}
|
||||
}
|
||||
|
||||
/* Volume Evaluation */
|
||||
|
||||
__device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
|
||||
float randb, int path_flag)
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
if(kg->osl.use) {
|
||||
OSLShader::eval_volume(kg, sd, randb, path_flag);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef __SVM__
|
||||
svm_eval_nodes(kg, sd, SHADER_TYPE_VOLUME, randb, path_flag);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Displacement Evaluation */
|
||||
|
||||
__device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd)
|
||||
{
|
||||
/* this will modify sd->P */
|
||||
|
||||
#ifdef WITH_OSL
|
||||
if(kg->osl.use) {
|
||||
OSLShader::eval_displacement(kg, sd);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef __SVM__
|
||||
svm_eval_nodes(kg, sd, SHADER_TYPE_DISPLACEMENT, 0.0f, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Free ShaderData */
|
||||
|
||||
__device void shader_release(KernelGlobals *kg, ShaderData *sd)
|
||||
{
|
||||
#ifdef WITH_OSL
|
||||
if(kg->osl.use)
|
||||
OSLShader::release(kg, sd);
|
||||
#endif
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
183
intern/cycles/kernel/kernel_triangle.h
Normal file
183
intern/cycles/kernel/kernel_triangle.h
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Point on triangle for Moller-Trumbore triangles */
|
||||
__device_inline float3 triangle_point_MT(KernelGlobals *kg, int tri_index, float u, float v)
|
||||
{
|
||||
/* load triangle vertices */
|
||||
float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri_index));
|
||||
|
||||
float3 v0 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
|
||||
float3 v1 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
|
||||
float3 v2 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
|
||||
|
||||
/* compute point */
|
||||
float t = 1.0f - u - v;
|
||||
return (u*v0 + v*v1 + t*v2);
|
||||
}
|
||||
|
||||
/* Sample point on triangle */
|
||||
__device_inline float3 triangle_sample_MT(KernelGlobals *kg, int tri_index, float randu, float randv)
|
||||
{
|
||||
/* compute point */
|
||||
randu = sqrtf(randu);
|
||||
|
||||
float u = 1.0f - randu;
|
||||
float v = randv*randu;
|
||||
|
||||
return triangle_point_MT(kg, tri_index, u, v);
|
||||
}
|
||||
|
||||
/* Normal for Moller-Trumbore triangles */
|
||||
__device_inline float3 triangle_normal_MT(KernelGlobals *kg, int tri_index, int *shader)
|
||||
{
|
||||
#if 0
|
||||
/* load triangle vertices */
|
||||
float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri_index));
|
||||
|
||||
float3 v0 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
|
||||
float3 v1 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
|
||||
float3 v2 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
|
||||
|
||||
/* compute normal */
|
||||
return normalize(cross(v2 - v0, v1 - v0));
|
||||
#else
|
||||
float4 Nm = kernel_tex_fetch(__tri_normal, tri_index);
|
||||
*shader = __float_as_int(Nm.w);
|
||||
return make_float3(Nm.x, Nm.y, Nm.z);
|
||||
#endif
|
||||
}
|
||||
|
||||
__device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int tri_index, float u, float v)
|
||||
{
|
||||
/* load triangle vertices */
|
||||
float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri_index));
|
||||
|
||||
float3 n0 = as_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x)));
|
||||
float3 n1 = as_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y)));
|
||||
float3 n2 = as_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z)));
|
||||
|
||||
return normalize((1.0f - u - v)*n2 + u*n0 + v*n1);
|
||||
}
|
||||
|
||||
__device_inline void triangle_dPdudv(KernelGlobals *kg, float3 *dPdu, float3 *dPdv, int tri)
|
||||
{
|
||||
/* fetch triangle vertex coordinates */
|
||||
float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri));
|
||||
|
||||
float3 p0 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
|
||||
float3 p1 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
|
||||
float3 p2 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
|
||||
|
||||
/* compute derivatives of P w.r.t. uv */
|
||||
*dPdu = (p0 - p2);
|
||||
*dPdv = (p1 - p2);
|
||||
}
|
||||
|
||||
/* attributes */
|
||||
|
||||
__device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
|
||||
{
|
||||
if(elem == ATTR_ELEMENT_FACE) {
|
||||
if(dx) *dx = 0.0f;
|
||||
if(dy) *dy = 0.0f;
|
||||
|
||||
return kernel_tex_fetch(__attributes_float, offset + sd->prim);
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_VERTEX) {
|
||||
float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, sd->prim));
|
||||
|
||||
float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x));
|
||||
float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y));
|
||||
float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z));
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#endif
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CORNER) {
|
||||
int tri = offset + sd->prim;
|
||||
float f0 = kernel_tex_fetch(__attributes_float, tri*3 + 0);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, tri*3 + 1);
|
||||
float f2 = kernel_tex_fetch(__attributes_float, tri*3 + 2);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#endif
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
}
|
||||
else {
|
||||
if(dx) *dx = 0.0f;
|
||||
if(dy) *dy = 0.0f;
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
__device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
|
||||
{
|
||||
if(elem == ATTR_ELEMENT_FACE) {
|
||||
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
return as_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim));
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_VERTEX) {
|
||||
float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, sd->prim));
|
||||
|
||||
float3 f0 = as_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
|
||||
float3 f1 = as_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
|
||||
float3 f2 = as_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#endif
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CORNER) {
|
||||
int tri = offset + sd->prim;
|
||||
float3 f0 = as_float3(kernel_tex_fetch(__attributes_float3, tri*3 + 0));
|
||||
float3 f1 = as_float3(kernel_tex_fetch(__attributes_float3, tri*3 + 1));
|
||||
float3 f2 = as_float3(kernel_tex_fetch(__attributes_float3, tri*3 + 2));
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
|
||||
if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
|
||||
#endif
|
||||
|
||||
return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
|
||||
}
|
||||
else {
|
||||
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
374
intern/cycles/kernel/kernel_types.h
Normal file
374
intern/cycles/kernel/kernel_types.h
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_TYPES_H__
|
||||
#define __KERNEL_TYPES_H__
|
||||
|
||||
#include "kernel_math.h"
|
||||
|
||||
#ifndef __KERNEL_OPENCL__
|
||||
|
||||
#include "svm_types.h"
|
||||
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#define OBJECT_SIZE 16
|
||||
|
||||
#define __INSTANCING__
|
||||
#define __DPDU__
|
||||
#define __UV__
|
||||
#define __BACKGROUND__
|
||||
#define __EMISSION__
|
||||
#define __CAUSTICS_TRICKS__
|
||||
#define __SVM__
|
||||
#define __SOBOL__
|
||||
#define __TEXTURES__
|
||||
#define __RAY_DIFFERENTIALS__
|
||||
#define __CAMERA_CLIPPING__
|
||||
#define __INTERSECTION_REFINE__
|
||||
//#define __SOBOL_FULL_SCREEN__
|
||||
//#define __MODIFY_TP__
|
||||
//#define __QBVH__
|
||||
|
||||
/* Path Tracing */
|
||||
|
||||
enum PathTraceDimension {
|
||||
PRNG_FILTER_U = 0,
|
||||
PRNG_FILTER_V = 1,
|
||||
PRNG_LENS_U = 2,
|
||||
PRNG_LENS_V = 3,
|
||||
PRNG_BASE_NUM = 4,
|
||||
|
||||
PRNG_BSDF_U = 0,
|
||||
PRNG_BSDF_V = 1,
|
||||
PRNG_BSDF = 2,
|
||||
PRNG_LIGHT = 3,
|
||||
PRNG_LIGHT_U = 4,
|
||||
PRNG_LIGHT_V = 5,
|
||||
PRNG_LIGHT_F = 6,
|
||||
PRNG_TERMINATE = 7,
|
||||
PRNG_BOUNCE_NUM = 8
|
||||
};
|
||||
|
||||
/* these flag values correspond exactly to OSL defaults, so be careful not to
|
||||
* change this, or if you do, set the "raytypes" shading system attribute with
|
||||
* your own new ray types and bitflag values */
|
||||
enum PathRayFlag {
|
||||
PATH_RAY_CAMERA = 1,
|
||||
PATH_RAY_SHADOW = 2,
|
||||
PATH_RAY_REFLECT = 4,
|
||||
PATH_RAY_TRANSMIT = 8,
|
||||
PATH_RAY_DIFFUSE = 16,
|
||||
PATH_RAY_GLOSSY = 32,
|
||||
PATH_RAY_SINGULAR = 64
|
||||
};
|
||||
|
||||
/* Bidirectional Path Tracing */
|
||||
|
||||
enum BidirTraceDimension {
|
||||
BRNG_FILTER_U = 0,
|
||||
BRNG_FILTER_V = 1,
|
||||
BRNG_LENS_U = 2,
|
||||
BRNG_LENS_V = 3,
|
||||
BRNG_LIGHT_U = 4,
|
||||
BRNG_LIGHT_V = 5,
|
||||
BRNG_LIGHT = 6,
|
||||
BRNG_LIGHT_F = 7,
|
||||
BRNG_EMISSIVE_U = 8,
|
||||
BRNG_EMISSIVE_V = 9,
|
||||
BRNG_BASE_NUM = 10,
|
||||
|
||||
BRNG_BSDF_U = 0,
|
||||
BRNG_BSDF_V = 1,
|
||||
BRNG_BSDF = 2,
|
||||
BRNG_TERMINATE = 3,
|
||||
BRNG_BOUNCE_NUM = 4
|
||||
};
|
||||
|
||||
/* Closure Label */
|
||||
|
||||
typedef enum ClosureLabel {
|
||||
LABEL_NONE = 0,
|
||||
LABEL_CAMERA = 1,
|
||||
LABEL_LIGHT = 2,
|
||||
LABEL_BACKGROUND = 4,
|
||||
LABEL_TRANSMIT = 8,
|
||||
LABEL_REFLECT = 16,
|
||||
LABEL_VOLUME = 32,
|
||||
LABEL_OBJECT = 64,
|
||||
LABEL_DIFFUSE = 128,
|
||||
LABEL_GLOSSY = 256,
|
||||
LABEL_SINGULAR = 512,
|
||||
LABEL_STRAIGHT = 1024,
|
||||
LABEL_STOP = 2048
|
||||
} ClosureLabel;
|
||||
|
||||
/* Ray Type */
|
||||
|
||||
typedef enum RayType {
|
||||
RayTypeCamera = 1,
|
||||
RayTypeShadow = 2,
|
||||
RayTypeReflection = 4,
|
||||
RayTypeRefraction = 8,
|
||||
RayTypeDiffuse = 16,
|
||||
RayTypeGlossy = 32
|
||||
} RayType;
|
||||
|
||||
/* Differential */
|
||||
|
||||
typedef struct differential3 {
|
||||
float3 dx;
|
||||
float3 dy;
|
||||
} differential3;
|
||||
|
||||
typedef struct differential {
|
||||
float dx;
|
||||
float dy;
|
||||
} differential;
|
||||
|
||||
/* Ray */
|
||||
|
||||
typedef struct Ray {
|
||||
float3 P;
|
||||
float3 D;
|
||||
float t;
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
differential3 dP;
|
||||
differential3 dD;
|
||||
#endif
|
||||
} Ray;
|
||||
|
||||
/* Intersection */
|
||||
|
||||
typedef struct Intersection {
|
||||
float t, u, v;
|
||||
int prim;
|
||||
int object;
|
||||
} Intersection;
|
||||
|
||||
/* Attributes */
|
||||
|
||||
typedef enum AttributeElement {
|
||||
ATTR_ELEMENT_FACE,
|
||||
ATTR_ELEMENT_VERTEX,
|
||||
ATTR_ELEMENT_CORNER,
|
||||
ATTR_ELEMENT_VALUE,
|
||||
ATTR_ELEMENT_NONE
|
||||
} AttributeElement;
|
||||
|
||||
/* OSL data */
|
||||
|
||||
#if !defined(__KERNEL_GPU__) && defined(WITH_OSL)
|
||||
|
||||
#define MAX_OSL_CLOSURE 8
|
||||
|
||||
struct FlatClosure {
|
||||
void *prim;
|
||||
float3 weight;
|
||||
float sample_weight;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* Shader Data
|
||||
*
|
||||
* Main shader state at a point on the surface or in a volume. All coordinates
|
||||
* are in world space. */
|
||||
|
||||
enum ShaderDataFlag {
|
||||
SD_BACKFACING = 1, /* backside of surface? */
|
||||
SD_EMISSION = 2, /* have emissive closure? */
|
||||
SD_BSDF_HAS_EVAL = 4, /* have non-singular bsdf closure? */
|
||||
SD_BSDF_GLOSSY = 8 /* have glossy bsdf */
|
||||
};
|
||||
|
||||
typedef struct ShaderData {
|
||||
/* position */
|
||||
float3 P;
|
||||
/* smooth normal for shading */
|
||||
float3 N;
|
||||
/* true geometric normal */
|
||||
float3 Ng;
|
||||
/* view/incoming direction */
|
||||
float3 I;
|
||||
/* shader id */
|
||||
int shader;
|
||||
/* booleans describing shader, see ShaderDataFlag */
|
||||
int flag;
|
||||
|
||||
/* primitive id if there is one, ~0 otherwise */
|
||||
int prim;
|
||||
/* parametric coordinates
|
||||
* - barycentric weights for triangles
|
||||
* - latlong coordinates for background */
|
||||
float u, v;
|
||||
/* object id if there is one, ~0 otherwise */
|
||||
int object;
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
/* differential of P. these are orthogonal to Ng, not N */
|
||||
differential3 dP;
|
||||
/* differential of I */
|
||||
differential3 dI;
|
||||
/* differential of u, v */
|
||||
differential du;
|
||||
differential dv;
|
||||
#endif
|
||||
#ifdef __DPDU__
|
||||
/* differential of P w.r.t. parametric coordinates. note that dPdu is
|
||||
* not readily suitable as a tangent for shading on triangles. */
|
||||
float3 dPdu, dPdv;
|
||||
#endif
|
||||
|
||||
/* SVM closure data. we always sample a single closure, to get fixed
|
||||
* memory usage, svm_closure_data contains closure parameters. */
|
||||
#ifndef __KERNEL_OPENCL__
|
||||
ClosureType svm_closure;
|
||||
#endif
|
||||
float3 svm_closure_weight;
|
||||
float svm_closure_data[3]; /* CUDA gives compile error if out of bounds */
|
||||
|
||||
#if !defined(__KERNEL_GPU__) && defined(WITH_OSL)
|
||||
/* OSL closure data and context. we store all closures flattened into
|
||||
* lists per type, different from SVM. */
|
||||
struct {
|
||||
FlatClosure bsdf[MAX_OSL_CLOSURE];
|
||||
FlatClosure emissive[MAX_OSL_CLOSURE];
|
||||
FlatClosure volume[MAX_OSL_CLOSURE];
|
||||
|
||||
int num_bsdf;
|
||||
int num_emissive;
|
||||
int num_volume;
|
||||
|
||||
float bsdf_sample_sum;
|
||||
float emissive_sample_sum;
|
||||
float volume_sample_sum;
|
||||
|
||||
float randb;
|
||||
} osl_closure;
|
||||
|
||||
void *osl_ctx;
|
||||
#endif
|
||||
} ShaderData;
|
||||
|
||||
/* Constrant Kernel Data */
|
||||
|
||||
typedef struct KernelCamera {
|
||||
/* type */
|
||||
int ortho;
|
||||
int pad;
|
||||
|
||||
/* size */
|
||||
int width, height;
|
||||
|
||||
/* matrices */
|
||||
Transform cameratoworld;
|
||||
Transform rastertocamera;
|
||||
|
||||
/* depth of field */
|
||||
float lensradius;
|
||||
float focaldistance;
|
||||
|
||||
/* motion blur */
|
||||
float shutteropen;
|
||||
float shutterclose;
|
||||
|
||||
/* differentials */
|
||||
float3 dx, dy;
|
||||
|
||||
/* clipping */
|
||||
float nearclip;
|
||||
float cliplength;
|
||||
|
||||
/* more matrices */
|
||||
Transform screentoworld;
|
||||
Transform rastertoworld;
|
||||
Transform ndctoworld;
|
||||
Transform worldtoscreen;
|
||||
Transform worldtoraster;
|
||||
Transform worldtondc;
|
||||
Transform worldtocamera;
|
||||
} KernelCamera;
|
||||
|
||||
typedef struct KernelFilm {
|
||||
float exposure;
|
||||
int use_response_curve;
|
||||
int pad1, pad2;
|
||||
} KernelFilm;
|
||||
|
||||
typedef struct KernelBackground {
|
||||
/* only shader index */
|
||||
int shader;
|
||||
int pad1, pad2, pad3;
|
||||
} KernelBackground;
|
||||
|
||||
typedef struct KernelSunSky {
|
||||
/* sun direction in spherical and cartesian */
|
||||
float theta, phi;
|
||||
float3 dir;
|
||||
float pad;
|
||||
|
||||
/* perez function parameters */
|
||||
float zenith_Y, zenith_x, zenith_y;
|
||||
float perez_Y[5], perez_x[5], perez_y[5];
|
||||
} KernelSunSky;
|
||||
|
||||
typedef struct KernelIntegrator {
|
||||
/* emission */
|
||||
int use_emission;
|
||||
int num_triangles;
|
||||
int num_distribution;
|
||||
int num_lights;
|
||||
float pdf_triangles;
|
||||
float pdf_lights;
|
||||
|
||||
/* path tracing */
|
||||
int minbounce;
|
||||
int maxbounce;
|
||||
|
||||
/* caustics */
|
||||
int no_caustics;
|
||||
float blur_caustics;
|
||||
|
||||
/* padding */
|
||||
int pad;
|
||||
} KernelIntegrator;
|
||||
|
||||
typedef struct KernelBVH {
|
||||
/* root node */
|
||||
int root;
|
||||
int attributes_map_stride;
|
||||
int pad1, pad2;
|
||||
} KernelBVH;
|
||||
|
||||
typedef struct KernelData {
|
||||
KernelCamera cam;
|
||||
KernelFilm film;
|
||||
KernelBackground background;
|
||||
KernelSunSky sunsky;
|
||||
KernelIntegrator integrator;
|
||||
KernelBVH bvh;
|
||||
} KernelData;
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __KERNEL_TYPES_H__ */
|
||||
|
33
intern/cycles/kernel/osl/CMakeLists.txt
Normal file
33
intern/cycles/kernel/osl/CMakeLists.txt
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
INCLUDE_DIRECTORIES(. ../ ../svm ../../render ../../util ../../device)
|
||||
|
||||
SET(sources
|
||||
background.cpp
|
||||
bsdf_ashikhmin_velvet.cpp
|
||||
bsdf_diffuse.cpp
|
||||
bsdf_microfacet.cpp
|
||||
bsdf_reflection.cpp
|
||||
bsdf_refraction.cpp
|
||||
bsdf_transparent.cpp
|
||||
bsdf_ward.cpp
|
||||
bsdf_westin.cpp
|
||||
bssrdf.cpp
|
||||
debug.cpp
|
||||
emissive.cpp
|
||||
osl_closures.cpp
|
||||
osl_services.cpp
|
||||
osl_shader.cpp
|
||||
vol_subsurface.cpp)
|
||||
|
||||
SET(headers
|
||||
osl_closures.h
|
||||
osl_globals.h
|
||||
osl_services.h
|
||||
osl_shader.h)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RTTI_DISABLE_FLAGS}")
|
||||
|
||||
ADD_LIBRARY(kernel_osl ${sources} ${headers})
|
||||
|
||||
ADD_SUBDIRECTORY(nodes)
|
||||
|
100
intern/cycles/kernel/osl/background.cpp
Normal file
100
intern/cycles/kernel/osl/background.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
/// Generic background closure
|
||||
///
|
||||
/// We only have a background closure for the shaders
|
||||
/// to return a color in background shaders. No methods,
|
||||
/// only the weight is taking into account
|
||||
///
|
||||
class GenericBackgroundClosure : public BackgroundClosure {
|
||||
public:
|
||||
GenericBackgroundClosure() { }
|
||||
|
||||
void setup() {};
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "background"; }
|
||||
|
||||
void print_on (std::ostream &out) const {
|
||||
out << name() << " ()";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// Holdout closure
|
||||
///
|
||||
/// This will be used by the shader to mark the
|
||||
/// amount of holdout for the current shading
|
||||
/// point. No parameters, only the weight will be
|
||||
/// used
|
||||
///
|
||||
class HoldoutClosure : ClosurePrimitive {
|
||||
public:
|
||||
HoldoutClosure () : ClosurePrimitive (Holdout) { }
|
||||
|
||||
void setup() {};
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "holdout"; }
|
||||
|
||||
void print_on (std::ostream &out) const {
|
||||
out << name() << " ()";
|
||||
}
|
||||
};
|
||||
|
||||
ClosureParam closure_background_params[] = {
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(GenericBackgroundClosure) };
|
||||
|
||||
CLOSURE_PREPARE(closure_background_prepare, GenericBackgroundClosure)
|
||||
|
||||
ClosureParam closure_holdout_params[] = {
|
||||
CLOSURE_FINISH_PARAM(HoldoutClosure) };
|
||||
|
||||
CLOSURE_PREPARE(closure_holdout_prepare, HoldoutClosure)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
175
intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp
Normal file
175
intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
class AshikhminVelvetClosure : public BSDFClosure {
|
||||
public:
|
||||
Vec3 m_N;
|
||||
float m_sigma;
|
||||
float m_invsigma2;
|
||||
|
||||
AshikhminVelvetClosure() : BSDFClosure(Labels::DIFFUSE) { }
|
||||
|
||||
void setup()
|
||||
{
|
||||
m_sigma = std::max(m_sigma, 0.01f);
|
||||
m_invsigma2 = 1.0f/(m_sigma * m_sigma);
|
||||
}
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const AshikhminVelvetClosure *comp = (const AshikhminVelvetClosure *)other;
|
||||
return m_N == comp->m_N && m_sigma == comp->m_sigma &&
|
||||
BSDFClosure::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "ashikhmin_velvet"; }
|
||||
|
||||
void print_on (std::ostream &out) const
|
||||
{
|
||||
out << name() << " (";
|
||||
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
|
||||
out << m_sigma;
|
||||
out << ")";
|
||||
}
|
||||
|
||||
float albedo (const Vec3 &omega_out) const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
if (cosNO > 0 && cosNI > 0) {
|
||||
Vec3 H = omega_in + omega_out;
|
||||
H.normalize();
|
||||
|
||||
float cosNH = m_N.dot(H);
|
||||
float cosHO = fabsf(omega_out.dot(H));
|
||||
|
||||
float cosNHdivHO = cosNH / cosHO;
|
||||
cosNHdivHO = std::max(cosNHdivHO, 0.00001f);
|
||||
|
||||
float fac1 = 2 * fabsf(cosNHdivHO * cosNO);
|
||||
float fac2 = 2 * fabsf(cosNHdivHO * cosNI);
|
||||
|
||||
float sinNH2 = 1 - cosNH * cosNH;
|
||||
float sinNH4 = sinNH2 * sinNH2;
|
||||
float cotangent2 = (cosNH * cosNH) / sinNH2;
|
||||
|
||||
float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * float(M_1_PI) / sinNH4;
|
||||
float G = std::min(1.0f, std::min(fac1, fac2)); // TODO: derive G from D analytically
|
||||
|
||||
float out = 0.25f * (D * G) / cosNO;
|
||||
|
||||
pdf = 0.5f * (float) M_1_PI;
|
||||
return Color3 (out, out, out);
|
||||
}
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
ustring sample (const Vec3 &Ng,
|
||||
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
|
||||
float &pdf, Color3 &eval) const
|
||||
{
|
||||
// we are viewing the surface from above - send a ray out with uniform
|
||||
// distribution over the hemisphere
|
||||
sample_uniform_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf);
|
||||
if (Ng.dot(omega_in) > 0) {
|
||||
Vec3 H = omega_in + omega_out;
|
||||
H.normalize();
|
||||
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
float cosNH = m_N.dot(H);
|
||||
float cosHO = fabsf(omega_out.dot(H));
|
||||
|
||||
float cosNHdivHO = cosNH / cosHO;
|
||||
cosNHdivHO = std::max(cosNHdivHO, 0.00001f);
|
||||
|
||||
float fac1 = 2 * fabsf(cosNHdivHO * cosNO);
|
||||
float fac2 = 2 * fabsf(cosNHdivHO * cosNI);
|
||||
|
||||
float sinNH2 = 1 - cosNH * cosNH;
|
||||
float sinNH4 = sinNH2 * sinNH2;
|
||||
float cotangent2 = (cosNH * cosNH) / sinNH2;
|
||||
|
||||
float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * float(M_1_PI) / sinNH4;
|
||||
float G = std::min(1.0f, std::min(fac1, fac2)); // TODO: derive G from D analytically
|
||||
|
||||
float power = 0.25f * (D * G) / cosNO;
|
||||
|
||||
eval.setValue(power, power, power);
|
||||
|
||||
// TODO: find a better approximation for the retroreflective bounce
|
||||
domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
|
||||
domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
|
||||
domega_in_dx *= 125;
|
||||
domega_in_dy *= 125;
|
||||
} else
|
||||
pdf = 0;
|
||||
return Labels::REFLECT;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
ClosureParam bsdf_ashikhmin_velvet_params[] = {
|
||||
CLOSURE_VECTOR_PARAM(AshikhminVelvetClosure, m_N),
|
||||
CLOSURE_FLOAT_PARAM (AshikhminVelvetClosure, m_sigma),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(AshikhminVelvetClosure) };
|
||||
|
||||
CLOSURE_PREPARE(bsdf_ashikhmin_velvet_prepare, AshikhminVelvetClosure)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
181
intern/cycles/kernel/osl/bsdf_diffuse.cpp
Normal file
181
intern/cycles/kernel/osl/bsdf_diffuse.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
class DiffuseClosure : public BSDFClosure {
|
||||
public:
|
||||
Vec3 m_N;
|
||||
|
||||
DiffuseClosure() : BSDFClosure(Labels::DIFFUSE) { }
|
||||
|
||||
void setup() {};
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const DiffuseClosure *comp = (const DiffuseClosure *)other;
|
||||
return m_N == comp->m_N && BSDFClosure::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "diffuse"; }
|
||||
|
||||
void print_on (std::ostream &out) const
|
||||
{
|
||||
out << name() << " ((" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))";
|
||||
}
|
||||
|
||||
float albedo (const Vec3 &omega_out) const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
float cos_pi = std::max(m_N.dot(omega_in),0.0f) * (float) M_1_PI;
|
||||
pdf = cos_pi;
|
||||
return Color3 (cos_pi, cos_pi, cos_pi);
|
||||
}
|
||||
|
||||
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
ustring sample (const Vec3 &Ng,
|
||||
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
|
||||
float &pdf, Color3 &eval) const
|
||||
{
|
||||
// we are viewing the surface from the right side - send a ray out with cosine
|
||||
// distribution over the hemisphere
|
||||
sample_cos_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf);
|
||||
if (Ng.dot(omega_in) > 0) {
|
||||
eval.setValue(pdf, pdf, pdf);
|
||||
// TODO: find a better approximation for the diffuse bounce
|
||||
domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
|
||||
domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
|
||||
domega_in_dx *= 125;
|
||||
domega_in_dy *= 125;
|
||||
} else
|
||||
pdf = 0;
|
||||
return Labels::REFLECT;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class TranslucentClosure : public BSDFClosure {
|
||||
public:
|
||||
Vec3 m_N;
|
||||
|
||||
TranslucentClosure() : BSDFClosure(Labels::DIFFUSE, Back) { }
|
||||
|
||||
void setup() {};
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const TranslucentClosure *comp = (const TranslucentClosure *)other;
|
||||
return m_N == comp->m_N && BSDFClosure::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "translucent"; }
|
||||
|
||||
void print_on (std::ostream &out) const
|
||||
{
|
||||
out << name() << " ((" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))";
|
||||
}
|
||||
|
||||
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
float albedo (const Vec3 &omega_out) const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
float cos_pi = std::max(-m_N.dot(omega_in), 0.0f) * (float) M_1_PI;
|
||||
pdf = cos_pi;
|
||||
return Color3 (cos_pi, cos_pi, cos_pi);
|
||||
}
|
||||
|
||||
ustring sample (const Vec3 &Ng,
|
||||
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
|
||||
float &pdf, Color3 &eval) const
|
||||
{
|
||||
// we are viewing the surface from the right side - send a ray out with cosine
|
||||
// distribution over the hemisphere
|
||||
sample_cos_hemisphere (-m_N, omega_out, randu, randv, omega_in, pdf);
|
||||
if (Ng.dot(omega_in) < 0) {
|
||||
eval.setValue(pdf, pdf, pdf);
|
||||
// TODO: find a better approximation for the diffuse bounce
|
||||
domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
|
||||
domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
|
||||
domega_in_dx *= -125;
|
||||
domega_in_dy *= -125;
|
||||
} else
|
||||
pdf = 0;
|
||||
return Labels::TRANSMIT;
|
||||
}
|
||||
};
|
||||
|
||||
ClosureParam bsdf_diffuse_params[] = {
|
||||
CLOSURE_VECTOR_PARAM (DiffuseClosure, m_N),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM (DiffuseClosure) };
|
||||
|
||||
ClosureParam bsdf_translucent_params[] = {
|
||||
CLOSURE_VECTOR_PARAM (TranslucentClosure, m_N),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM (TranslucentClosure) };
|
||||
|
||||
CLOSURE_PREPARE(bsdf_diffuse_prepare, DiffuseClosure)
|
||||
CLOSURE_PREPARE(bsdf_translucent_prepare, TranslucentClosure)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
533
intern/cycles/kernel/osl/bsdf_microfacet.cpp
Normal file
533
intern/cycles/kernel/osl/bsdf_microfacet.cpp
Normal file
@ -0,0 +1,533 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
#include "util_math.h"
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
// TODO: fresnel_dielectric is only used for derivatives, could be optimized
|
||||
|
||||
// TODO: refactor these two classes so they share everything by the microfacet
|
||||
// distribution terms
|
||||
|
||||
// microfacet model with GGX facet distribution
|
||||
// see http://www.graphics.cornell.edu/~bjw/microfacetbsdf.pdf
|
||||
template <int Refractive = 0>
|
||||
class MicrofacetGGXClosure : public BSDFClosure {
|
||||
public:
|
||||
Vec3 m_N;
|
||||
float m_ag; // width parameter (roughness)
|
||||
float m_eta; // index of refraction (for fresnel term)
|
||||
MicrofacetGGXClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) { m_eta = 1.0f; }
|
||||
|
||||
void setup()
|
||||
{
|
||||
m_ag = clamp(m_ag, 1e-5f, 1.0f);
|
||||
}
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const MicrofacetGGXClosure *comp = (const MicrofacetGGXClosure *)other;
|
||||
return m_N == comp->m_N && m_ag == comp->m_ag &&
|
||||
m_eta == comp->m_eta && BSDFClosure::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const {
|
||||
return Refractive ? "microfacet_ggx_refraction" : "microfacet_ggx";
|
||||
}
|
||||
|
||||
void print_on (std::ostream &out) const {
|
||||
out << name() << " (";
|
||||
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
|
||||
out << m_ag << ", ";
|
||||
out << m_eta;
|
||||
out << ")";
|
||||
}
|
||||
|
||||
float albedo (const Vec3 &omega_out) const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
if (Refractive == 1) return Color3 (0, 0, 0);
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
if (cosNI > 0 && cosNO > 0) {
|
||||
// get half vector
|
||||
Vec3 Hr = omega_in + omega_out;
|
||||
Hr.normalize();
|
||||
// eq. 20: (F*G*D)/(4*in*on)
|
||||
// eq. 33: first we calculate D(m) with m=Hr:
|
||||
float alpha2 = m_ag * m_ag;
|
||||
float cosThetaM = m_N.dot(Hr);
|
||||
float cosThetaM2 = cosThetaM * cosThetaM;
|
||||
float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
|
||||
float cosThetaM4 = cosThetaM2 * cosThetaM2;
|
||||
float D = alpha2 / ((float) M_PI * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
|
||||
// eq. 34: now calculate G1(i,m) and G1(o,m)
|
||||
float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
|
||||
float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
|
||||
float G = G1o * G1i;
|
||||
float out = (G * D) * 0.25f / cosNO;
|
||||
// eq. 24
|
||||
float pm = D * cosThetaM;
|
||||
// convert into pdf of the sampled direction
|
||||
// eq. 38 - but see also:
|
||||
// eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
|
||||
pdf = pm * 0.25f / Hr.dot(omega_out);
|
||||
return Color3 (out, out, out);
|
||||
}
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
if (Refractive == 0) return Color3 (0, 0, 0);
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
if (cosNO <= 0 || cosNI >= 0)
|
||||
return Color3 (0, 0, 0); // vectors on same side -- not possible
|
||||
// compute half-vector of the refraction (eq. 16)
|
||||
Vec3 ht = -(m_eta * omega_in + omega_out);
|
||||
Vec3 Ht = ht; Ht.normalize();
|
||||
float cosHO = Ht.dot(omega_out);
|
||||
|
||||
float cosHI = Ht.dot(omega_in);
|
||||
// eq. 33: first we calculate D(m) with m=Ht:
|
||||
float alpha2 = m_ag * m_ag;
|
||||
float cosThetaM = m_N.dot(Ht);
|
||||
float cosThetaM2 = cosThetaM * cosThetaM;
|
||||
float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
|
||||
float cosThetaM4 = cosThetaM2 * cosThetaM2;
|
||||
float D = alpha2 / ((float) M_PI * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
|
||||
// eq. 34: now calculate G1(i,m) and G1(o,m)
|
||||
float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
|
||||
float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
|
||||
float G = G1o * G1i;
|
||||
// probability
|
||||
float invHt2 = 1 / ht.dot(ht);
|
||||
pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2;
|
||||
float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO;
|
||||
return Color3 (out, out, out);
|
||||
}
|
||||
|
||||
ustring sample (const Vec3 &Ng,
|
||||
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
|
||||
float &pdf, Color3 &eval) const
|
||||
{
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
if (cosNO > 0) {
|
||||
Vec3 X, Y, Z = m_N;
|
||||
make_orthonormals(Z, X, Y);
|
||||
// generate a random microfacet normal m
|
||||
// eq. 35,36:
|
||||
// we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
|
||||
// and sin(atan(x)) == x/sqrt(1+x^2)
|
||||
float alpha2 = m_ag * m_ag;
|
||||
float tanThetaM2 = alpha2 * randu / (1 - randu);
|
||||
float cosThetaM = 1 / sqrtf(1 + tanThetaM2);
|
||||
float sinThetaM = cosThetaM * sqrtf(tanThetaM2);
|
||||
float phiM = 2 * float(M_PI) * randv;
|
||||
Vec3 m = (cosf(phiM) * sinThetaM) * X +
|
||||
(sinf(phiM) * sinThetaM) * Y +
|
||||
cosThetaM * Z;
|
||||
if (Refractive == 0) {
|
||||
float cosMO = m.dot(omega_out);
|
||||
if (cosMO > 0) {
|
||||
// eq. 39 - compute actual reflected direction
|
||||
omega_in = 2 * cosMO * m - omega_out;
|
||||
if (Ng.dot(omega_in) > 0) {
|
||||
// microfacet normal is visible to this ray
|
||||
// eq. 33
|
||||
float cosThetaM2 = cosThetaM * cosThetaM;
|
||||
float cosThetaM4 = cosThetaM2 * cosThetaM2;
|
||||
float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
|
||||
// eq. 24
|
||||
float pm = D * cosThetaM;
|
||||
// convert into pdf of the sampled direction
|
||||
// eq. 38 - but see also:
|
||||
// eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
|
||||
pdf = pm * 0.25f / cosMO;
|
||||
// eval BRDF*cosNI
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
// eq. 34: now calculate G1(i,m) and G1(o,m)
|
||||
float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
|
||||
float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
|
||||
float G = G1o * G1i;
|
||||
// eq. 20: (F*G*D)/(4*in*on)
|
||||
float out = (G * D) * 0.25f / cosNO;
|
||||
eval.setValue(out, out, out);
|
||||
domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx;
|
||||
domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy;
|
||||
|
||||
/* disabled for now - gives texture filtering problems */
|
||||
#if 0
|
||||
// Since there is some blur to this reflection, make the
|
||||
// derivatives a bit bigger. In theory this varies with the
|
||||
// roughness but the exact relationship is complex and
|
||||
// requires more ops than are practical.
|
||||
domega_in_dx *= 10;
|
||||
domega_in_dy *= 10;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CAUTION: the i and o variables are inverted relative to the paper
|
||||
// eq. 39 - compute actual refractive direction
|
||||
Vec3 R, dRdx, dRdy;
|
||||
Vec3 T, dTdx, dTdy;
|
||||
bool inside;
|
||||
fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy,
|
||||
R, dRdx, dRdy,
|
||||
T, dTdx, dTdy,
|
||||
inside);
|
||||
|
||||
if (!inside) {
|
||||
omega_in = T;
|
||||
domega_in_dx = dTdx;
|
||||
domega_in_dy = dTdy;
|
||||
// eq. 33
|
||||
float cosThetaM2 = cosThetaM * cosThetaM;
|
||||
float cosThetaM4 = cosThetaM2 * cosThetaM2;
|
||||
float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
|
||||
// eq. 24
|
||||
float pm = D * cosThetaM;
|
||||
// eval BRDF*cosNI
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
// eq. 34: now calculate G1(i,m) and G1(o,m)
|
||||
float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
|
||||
float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
|
||||
float G = G1o * G1i;
|
||||
// eq. 21
|
||||
float cosHI = m.dot(omega_in);
|
||||
float cosHO = m.dot(omega_out);
|
||||
float Ht2 = m_eta * cosHI + cosHO;
|
||||
Ht2 *= Ht2;
|
||||
float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2);
|
||||
// eq. 38 and eq. 17
|
||||
pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2;
|
||||
eval.setValue(out, out, out);
|
||||
|
||||
/* disabled for now - gives texture filtering problems */
|
||||
#if 0
|
||||
// Since there is some blur to this refraction, make the
|
||||
// derivatives a bit bigger. In theory this varies with the
|
||||
// roughness but the exact relationship is complex and
|
||||
// requires more ops than are practical.
|
||||
domega_in_dx *= 10;
|
||||
domega_in_dy *= 10;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
return Refractive ? Labels::TRANSMIT : Labels::REFLECT;
|
||||
}
|
||||
};
|
||||
|
||||
// microfacet model with Beckmann facet distribution
|
||||
// see http://www.graphics.cornell.edu/~bjw/microfacetbsdf.pdf
|
||||
template <int Refractive = 0>
|
||||
class MicrofacetBeckmannClosure : public BSDFClosure {
|
||||
public:
|
||||
Vec3 m_N;
|
||||
float m_ab; // width parameter (roughness)
|
||||
float m_eta; // index of refraction (for fresnel term)
|
||||
MicrofacetBeckmannClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) { }
|
||||
|
||||
void setup()
|
||||
{
|
||||
m_ab = clamp(m_ab, 1e-5f, 1.0f);
|
||||
}
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const MicrofacetBeckmannClosure *comp = (const MicrofacetBeckmannClosure *)other;
|
||||
return m_N == comp->m_N && m_ab == comp->m_ab &&
|
||||
m_eta == comp->m_eta && BSDFClosure::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char * name () const {
|
||||
return Refractive ? "microfacet_beckmann_refraction"
|
||||
: "microfacet_beckmann";
|
||||
}
|
||||
|
||||
void print_on (std::ostream &out) const
|
||||
{
|
||||
out << name() << " (";
|
||||
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
|
||||
out << m_ab << ", ";
|
||||
out << m_eta;
|
||||
out << ")";
|
||||
}
|
||||
|
||||
float albedo (const Vec3 &omega_out) const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
if (Refractive == 1) return Color3 (0, 0, 0);
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
if (cosNO > 0 && cosNI > 0) {
|
||||
// get half vector
|
||||
Vec3 Hr = omega_in + omega_out;
|
||||
Hr.normalize();
|
||||
// eq. 20: (F*G*D)/(4*in*on)
|
||||
// eq. 25: first we calculate D(m) with m=Hr:
|
||||
float alpha2 = m_ab * m_ab;
|
||||
float cosThetaM = m_N.dot(Hr);
|
||||
float cosThetaM2 = cosThetaM * cosThetaM;
|
||||
float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
|
||||
float cosThetaM4 = cosThetaM2 * cosThetaM2;
|
||||
float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4);
|
||||
// eq. 26, 27: now calculate G1(i,m) and G1(o,m)
|
||||
float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
|
||||
float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
|
||||
float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
|
||||
float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
|
||||
float G = G1o * G1i;
|
||||
float out = (G * D) * 0.25f / cosNO;
|
||||
// eq. 24
|
||||
float pm = D * cosThetaM;
|
||||
// convert into pdf of the sampled direction
|
||||
// eq. 38 - but see also:
|
||||
// eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
|
||||
pdf = pm * 0.25f / Hr.dot(omega_out);
|
||||
return Color3 (out, out, out);
|
||||
}
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
if (Refractive == 0) return Color3 (0, 0, 0);
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
if (cosNO <= 0 || cosNI >= 0)
|
||||
return Color3 (0, 0, 0);
|
||||
// compute half-vector of the refraction (eq. 16)
|
||||
Vec3 ht = -(m_eta * omega_in + omega_out);
|
||||
Vec3 Ht = ht; Ht.normalize();
|
||||
float cosHO = Ht.dot(omega_out);
|
||||
|
||||
float cosHI = Ht.dot(omega_in);
|
||||
// eq. 33: first we calculate D(m) with m=Ht:
|
||||
float alpha2 = m_ab * m_ab;
|
||||
float cosThetaM = m_N.dot(Ht);
|
||||
float cosThetaM2 = cosThetaM * cosThetaM;
|
||||
float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
|
||||
float cosThetaM4 = cosThetaM2 * cosThetaM2;
|
||||
float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4);
|
||||
// eq. 26, 27: now calculate G1(i,m) and G1(o,m)
|
||||
float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
|
||||
float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
|
||||
float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
|
||||
float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
|
||||
float G = G1o * G1i;
|
||||
// probability
|
||||
float invHt2 = 1 / ht.dot(ht);
|
||||
pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2;
|
||||
float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO;
|
||||
return Color3 (out, out, out);
|
||||
}
|
||||
|
||||
ustring sample (const Vec3 &Ng,
|
||||
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
|
||||
float &pdf, Color3 &eval) const
|
||||
{
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
if (cosNO > 0) {
|
||||
Vec3 X, Y, Z = m_N;
|
||||
make_orthonormals(Z, X, Y);
|
||||
// generate a random microfacet normal m
|
||||
// eq. 35,36:
|
||||
// we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
|
||||
// and sin(atan(x)) == x/sqrt(1+x^2)
|
||||
float alpha2 = m_ab * m_ab;
|
||||
float tanThetaM = sqrtf(-alpha2 * logf(1 - randu));
|
||||
float cosThetaM = 1 / sqrtf(1 + tanThetaM * tanThetaM);
|
||||
float sinThetaM = cosThetaM * tanThetaM;
|
||||
float phiM = 2 * float(M_PI) * randv;
|
||||
Vec3 m = (cosf(phiM) * sinThetaM) * X +
|
||||
(sinf(phiM) * sinThetaM) * Y +
|
||||
cosThetaM * Z;
|
||||
if (Refractive == 0) {
|
||||
float cosMO = m.dot(omega_out);
|
||||
if (cosMO > 0) {
|
||||
// eq. 39 - compute actual reflected direction
|
||||
omega_in = 2 * cosMO * m - omega_out;
|
||||
if (Ng.dot(omega_in) > 0) {
|
||||
// microfacet normal is visible to this ray
|
||||
// eq. 25
|
||||
float cosThetaM2 = cosThetaM * cosThetaM;
|
||||
float tanThetaM2 = tanThetaM * tanThetaM;
|
||||
float cosThetaM4 = cosThetaM2 * cosThetaM2;
|
||||
float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4);
|
||||
// eq. 24
|
||||
float pm = D * cosThetaM;
|
||||
// convert into pdf of the sampled direction
|
||||
// eq. 38 - but see also:
|
||||
// eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
|
||||
pdf = pm * 0.25f / cosMO;
|
||||
// Eval BRDF*cosNI
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
// eq. 26, 27: now calculate G1(i,m) and G1(o,m)
|
||||
float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
|
||||
float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
|
||||
float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
|
||||
float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
|
||||
float G = G1o * G1i;
|
||||
// eq. 20: (F*G*D)/(4*in*on)
|
||||
float out = (G * D) * 0.25f / cosNO;
|
||||
eval.setValue(out, out, out);
|
||||
domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx;
|
||||
domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy;
|
||||
|
||||
/* disabled for now - gives texture filtering problems */
|
||||
#if 0
|
||||
// Since there is some blur to this reflection, make the
|
||||
// derivatives a bit bigger. In theory this varies with the
|
||||
// roughness but the exact relationship is complex and
|
||||
// requires more ops than are practical.
|
||||
domega_in_dx *= 10;
|
||||
domega_in_dy *= 10;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CAUTION: the i and o variables are inverted relative to the paper
|
||||
// eq. 39 - compute actual refractive direction
|
||||
Vec3 R, dRdx, dRdy;
|
||||
Vec3 T, dTdx, dTdy;
|
||||
bool inside;
|
||||
fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy,
|
||||
R, dRdx, dRdy,
|
||||
T, dTdx, dTdy,
|
||||
inside);
|
||||
if (!inside) {
|
||||
omega_in = T;
|
||||
domega_in_dx = dTdx;
|
||||
domega_in_dy = dTdy;
|
||||
// eq. 33
|
||||
float cosThetaM2 = cosThetaM * cosThetaM;
|
||||
float tanThetaM2 = tanThetaM * tanThetaM;
|
||||
float cosThetaM4 = cosThetaM2 * cosThetaM2;
|
||||
float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4);
|
||||
// eq. 24
|
||||
float pm = D * cosThetaM;
|
||||
// eval BRDF*cosNI
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
// eq. 26, 27: now calculate G1(i,m) and G1(o,m)
|
||||
float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
|
||||
float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
|
||||
float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
|
||||
float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
|
||||
float G = G1o * G1i;
|
||||
// eq. 21
|
||||
float cosHI = m.dot(omega_in);
|
||||
float cosHO = m.dot(omega_out);
|
||||
float Ht2 = m_eta * cosHI + cosHO;
|
||||
Ht2 *= Ht2;
|
||||
float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2);
|
||||
// eq. 38 and eq. 17
|
||||
pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2;
|
||||
eval.setValue(out, out, out);
|
||||
|
||||
/* disabled for now - gives texture filtering problems */
|
||||
#if 0
|
||||
// Since there is some blur to this refraction, make the
|
||||
// derivatives a bit bigger. In theory this varies with the
|
||||
// roughness but the exact relationship is complex and
|
||||
// requires more ops than are practical.
|
||||
domega_in_dx *= 10;
|
||||
domega_in_dy *= 10;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
return Refractive ? Labels::TRANSMIT : Labels::REFLECT;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
ClosureParam bsdf_microfacet_ggx_params[] = {
|
||||
CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<0>, m_N),
|
||||
CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<0>, m_ag),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<0>) };
|
||||
|
||||
ClosureParam bsdf_microfacet_ggx_refraction_params[] = {
|
||||
CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<1>, m_N),
|
||||
CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<1>, m_ag),
|
||||
CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<1>, m_eta),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<1>) };
|
||||
|
||||
ClosureParam bsdf_microfacet_beckmann_params[] = {
|
||||
CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<0>, m_N),
|
||||
CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<0>, m_ab),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<0>) };
|
||||
|
||||
ClosureParam bsdf_microfacet_beckmann_refraction_params[] = {
|
||||
CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<1>, m_N),
|
||||
CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<1>, m_ab),
|
||||
CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<1>, m_eta),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<1>) };
|
||||
|
||||
CLOSURE_PREPARE(bsdf_microfacet_ggx_prepare, MicrofacetGGXClosure<0>)
|
||||
CLOSURE_PREPARE(bsdf_microfacet_ggx_refraction_prepare, MicrofacetGGXClosure<1>)
|
||||
CLOSURE_PREPARE(bsdf_microfacet_beckmann_prepare, MicrofacetBeckmannClosure<0>)
|
||||
CLOSURE_PREPARE(bsdf_microfacet_beckmann_refraction_prepare, MicrofacetBeckmannClosure<1>)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
108
intern/cycles/kernel/osl/bsdf_reflection.cpp
Normal file
108
intern/cycles/kernel/osl/bsdf_reflection.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
class ReflectionClosure : public BSDFClosure {
|
||||
public:
|
||||
Vec3 m_N; // shading normal
|
||||
ReflectionClosure() : BSDFClosure(Labels::SINGULAR) { }
|
||||
|
||||
void setup() {};
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const ReflectionClosure *comp = (const ReflectionClosure *)other;
|
||||
return m_N == comp->m_N && BSDFClosure::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "reflection"; }
|
||||
|
||||
void print_on (std::ostream &out) const {
|
||||
out << name() << " (";
|
||||
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))";
|
||||
}
|
||||
|
||||
float albedo (const Vec3 &omega_out) const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
ustring sample (const Vec3 &Ng,
|
||||
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
|
||||
float &pdf, Color3 &eval) const
|
||||
{
|
||||
// only one direction is possible
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
if (cosNO > 0) {
|
||||
omega_in = (2 * cosNO) * m_N - omega_out;
|
||||
if (Ng.dot(omega_in) > 0) {
|
||||
domega_in_dx = 2 * m_N.dot(domega_out_dx) * m_N - domega_out_dx;
|
||||
domega_in_dy = 2 * m_N.dot(domega_out_dy) * m_N - domega_out_dy;
|
||||
pdf = 1;
|
||||
eval.setValue(1, 1, 1);
|
||||
}
|
||||
}
|
||||
return Labels::REFLECT;
|
||||
}
|
||||
};
|
||||
|
||||
ClosureParam bsdf_reflection_params[] = {
|
||||
CLOSURE_VECTOR_PARAM(ReflectionClosure, m_N),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(ReflectionClosure) };
|
||||
|
||||
CLOSURE_PREPARE(bsdf_reflection_prepare, ReflectionClosure)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
120
intern/cycles/kernel/osl/bsdf_refraction.cpp
Normal file
120
intern/cycles/kernel/osl/bsdf_refraction.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
class RefractionClosure : public BSDFClosure {
|
||||
public:
|
||||
Vec3 m_N; // shading normal
|
||||
float m_eta; // ratio of indices of refraction (inside / outside)
|
||||
RefractionClosure() : BSDFClosure(Labels::SINGULAR, Back) { }
|
||||
|
||||
void setup() {}
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const RefractionClosure *comp = (const RefractionClosure *)other;
|
||||
return m_N == comp->m_N && m_eta == comp->m_eta &&
|
||||
BSDFClosure::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "refraction"; }
|
||||
|
||||
void print_on (std::ostream &out) const {
|
||||
out << name() << " (";
|
||||
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
|
||||
out << m_eta;
|
||||
out << ")";
|
||||
}
|
||||
|
||||
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
float albedo (const Vec3 &omega_out) const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
ustring sample (const Vec3 &Ng,
|
||||
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
|
||||
float &pdf, Color3 &eval) const
|
||||
{
|
||||
Vec3 R, dRdx, dRdy;
|
||||
Vec3 T, dTdx, dTdy;
|
||||
bool inside;
|
||||
|
||||
fresnel_dielectric(m_eta, m_N,
|
||||
omega_out, domega_out_dx, domega_out_dy,
|
||||
R, dRdx, dRdy,
|
||||
T, dTdx, dTdy,
|
||||
inside);
|
||||
|
||||
if (!inside) {
|
||||
pdf = 1;
|
||||
eval.setValue(1.0f, 1.0f, 1.0f);
|
||||
omega_in = T;
|
||||
domega_in_dx = dTdx;
|
||||
domega_in_dy = dTdy;
|
||||
}
|
||||
|
||||
return Labels::TRANSMIT;
|
||||
}
|
||||
};
|
||||
|
||||
ClosureParam bsdf_refraction_params[] = {
|
||||
CLOSURE_VECTOR_PARAM(RefractionClosure, m_N),
|
||||
CLOSURE_FLOAT_PARAM (RefractionClosure, m_eta),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(RefractionClosure) };
|
||||
|
||||
CLOSURE_PREPARE(bsdf_refraction_prepare, RefractionClosure)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
97
intern/cycles/kernel/osl/bsdf_transparent.cpp
Normal file
97
intern/cycles/kernel/osl/bsdf_transparent.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
class TransparentClosure : public BSDFClosure {
|
||||
public:
|
||||
TransparentClosure() : BSDFClosure(Labels::STRAIGHT, Back) { }
|
||||
|
||||
void setup() {}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "transparent"; }
|
||||
|
||||
void print_on (std::ostream &out) const {
|
||||
out << name() << " ()";
|
||||
}
|
||||
|
||||
float albedo (const Vec3 &omega_out) const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
ustring sample (const Vec3 &Ng,
|
||||
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
|
||||
float &pdf, Color3 &eval) const
|
||||
{
|
||||
// only one direction is possible
|
||||
omega_in = -omega_out;
|
||||
domega_in_dx = -domega_out_dx;
|
||||
domega_in_dy = -domega_out_dy;
|
||||
pdf = 1;
|
||||
eval.setValue(1, 1, 1);
|
||||
return Labels::TRANSMIT;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
ClosureParam bsdf_transparent_params[] = {
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(TransparentClosure) };
|
||||
|
||||
CLOSURE_PREPARE(bsdf_transparent_prepare, TransparentClosure)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
222
intern/cycles/kernel/osl/bsdf_ward.cpp
Normal file
222
intern/cycles/kernel/osl/bsdf_ward.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
#include "util_math.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
// anisotropic ward - leaks energy at grazing angles
|
||||
// see http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
|
||||
class WardClosure : public BSDFClosure {
|
||||
public:
|
||||
Vec3 m_N;
|
||||
Vec3 m_T;
|
||||
float m_ax, m_ay;
|
||||
WardClosure() : BSDFClosure(Labels::GLOSSY) { }
|
||||
|
||||
void setup()
|
||||
{
|
||||
m_ax = clamp(m_ax, 1e-5f, 1.0f);
|
||||
m_ay = clamp(m_ay, 1e-5f, 1.0f);
|
||||
}
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const WardClosure *comp = (const WardClosure *)other;
|
||||
return m_N == comp->m_N && m_T == comp->m_T &&
|
||||
m_ax == comp->m_ax && m_ay == comp->m_ay &&
|
||||
BSDFClosure::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "ward"; }
|
||||
|
||||
void print_on (std::ostream &out) const {
|
||||
out << name() << " ((";
|
||||
out << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), (";
|
||||
out << m_T[0] << ", " << m_T[1] << ", " << m_T[2] << "), ";
|
||||
out << m_ax << ", " << m_ay << ")";
|
||||
}
|
||||
|
||||
float albedo (const Vec3 &omega_out) const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
if (cosNI > 0 && cosNO > 0) {
|
||||
// get half vector and get x,y basis on the surface for anisotropy
|
||||
Vec3 H = omega_in + omega_out;
|
||||
H.normalize(); // normalize needed for pdf
|
||||
Vec3 X, Y;
|
||||
make_orthonormals(m_N, m_T, X, Y);
|
||||
// eq. 4
|
||||
float dotx = H.dot(X) / m_ax;
|
||||
float doty = H.dot(Y) / m_ay;
|
||||
float dotn = H.dot(m_N);
|
||||
float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn);
|
||||
float denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI));
|
||||
float exp_val = expf(-exp_arg);
|
||||
float out = cosNI * exp_val / denom;
|
||||
float oh = H.dot(omega_out);
|
||||
denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn;
|
||||
pdf = exp_val / denom;
|
||||
return Color3 (out, out, out);
|
||||
}
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
ustring sample (const Vec3 &Ng,
|
||||
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
|
||||
float &pdf, Color3 &eval) const
|
||||
{
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
if (cosNO > 0) {
|
||||
// get x,y basis on the surface for anisotropy
|
||||
Vec3 X, Y;
|
||||
make_orthonormals(m_N, m_T, X, Y);
|
||||
// generate random angles for the half vector
|
||||
// eq. 7 (taking care around discontinuities to keep
|
||||
// output angle in the right quadrant)
|
||||
// we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
|
||||
// and sin(atan(x)) == x/sqrt(1+x^2)
|
||||
float alphaRatio = m_ay / m_ax;
|
||||
float cosPhi, sinPhi;
|
||||
if (randu < 0.25f) {
|
||||
float val = 4 * randu;
|
||||
float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
|
||||
cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi);
|
||||
sinPhi = tanPhi * cosPhi;
|
||||
} else if (randu < 0.5) {
|
||||
float val = 1 - 4 * (0.5f - randu);
|
||||
float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
|
||||
// phi = (float) M_PI - phi;
|
||||
cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi);
|
||||
sinPhi = -tanPhi * cosPhi;
|
||||
} else if (randu < 0.75f) {
|
||||
float val = 4 * (randu - 0.5f);
|
||||
float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
|
||||
//phi = (float) M_PI + phi;
|
||||
cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi);
|
||||
sinPhi = tanPhi * cosPhi;
|
||||
} else {
|
||||
float val = 1 - 4 * (1 - randu);
|
||||
float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
|
||||
// phi = 2 * (float) M_PI - phi;
|
||||
cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi);
|
||||
sinPhi = -tanPhi * cosPhi;
|
||||
}
|
||||
// eq. 6
|
||||
// we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
|
||||
// and sin(atan(x)) == x/sqrt(1+x^2)
|
||||
float thetaDenom = (cosPhi * cosPhi) / (m_ax * m_ax) + (sinPhi * sinPhi) / (m_ay * m_ay);
|
||||
float tanTheta2 = -logf(1 - randv) / thetaDenom;
|
||||
float cosTheta = 1 / sqrtf(1 + tanTheta2);
|
||||
float sinTheta = cosTheta * sqrtf(tanTheta2);
|
||||
|
||||
Vec3 h; // already normalized becaused expressed from spherical coordinates
|
||||
h.x = sinTheta * cosPhi;
|
||||
h.y = sinTheta * sinPhi;
|
||||
h.z = cosTheta;
|
||||
// compute terms that are easier in local space
|
||||
float dotx = h.x / m_ax;
|
||||
float doty = h.y / m_ay;
|
||||
float dotn = h.z;
|
||||
// transform to world space
|
||||
h = h.x * X + h.y * Y + h.z * m_N;
|
||||
// generate the final sample
|
||||
float oh = h.dot(omega_out);
|
||||
omega_in.x = 2 * oh * h.x - omega_out.x;
|
||||
omega_in.y = 2 * oh * h.y - omega_out.y;
|
||||
omega_in.z = 2 * oh * h.z - omega_out.z;
|
||||
if (Ng.dot(omega_in) > 0) {
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
if (cosNI > 0) {
|
||||
// eq. 9
|
||||
float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn);
|
||||
float denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn;
|
||||
pdf = expf(-exp_arg) / denom;
|
||||
// compiler will reuse expressions already computed
|
||||
denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI));
|
||||
float power = cosNI * expf(-exp_arg) / denom;
|
||||
eval.setValue(power, power, power);
|
||||
domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
|
||||
domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
|
||||
|
||||
/* disabled for now - gives texture filtering problems */
|
||||
#if 0
|
||||
// Since there is some blur to this reflection, make the
|
||||
// derivatives a bit bigger. In theory this varies with the
|
||||
// roughness but the exact relationship is complex and
|
||||
// requires more ops than are practical.
|
||||
domega_in_dx *= 10;
|
||||
domega_in_dy *= 10;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
return Labels::REFLECT;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
ClosureParam bsdf_ward_params[] = {
|
||||
CLOSURE_VECTOR_PARAM(WardClosure, m_N),
|
||||
CLOSURE_VECTOR_PARAM(WardClosure, m_T),
|
||||
CLOSURE_FLOAT_PARAM (WardClosure, m_ax),
|
||||
CLOSURE_FLOAT_PARAM (WardClosure, m_ay),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(WardClosure) };
|
||||
|
||||
CLOSURE_PREPARE(bsdf_ward_prepare, WardClosure)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
239
intern/cycles/kernel/osl/bsdf_westin.cpp
Normal file
239
intern/cycles/kernel/osl/bsdf_westin.cpp
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
#include "util_math.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
class WestinBackscatterClosure : public BSDFClosure {
|
||||
public:
|
||||
Vec3 m_N;
|
||||
float m_roughness;
|
||||
float m_invroughness;
|
||||
WestinBackscatterClosure() : BSDFClosure(Labels::GLOSSY) { }
|
||||
|
||||
void setup()
|
||||
{
|
||||
m_roughness = clamp(m_roughness, 1e-5f, 1.0f);
|
||||
m_invroughness = m_roughness > 0 ? 1 / m_roughness : 0;
|
||||
}
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const WestinBackscatterClosure *comp = (const WestinBackscatterClosure *)other;
|
||||
return m_N == comp->m_N && m_roughness == comp->m_roughness &&
|
||||
BSDFClosure::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "westin_backscatter"; }
|
||||
|
||||
void print_on (std::ostream &out) const
|
||||
{
|
||||
out << name() << " (";
|
||||
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
|
||||
out << m_roughness;
|
||||
out << ")";
|
||||
}
|
||||
|
||||
float albedo (const Vec3 &omega_out) const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
|
||||
{
|
||||
// pdf is implicitly 0 (no indirect sampling)
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
if (cosNO > 0 && cosNI > 0) {
|
||||
float cosine = omega_out.dot(omega_in);
|
||||
pdf = cosine > 0 ? (m_invroughness + 1) * powf(cosine, m_invroughness) : 0;
|
||||
pdf *= 0.5f * float(M_1_PI);
|
||||
return Color3 (pdf, pdf, pdf);
|
||||
}
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
ustring sample (const Vec3 &Ng,
|
||||
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
|
||||
float &pdf, Color3 &eval) const
|
||||
{
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
if (cosNO > 0) {
|
||||
domega_in_dx = domega_out_dx;
|
||||
domega_in_dy = domega_out_dy;
|
||||
Vec3 T, B;
|
||||
make_orthonormals (omega_out, T, B);
|
||||
float phi = 2 * (float) M_PI * randu;
|
||||
float cosTheta = powf(randv, 1 / (m_invroughness + 1));
|
||||
float sinTheta2 = 1 - cosTheta * cosTheta;
|
||||
float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0;
|
||||
omega_in = (cosf(phi) * sinTheta) * T +
|
||||
(sinf(phi) * sinTheta) * B +
|
||||
( cosTheta) * omega_out;
|
||||
if (Ng.dot(omega_in) > 0)
|
||||
{
|
||||
// common terms for pdf and eval
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
// make sure the direction we chose is still in the right hemisphere
|
||||
if (cosNI > 0)
|
||||
{
|
||||
pdf = 0.5f * (float) M_1_PI * powf(cosTheta, m_invroughness);
|
||||
pdf = (m_invroughness + 1) * pdf;
|
||||
eval.setValue(pdf, pdf, pdf);
|
||||
// Since there is some blur to this reflection, make the
|
||||
// derivatives a bit bigger. In theory this varies with the
|
||||
// exponent but the exact relationship is complex and
|
||||
// requires more ops than are practical.
|
||||
domega_in_dx *= 10;
|
||||
domega_in_dy *= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Labels::REFLECT;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class WestinSheenClosure : public BSDFClosure {
|
||||
public:
|
||||
Vec3 m_N;
|
||||
float m_edginess;
|
||||
// float m_normalization;
|
||||
WestinSheenClosure() : BSDFClosure(Labels::DIFFUSE) { }
|
||||
|
||||
void setup() {};
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const WestinSheenClosure *comp = (const WestinSheenClosure *)other;
|
||||
return m_N == comp->m_N && m_edginess == comp->m_edginess &&
|
||||
BSDFClosure::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "westin_sheen"; }
|
||||
|
||||
void print_on (std::ostream &out) const
|
||||
{
|
||||
out << name() << " (";
|
||||
out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
|
||||
out << m_edginess;
|
||||
out << ")";
|
||||
}
|
||||
|
||||
float albedo (const Vec3 &omega_out) const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
|
||||
{
|
||||
// pdf is implicitly 0 (no indirect sampling)
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
float cosNI = m_N.dot(omega_in);
|
||||
if (cosNO > 0 && cosNI > 0) {
|
||||
float sinNO2 = 1 - cosNO * cosNO;
|
||||
pdf = cosNI * float(M_1_PI);
|
||||
float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * pdf : 0;
|
||||
return Color3 (westin, westin, westin);
|
||||
}
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
|
||||
{
|
||||
return Color3 (0, 0, 0);
|
||||
}
|
||||
|
||||
ustring sample (const Vec3 &Ng,
|
||||
const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
|
||||
float randu, float randv,
|
||||
Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
|
||||
float &pdf, Color3 &eval) const
|
||||
{
|
||||
// we are viewing the surface from the right side - send a ray out with cosine
|
||||
// distribution over the hemisphere
|
||||
sample_cos_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf);
|
||||
if (Ng.dot(omega_in) > 0) {
|
||||
// TODO: account for sheen when sampling
|
||||
float cosNO = m_N.dot(omega_out);
|
||||
float sinNO2 = 1 - cosNO * cosNO;
|
||||
float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * pdf : 0;
|
||||
eval.setValue(westin, westin, westin);
|
||||
// TODO: find a better approximation for the diffuse bounce
|
||||
domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
|
||||
domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
|
||||
domega_in_dx *= 125;
|
||||
domega_in_dy *= 125;
|
||||
} else
|
||||
pdf = 0;
|
||||
return Labels::REFLECT;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
ClosureParam bsdf_westin_backscatter_params[] = {
|
||||
CLOSURE_VECTOR_PARAM(WestinBackscatterClosure, m_N),
|
||||
CLOSURE_FLOAT_PARAM (WestinBackscatterClosure, m_roughness),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(WestinBackscatterClosure) };
|
||||
|
||||
ClosureParam bsdf_westin_sheen_params[] = {
|
||||
CLOSURE_VECTOR_PARAM(WestinSheenClosure, m_N),
|
||||
CLOSURE_FLOAT_PARAM (WestinSheenClosure, m_edginess),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(WestinSheenClosure) };
|
||||
|
||||
CLOSURE_PREPARE(bsdf_westin_backscatter_prepare, WestinBackscatterClosure)
|
||||
CLOSURE_PREPARE(bsdf_westin_sheen_prepare, WestinSheenClosure)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
105
intern/cycles/kernel/osl/bssrdf.cpp
Normal file
105
intern/cycles/kernel/osl/bssrdf.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
class BSSRDFCubicClosure : public BSSRDFClosure {
|
||||
public:
|
||||
Color3 m_radius;
|
||||
Color3 m_scale;
|
||||
float m_max_radius;
|
||||
|
||||
template <typename T>
|
||||
static inline T pow3 (const T &x) { return x * x * x; }
|
||||
|
||||
template <typename T>
|
||||
static inline T pow5 (const T &x) { T x2 = x * x; return x2 * x2 * x; }
|
||||
|
||||
BSSRDFCubicClosure() { }
|
||||
|
||||
void setup()
|
||||
{
|
||||
// pre-compute some terms
|
||||
m_max_radius = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
m_scale[i] = m_radius[i] > 0 ? 4 / pow5 (m_radius[i]) : 0;
|
||||
m_max_radius = std::max (m_max_radius, m_radius[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const BSSRDFCubicClosure *comp = (const BSSRDFCubicClosure *)other;
|
||||
return m_radius == comp->m_radius && BSSRDFClosure::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "bssrdf_cubic"; }
|
||||
|
||||
void print_on (std::ostream &out) const
|
||||
{
|
||||
out << name() << " ((" << m_radius[0] << ", " << m_radius[1] << ", " << m_radius[2] << "), ("
|
||||
<< m_scale[0] << ", " << m_scale[1] << ", " << m_scale[2] << "))";
|
||||
}
|
||||
|
||||
Color3 eval (float r) const
|
||||
{
|
||||
return Color3 ((r < m_radius.x) ? pow3 (m_radius.x - r) * m_scale.x : 0,
|
||||
(r < m_radius.y) ? pow3 (m_radius.y - r) * m_scale.y : 0,
|
||||
(r < m_radius.z) ? pow3 (m_radius.z - r) * m_scale.z : 0);
|
||||
}
|
||||
|
||||
float max_radius() const
|
||||
{
|
||||
return m_max_radius;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
ClosureParam closure_bssrdf_cubic_params[] = {
|
||||
CLOSURE_COLOR_PARAM (BSSRDFCubicClosure, m_radius),
|
||||
CLOSURE_STRING_KEYPARAM ("label"),
|
||||
CLOSURE_FINISH_PARAM(BSSRDFCubicClosure) };
|
||||
|
||||
CLOSURE_PREPARE(closure_bssrdf_cubic_prepare, BSSRDFCubicClosure)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
80
intern/cycles/kernel/osl/debug.cpp
Normal file
80
intern/cycles/kernel/osl/debug.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
/// Debug closure
|
||||
///
|
||||
/// This is going to be used for mask AOV's and similar
|
||||
/// purposes. A tag (string) is always associated with
|
||||
/// this closure, that "selects: the channel where the
|
||||
/// weight should be sent.
|
||||
|
||||
class DebugClosure : public ClosurePrimitive {
|
||||
public:
|
||||
ustring m_tag;
|
||||
|
||||
DebugClosure () : ClosurePrimitive (Debug) { }
|
||||
|
||||
bool mergeable (const ClosurePrimitive *other) const {
|
||||
const DebugClosure *comp = (const DebugClosure *)other;
|
||||
return m_tag == comp->m_tag &&
|
||||
ClosurePrimitive::mergeable(other);
|
||||
}
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "debug"; }
|
||||
|
||||
void print_on (std::ostream &out) const {
|
||||
out << name() << " (\"" << m_tag.c_str() << "\")";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ClosureParam closure_debug_params[] = {
|
||||
CLOSURE_STRING_PARAM(DebugClosure, m_tag),
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(DebugClosure) };
|
||||
|
||||
CLOSURE_PREPARE(closure_debug_prepare, DebugClosure)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
107
intern/cycles/kernel/osl/emissive.cpp
Normal file
107
intern/cycles/kernel/osl/emissive.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Adapted from Open Shading Language with this license:
|
||||
*
|
||||
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Modifications Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Sony Pictures Imageworks nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <OpenImageIO/fmath.h>
|
||||
|
||||
#include <OSL/genclosure.h>
|
||||
|
||||
#include "osl_closures.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OSL;
|
||||
|
||||
/// Variable cone emissive closure
|
||||
///
|
||||
/// This primitive emits in a cone having a configurable
|
||||
/// penumbra area where the light decays to 0 reaching the
|
||||
/// outer_angle limit. It can also behave as a lambertian emitter
|
||||
/// if the provided angles are PI/2, which is the default
|
||||
///
|
||||
class GenericEmissiveClosure : public EmissiveClosure {
|
||||
public:
|
||||
GenericEmissiveClosure() { }
|
||||
|
||||
void setup() { }
|
||||
|
||||
size_t memsize () const { return sizeof(*this); }
|
||||
|
||||
const char *name () const { return "emission"; }
|
||||
|
||||
void print_on (std::ostream &out) const {
|
||||
out << name() << "()";
|
||||
}
|
||||
|
||||
Color3 eval (const Vec3 &Ng, const Vec3 &omega_out) const
|
||||
{
|
||||
float cosNO = fabsf(Ng.dot(omega_out));
|
||||
float res = cosNO > 0 ? 1.0f / float(M_PI) : 0.0f;
|
||||
return Color3(res, res, res);
|
||||
}
|
||||
|
||||
void sample (const Vec3 &Ng, float randu, float randv,
|
||||
Vec3 &omega_out, float &pdf) const
|
||||
{
|
||||
// We don't do anything sophisticated here for the step
|
||||
// We just sample the whole cone uniformly to the cosine
|
||||
Vec3 T, B;
|
||||
make_orthonormals(Ng, T, B);
|
||||
float phi = 2 * (float) M_PI * randu;
|
||||
float cosTheta = sqrtf(1.0f - 1.0f * randv);
|
||||
float sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
|
||||
omega_out = (cosf(phi) * sinTheta) * T +
|
||||
(sinf(phi) * sinTheta) * B +
|
||||
cosTheta * Ng;
|
||||
pdf = 1.0f / float(M_PI);
|
||||
}
|
||||
|
||||
/// Return the probability distribution function in the direction omega_out,
|
||||
/// given the parameters and the light's surface normal. This MUST match
|
||||
/// the PDF computed by sample().
|
||||
float pdf (const Vec3 &Ng,
|
||||
const Vec3 &omega_out) const
|
||||
{
|
||||
float cosNO = Ng.dot(omega_out);
|
||||
return cosNO > 0 ? 1.0f / float(M_PI) : 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
ClosureParam closure_emission_params[] = {
|
||||
CLOSURE_STRING_KEYPARAM("label"),
|
||||
CLOSURE_FINISH_PARAM(GenericEmissiveClosure) };
|
||||
|
||||
CLOSURE_PREPARE(closure_emission_prepare, GenericEmissiveClosure)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
69
intern/cycles/kernel/osl/nodes/CMakeLists.txt
Normal file
69
intern/cycles/kernel/osl/nodes/CMakeLists.txt
Normal file
@ -0,0 +1,69 @@
|
||||
|
||||
# OSL node shaders
|
||||
|
||||
SET(osl_sources
|
||||
node_add_closure.osl
|
||||
node_attribute.osl
|
||||
node_background.osl
|
||||
node_blend_texture.osl
|
||||
node_bump.osl
|
||||
node_clouds_texture.osl
|
||||
node_convert_from_color.osl
|
||||
node_convert_from_float.osl
|
||||
node_convert_from_normal.osl
|
||||
node_convert_from_point.osl
|
||||
node_convert_from_vector.osl
|
||||
node_diffuse_bsdf.osl
|
||||
node_distorted_noise_texture.osl
|
||||
node_emission.osl
|
||||
node_environment_texture.osl
|
||||
node_fresnel.osl
|
||||
node_geometry.osl
|
||||
node_glass_bsdf.osl
|
||||
node_glossy_bsdf.osl
|
||||
node_image_texture.osl
|
||||
node_light_path.osl
|
||||
node_magic_texture.osl
|
||||
node_mapping.osl
|
||||
node_marble_texture.osl
|
||||
node_math.osl
|
||||
node_mix.osl
|
||||
node_mix_closure.osl
|
||||
node_musgrave_texture.osl
|
||||
node_noise_texture.osl
|
||||
node_output_displacement.osl
|
||||
node_output_surface.osl
|
||||
node_output_volume.osl
|
||||
node_sky_texture.osl
|
||||
node_stucci_texture.osl
|
||||
node_texture_coordinate.osl
|
||||
node_translucent_bsdf.osl
|
||||
node_transparent_bsdf.osl
|
||||
node_value.osl
|
||||
node_vector_math.osl
|
||||
node_velvet_bsdf.osl
|
||||
node_voronoi_texture.osl
|
||||
node_ward_bsdf.osl
|
||||
node_wood_texture.osl)
|
||||
|
||||
SET(osl_headers
|
||||
node_texture.h
|
||||
stdosl.h)
|
||||
|
||||
SET(oso_sources)
|
||||
|
||||
FOREACH(_file ${osl_sources})
|
||||
SET(osl_file ${CMAKE_CURRENT_SOURCE_DIR}/${_file})
|
||||
STRING(REPLACE ".osl" ".oso" oso_file ${osl_file})
|
||||
STRING(REPLACE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} oso_file ${oso_file})
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${oso_file}
|
||||
COMMAND ${OSL_COMPILER} -O2 ${osl_file}
|
||||
DEPENDS ${osl_file} ${osl_headers})
|
||||
LIST(APPEND oso_sources ${oso_file})
|
||||
ENDFOREACH()
|
||||
|
||||
ADD_CUSTOM_TARGET(shader ALL DEPENDS ${oso_sources} ${osl_headers})
|
||||
|
||||
INSTALL(FILES ${oso_sources} DESTINATION ${INSTALL_PATH}/cycles/shader)
|
||||
|
28
intern/cycles/kernel/osl/nodes/node_add_closure.osl
Normal file
28
intern/cycles/kernel/osl/nodes/node_add_closure.osl
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "stdosl.h"
|
||||
|
||||
shader node_add_closure(
|
||||
closure color Closure1 = background(),
|
||||
closure color Closure2 = background(),
|
||||
output closure color Closure = background())
|
||||
{
|
||||
Closure = Closure1 + Closure2;
|
||||
}
|
||||
|
43
intern/cycles/kernel/osl/nodes/node_attribute.osl
Normal file
43
intern/cycles/kernel/osl/nodes/node_attribute.osl
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "stdosl.h"
|
||||
|
||||
shader node_attribute(
|
||||
string bump_offset = "center",
|
||||
string name = "",
|
||||
output point Vector = point(0.0, 0.0, 0.0),
|
||||
output color Color = color(0.0, 0.0, 0.0),
|
||||
output float Fac = 0.0)
|
||||
{
|
||||
getattribute(name, Color);
|
||||
Vector = point(Color);
|
||||
getattribute(name, Fac);
|
||||
|
||||
if(bump_offset == "dx") {
|
||||
Color += Dx(Color);
|
||||
Vector += Dx(Vector);
|
||||
Fac += Dx(Fac);
|
||||
}
|
||||
else if(bump_offset == "dy") {
|
||||
Color += Dy(Color);
|
||||
Vector += Dy(Vector);
|
||||
Fac += Dy(Fac);
|
||||
}
|
||||
}
|
||||
|
28
intern/cycles/kernel/osl/nodes/node_background.osl
Normal file
28
intern/cycles/kernel/osl/nodes/node_background.osl
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "stdosl.h"
|
||||
|
||||
shader node_background(
|
||||
color Color = color(0.8, 0.8, 0.8),
|
||||
float Strength = 1.0,
|
||||
output closure color Background = background())
|
||||
{
|
||||
Background = Color*Strength*background();
|
||||
}
|
||||
|
78
intern/cycles/kernel/osl/nodes/node_blend_texture.osl
Normal file
78
intern/cycles/kernel/osl/nodes/node_blend_texture.osl
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2011, Blender Foundation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "stdosl.h"
|
||||
#include "node_texture.h"
|
||||
|
||||
/* Blend */
|
||||
|
||||
float blend(point p, string progression, string axis)
|
||||
{
|
||||
float x, y;
|
||||
|
||||
if(axis == "Vertical") {
|
||||
x= p[1];
|
||||
y= p[0];
|
||||
}
|
||||
else {
|
||||
x= p[0];
|
||||
y= p[1];
|
||||
}
|
||||
|
||||
float result = 0.0;
|
||||
|
||||
if(progression == "Linear") {
|
||||
result = (1.0 + x)/2.0;
|
||||
}
|
||||
else if(progression == "Quadratic") {
|
||||
float r = max((1.0 + x)/2.0, 0.0);
|
||||
result = r*r;
|
||||
}
|
||||
else if(progression == "Easing") {
|
||||
float r = min(max((1.0 + x)/2.0, 0.0), 1.0);
|
||||
float t = r*r;
|
||||
|
||||
result = (3.0*t - 2.0*t*r);
|
||||
}
|
||||
else if(progression == "Diagonal") {
|
||||
result = (2.0 + x + y)/4.0;
|
||||
}
|
||||
else if(progression == "Radial") {
|
||||
result = atan2(y, x)/(2*M_PI) + 0.5;
|
||||
}
|
||||
else {
|
||||
float r = max(1.0 - sqrt(x*x + y*y + p[2]*p[2]), 0.0);
|
||||
|
||||
if(progression == "Quadratic Sphere")
|
||||
result = r*r;
|
||||
else if(progression == "Spherical")
|
||||
result = r;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
shader node_blend_texture(
|
||||
string Progression = "Linear",
|
||||
string Axis = "Horizontal",
|
||||
point Vector = P,
|
||||
output float Fac = 0.0)
|
||||
{
|
||||
Fac = blend(Vector, Progression, Axis);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user