Merged changes in the trunk up to revision 53584.

Conflicts resolved:
release/scripts/startup/bl_ui/properties_render.py
source/blender/blenloader/intern/readfile.c
source/blender/editors/interface/interface_templates.c
source/blender/makesrna/RNA_enum_types.h

Also made additional code updates for:
r53355 UIList - Python-extendable list of UI items
r53460 Alpha premul pipeline cleanup
This commit is contained in:
2013-01-05 22:24:05 +00:00
577 changed files with 20475 additions and 7280 deletions

View File

@@ -129,6 +129,8 @@ option(WITH_IK_ITASC "Enable ITASC IK solver (only disable for development
option(WITH_IK_SOLVER "Enable Legacy IK solver (only disable for development)" ON)
option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke and audio effects)" ON)
option(WITH_BULLET "Enable Bullet (Physics Engine)" ON)
option(WITH_SYSTEM_BULLET "Use the systems bullet library (currently unsupported due to missing features in upstream!)" )
mark_as_advanced(WITH_SYSTEM_BULLET)
option(WITH_GAMEENGINE "Enable Game Engine" ON)
option(WITH_PLAYER "Build Player" OFF)
option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ON)
@@ -149,6 +151,9 @@ mark_as_advanced(WITH_HEADLESS)
option(WITH_AUDASPACE "Build with blenders audio library (only disable if you know what you're doing!)" ON)
mark_as_advanced(WITH_AUDASPACE)
option(WITH_BOOL_COMPAT "Continue defining \"TRUE\" and \"FALSE\" until these can be replaced with \"true\" and \"false\" from stdbool.h" ON)
mark_as_advanced(WITH_BOOL_COMPAT)
# (unix defaults to OpenMP On)
if((UNIX AND NOT APPLE) OR (MINGW))
@@ -267,7 +272,6 @@ mark_as_advanced(WITH_CXX_GUARDEDALLOC)
option(WITH_ASSERT_ABORT "Call abort() when raising an assertion through BLI_assert()" OFF)
mark_as_advanced(WITH_ASSERT_ABORT)
if(APPLE)
cmake_minimum_required(VERSION 2.8.8)
cmake_policy(VERSION 2.8.8)
@@ -426,6 +430,13 @@ endif()
TEST_SSE_SUPPORT(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG)
TEST_STDBOOL_SUPPORT()
if(HAVE_STDBOOL_H)
add_definitions(-DHAVE_STDBOOL_H)
endif()
if(WITH_BOOL_COMPAT)
add_definitions(-DWITH_BOOL_COMPAT)
endif()
#-----------------------------------------------------------------------------
# Check for valid directories
@@ -1090,14 +1101,16 @@ elseif(WIN32)
if(WITH_PYTHON)
# normally cached but not since we include them with blender
if(MSVC10)
set(PYTHON_VERSION 3.2) # CACHE STRING)
set(PYTHON_VERSION 3.3) # CACHE STRING)
else()
set(PYTHON_VERSION 3.3) # CACHE STRING)
endif()
set_lib_path(PYTHON "python")
STRING(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
set(PYTHON_LIBRARY ${PYTHON}/lib/python${_PYTHON_VERSION_NO_DOTS}.lib) #CACHE FILEPATH
# Use shared libs for vc2008 and vc2010 until we actually have vc2010 libs
set(PYTHON_LIBRARY ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.lib)
# set(PYTHON_LIBRARY ${PYTHON}/lib/python${_PYTHON_VERSION_NO_DOTS}.lib) #CACHE FILEPATH
unset(_PYTHON_VERSION_NO_DOTS)
#Shared includes for both vc2008 and vc2010
@@ -1836,6 +1849,20 @@ else()
set(GLEW_INCLUDE_PATH "${CMAKE_SOURCE_DIR}/extern/glew/include")
endif()
#-----------------------------------------------------------------------------
# Configure Bullet
if(WITH_BULLET AND WITH_SYSTEM_BULLET)
find_package(Bullet)
if(NOT BULLET_FOUND)
set(WITH_BULLET OFF)
endif()
else()
set(BULLET_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/extern/bullet2/src")
# set(BULLET_LIBRARIES "")
endif()
#-----------------------------------------------------------------------------
# Configure Python.
@@ -2140,3 +2167,8 @@ if(FIRST_RUN)
message("${_config_msg}")
endif()
# debug
message(
STATUS "HAVE_STDBOOL_H = ${HAVE_STDBOOL_H}"
)

View File

@@ -374,9 +374,10 @@ if btools.ENDIAN == "big":
else:
env['CPPFLAGS'].append('-D__LITTLE_ENDIAN__')
# TODO, make optional
# TODO, make optional (as with CMake)
env['CPPFLAGS'].append('-DWITH_AUDASPACE')
env['CPPFLAGS'].append('-DWITH_AVI')
env['CPPFLAGS'].append('-DWITH_BOOL_COMPAT')
# lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir
B.root_build_dir = env['BF_BUILDDIR']
@@ -443,11 +444,12 @@ if env['WITH_BF_PYTHON']:
found_pyconfig_h = True
if not (found_python_h and found_pyconfig_h):
print("\nMissing: Python.h and/or pyconfig.h in\"" + env.subst('${BF_PYTHON_INC}') + "\",\n"
" Set 'BF_PYTHON_INC' to point "
"to valid python include path(s).\n Containing "
"Python.h and pyconfig.h for python version \"" + env.subst('${BF_PYTHON_VERSION}') + "\"")
print("""\nMissing: Python.h and/or pyconfig.h in "%s"
Set 'BF_PYTHON_INC' to point to valid include path(s),
containing Python.h and pyconfig.h for Python version "%s".
Example: python scons/scons.py BF_PYTHON_INC=../Python/include
""" % (env.subst('${BF_PYTHON_INC}'), env.subst('${BF_PYTHON_VERSION}')))
Exit()

File diff suppressed because it is too large Load Diff

View File

@@ -66,6 +66,7 @@ SET(_opencollada_SEARCH_DIRS
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt/lib/opencollada
)
SET(_opencollada_INCLUDES)

View File

@@ -75,12 +75,12 @@ def is_cmake(filename):
def is_c_header(filename):
ext = splitext(filename)[1]
return (ext in (".h", ".hpp", ".hxx"))
return (ext in {".h", ".hpp", ".hxx", ".hh"})
def is_c(filename):
ext = splitext(filename)[1]
return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc", ".cc", ".inl"))
return (ext in {".c", ".cpp", ".cxx", ".m", ".mm", ".rc", ".cc", ".inl"})
def is_c_any(filename):

View File

@@ -282,7 +282,9 @@ macro(setup_liblinks
if(WITH_SYSTEM_GLEW)
target_link_libraries(${target} ${GLEW_LIBRARY})
endif()
if(WITH_BULLET AND WITH_SYSTEM_BULLET)
target_link_libraries(${target} ${BULLET_LIBRARIES})
endif()
if(WITH_OPENAL)
target_link_libraries(${target} ${OPENAL_LIBRARY})
endif()
@@ -441,6 +443,15 @@ macro(TEST_SSE_SUPPORT
unset(CMAKE_REQUIRED_FLAGS)
endmacro()
macro(TEST_STDBOOL_SUPPORT)
# This program will compile correctly if and only if
# this C compiler supports C99 stdbool.
check_c_source_runs("
#include <stdbool.h>
int main(void) { return (int)false; }"
HAVE_STDBOOL_H)
endmacro()
# when we have warnings as errors applied globally this
# needs to be removed for some external libs which we dont maintain.

View File

@@ -97,7 +97,7 @@ def is_cmake(filename):
def is_c_header(filename):
ext = splitext(filename)[1]
return (ext in (".h", ".hpp", ".hxx"))
return (ext in {".h", ".hpp", ".hxx", ".hh"})
def is_py(filename):

View File

@@ -43,7 +43,7 @@ SOURCE_DIR = abspath(SOURCE_DIR)
def is_c_header(filename):
ext = os.path.splitext(filename)[1]
return (ext in (".h", ".hpp", ".hxx"))
return (ext in {".h", ".hpp", ".hxx", ".hh"})
def is_c(filename):

View File

@@ -77,6 +77,7 @@ fi || :
%{_bindir}/%{name}
%{_datadir}/%{name}/%{blender_api}/datafiles/fonts
%{_datadir}/%{name}/%{blender_api}/datafiles/colormanagement
%{_datadir}/%{name}/%{blender_api}/datafiles/locale/languages
%{_datadir}/%{name}/%{blender_api}/scripts
%{_datadir}/icons/hicolor/*/apps/%{name}.*
%{_datadir}/applications/%{name}.desktop

View File

@@ -0,0 +1,70 @@
bl_info = {
"name": "Example Addon Preferences",
"author": "Your Name Here",
"version": (1, 0),
"blender": (2, 65, 0),
"location": "SpaceBar Search -> Addon Preferences Example",
"description": "Example Addon",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "Object"}
import bpy
from bpy.types import Operator, AddonPreferences
from bpy.props import StringProperty, IntProperty, BoolProperty
class ExampleAddonPreferences(AddonPreferences):
bl_idname = __name__
filepath = StringProperty(
name="Example File Path",
subtype='FILE_PATH',
)
number = IntProperty(
name="Example Number",
default=4,
)
boolean = BoolProperty(
name="Example Boolean",
default=False,
)
def draw(self, context):
layout = self.layout
layout.label(text="This is a preferences view for our addon")
layout.prop(self, "filepath")
layout.prop(self, "number")
layout.prop(self, "boolean")
class OBJECT_OT_addon_prefs_example(Operator):
"""Display example preferences"""
bl_idname = "object.addon_prefs_example"
bl_label = "Addon Preferences Example"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
user_preferences = context.user_preferences
addon_prefs = user_preferences.addons[__name__].preferences
info = ("Path: %s, Number: %d, Boolean %r" %
(addon_prefs.filepath, addon_prefs.number, addon_prefs.boolean))
self.report({'INFO'}, info)
print(info)
return {'FINISHED'}
# Registration
def register():
bpy.utils.register_class(OBJECT_OT_addon_prefs_example)
bpy.utils.register_class(ExampleAddonPreferences)
def unregister():
bpy.utils.unregister_class(OBJECT_OT_addon_prefs_example)
bpy.utils.unregister_class(ExampleAddonPreferences)

View File

@@ -0,0 +1,89 @@
"""
Basic UIList Example
+++++++++++++++++++
This script is the UIList subclass used to show material slots, with a bunch of additional commentaries.
Notice the name of the class, this naming convention is similar as the one for panels or menus.
.. note::
UIList subclasses must be registered for blender to use them.
"""
import bpy
class MATERIAL_UL_matslots_example(bpy.types.UIList):
# The draw_item function is called for each item of the collection that is visible in the list.
# data is the RNA object containing the collection,
# item is the current drawn item of the collection,
# icon is the "computed" icon for the item (as an integer, because some objects like materials or textures
# have custom icons ID, which are not available as enum items).
# active_data is the RNA object containing the active property for the collection (i.e. integer pointing to the
# active item of the collection).
# active_propname is the name of the active property (use 'getattr(active_data, active_propname)').
# index is index of the current item in the collection.
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
ob = data
slot = item
ma = slot.material
# draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
if self.layout_type in {'DEFAULT', 'COMPACT'}:
# You should always start your row layout by a label (icon + text), this will also make the row easily
# selectable in the list!
# We use icon_value of label, as our given icon is an integer value, not an enum ID.
layout.label(ma.name if ma else "", icon_value=icon)
# And now we can add other UI stuff...
# Here, we add nodes info if this material uses (old!) shading nodes.
if ma and not context.scene.render.use_shading_nodes:
manode = ma.active_node_material
if manode:
# The static method UILayout.icon returns the integer value of the icon ID "computed" for the given
# RNA object.
layout.label("Node %s" % manode.name, icon_value=layout.icon(manode))
elif ma.use_nodes:
layout.label("Node <none>")
else:
layout.label("")
# 'GRID' layout type should be as compact as possible (typically a single icon!).
elif self.layout_type in {'GRID'}:
layout.alignment = 'CENTER'
layout.label("", icon_value=icon)
# And now we can use this list everywhere in Blender. Here is a small example panel.
class UIListPanelExample(bpy.types.Panel):
"""Creates a Panel in the Object properties window"""
bl_label = "UIList Panel"
bl_idname = "OBJECT_PT_ui_list_example"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"
def draw(self, context):
layout = self.layout
obj = context.object
# template_list now takes two new args.
# The first one is the identifier of the registered UIList to use (if you want only the default list,
# with no custom draw code, use "UI_UL_list").
layout.template_list("MATERIAL_UL_matslots_example", "", obj, "material_slots", obj, "active_material_index")
# The second one can usually be left as an empty string. It's an additional ID used to distinguish lists in case you
# use the same list several times in a given area.
layout.template_list("MATERIAL_UL_matslots_example", "compact", obj, "material_slots",
obj, "active_material_index", type='COMPACT')
def register():
bpy.utils.register_class(MATERIAL_UL_matslots_example)
bpy.utils.register_class(UIListPanelExample)
def unregister():
bpy.utils.unregister_class(MATERIAL_UL_matslots_example)
bpy.utils.unregister_class(UIListPanelExample)
if __name__ == "__main__":
register()

View File

@@ -3749,6 +3749,18 @@ Types
:type: float
.. attribute:: maxJumps
The maximum number of jumps a character can perform before having to touch the ground. By default this is set to 1. 2 allows for a double jump, etc.
:type: int
.. attribute:: jumpCount
The current jump count. This can be used to have different logic for a single jump versus a double jump. For example, a different animation for the second jump.
:type: int
.. method:: jump()
The character jumps based on it's jump speed.

View File

@@ -614,6 +614,10 @@ def pyfunc2sphinx(ident, fw, identifier, py_func, is_class=True):
'''
function or class method to sphinx
'''
if type(py_func) == type(bpy.types.Space.draw_handler_add):
return
arg_str = inspect.formatargspec(*inspect.getargspec(py_func))
if not is_class:

View File

@@ -27,10 +27,13 @@
remove_strict_flags()
add_subdirectory(colamd)
add_subdirectory(rangetree)
if(WITH_BULLET)
if(NOT WITH_SYSTEM_BULLET)
add_subdirectory(bullet2)
endif()
endif()
# now only available in a branch
#if(WITH_MOD_CLOTH_ELTOPO)

1
extern/SConscript vendored
View File

@@ -4,6 +4,7 @@ Import('env')
SConscript(['glew/SConscript'])
SConscript(['colamd/SConscript'])
SConscript(['rangetree/SConscript'])
if env['WITH_BF_GAMEENGINE']:
SConscript(['recastnavigation/SConscript'])

31
extern/rangetree/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,31 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
)
set(SRC
range_tree.hh
range_tree_c_api.h
range_tree_c_api.cc
)
blender_add_lib(extern_rangetree "${SRC}" "${INC}" "")

13
extern/rangetree/README.org vendored Normal file
View File

@@ -0,0 +1,13 @@
* Overview
Basic class for storing non-overlapping scalar ranges. Underlying
representation is a C++ STL set for fast lookups.
* License
GPL version 2 or later (see COPYING)
* Author Note
This implementation is intended for storing free unique IDs in a new
undo system for BMesh in Blender, but could be useful elsewhere.
* Website
https://github.com/nicholasbishop/RangeTree

9
extern/rangetree/SConscript vendored Normal file
View File

@@ -0,0 +1,9 @@
2#!/usr/bin/python
Import ('env')
sources = env.Glob('*.cc')
incs = '.'
defs = ''
env.BlenderLib ('extern_rangetree', sources, Split(incs), Split(defs), libtype=['extern'], priority=[100] )

228
extern/rangetree/range_tree.hh vendored Normal file
View File

@@ -0,0 +1,228 @@
/* 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 <cassert>
#include <climits>
#include <iostream>
#include <set>
#ifndef RANGE_TREE_DEBUG_PRINT_FUNCTION
# define RANGE_TREE_DEBUG_PRINT_FUNCTION 0
#endif
template <typename T>
struct RangeTree {
struct Range {
Range(T min_, T max_)
: min(min_), max(max_), single(min_ == max_) {
assert(min_ <= max_);
}
Range(T t)
: min(t), max(t), single(true)
{}
bool operator<(const Range& v) const {
return max < v.min;
}
const T min;
const T max;
const bool single;
};
typedef std::set<Range> Tree;
typedef typename Tree::iterator TreeIter;
typedef typename Tree::reverse_iterator TreeIterReverse;
typedef typename Tree::const_iterator TreeIterConst;
/* Initialize with a single range from 'min' to 'max', inclusive. */
RangeTree(T min, T max) {
tree.insert(Range(min, max));
}
/* Initialize with a single range from 0 to 'max', inclusive. */
RangeTree(T max) {
tree.insert(Range(0, max));
}
RangeTree(const RangeTree<T>& src) {
tree = src.tree;
}
/* Remove 't' from the associated range in the tree. Precondition:
a range including 't' must exist in the tree. */
void take(T t) {
#if RANGE_TREE_DEBUG_PRINT_FUNCTION
std::cout << __func__ << "(" << t << ")\n";
#endif
/* Find the range that includes 't' and its neighbors */
TreeIter iter = tree.find(Range(t));
assert(iter != tree.end());
Range cur = *iter;
TreeIter prev = iter;
TreeIter next = iter;
--prev;
++next;
/* Remove the original range (note that this does not
invalidate the prev/next iterators) */
tree.erase(iter);
/* Construct two new ranges that together cover the original
range, except for 't' */
if (t > cur.min)
tree.insert(Range(cur.min, t - 1));
if (t + 1 <= cur.max)
tree.insert(Range(t + 1, cur.max));
}
/* Take the first element out of the first range in the
tree. Precondition: tree must not be empty. */
T take_any() {
#if RANGE_TREE_DEBUG_PRINT_FUNCTION
std::cout << __func__ << "()\n";
#endif
/* Find the first element */
TreeIter iter = tree.begin();
assert(iter != tree.end());
T first = iter->min;
/* Take the first element */
take(first);
return first;
}
/* Return 't' to the tree, either expanding/merging existing
ranges or adding a range to cover it. Precondition: 't' cannot
be in an existing range. */
void release(T t) {
#if RANGE_TREE_DEBUG_PRINT_FUNCTION
std::cout << __func__ << "(" << t << ")\n";
#endif
/* TODO: these cases should be simplified/unified */
TreeIter right = tree.upper_bound(t);
if (right != tree.end()) {
TreeIter left = right;
if (left != tree.begin())
--left;
if (left == right) {
/* 't' lies before any existing ranges */
if (t + 1 == left->min) {
/* 't' lies directly before the first range,
resize and replace that range */
const Range r(t, left->max);
tree.erase(left);
tree.insert(r);
}
else {
/* There's a gap between 't' and the first range,
add a new range */
tree.insert(Range(t));
}
}
else if ((left->max + 1 == t) &&
(t + 1 == right->min)) {
/* 't' fills a hole. Remove left and right, and insert a
new range that covers both. */
const Range r(left->min, right->max);
tree.erase(left);
tree.erase(right);
tree.insert(r);
}
else if (left->max + 1 == t) {
/* 't' lies directly after 'left' range, resize and
replace that range */
const Range r(left->min, t);
tree.erase(left);
tree.insert(r);
}
else if (t + 1 == right->min) {
/* 't' lies directly before 'right' range, resize and
replace that range */
const Range r(t, right->max);
tree.erase(right);
tree.insert(r);
}
else {
/* There's a gap between 't' and both adjacent ranges,
add a new range */
tree.insert(Range(t));
}
}
else {
/* 't' lies after any existing ranges */
right = tree.end();
right--;
if (right->max + 1 == t) {
/* 't' lies directly after last range, resize and
replace that range */
const Range r(right->min, t);
tree.erase(right);
tree.insert(r);
}
else {
/* There's a gap between the last range and 't', add a
new range */
tree.insert(Range(t));
}
}
}
bool has(T t) const {
TreeIterConst iter = tree.find(Range(t));
return (iter != tree.end()) && (t <= iter->max);
}
bool has_range(T min, T max) const {
TreeIterConst iter = tree.find(Range(min, max));
return (iter != tree.end()) && (min == iter->min && max == iter->max);
}
bool empty() const {
return tree.empty();
}
int size() const {
return tree.size();
}
void print() const {
std::cout << "RangeTree:\n";
for (TreeIterConst iter = tree.begin(); iter != tree.end(); ++iter) {
const Range& r = *iter;
if (r.single)
std::cout << " [" << r.min << "]\n";
else
std::cout << " [" << r.min << ", " << r.max << "]\n";
}
if (empty())
std::cout << " <empty>";
std::cout << "\n";
}
unsigned int allocation_lower_bound() const {
return tree.size() * sizeof(Range);
}
private:
Tree tree;
};

86
extern/rangetree/range_tree_c_api.cc vendored Normal file
View File

@@ -0,0 +1,86 @@
/* 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 "range_tree.hh"
/* Give RangeTreeUInt a real type rather than the opaque struct type
defined for external use. */
#define RANGE_TREE_C_API_INTERNAL
typedef RangeTree<unsigned> RangeTreeUInt;
#include "range_tree_c_api.h"
RangeTreeUInt *range_tree_uint_alloc(unsigned min, unsigned max)
{
return new RangeTreeUInt(min, max);
}
RangeTreeUInt *range_tree_uint_copy(RangeTreeUInt *src)
{
return new RangeTreeUInt(*src);
}
void range_tree_uint_free(RangeTreeUInt *rt)
{
delete rt;
}
void range_tree_uint_take(RangeTreeUInt *rt, unsigned v)
{
rt->take(v);
}
unsigned range_tree_uint_take_any(RangeTreeUInt *rt)
{
return rt->take_any();
}
void range_tree_uint_release(RangeTreeUInt *rt, unsigned v)
{
rt->release(v);
}
int range_tree_uint_has(const RangeTreeUInt *rt, unsigned v)
{
return rt->has(v);
}
int range_tree_uint_has_range(const RangeTreeUInt *rt,
unsigned vmin,
unsigned vmax)
{
return rt->has_range(vmin, vmax);
}
int range_tree_uint_empty(const RangeTreeUInt *rt)
{
return rt->empty();
}
unsigned range_tree_uint_size(const RangeTreeUInt *rt)
{
return rt->size();
}
void range_tree_uint_print(const RangeTreeUInt *rt)
{
rt->print();
}
unsigned int range_tree_uint_allocation_lower_bound(const RangeTreeUInt *rt)
{
return rt->allocation_lower_bound();
}

60
extern/rangetree/range_tree_c_api.h vendored Normal file
View File

@@ -0,0 +1,60 @@
/* 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 RANGE_TREE_C_API_H
#define RANGE_TREE_C_API_H
#ifdef __cplusplus
extern "C" {
#endif
/* Simple C-accessible wrapper for RangeTree<unsigned> */
#ifndef RANGE_TREE_C_API_INTERNAL
typedef struct RangeTreeUInt RangeTreeUInt;
#endif
RangeTreeUInt *range_tree_uint_alloc(unsigned min, unsigned max);
RangeTreeUInt *range_tree_uint_copy(RangeTreeUInt *src);
void range_tree_uint_free(RangeTreeUInt *rt);
void range_tree_uint_take(RangeTreeUInt *rt, unsigned v);
unsigned range_tree_uint_take_any(RangeTreeUInt *rt);
void range_tree_uint_release(RangeTreeUInt *rt, unsigned v);
int range_tree_uint_has(const RangeTreeUInt *rt, unsigned v);
int range_tree_uint_has_range(const RangeTreeUInt *rt,
unsigned vmin,
unsigned vmax);
int range_tree_uint_empty(const RangeTreeUInt *rt);
unsigned range_tree_uint_size(const RangeTreeUInt *rt);
void range_tree_uint_print(const RangeTreeUInt *rt);
unsigned int range_tree_uint_allocation_lower_bound(const RangeTreeUInt *rt);
#ifdef __cplusplus
}
#endif
#endif /* __DUALCON_H__ */

View File

@@ -24,6 +24,7 @@ set(SRC
blender_mesh.cpp
blender_object.cpp
blender_particles.cpp
blender_curves.cpp
blender_python.cpp
blender_session.cpp
blender_shader.cpp

View File

@@ -21,7 +21,7 @@
bl_info = {
"name": "Cycles Render Engine",
"author": "",
"blender": (2, 6, 5),
"blender": (2, 60, 5),
"location": "Info header, render engine menu",
"description": "Cycles Render Engine integration",
"warning": "",

View File

@@ -64,6 +64,38 @@ enum_panorama_types = (
"Similar to most fisheye modern lens, takes sensor dimensions into consideration"),
)
enum_curve_presets = (
('CUSTOM', "Custom", "Set general parameters"),
('TANGENT_SHADING', "Tangent Normal", "Use planar geometry and tangent normals"),
('TRUE_NORMAL', "True Normal", "Use true normals (good for thin strands)"),
('ACCURATE_PRESET', "Accurate", "Use best settings (suitable for glass materials)"),
)
enum_curve_primitives = (
('TRIANGLES', "Triangles", "Create triangle geometry around strands"),
('LINE_SEGMENTS', "Line Segments", "Use line segment primitives"),
('CURVE_SEGMENTS', "?Curve Segments?", "Use curve segment primitives (not implemented)"),
)
enum_triangle_curves = (
('CAMERA', "Planes", "Create individual triangles forming planes that face camera"),
('RIBBONS', "Ribbons", "Create individual triangles forming ribbon"),
('TESSELLATED', "Tessellated", "Create mesh surrounding each strand"),
)
enum_line_curves = (
('ACCURATE', "Accurate", "Always take into consideration strand width for intersections"),
('QT_CORRECTED', "Corrected", "Ignore width for initial intersection and correct later"),
('ENDCORRECTED', "Correct found", "Ignore width for all intersections and only correct closest"),
('QT_UNCORRECTED', "Uncorrected", "Calculate intersections without considering width"),
)
enum_curves_interpolation = (
('LINEAR', "Linear interpolation", "Use Linear interpolation between segments"),
('CARDINAL', "Cardinal interpolation", "Use cardinal interpolation between segments"),
('BSPLINE', "B-spline interpolation", "Use b-spline interpolation between segments"),
)
class CyclesRenderSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
@@ -237,7 +269,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
)
cls.film_transparent = BoolProperty(
name="Transparent",
description="World background is transparent",
description="World background is transparent with premultiplied alpha",
default=False,
)
@@ -573,6 +605,157 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
del bpy.types.Curve.cycles
del bpy.types.MetaBall.cycles
class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
bpy.types.Scene.cycles_curves = PointerProperty(
name="Cycles Hair Rendering Settings",
description="Cycles hair rendering settings",
type=cls,
)
cls.preset = EnumProperty(
name="Mode",
description="Hair rendering mode",
items=enum_curve_presets,
default='TRUE_NORMAL',
)
cls.primitive = EnumProperty(
name="Primitive",
description="Type of primitive used for hair rendering",
items=enum_curve_primitives,
default='LINE_SEGMENTS',
)
cls.triangle_method = EnumProperty(
name="Mesh Geometry",
description="Method for creating triangle geometry",
items=enum_triangle_curves,
default='CAMERA',
)
cls.line_method = EnumProperty(
name="Intersection Method",
description="Method for line segment intersection",
items=enum_line_curves,
default='ACCURATE',
)
cls.interpolation = EnumProperty(
name="Interpolation",
description="Interpolation method",
items=enum_curves_interpolation,
default='BSPLINE',
)
cls.use_backfacing = BoolProperty(
name="Check back-faces",
description="Test back-faces of strands",
default=False,
)
cls.use_encasing = BoolProperty(
name="Exclude encasing",
description="Ignore strands encasing a ray's initial location",
default=True,
)
cls.use_tangent_normal_geometry = BoolProperty(
name="Tangent normal geometry",
description="Use the tangent normal for actual normal",
default=False,
)
cls.use_tangent_normal = BoolProperty(
name="Tangent normal default",
description="Use the tangent normal for all normals",
default=False,
)
cls.use_tangent_normal_correction = BoolProperty(
name="Strand slope correction",
description="Correct the tangent normal for the strand's slope",
default=False,
)
cls.use_cache = BoolProperty(
name="Export Cached data",
default=True,
)
cls.use_parents = BoolProperty(
name="Use parent strands",
description="Use parents with children",
default=False,
)
cls.use_smooth = BoolProperty(
name="Smooth Strands",
description="Use vertex normals",
default=True,
)
cls.use_joined = BoolProperty(
name="Join",
description="Fill gaps between segments (requires more memory)",
default=False,
)
cls.use_curves = BoolProperty(
name="Use Cycles Hair Rendering",
description="Activate Cycles hair rendering for particle system",
default=True,
)
cls.segments = IntProperty(
name="Segments",
description="Number of segments between path keys (note that this combines with the 'draw step' value)",
min=1, max=64,
default=1,
)
cls.resolution = IntProperty(
name="Resolution",
description="Resolution of generated mesh",
min=3, max=64,
default=3,
)
cls.normalmix = FloatProperty(
name="Normal mix",
description="Scale factor for tangent normal removal (zero gives ray normal)",
min=0, max=2.0,
default=1,
)
cls.encasing_ratio = FloatProperty(
name="Encasing ratio",
description="Scale factor for encasing strand width",
min=0, max=100.0,
default=1.01,
)
@classmethod
def unregister(cls):
del bpy.types.Scene.cycles_curves
class CyclesCurveSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
bpy.types.ParticleSettings.cycles = PointerProperty(
name="Cycles Hair Settings",
description="Cycles hair settings",
type=cls,
)
cls.root_width = FloatProperty(
name="Root Size Multiplier",
description="Multiplier of particle size for the strand's width at root",
min=0.0, max=1000.0,
default=1.0,
)
cls.tip_width = FloatProperty(
name="Tip Size Multiplier",
description="Multiplier of particle size for the strand's width at tip",
min=0.0, max=1000.0,
default=0.0,
)
cls.shape = FloatProperty(
name="Strand Shape",
description="Strand shape parameter",
min=-1.0, max=1.0,
default=0.0,
)
cls.use_closetip = BoolProperty(
name="Close tip",
description="Set tip radius to zero",
default=True,
)
@classmethod
def unregister(cls):
del bpy.types.ParticleSettings.cycles
def register():
bpy.utils.register_class(CyclesRenderSettings)
@@ -582,6 +765,8 @@ def register():
bpy.utils.register_class(CyclesWorldSettings)
bpy.utils.register_class(CyclesVisibilitySettings)
bpy.utils.register_class(CyclesMeshSettings)
bpy.utils.register_class(CyclesCurveRenderSettings)
bpy.utils.register_class(CyclesCurveSettings)
def unregister():
@@ -592,3 +777,5 @@ def unregister():
bpy.utils.unregister_class(CyclesWorldSettings)
bpy.utils.unregister_class(CyclesMeshSettings)
bpy.utils.unregister_class(CyclesVisibilitySettings)
bpy.utils.unregister_class(CyclesCurveRenderSettings)
bpy.utils.unregister_class(CyclesCurveSettings)

View File

@@ -290,7 +290,7 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
rd = scene.render
row = layout.row()
row.template_list(rd, "layers", rd.layers, "active_index", rows=2)
row.template_list("RENDER_UL_renderlayers", "", rd, "layers", rd.layers, "active_index", rows=2)
col = row.column(align=True)
col.operator("scene.render_layer_add", icon='ZOOMIN', text="")
@@ -407,7 +407,7 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
if ob:
row = layout.row()
row.template_list(ob, "material_slots", ob, "active_material_index", rows=2)
row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=2)
col = row.column(align=True)
col.operator("object.material_slot_add", icon='ZOOMIN', text="")
@@ -962,7 +962,7 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
part = psys.settings
row = layout.row()
row.template_list(part, "texture_slots", part, "active_texture_index", rows=2)
row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2)
col = row.column(align=True)
col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
@@ -975,6 +975,89 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
slot = part.texture_slots[part.active_texture_index]
layout.template_ID(slot, "texture", new="texture.new")
class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
bl_label = "Cycles Hair Rendering"
bl_context = "particle"
@classmethod
def poll(cls, context):
psys = context.particle_system
device_type = context.user_preferences.system.compute_device_type
experimental = context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE')
return CyclesButtonsPanel.poll(context) and experimental and psys
def draw_header(self, context):
cscene = context.scene.cycles_curves
self.layout.prop(cscene, "use_curves", text="")
def draw(self, context):
layout = self.layout
scene = context.scene
cscene = scene.cycles_curves
layout.active = cscene.use_curves
layout.prop(cscene, "preset", text="Mode")
if cscene.preset == 'CUSTOM':
layout.prop(cscene, "primitive", text="Primitive")
if cscene.primitive == 'TRIANGLES':
layout.prop(cscene, "triangle_method", text="Method")
if cscene.triangle_method == 'TESSELLATED':
layout.prop(cscene, "resolution", text="Resolution")
layout.prop(cscene, "use_smooth", text="Smooth")
elif cscene.primitive == 'LINE_SEGMENTS':
layout.prop(cscene, "use_backfacing", text="Check back-faces")
row = layout.row()
row.prop(cscene, "use_encasing", text="Exclude encasing")
sub = row.row()
sub.active = cscene.use_encasing
sub.prop(cscene, "encasing_ratio", text="Ratio for encasing")
layout.prop(cscene, "line_method", text="Method")
layout.prop(cscene, "use_tangent_normal", text="Use tangent normal as default")
layout.prop(cscene, "use_tangent_normal_geometry", text="Use tangent normal geometry")
layout.prop(cscene, "use_tangent_normal_correction", text="Correct tangent normal for slope")
layout.prop(cscene, "interpolation", text="Interpolation")
row = layout.row()
row.prop(cscene, "segments", text="Segments")
row.prop(cscene, "normalmix", text="Ray Mix")
row = layout.row()
row.prop(cscene, "use_cache", text="Export cache with children")
if cscene.use_cache:
row.prop(cscene, "use_parents", text="Include parents")
class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
bl_label = "Cycles Hair Settings"
bl_context = "particle"
@classmethod
def poll(cls, context):
use_curves = context.scene.cycles_curves.use_curves and context.particle_system
device_type = context.user_preferences.system.compute_device_type
experimental = context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE')
return CyclesButtonsPanel.poll(context) and experimental and use_curves
def draw(self, context):
layout = self.layout
psys = context.particle_settings
cpsys = psys.cycles
row = layout.row()
row.prop(cpsys, "shape", text="Shape")
row.prop(cpsys, "use_closetip", text="Close tip")
layout.label(text="Width multiplier:")
row = layout.row()
row.prop(cpsys, "root_width", text="Root")
row.prop(cpsys, "tip_width", text="Tip")
class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
bl_label = "Simplify"

File diff suppressed because it is too large Load Diff

View File

@@ -147,7 +147,7 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la
if(active_render)
attr = mesh->attributes.add(ATTR_STD_UV_TANGENT, name);
else
attr = mesh->attributes.add(name, TypeDesc::TypeVector, Attribute::CORNER);
attr = mesh->attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
float3 *tangent = attr->data_float3();
@@ -161,7 +161,7 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la
if(active_render)
attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign);
else
attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, Attribute::CORNER);
attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
tangent_sign = attr_sign->data_float();
}
@@ -223,10 +223,19 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
int shader = used_shaders[mi];
bool smooth = f->use_smooth();
if(n == 4) {
if(len_squared(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) == 0.0f ||
len_squared(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])) == 0.0f) {
mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth);
mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth);
}
else {
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);
}
}
else
mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
nverts.push_back(n);
}
@@ -240,7 +249,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
continue;
Attribute *attr = mesh->attributes.add(
ustring(l->name().c_str()), TypeDesc::TypeColor, Attribute::CORNER);
ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER);
BL::MeshColorLayer::data_iterator c;
float3 *fdata = attr->data_float3();
@@ -279,7 +288,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
if(active_render)
attr = mesh->attributes.add(std, name);
else
attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER);
attr = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
BL::MeshTextureFaceLayer::data_iterator t;
float3 *fdata = attr->data_float3();
@@ -319,14 +328,9 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
* is available in the api. */
if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
Attribute *attr = mesh->attributes.add(ATTR_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 loc, size;
mesh_texture_space(b_mesh, loc, size);
float3 *generated = attr->data_float3();
size_t i = 0;
@@ -376,7 +380,7 @@ static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, con
/* Sync */
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris)
{
/* test if we can instance or if the object is modified */
BL::ID b_ob_data = b_ob.data();
@@ -436,15 +440,23 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
vector<Mesh::Triangle> oldtriangle = mesh->triangles;
/* compares curve_keys rather than strands in order to handle quick hair adjustsments in dynamic BVH - other methods could probably do this better*/
vector<Mesh::CurveKey> oldcurve_keys = mesh->curve_keys;
mesh->clear();
mesh->used_shaders = used_shaders;
mesh->name = ustring(b_ob_data.name().c_str());
if(b_mesh) {
if(!(hide_tris && experimental && is_cpu)) {
if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
else
create_mesh(scene, mesh, b_mesh, used_shaders);
}
if(experimental && is_cpu)
sync_curves(mesh, b_mesh, b_ob, object_updated);
/* free derived mesh */
b_data.meshes.remove(b_mesh);
@@ -472,6 +484,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
rebuild = true;
}
if(oldcurve_keys.size() != mesh->curve_keys.size())
rebuild = true;
else if(oldcurve_keys.size()) {
if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(Mesh::CurveKey)*oldcurve_keys.size()) != 0)
rebuild = true;
}
mesh->tag_update(scene, rebuild);
return mesh;

View File

@@ -196,7 +196,7 @@ void BlenderSync::sync_background_light()
/* Object */
Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion)
Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion, bool hide_tris)
{
BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
@@ -247,7 +247,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0;
/* mesh sync */
object->mesh = sync_mesh(b_ob, object_updated);
object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
/* sspecial case not tracked by object update flags */
if(use_holdout != object->use_holdout) {
@@ -390,7 +390,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
/* sync object and mesh or light data */
Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion);
Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion, false);
/* sync possible particle data, note particle_id
* starts counting at 1, first is dummy particle */
@@ -412,9 +412,23 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
/* check if we should render or hide particle emitter */
BL::Object::particle_systems_iterator b_psys;
for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
if(b_psys->settings().use_render_emitter())
bool hair_present = false;
bool show_emitter = false;
bool hide_tris = false;
for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) {
if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR))
hair_present = true;
if(b_psys->settings().use_render_emitter()) {
hide = false;
show_emitter = true;
}
}
if(hair_present && !show_emitter)
hide_tris = true;
/* hide original object for duplis */
BL::Object parent = b_ob->parent();
@@ -424,7 +438,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
if(!hide) {
/* object itself */
Transform tfm = get_transform(b_ob->matrix_world());
sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion);
sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion, hide_tris);
}
}

View File

@@ -96,7 +96,7 @@ void BlenderSession::create_session()
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
/* create sync */
sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, session_params.device.type == DEVICE_CPU);
sync->sync_data(b_v3d, b_engine.camera_override());
if(b_rv3d)
@@ -107,6 +107,8 @@ void BlenderSession::create_session()
/* set buffer parameters */
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_v3d, b_rv3d, scene->camera, width, height);
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
}
void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
@@ -143,12 +145,14 @@ void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
session->stats.mem_peak = session->stats.mem_used;
/* sync object should be re-created */
sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, session_params.device.type == DEVICE_CPU);
sync->sync_data(b_v3d, b_engine.camera_override());
sync->sync_camera(b_engine.camera_override(), width, height);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, PointerRNA_NULL, PointerRNA_NULL, scene->camera, width, height);
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
}
void BlenderSession::free_session()
@@ -252,7 +256,15 @@ void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_upda
if (do_update_only) {
/* update only needed */
if (rtile.sample != 0) {
/* sample would be zero at initial tile update, which is only needed
* to tag tile form blender side as IN PROGRESS for proper highlight
* no buffers should be sent to blender yet
*/
update_render_result(b_rr, b_rlay, rtile);
}
end_render_result(b_engine, b_rr, true);
}
else {

View File

@@ -447,6 +447,10 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
node = new ParticleInfoNode();
break;
}
case BL::ShaderNode::type_HAIR_INFO: {
node = new HairInfoNode();
break;
}
case BL::ShaderNode::type_BUMP: {
node = new BumpNode();
break;

View File

@@ -28,6 +28,7 @@
#include "object.h"
#include "scene.h"
#include "shader.h"
#include "curves.h"
#include "device.h"
@@ -41,7 +42,7 @@ CCL_NAMESPACE_BEGIN
/* Constructor */
BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_, Progress &progress_)
BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_, Progress &progress_, bool is_cpu_)
: b_engine(b_engine_),
b_data(b_data_), b_scene(b_scene_),
shader_map(&scene_->shaders),
@@ -56,6 +57,7 @@ BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::
{
scene = scene_;
preview = preview_;
is_cpu = is_cpu_;
}
BlenderSync::~BlenderSync()
@@ -141,6 +143,7 @@ void BlenderSync::sync_data(BL::SpaceView3D b_v3d, BL::Object b_override, const
sync_integrator();
sync_film();
sync_shaders();
sync_curve_settings();
sync_objects(b_v3d);
sync_motion(b_v3d, b_override);
}

View File

@@ -50,7 +50,7 @@ class ShaderNode;
class BlenderSync {
public:
BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_, Progress &progress_);
BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_, Progress &progress_, bool is_cpu_);
~BlenderSync();
/* sync */
@@ -78,10 +78,12 @@ private:
void sync_world(bool update_all);
void sync_render_layers(BL::SpaceView3D b_v3d, const char *layer);
void sync_shaders();
void sync_curve_settings();
void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
Mesh *sync_mesh(BL::Object b_ob, bool object_updated);
Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_object, Transform& tfm, uint layer_flag, int motion);
Mesh *sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris);
void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool object_updated);
Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_object, Transform& tfm, uint layer_flag, int motion, bool hide_tris);
void sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm);
void sync_background_light();
void sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion);
@@ -113,6 +115,7 @@ private:
Scene *scene;
bool preview;
bool experimental;
bool is_cpu;
struct RenderLayerInfo {
RenderLayerInfo()

View File

@@ -242,6 +242,20 @@ static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, co
return path;
}
/* Texture Space */
static inline void mesh_texture_space(BL::Mesh b_mesh, float3& loc, float3& size)
{
loc = get_float3(b_mesh.texspace_location());
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);
}
/* ID Map
*
* Utility class to keep in sync with blender data.

View File

@@ -75,6 +75,8 @@ bool BVH::cache_read(CacheData& key)
foreach(Object *ob, objects) {
key.add(ob->mesh->verts);
key.add(ob->mesh->triangles);
key.add(ob->mesh->curve_keys);
key.add(ob->mesh->curves);
key.add(&ob->bounds, sizeof(ob->bounds));
key.add(&ob->visibility, sizeof(ob->visibility));
key.add(&ob->mesh->transform_applied, sizeof(bool));
@@ -91,6 +93,7 @@ bool BVH::cache_read(CacheData& key)
value.read(pack.nodes);
value.read(pack.object_node);
value.read(pack.tri_woop);
value.read(pack.prim_segment);
value.read(pack.prim_visibility);
value.read(pack.prim_index);
value.read(pack.prim_object);
@@ -112,6 +115,7 @@ void BVH::cache_write(CacheData& key)
value.add(pack.nodes);
value.add(pack.object_node);
value.add(pack.tri_woop);
value.add(pack.prim_segment);
value.add(pack.prim_visibility);
value.add(pack.prim_index);
value.add(pack.prim_object);
@@ -157,10 +161,11 @@ void BVH::build(Progress& progress)
}
/* build nodes */
vector<int> prim_segment;
vector<int> prim_index;
vector<int> prim_object;
BVHBuild bvh_build(objects, prim_index, prim_object, params, progress);
BVHBuild bvh_build(objects, prim_segment, prim_index, prim_object, params, progress);
BVHNode *root = bvh_build.run();
if(progress.get_cancel()) {
@@ -169,6 +174,7 @@ void BVH::build(Progress& progress)
}
/* todo: get rid of this copy */
pack.prim_segment = prim_segment;
pack.prim_index = prim_index;
pack.prim_object = prim_object;
@@ -182,8 +188,8 @@ void BVH::build(Progress& progress)
}
/* pack triangles */
progress.set_substatus("Packing BVH triangles");
pack_triangles();
progress.set_substatus("Packing BVH triangles and strands");
pack_primitives();
if(progress.get_cancel()) {
root->deleteSubtree();
@@ -215,8 +221,8 @@ void BVH::build(Progress& progress)
void BVH::refit(Progress& progress)
{
progress.set_substatus("Packing BVH triangles");
pack_triangles();
progress.set_substatus("Packing BVH primitives");
pack_primitives();
if(progress.get_cancel()) return;
@@ -263,7 +269,52 @@ void BVH::pack_triangle(int idx, float4 woop[3])
}
}
void BVH::pack_triangles()
/* Curves*/
void BVH::pack_curve_segment(int idx, float4 woop[3])
{
int tob = pack.prim_object[idx];
const Mesh *mesh = objects[tob]->mesh;
int tidx = pack.prim_index[idx];
int segment = pack.prim_segment[idx];
int k0 = mesh->curves[tidx].first_key + segment;
int k1 = mesh->curves[tidx].first_key + segment + 1;
float3 v0 = mesh->curve_keys[k0].co;
float3 v1 = mesh->curve_keys[k1].co;
float3 d0 = v1 - v0;
float l = len(d0);
/*Plan
*Transform tfm = make_transform(
* location <3> , l,
* extra curve data <3> , StrID,
* nextkey, flags/tip?, 0, 0);
*/
Attribute *attr_tangent = mesh->curve_attributes.find(ATTR_STD_CURVE_TANGENT);
float3 tg0 = make_float3(1.0f, 0.0f, 0.0f);
float3 tg1 = make_float3(1.0f, 0.0f, 0.0f);
if(attr_tangent) {
const float3 *data_tangent = attr_tangent->data_float3();
tg0 = data_tangent[k0];
tg1 = data_tangent[k1];
}
Transform tfm = make_transform(
tg0.x, tg0.y, tg0.z, l,
tg1.x, tg1.y, tg1.z, 0,
0, 0, 0, 0,
0, 0, 0, 1);
woop[0] = tfm.x;
woop[1] = tfm.y;
woop[2] = tfm.z;
}
void BVH::pack_primitives()
{
int nsize = TRI_NODE_SIZE;
size_t tidx_size = pack.prim_index.size();
@@ -277,7 +328,11 @@ void BVH::pack_triangles()
if(pack.prim_index[i] != -1) {
float4 woop[3];
if(pack.prim_segment[i] != ~0)
pack_curve_segment(i, woop);
else
pack_triangle(i, woop);
memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
int tob = pack.prim_object[i];
@@ -300,11 +355,15 @@ void BVH::pack_instances(size_t nodes_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)
if(pack.prim_index[i] != -1) {
if(pack.prim_segment[i] != ~0)
pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset;
else
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 prim_offset = pack.prim_index.size();
size_t nodes_offset = nodes_size;
/* clear array that gives the node indexes for instanced objects */
@@ -339,6 +398,7 @@ void BVH::pack_instances(size_t nodes_size)
mesh_map.clear();
pack.prim_index.resize(prim_index_size);
pack.prim_segment.resize(prim_index_size);
pack.prim_object.resize(prim_index_size);
pack.prim_visibility.resize(prim_index_size);
pack.tri_woop.resize(tri_woop_size);
@@ -346,6 +406,7 @@ void BVH::pack_instances(size_t nodes_size)
pack.object_node.resize(objects.size());
int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL;
int *pack_prim_segment = (pack.prim_segment.size())? &pack.prim_segment[0]: NULL;
int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL;
float4 *pack_tri_woop = (pack.tri_woop.size())? &pack.tri_woop[0]: NULL;
@@ -376,6 +437,7 @@ void BVH::pack_instances(size_t nodes_size)
int noffset = nodes_offset/nsize;
int mesh_tri_offset = mesh->tri_offset;
int mesh_curve_offset = mesh->curve_offset;
/* fill in node indexes for instances */
if((bvh->pack.is_leaf.size() != 0) && bvh->pack.is_leaf[0])
@@ -389,10 +451,16 @@ void BVH::pack_instances(size_t nodes_size)
if(bvh->pack.prim_index.size()) {
size_t bvh_prim_index_size = bvh->pack.prim_index.size();
int *bvh_prim_index = &bvh->pack.prim_index[0];
int *bvh_prim_segment = &bvh->pack.prim_segment[0];
uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
for(size_t i = 0; i < bvh_prim_index_size; i++) {
if(bvh->pack.prim_segment[i] != ~0)
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
else
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
pack_prim_segment[pack_prim_index_offset] = bvh_prim_segment[i];
pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
pack_prim_index_offset++;
@@ -420,8 +488,8 @@ void BVH::pack_instances(size_t nodes_size)
int4 data = bvh_nodes[i + nsize_bbox];
if(bvh_is_leaf && bvh_is_leaf[j]) {
data.x += tri_offset;
data.y += tri_offset;
data.x += prim_offset;
data.y += prim_offset;
}
else {
data.x += (data.x < 0)? -noffset: noffset;
@@ -443,7 +511,7 @@ void BVH::pack_instances(size_t nodes_size)
}
nodes_offset += bvh->pack.nodes.size();
tri_offset += bvh->pack.prim_index.size();
prim_offset += bvh->pack.prim_index.size();
}
}
@@ -544,26 +612,39 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
if(leaf) {
/* refit leaf node */
for(int tri = c0; tri < c1; tri++) {
int tidx = pack.prim_index[tri];
int tob = pack.prim_object[tri];
for(int prim = c0; prim < c1; prim++) {
int pidx = pack.prim_index[prim];
int tob = pack.prim_object[prim];
Object *ob = objects[tob];
if(tidx == -1) {
if(pidx == -1) {
/* object instance */
bbox.grow(ob->bounds);
}
else {
/* triangles */
/* primitives */
const Mesh *mesh = ob->mesh;
if(pack.prim_segment[prim] != ~0) {
/* curves */
int str_offset = (params.top_level)? mesh->curve_offset: 0;
int k0 = mesh->curves[pidx - str_offset].first_key + pack.prim_segment[prim]; // XXX!
int k1 = k0 + 1;
bbox.grow(mesh->curve_keys[k0].co, mesh->curve_keys[k0].radius);
bbox.grow(mesh->curve_keys[k1].co, mesh->curve_keys[k1].radius);
}
else {
/* triangles */
int tri_offset = (params.top_level)? mesh->tri_offset: 0;
const int *vidx = mesh->triangles[tidx - tri_offset].v;
const int *vidx = mesh->triangles[pidx - tri_offset].v;
const float3 *vpos = &mesh->verts[0];
bbox.grow(vpos[vidx[0]]);
bbox.grow(vpos[vidx[1]]);
bbox.grow(vpos[vidx[2]]);
}
}
visibility |= ob->visibility;
}

View File

@@ -52,6 +52,8 @@ struct PackedBVH {
array<int> object_node;
/* precomputed triangle intersection data, one triangle is 4x float4 */
array<float4> tri_woop;
/* primitive type - triangle or strand (should be moved to flag?) */
array<int> prim_segment;
/* visibility visibilitys for primitives */
array<uint> prim_visibility;
/* mapping from BVH primitive index to true primitive index, as primitives
@@ -101,9 +103,10 @@ protected:
bool cache_read(CacheData& key);
void cache_write(CacheData& key);
/* triangles */
void pack_triangles();
/* triangles and strands*/
void pack_primitives();
void pack_triangle(int idx, float4 woop[3]);
void pack_curve_segment(int idx, float4 woop[3]);
/* merge instance BVH's */
void pack_instances(size_t nodes_size);

View File

@@ -48,9 +48,10 @@ public:
/* Constructor / Destructor */
BVHBuild::BVHBuild(const vector<Object*>& objects_,
vector<int>& prim_index_, vector<int>& prim_object_,
vector<int>& prim_segment_, vector<int>& prim_index_, vector<int>& prim_object_,
const BVHParams& params_, Progress& progress_)
: objects(objects_),
prim_segment(prim_segment_),
prim_index(prim_index_),
prim_object(prim_object_),
params(params_),
@@ -73,25 +74,55 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh,
BoundBox bounds = BoundBox::empty;
for(int k = 0; k < 3; k++) {
float3 pt = mesh->verts[t.v[k]];
bounds.grow(pt);
float3 co = mesh->verts[t.v[k]];
bounds.grow(co);
}
if(bounds.valid()) {
references.push_back(BVHReference(bounds, j, i));
references.push_back(BVHReference(bounds, j, i, ~0));
root.grow(bounds);
center.grow(bounds.center2());
}
}
for(uint j = 0; j < mesh->curves.size(); j++) {
Mesh::Curve curve = mesh->curves[j];
for(int k = 0; k < curve.num_keys - 1; k++) {
BoundBox bounds = BoundBox::empty;
float3 co0 = mesh->curve_keys[curve.first_key + k].co;
float3 co1 = mesh->curve_keys[curve.first_key + k + 1].co;
bounds.grow(co0, mesh->curve_keys[curve.first_key + k].radius);
bounds.grow(co1, mesh->curve_keys[curve.first_key + k + 1].radius);
if(bounds.valid()) {
references.push_back(BVHReference(bounds, j, i, k));
root.grow(bounds);
center.grow(bounds.center2());
}
}
}
}
void BVHBuild::add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i)
{
references.push_back(BVHReference(ob->bounds, -1, i));
references.push_back(BVHReference(ob->bounds, -1, i, false));
root.grow(ob->bounds);
center.grow(ob->bounds.center2());
}
static size_t count_curve_segments(Mesh *mesh)
{
size_t num = 0, num_curves = mesh->curves.size();
for(size_t i = 0; i < num_curves; i++)
num += mesh->curves[i].num_keys - 1;
return num;
}
void BVHBuild::add_references(BVHRange& root)
{
/* reserve space for references */
@@ -99,13 +130,17 @@ void BVHBuild::add_references(BVHRange& root)
foreach(Object *ob, objects) {
if(params.top_level) {
if(ob->mesh->transform_applied)
if(ob->mesh->transform_applied) {
num_alloc_references += ob->mesh->triangles.size();
num_alloc_references += count_curve_segments(ob->mesh);
}
else
num_alloc_references++;
}
else
else {
num_alloc_references += ob->mesh->triangles.size();
num_alloc_references += count_curve_segments(ob->mesh);
}
}
references.reserve(num_alloc_references);
@@ -162,6 +197,7 @@ BVHNode* BVHBuild::run()
progress_total = references.size();
progress_original_total = progress_total;
prim_segment.resize(references.size());
prim_index.resize(references.size());
prim_object.resize(references.size());
@@ -319,10 +355,12 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start,
if(start == prim_index.size()) {
assert(params.use_spatial_split);
prim_segment.push_back(ref->prim_segment());
prim_index.push_back(ref->prim_index());
prim_object.push_back(ref->prim_object());
}
else {
prim_segment[start] = ref->prim_segment();
prim_index[start] = ref->prim_index();
prim_object[start] = ref->prim_object();
}
@@ -345,6 +383,7 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start,
BVHNode* BVHBuild::create_leaf_node(const BVHRange& range)
{
vector<int>& p_segment = prim_segment;
vector<int>& p_index = prim_index;
vector<int>& p_object = prim_object;
BoundBox bounds = BoundBox::empty;
@@ -358,10 +397,12 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range)
if(range.start() + num == prim_index.size()) {
assert(params.use_spatial_split);
p_segment.push_back(ref.prim_segment());
p_index.push_back(ref.prim_index());
p_object.push_back(ref.prim_object());
}
else {
p_segment[range.start() + num] = ref.prim_segment();
p_index[range.start() + num] = ref.prim_index();
p_object[range.start() + num] = ref.prim_object();
}

View File

@@ -44,6 +44,7 @@ public:
/* Constructor/Destructor */
BVHBuild(
const vector<Object*>& objects,
vector<int>& prim_segment,
vector<int>& prim_index,
vector<int>& prim_object,
const BVHParams& params,
@@ -87,6 +88,7 @@ protected:
int num_original_references;
/* output primitive indexes and objects */
vector<int>& prim_segment;
vector<int>& prim_index;
vector<int>& prim_object;

View File

@@ -98,19 +98,22 @@ class BVHReference
public:
__forceinline BVHReference() {}
__forceinline BVHReference(const BoundBox& bounds_, int prim_index_, int prim_object_)
__forceinline BVHReference(const BoundBox& bounds_, int prim_index_, int prim_object_, int prim_segment)
: rbounds(bounds_)
{
rbounds.min.w = __int_as_float(prim_index_);
rbounds.max.w = __int_as_float(prim_object_);
segment = prim_segment;
}
__forceinline const BoundBox& bounds() const { return rbounds; }
__forceinline int prim_index() const { return __float_as_int(rbounds.min.w); }
__forceinline int prim_object() const { return __float_as_int(rbounds.max.w); }
__forceinline int prim_segment() const { return segment; }
protected:
BoundBox rbounds;
uint segment;
};
/* BVH Range

View File

@@ -43,6 +43,8 @@ public:
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;
else if(ra.prim_segment() < rb.prim_segment()) return true;
else if(ra.prim_segment() > rb.prim_segment()) return false;
return false;
}

View File

@@ -252,6 +252,8 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
/* loop over vertices/edges. */
Object *ob = builder->objects[ref.prim_object()];
const Mesh *mesh = ob->mesh;
if (ref.prim_segment() == ~0) {
const int *inds = mesh->triangles[ref.prim_index()].v;
const float3 *verts = &mesh->verts[0];
const float3* v1 = &verts[inds[2]];
@@ -277,6 +279,37 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
right_bounds.grow(t);
}
}
}
else {
/* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/
const int k0 = mesh->curves[ref.prim_index()].first_key + ref.prim_segment();
const int k1 = k0 + 1;
const float3* v0 = &mesh->curve_keys[k0].co;
const float3* v1 = &mesh->curve_keys[k1].co;
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);
if(v1p <= pos)
left_bounds.grow(*v1);
if(v1p >= pos)
right_bounds.grow(*v1);
/* 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;
@@ -284,9 +317,9 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH
left_bounds.intersect(ref.bounds());
right_bounds.intersect(ref.bounds());
/* set referecnes */
left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object());
right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object());
/* set references */
left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object(), ref.prim_segment());
right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_segment());
}
CCL_NAMESPACE_END

View File

@@ -84,6 +84,7 @@ public:
/* info */
DeviceInfo info;
virtual const string& error_message() { return error_msg; }
bool have_error() { return !error_message().empty(); }
/* statistics */
Stats &stats;

View File

@@ -124,7 +124,7 @@ public:
if(error_msg == "") \
error_msg = message; \
fprintf(stderr, "%s\n", message.c_str()); \
cuda_abort(); \
/*cuda_abort();*/ \
} \
}
@@ -326,6 +326,7 @@ public:
void mem_copy_to(device_memory& mem)
{
cuda_push_context();
if(mem.device_pointer)
cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size()))
cuda_pop_context();
}
@@ -336,8 +337,13 @@ public:
size_t size = elem*w*h;
cuda_push_context();
if(mem.device_pointer) {
cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset,
(CUdeviceptr)((uchar*)mem.device_pointer + offset), size))
}
else {
memset((char*)mem.data_pointer + offset, 0, size);
}
cuda_pop_context();
}
@@ -346,6 +352,7 @@ public:
memset((void*)mem.data_pointer, 0, mem.memory_size());
cuda_push_context();
if(mem.device_pointer)
cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size()))
cuda_pop_context();
}
@@ -390,13 +397,18 @@ public:
default: assert(0); return;
}
CUtexref texref;
CUtexref texref = NULL;
cuda_push_context();
cuda_assert(cuModuleGetTexRef(&texref, cuModule, name))
if(!texref) {
cuda_pop_context();
return;
}
if(interpolation) {
CUarray handle;
CUarray handle = NULL;
CUDA_ARRAY_DESCRIPTOR desc;
desc.Width = mem.data_width;
@@ -406,6 +418,11 @@ public:
cuda_assert(cuArrayCreate(&handle, &desc))
if(!handle) {
cuda_pop_context();
return;
}
if(mem.data_height > 1) {
CUDA_MEMCPY2D param;
memset(&param, 0, sizeof(param));
@@ -481,6 +498,9 @@ public:
void path_trace(RenderTile& rtile, int sample)
{
if(have_error())
return;
cuda_push_context();
CUfunction cuPathTrace;
@@ -546,6 +566,9 @@ public:
void tonemap(DeviceTask& task, device_ptr buffer, device_ptr rgba)
{
if(have_error())
return;
cuda_push_context();
CUfunction cuFilmConvert;
@@ -615,6 +638,9 @@ public:
void shader(DeviceTask& task)
{
if(have_error())
return;
cuda_push_context();
CUfunction cuDisplace;

View File

@@ -20,12 +20,12 @@ set(SRC
set(SRC_HEADERS
kernel.h
kernel_accumulate.h
kernel_attribute.h
kernel_bvh.h
kernel_camera.h
kernel_compat_cpu.h
kernel_compat_cuda.h
kernel_compat_opencl.h
kernel_curve.h
kernel_differential.h
kernel_displace.h
kernel_emission.h
@@ -37,6 +37,7 @@ set(SRC_HEADERS
kernel_object.h
kernel_passes.h
kernel_path.h
kernel_primitive.h
kernel_projection.h
kernel_random.h
kernel_shader.h

View File

@@ -1,50 +0,0 @@
/*
* 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_ATTRIBUTE_CL__
#define __KERNEL_ATTRIBUTE_CL__
CCL_NAMESPACE_BEGIN
/* note: declared in kernel.h, have to add it here because kernel.h is not available */
bool kernel_osl_use(KernelGlobals *kg);
__device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id)
{
#ifdef __OSL__
if (kg->osl) {
return OSLShader::find_attribute(kg, sd, id);
}
else
#endif
{
/* for SVM, find attribute by unique id */
uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
while(attr_map.x != id)
attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset);
/* return result */
return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
}
}
CCL_NAMESPACE_END
#endif /* __KERNEL_ATTRIBUTE_CL__ */

View File

@@ -205,6 +205,145 @@ __device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *ise
}
}
#ifdef __HAIR__
__device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment)
{
/* curve Intersection check */
int flags = kernel_data.curve_kernel_data.curveflags;
int prim = kernel_tex_fetch(__prim_index, curveAddr);
float4 v00 = kernel_tex_fetch(__curves, prim);
int k0 = __float_as_int(v00.x) + segment;
int k1 = k0 + 1;
float4 P1 = kernel_tex_fetch(__curve_keys, k0);
float4 P2 = kernel_tex_fetch(__curve_keys, k1);
float l = len(P2 - P1);
float r1 = P1.w;
float r2 = P2.w;
float mr = max(r1,r2);
float3 p1 = float4_to_float3(P1);
float3 p2 = float4_to_float3(P2);
float3 dif = P - p1;
float3 dir = 1.0f/idir;
float sp_r = mr + 0.5f * l;
float3 sphere_dif = P - ((p1 + p2) * 0.5f);
float sphere_b = dot(dir,sphere_dif);
sphere_dif = sphere_dif - sphere_b * dir;
sphere_b = dot(dir,sphere_dif);
float sdisc = sphere_b * sphere_b - len_squared(sphere_dif) + sp_r * sp_r;
if(sdisc < 0.0f)
return;
/* obtain parameters and test midpoint distance for suitable modes*/
float3 tg = (p2 - p1) / l;
float gd = (r2 - r1) / l;
float dirz = dot(dir,tg);
float difz = dot(dif,tg);
float a = 1.0f - (dirz*dirz*(1 + gd*gd));
float halfb = (dot(dir,dif) - dirz*(difz + gd*(difz*gd + r1)));
float tcentre = -halfb/a;
float zcentre = difz + (dirz * tcentre);
if((tcentre > isect->t) && !(flags & CURVE_KN_ACCURATE))
return;
if((zcentre < 0 || zcentre > l) && !(flags & CURVE_KN_ACCURATE) && !(flags & CURVE_KN_INTERSECTCORRECTION))
return;
/* test minimum separation*/
float3 cprod = cross(tg, dir);
float3 cprod2 = cross(tg, dif);
float cprodsq = len_squared(cprod);
float cprod2sq = len_squared(cprod2);
float distscaled = dot(cprod,dif);
if(cprodsq == 0)
distscaled = cprod2sq;
else
distscaled = (distscaled*distscaled)/cprodsq;
if(distscaled > mr*mr)
return;
/* calculate true intersection*/
float3 tdif = P - p1 + tcentre * dir;
float tdifz = dot(tdif,tg);
float tb = 2*(dot(dir,tdif) - dirz*(tdifz + gd*(tdifz*gd + r1)));
float tc = dot(tdif,tdif) - tdifz * tdifz * (1 + gd*gd) - r1*r1 - 2*r1*tdifz*gd;
float td = tb*tb - 4*a*tc;
if (td < 0.0f)
return;
float rootd = 0.0f;
float correction = 0.0f;
if(flags & CURVE_KN_ACCURATE) {
rootd = sqrtf(td);
correction = ((-tb - rootd)/(2*a));
}
float t = tcentre + correction;
if(t < isect->t) {
if(flags & CURVE_KN_INTERSECTCORRECTION) {
rootd = sqrtf(td);
correction = ((-tb - rootd)/(2*a));
t = tcentre + correction;
}
float z = zcentre + (dirz * correction);
bool backface = false;
if(flags & CURVE_KN_BACKFACING && (t < 0.0f || z < 0 || z > l)) {
backface = true;
correction = ((-tb + rootd)/(2*a));
t = tcentre + correction;
z = zcentre + (dirz * correction);
}
if(t > 0.0f && t < isect->t && z >= 0 && z <= l) {
if (flags & CURVE_KN_ENCLOSEFILTER) {
float enc_ratio = kernel_data.curve_kernel_data.encasing_ratio;
if((dot(P - p1, tg) > -r1 * enc_ratio) && (dot(P - p2, tg) < r2 * enc_ratio)) {
float a2 = 1.0f - (dirz*dirz*(1 + gd*gd*enc_ratio*enc_ratio));
float c2 = dot(dif,dif) - difz * difz * (1 + gd*gd*enc_ratio*enc_ratio) - r1*r1*enc_ratio*enc_ratio - 2*r1*difz*gd*enc_ratio;
if(a2*c2 < 0.0f)
return;
}
}
#ifdef __VISIBILITY_FLAG__
/* visibility flag test. we do it here under the assumption
* that most triangles are culled by node flags */
if(kernel_tex_fetch(__prim_visibility, curveAddr) & visibility)
#endif
{
/* record intersection */
isect->prim = curveAddr;
isect->segment = segment;
isect->object = object;
isect->u = z/l;
isect->v = td/(4*a*a);
isect->t = t;
if(backface)
isect->u = -isect->u;
}
}
}
}
#endif
__device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
{
/* traversal stack in CUDA thread-local memory */
@@ -281,9 +420,15 @@ __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint
nodeAddr = traversalStack[stackPtr];
--stackPtr;
/* triangle intersection */
/* primitive intersection */
while(primAddr < primAddr2) {
/* intersect ray against triangle */
/* intersect ray against primitive */
#ifdef __HAIR__
uint segment = kernel_tex_fetch(__prim_segment, primAddr);
if(segment != ~0)
bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
else
#endif
bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
/* shadow ray early termination */
@@ -401,9 +546,15 @@ __device_inline bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, con
nodeAddr = traversalStack[stackPtr];
--stackPtr;
/* triangle intersection */
/* primitive intersection */
while(primAddr < primAddr2) {
/* intersect ray against triangle */
/* intersect ray against primitive */
#ifdef __HAIR__
uint segment = kernel_tex_fetch(__prim_segment, primAddr);
if(segment != ~0)
bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
else
#endif
bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
/* shadow ray early termination */
@@ -457,12 +608,15 @@ __device_inline float3 ray_offset(float3 P, float3 Ng)
{
#ifdef __INTERSECTION_REFINE__
const float epsilon_f = 1e-5f;
/* ideally this should match epsilon_f, but instancing/mblur
* precision makes it problematic */
const float epsilon_test = 1e-1f;
const int epsilon_i = 32;
float3 res;
/* x component */
if(fabsf(P.x) < epsilon_f) {
if(fabsf(P.x) < epsilon_test) {
res.x = P.x + Ng.x*epsilon_f;
}
else {
@@ -472,7 +626,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng)
}
/* y component */
if(fabsf(P.y) < epsilon_f) {
if(fabsf(P.y) < epsilon_test) {
res.y = P.y + Ng.y*epsilon_f;
}
else {
@@ -482,7 +636,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng)
}
/* z component */
if(fabsf(P.z) < epsilon_f) {
if(fabsf(P.z) < epsilon_test) {
res.z = P.z + Ng.z*epsilon_f;
}
else {
@@ -542,5 +696,105 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, co
#endif
}
#ifdef __HAIR__
__device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float t)
{
int flag = kernel_data.curve_kernel_data.curveflags;
float3 P = ray->P;
float3 D = ray->D;
if(isect->object != ~0) {
#ifdef __OBJECT_MOTION__
Transform tfm = sd->ob_itfm;
#else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
#endif
P = transform_point(&tfm, P);
D = transform_direction(&tfm, D*t);
D = normalize_len(D, &t);
}
int prim = kernel_tex_fetch(__prim_index, isect->prim);
float4 v00 = kernel_tex_fetch(__curves, prim);
int k0 = __float_as_int(v00.x) + isect->segment;
int k1 = k0 + 1;
float4 P1 = kernel_tex_fetch(__curve_keys, k0);
float4 P2 = kernel_tex_fetch(__curve_keys, k1);
float l = len(P2 - P1);
float r1 = P1.w;
float r2 = P2.w;
float3 tg = float4_to_float3(P2 - P1) / l;
float3 dif = P - float4_to_float3(P1) + t * D;
float gd = ((r2 - r1)/l);
P = P + D*t;
dif = P - float4_to_float3(P1);
#ifdef __UV__
sd->u = dot(dif,tg)/l;
sd->v = 0.0f;
#endif
if (flag & CURVE_KN_TRUETANGENTGNORMAL) {
sd->Ng = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
sd->Ng = normalize(sd->Ng);
if (flag & CURVE_KN_NORMALCORRECTION)
{
//sd->Ng = normalize(sd->Ng);
sd->Ng = sd->Ng - gd * tg;
sd->Ng = normalize(sd->Ng);
}
}
else {
sd->Ng = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
if (gd != 0.0f) {
sd->Ng = sd->Ng - gd * tg ;
sd->Ng = normalize(sd->Ng);
}
}
sd->N = sd->Ng;
if (flag & CURVE_KN_TANGENTGNORMAL && !(flag & CURVE_KN_TRUETANGENTGNORMAL)) {
sd->N = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
sd->N = normalize(sd->N);
if (flag & CURVE_KN_NORMALCORRECTION) {
//sd->N = normalize(sd->N);
sd->N = sd->N - gd * tg;
sd->N = normalize(sd->N);
}
}
if (!(flag & CURVE_KN_TANGENTGNORMAL) && flag & CURVE_KN_TRUETANGENTGNORMAL) {
sd->N = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
if (gd != 0.0f) {
sd->N = sd->N - gd * tg ;
sd->N = normalize(sd->N);
}
}
#ifdef __DPDU__
/* dPdu/dPdv */
sd->dPdu = tg;
sd->dPdv = cross(tg,sd->Ng);
#endif
if(isect->object != ~0) {
#ifdef __OBJECT_MOTION__
Transform tfm = sd->ob_tfm;
#else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
#endif
P = transform_point(&tfm, P);
}
return P;
}
#endif
CCL_NAMESPACE_END

View File

@@ -0,0 +1,141 @@
/*
* 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
#ifdef __HAIR__
/* curve attributes */
__device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
{
if(elem == ATTR_ELEMENT_CURVE) {
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = 0.0f;
if(dy) *dy = 0.0f;
#endif
return kernel_tex_fetch(__attributes_float, offset + sd->prim);
}
else if(elem == ATTR_ELEMENT_CURVE_KEY) {
float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
int k0 = __float_as_int(curvedata.x) + sd->segment;
int k1 = k0 + 1;
float f0 = kernel_tex_fetch(__attributes_float, offset + k0);
float f1 = kernel_tex_fetch(__attributes_float, offset + k1);
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = sd->du.dx*(f1 - f0);
if(dy) *dy = 0.0f;
#endif
return (1.0f - sd->u)*f0 + sd->u*f1;
}
else {
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = 0.0f;
if(dy) *dy = 0.0f;
#endif
return 0.0f;
}
}
__device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
{
if(elem == ATTR_ELEMENT_CURVE) {
/* idea: we can't derive any useful differentials here, but for tiled
* mipmap image caching it would be useful to avoid reading the highest
* detail level always. maybe a derivative based on the hair density
* could be computed somehow? */
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
#endif
return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim));
}
else if(elem == ATTR_ELEMENT_CURVE_KEY) {
float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
int k0 = __float_as_int(curvedata.x) + sd->segment;
int k1 = k0 + 1;
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k0));
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k1));
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = sd->du.dx*(f1 - f0);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
#endif
return (1.0f - sd->u)*f0 + sd->u*f1;
}
else {
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
#endif
return make_float3(0.0f, 0.0f, 0.0f);
}
}
/* hair info node functions */
__device float curve_thickness(KernelGlobals *kg, ShaderData *sd)
{
float r = 0.0f;
if(sd->segment != ~0) {
float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
int k0 = __float_as_int(curvedata.x) + sd->segment;
int k1 = k0 + 1;
float4 P1 = kernel_tex_fetch(__curve_keys, k0);
float4 P2 = kernel_tex_fetch(__curve_keys, k1);
r = (P2.w - P1.w) * sd->u + P1.w;
}
return r*2.0f;
}
__device float3 curve_tangent_normal(KernelGlobals *kg, ShaderData *sd)
{
float3 tgN = make_float3(0.0f,0.0f,0.0f);
if(sd->segment != ~0) {
float normalmix = kernel_data.curve_kernel_data.normalmix;
tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu,-sd->I) * normalmix / len_squared(sd->dPdu)));
tgN = normalize(tgN);
/* need to find suitable scaled gd for corrected normal */
#if 0
if (kernel_data.curve_kernel_data.use_tangent_normal_correction)
tgN = normalize(tgN - gd * sd->dPdu);
#endif
}
return tgN;
}
#endif
CCL_NAMESPACE_END

View File

@@ -47,7 +47,13 @@ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
else
#endif
{
#ifdef __HAIR__
if(ls->type == LIGHT_STRAND)
shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, ls->prim);
else
#endif
shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time);
ls->Ng = sd.Ng;
/* no path flag, we're evaluating this for all closures. that's weak but
@@ -150,7 +156,11 @@ __device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, in
/* evaluate emissive closure */
float3 L = shader_emissive_eval(kg, sd);
#ifdef __HAIR__
if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT) && (sd->segment == ~0)) {
#else
if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT)) {
#endif
/* multiple importance sampling, get triangle light pdf,
* and compute weight with respect to BSDF pdf */
float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t);

View File

@@ -326,6 +326,61 @@ __device float triangle_light_pdf(KernelGlobals *kg,
return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi;
}
#ifdef __HAIR__
/* Strand Light */
__device void curve_segment_light_sample(KernelGlobals *kg, int prim, int object,
int segment, float randu, float randv, float time, LightSample *ls)
{
/* this strand code needs completion */
float4 v00 = kernel_tex_fetch(__curves, prim);
int k0 = __float_as_int(v00.x) + segment;
int k1 = k0 + 1;
float4 P1 = kernel_tex_fetch(__curve_keys, k0);
float4 P2 = kernel_tex_fetch(__curve_keys, k1);
float l = len(P2 - P1);
float r1 = P1.w;
float r2 = P2.w;
float3 tg = float4_to_float3(P2 - P1) / l;
float3 xc = make_float3(tg.x * tg.z, tg.y * tg.z, -(tg.x * tg.x + tg.y * tg.y));
if (dot(xc, xc) == 0.0f)
xc = make_float3(tg.x * tg.y, -(tg.x * tg.x + tg.z * tg.z), tg.z * tg.y);
xc = normalize(xc);
float3 yc = cross(tg, xc);
float gd = ((r2 - r1)/l);
/* normal currently ignores gradient */
ls->Ng = sinf(2 * M_PI_F * randv) * xc + cosf(2 * M_PI_F * randv) * yc;
ls->P = randu * l * tg + (gd * l + r1) * ls->Ng;
ls->object = object;
ls->prim = prim;
ls->t = 0.0f;
ls->type = LIGHT_STRAND;
ls->eval_fac = 1.0f;
ls->shader = __float_as_int(v00.z);
#ifdef __INSTANCING__
/* instance transform */
if(ls->object >= 0) {
#ifdef __OBJECT_MOTION__
Transform itfm;
Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm);
#else
Transform tfm = object_fetch_transform(kg, ls->object, OBJECT_TRANSFORM);
Transform itfm = object_fetch_transform(kg, ls->object, OBJECT_INVERSE_TRANSFORM);
#endif
ls->P = transform_point(&tfm, ls->P);
ls->Ng = normalize(transform_direction(&tfm, ls->Ng));
}
#endif
}
#endif
/* Light Distribution */
__device int light_distribution_sample(KernelGlobals *kg, float randt)
@@ -365,9 +420,18 @@ __device void light_sample(KernelGlobals *kg, float randt, float randu, float ra
/* fetch light data */
float4 l = kernel_tex_fetch(__light_distribution, index);
int prim = __float_as_int(l.y);
#ifdef __HAIR__
int segment = __float_as_int(l.z);
#endif
if(prim >= 0) {
int object = __float_as_int(l.w);
#ifdef __HAIR__
if (segment != ~0)
curve_segment_light_sample(kg, prim, object, segment, randu, randv, time, ls);
else
#endif
triangle_light_sample(kg, prim, object, randu, randv, time, ls);
}
else {

View File

@@ -70,11 +70,11 @@ __device_inline void kernel_write_data_passes(KernelGlobals *kg, __global float
kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, sample, normal);
}
if(flag & PASS_UV) {
float3 uv = triangle_uv(kg, sd);
float3 uv = primitive_uv(kg, sd);
kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, sample, uv);
}
if(flag & PASS_MOTION) {
float4 speed = triangle_motion_vector(kg, sd);
float4 speed = primitive_motion_vector(kg, sd);
kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, sample, speed);
kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, sample, 1.0f);
}

View File

@@ -24,9 +24,10 @@
#include "kernel_montecarlo.h"
#include "kernel_projection.h"
#include "kernel_object.h"
#include "kernel_attribute.h"
#include "kernel_projection.h"
#include "kernel_triangle.h"
#include "kernel_curve.h"
#include "kernel_primitive.h"
#include "kernel_projection.h"
#ifdef __QBVH__
#include "kernel_qbvh.h"
#else

View File

@@ -0,0 +1,185 @@
/*
* 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_ATTRIBUTE_CL__
#define __KERNEL_ATTRIBUTE_CL__
CCL_NAMESPACE_BEGIN
/* attribute lookup */
__device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id, AttributeElement *elem)
{
if(sd->object == ~0)
return (int)ATTR_STD_NOT_FOUND;
#ifdef __OSL__
if (kg->osl) {
return OSLShader::find_attribute(kg, sd, id, elem);
}
else
#endif
{
/* for SVM, find attribute by unique id */
uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
#ifdef __HAIR__
attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE;
#endif
uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
while(attr_map.x != id) {
attr_offset += ATTR_PRIM_TYPES;
attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
}
*elem = (AttributeElement)attr_map.y;
/* return result */
return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
}
}
__device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
{
#ifdef __HAIR__
if(sd->segment == ~0)
#endif
return triangle_attribute_float(kg, sd, elem, offset, dx, dy);
#ifdef __HAIR__
else
return curve_attribute_float(kg, sd, elem, offset, dx, dy);
#endif
}
__device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
{
#ifdef __HAIR__
if(sd->segment == ~0)
#endif
return triangle_attribute_float3(kg, sd, elem, offset, dx, dy);
#ifdef __HAIR__
else
return curve_attribute_float3(kg, sd, elem, offset, dx, dy);
#endif
}
__device float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
{
AttributeElement elem_uv;
int offset_uv = find_attribute(kg, sd, ATTR_STD_UV, &elem_uv);
if(offset_uv == ATTR_STD_NOT_FOUND)
return make_float3(0.0f, 0.0f, 0.0f);
float3 uv = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL);
uv.z = 1.0f;
return uv;
}
__device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
{
#ifdef __HAIR__
if(sd->segment != ~0)
return normalize(sd->dPdu);
#endif
/* try to create spherical tangent from generated coordinates */
AttributeElement attr_elem;
int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED, &attr_elem);
if(attr_offset != ATTR_STD_NOT_FOUND) {
float3 data = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
object_normal_transform(kg, sd, &data);
return cross(sd->N, normalize(cross(data, sd->N)));;
}
else {
/* otherwise use surface derivatives */
return normalize(sd->dPdu);
}
}
/* motion */
__device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
{
float3 motion_pre = sd->P, motion_post = sd->P;
/* deformation motion */
AttributeElement elem_pre, elem_post;
int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE, &elem_pre);
int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST, &elem_post);
if(offset_pre != ATTR_STD_NOT_FOUND)
motion_pre = primitive_attribute_float3(kg, sd, elem_pre, offset_pre, NULL, NULL);
if(offset_post != ATTR_STD_NOT_FOUND)
motion_post = primitive_attribute_float3(kg, sd, elem_post, offset_post, NULL, NULL);
/* object motion. note that depending on the mesh having motion vectors, this
* transformation was set match the world/object space of motion_pre/post */
Transform tfm;
tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
motion_pre = transform_point(&tfm, motion_pre);
tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
motion_post = transform_point(&tfm, motion_post);
float3 P;
/* camera motion, for perspective/orthographic motion.pre/post will be a
* world-to-raster matrix, for panorama it's world-to-camera */
if (kernel_data.cam.type != CAMERA_PANORAMA) {
tfm = kernel_data.cam.worldtoraster;
P = transform_perspective(&tfm, sd->P);
tfm = kernel_data.cam.motion.pre;
motion_pre = transform_perspective(&tfm, motion_pre);
tfm = kernel_data.cam.motion.post;
motion_post = transform_perspective(&tfm, motion_post);
}
else {
tfm = kernel_data.cam.worldtocamera;
P = normalize(transform_point(&tfm, sd->P));
P = float2_to_float3(direction_to_panorama(kg, P));
P.x *= kernel_data.cam.width;
P.y *= kernel_data.cam.height;
tfm = kernel_data.cam.motion.pre;
motion_pre = normalize(transform_point(&tfm, motion_pre));
motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre));
motion_pre.x *= kernel_data.cam.width;
motion_pre.y *= kernel_data.cam.height;
tfm = kernel_data.cam.motion.post;
motion_post = normalize(transform_point(&tfm, motion_post));
motion_post = float2_to_float3(direction_to_panorama(kg, motion_post));
motion_post.x *= kernel_data.cam.width;
motion_post.y *= kernel_data.cam.height;
}
motion_pre = motion_pre - P;
motion_post = P - motion_post;
return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
}
CCL_NAMESPACE_END
#endif /* __KERNEL_ATTRIBUTE_CL__ */

View File

@@ -56,24 +56,11 @@ __device_noinline void shader_setup_object_transforms(KernelGlobals *kg, ShaderD
__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);
/* triangle */
#ifdef __INSTANCING__
sd->object = (isect->object == ~0)? kernel_tex_fetch(__prim_object, isect->prim): isect->object;
#endif
sd->prim = prim;
#ifdef __UV__
sd->u = isect->u;
sd->v = isect->v;
#endif
sd->flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2);
sd->flag |= kernel_tex_fetch(__object_flag, sd->object);
sd->flag = kernel_tex_fetch(__object_flag, sd->object);
/* matrices and time */
#ifdef __OBJECT_MOTION__
@@ -81,13 +68,45 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
sd->time = ray->time;
#endif
sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
sd->ray_length = isect->t;
#ifdef __HAIR__
if(kernel_tex_fetch(__prim_segment, isect->prim) != ~0) {
/* Strand Shader setting*/
float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
sd->shader = __float_as_int(curvedata.z);
sd->segment = isect->segment;
float tcorr = isect->t;
if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_POSTINTERSECTCORRECTION) {
tcorr = (isect->u < 0)? tcorr + sqrtf(isect->v) : tcorr - sqrtf(isect->v);
sd->ray_length = tcorr;
}
sd->P = bvh_curve_refine(kg, sd, isect, ray, tcorr);
}
else {
#endif
/* fetch triangle data */
float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim);
float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
sd->shader = __float_as_int(Ns.w);
#ifdef __HAIR__
sd->segment = ~0;
#endif
#ifdef __UV__
sd->u = isect->u;
sd->v = isect->v;
#endif
/* vectors */
sd->P = bvh_triangle_refine(kg, sd, isect, ray);
sd->Ng = Ng;
sd->N = Ng;
sd->I = -ray->D;
sd->shader = shader;
sd->ray_length = isect->t;
/* smooth normal */
if(sd->shader & SHADER_SMOOTH_NORMAL)
@@ -98,6 +117,14 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
#endif
#ifdef __HAIR__
}
#endif
sd->I = -ray->D;
sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
#ifdef __INSTANCING__
if(isect->object != ~0) {
/* instance transform */
@@ -135,7 +162,7 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
__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, float t, float time)
int shader, int object, int prim, float u, float v, float t, float time, int segment = ~0)
{
/* vectors */
sd->P = P;
@@ -143,11 +170,15 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
sd->Ng = Ng;
sd->I = I;
sd->shader = shader;
#ifdef __HAIR__
sd->segment = segment;
#endif
/* primitive */
#ifdef __INSTANCING__
sd->object = object;
#endif
/* currently no access to bvh prim index for strand sd->prim - this will cause errors with needs fixing*/
sd->prim = prim;
#ifdef __UV__
sd->u = u;
@@ -183,8 +214,13 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
#endif
/* smooth normal */
#ifdef __HAIR__
if(sd->shader & SHADER_SMOOTH_NORMAL && sd->segment == ~0) {
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
#else
if(sd->shader & SHADER_SMOOTH_NORMAL) {
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
#endif
#ifdef __INSTANCING__
if(instanced)
@@ -194,10 +230,17 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
#ifdef __DPDU__
/* dPdu/dPdv */
#ifdef __HAIR__
if(sd->prim == ~0 || sd->segment != ~0) {
sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
}
#else
if(sd->prim == ~0) {
sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
}
#endif
else {
triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
@@ -279,6 +322,9 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData
sd->object = ~0;
#endif
sd->prim = ~0;
#ifdef __HAIR__
sd->segment = ~0;
#endif
#ifdef __UV__
sd->u = 0.0f;
sd->v = 0.0f;
@@ -732,8 +778,20 @@ __device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, Shader
__device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect)
{
int prim = kernel_tex_fetch(__prim_index, isect->prim);
int shader = 0;
#ifdef __HAIR__
if(kernel_tex_fetch(__prim_segment, isect->prim) == ~0) {
#endif
float4 Ns = kernel_tex_fetch(__tri_normal, prim);
int shader = __float_as_int(Ns.w);
shader = __float_as_int(Ns.w);
#ifdef __HAIR__
}
else {
float4 str = kernel_tex_fetch(__curves, prim);
shader = __float_as_int(str.z);
}
#endif
int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2);
return (flag & SD_HAS_SURFACE_TRANSPARENT) != 0;

View File

@@ -27,6 +27,7 @@
/* bvh */
KERNEL_TEX(float4, texture_float4, __bvh_nodes)
KERNEL_TEX(float4, texture_float4, __tri_woop)
KERNEL_TEX(uint, texture_uint, __prim_segment)
KERNEL_TEX(uint, texture_uint, __prim_visibility)
KERNEL_TEX(uint, texture_uint, __prim_index)
KERNEL_TEX(uint, texture_uint, __prim_object)
@@ -42,6 +43,10 @@ KERNEL_TEX(float4, texture_float4, __tri_vnormal)
KERNEL_TEX(float4, texture_float4, __tri_vindex)
KERNEL_TEX(float4, texture_float4, __tri_verts)
/* curves */
KERNEL_TEX(float4, texture_float4, __curves)
KERNEL_TEX(float4, texture_float4, __curve_keys)
/* attributes */
KERNEL_TEX(uint4, texture_uint4, __attributes_map)
KERNEL_TEX(float, texture_float, __attributes_float)

View File

@@ -190,82 +190,5 @@ __device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *s
}
}
/* motion */
__device float4 triangle_motion_vector(KernelGlobals *kg, ShaderData *sd)
{
float3 motion_pre = sd->P, motion_post = sd->P;
/* deformation motion */
int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE);
int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST);
if(offset_pre != ATTR_STD_NOT_FOUND)
motion_pre = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_pre, NULL, NULL);
if(offset_post != ATTR_STD_NOT_FOUND)
motion_post = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_post, NULL, NULL);
/* object motion. note that depending on the mesh having motion vectors, this
* transformation was set match the world/object space of motion_pre/post */
Transform tfm;
tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
motion_pre = transform_point(&tfm, motion_pre);
tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
motion_post = transform_point(&tfm, motion_post);
float3 P;
/* camera motion, for perspective/orthographic motion.pre/post will be a
* world-to-raster matrix, for panorama it's world-to-camera */
if (kernel_data.cam.type != CAMERA_PANORAMA) {
tfm = kernel_data.cam.worldtoraster;
P = transform_perspective(&tfm, sd->P);
tfm = kernel_data.cam.motion.pre;
motion_pre = transform_perspective(&tfm, motion_pre);
tfm = kernel_data.cam.motion.post;
motion_post = transform_perspective(&tfm, motion_post);
}
else {
tfm = kernel_data.cam.worldtocamera;
P = normalize(transform_point(&tfm, sd->P));
P = float2_to_float3(direction_to_panorama(kg, P));
P.x *= kernel_data.cam.width;
P.y *= kernel_data.cam.height;
tfm = kernel_data.cam.motion.pre;
motion_pre = normalize(transform_point(&tfm, motion_pre));
motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre));
motion_pre.x *= kernel_data.cam.width;
motion_pre.y *= kernel_data.cam.height;
tfm = kernel_data.cam.motion.post;
motion_post = normalize(transform_point(&tfm, motion_post));
motion_post = float2_to_float3(direction_to_panorama(kg, motion_post));
motion_post.x *= kernel_data.cam.width;
motion_post.y *= kernel_data.cam.height;
}
motion_pre = motion_pre - P;
motion_post = P - motion_post;
return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
}
__device float3 triangle_uv(KernelGlobals *kg, ShaderData *sd)
{
int offset_uv = find_attribute(kg, sd, ATTR_STD_UV);
if(offset_uv == ATTR_STD_NOT_FOUND)
return make_float3(0.0f, 0.0f, 0.0f);
float3 uv = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, offset_uv, NULL, NULL);
uv.z = 1.0f;
return uv;
}
CCL_NAMESPACE_END

View File

@@ -47,6 +47,7 @@ CCL_NAMESPACE_BEGIN
#define __OSL__
#endif
#define __NON_PROGRESSIVE__
#define __HAIR__
#endif
#ifdef __KERNEL_CUDA__
@@ -116,7 +117,6 @@ CCL_NAMESPACE_BEGIN
#define __ANISOTROPIC__
#define __OBJECT_MOTION__
#endif
//#define __SOBOL_FULL_SCREEN__
/* Shader Evaluation */
@@ -292,7 +292,8 @@ typedef enum LightType {
LIGHT_BACKGROUND,
LIGHT_AREA,
LIGHT_AO,
LIGHT_SPOT
LIGHT_SPOT,
LIGHT_STRAND
} LightType;
/* Camera Type */
@@ -343,18 +344,44 @@ typedef struct Intersection {
float t, u, v;
int prim;
int object;
int segment;
} Intersection;
/* Attributes */
#define ATTR_PRIM_TYPES 2
#define ATTR_PRIM_CURVE 1
typedef enum AttributeElement {
ATTR_ELEMENT_NONE,
ATTR_ELEMENT_VALUE,
ATTR_ELEMENT_FACE,
ATTR_ELEMENT_VERTEX,
ATTR_ELEMENT_CORNER,
ATTR_ELEMENT_VALUE,
ATTR_ELEMENT_NONE
ATTR_ELEMENT_CURVE,
ATTR_ELEMENT_CURVE_KEY
} AttributeElement;
typedef enum AttributeStandard {
ATTR_STD_NONE = 0,
ATTR_STD_VERTEX_NORMAL,
ATTR_STD_FACE_NORMAL,
ATTR_STD_UV,
ATTR_STD_UV_TANGENT,
ATTR_STD_UV_TANGENT_SIGN,
ATTR_STD_GENERATED,
ATTR_STD_POSITION_UNDEFORMED,
ATTR_STD_POSITION_UNDISPLACED,
ATTR_STD_MOTION_PRE,
ATTR_STD_MOTION_POST,
ATTR_STD_PARTICLE,
ATTR_STD_CURVE_TANGENT,
ATTR_STD_CURVE_INTERCEPT,
ATTR_STD_NUM,
ATTR_STD_NOT_FOUND = ~0
} AttributeStandard;
/* Closure data */
#define MAX_CLOSURE 8
@@ -436,6 +463,11 @@ typedef struct ShaderData {
/* primitive id if there is one, ~0 otherwise */
int prim;
#ifdef __HAIR__
/* for curves, segment number in curve, ~0 for triangles */
int segment;
#endif
/* parametric coordinates
* - barycentric weights for triangles */
float u, v;
@@ -650,6 +682,29 @@ typedef struct KernelBVH {
int pad2;
} KernelBVH;
typedef enum CurveFlag {
/* runtime flags */
CURVE_KN_BACKFACING = 1, /* backside of cylinder? */
CURVE_KN_ENCLOSEFILTER = 2, /* don't consider strands surrounding start point? */
CURVE_KN_CURVEDATA = 4, /* curve data available? */
CURVE_KN_INTERPOLATE = 8, /* render as a curve? - not supported yet */
CURVE_KN_ACCURATE = 16, /* use accurate intersections test? */
CURVE_KN_INTERSECTCORRECTION = 32, /* correct for width after determing closest midpoint? */
CURVE_KN_POSTINTERSECTCORRECTION = 64, /* correct for width after intersect? */
CURVE_KN_NORMALCORRECTION = 128, /* correct tangent normal for slope? */
CURVE_KN_TRUETANGENTGNORMAL = 256, /* use tangent normal for geometry? */
CURVE_KN_TANGENTGNORMAL = 512, /* use tangent normal for shader? */
} CurveFlag;
typedef struct KernelCurves {
/* strand intersect and normal parameters - many can be changed to flags*/
float normalmix;
float encasing_ratio;
int curveflags;
int pad;
} KernelCurves;
typedef struct KernelData {
KernelCamera cam;
KernelFilm film;
@@ -657,6 +712,7 @@ typedef struct KernelData {
KernelSunSky sunsky;
KernelIntegrator integrator;
KernelBVH bvh;
KernelCurves curve_kernel_data;
} KernelData;
CCL_NAMESPACE_END

View File

@@ -37,9 +37,10 @@
#include "kernel_differential.h"
#include "kernel_object.h"
#include "kernel_bvh.h"
#include "kernel_attribute.h"
#include "kernel_projection.h"
#include "kernel_triangle.h"
#include "kernel_curve.h"
#include "kernel_primitive.h"
#include "kernel_projection.h"
#include "kernel_accumulate.h"
#include "kernel_shader.h"
@@ -74,6 +75,11 @@ ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices");
ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices");
ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices");
ustring OSLRenderServices::u_geom_name("geom:name");
#ifdef __HAIR__
ustring OSLRenderServices::u_is_curve("geom:is_curve");
ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
#endif
ustring OSLRenderServices::u_path_ray_length("path:ray_length");
ustring OSLRenderServices::u_trace("trace");
ustring OSLRenderServices::u_hit("hit");
@@ -495,13 +501,13 @@ static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OS
attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
{
float3 fval[3];
fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset,
fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset,
(derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float3(fval, type, derivatives, val);
}
else if (attr.type == TypeDesc::TypeFloat) {
float fval[3];
fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset,
fval[0] = primitive_attribute_float(kg, sd, attr.elem, attr.offset,
(derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float(fval, type, derivatives, val);
}
@@ -593,10 +599,13 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD
float3 f = particle_angular_velocity(kg, particle_id);
return set_attribute_float3(f, type, derivatives, val);
}
/* Geometry Attributes */
else if (name == u_geom_numpolyvertices) {
return set_attribute_int(3, type, derivatives, val);
}
else if (name == u_geom_trianglevertices || name == u_geom_polyvertices) {
else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices)
&& sd->segment == ~0) {
float3 P[3];
triangle_vertices(kg, sd->prim, P);
@@ -612,6 +621,22 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD
ustring object_name = kg->osl->object_names[sd->object];
return set_attribute_string(object_name, type, derivatives, val);
}
#ifdef __HAIR__
/* Hair Attributes */
else if (name == u_is_curve) {
float f = (sd->segment != ~0);
return set_attribute_float(f, type, derivatives, val);
}
else if (name == u_curve_thickness) {
float f = curve_thickness(kg, sd);
return set_attribute_float(f, type, derivatives, val);
}
else if (name == u_curve_tangent_normal) {
float3 f = curve_tangent_normal(kg, sd);
return set_attribute_float3(f, type, derivatives, val);
}
#endif
else
return false;
}
@@ -634,7 +659,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
{
KernelGlobals *kg = kernel_globals;
ShaderData *sd = (ShaderData *)renderstate;
int object, tri;
int object, prim, segment;
/* lookup of attribute on another object */
if (object_name != u_empty || sd == NULL) {
@@ -644,17 +669,20 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
return false;
object = it->second;
tri = ~0;
prim = ~0;
segment = ~0;
}
else {
object = sd->object;
tri = sd->prim;
prim = sd->prim;
segment = sd->segment;
if (object == ~0)
return get_background_attribute(kg, sd, name, type, derivatives, val);
}
/* find attribute on object */
object = object*ATTR_PRIM_TYPES + (segment != ~0);
OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object];
OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
@@ -663,7 +691,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
if (attr.elem != ATTR_ELEMENT_VALUE) {
/* triangle and vertex attributes */
if (tri != ~0)
if (prim != ~0)
return get_mesh_attribute(kg, sd, attr, type, derivatives, val);
}
else {

View File

@@ -130,6 +130,9 @@ public:
static ustring u_geom_trianglevertices;
static ustring u_geom_polyvertices;
static ustring u_geom_name;
static ustring u_is_curve;
static ustring u_curve_thickness;
static ustring u_curve_tangent_normal;
static ustring u_path_ray_length;
static ustring u_trace;
static ustring u_hit;

View File

@@ -26,9 +26,10 @@
#include "osl_services.h"
#include "osl_shader.h"
#include "util_attribute.h"
#include "util_foreach.h"
#include "attribute.h"
#include <OSL/oslexec.h>
CCL_NAMESPACE_BEGIN
@@ -453,15 +454,17 @@ float3 OSLShader::volume_eval_phase(const ShaderClosure *sc, const float3 omega_
/* Attributes */
int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
{
/* for OSL, a hash map is used to lookup the attribute by name. */
OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[sd->object];
ustring stdname(std::string("std::") + std::string(attribute_standard_name((AttributeStandard)id)));
int object = sd->object*ATTR_PRIM_TYPES + (sd->segment != ~0);
OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object];
ustring stdname(std::string("geom:") + std::string(Attribute::standard_name((AttributeStandard)id)));
OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
if (it != attr_map.end()) {
const OSLGlobals::Attribute &osl_attr = it->second;
*elem = osl_attr.elem;
/* return result */
return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
}

View File

@@ -74,7 +74,7 @@ public:
const float3 omega_in, const float3 omega_out);
/* attributes */
static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id);
static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem);
};
CCL_NAMESPACE_END

View File

@@ -27,6 +27,7 @@ set(SRC_OSL
node_glass_bsdf.osl
node_glossy_bsdf.osl
node_gradient_texture.osl
node_hair_info.osl
node_holdout.osl
node_hsv.osl
node_image_texture.osl

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2012, 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_hair_info(
output float IsStrand = 0.0,
output float Intercept = 0.0,
output float Thickness = 0.0,
output normal TangentNormal = N)
{
getattribute("geom:is_curve", IsStrand);
getattribute("geom:curve_intercept", Intercept);
getattribute("geom:curve_thickness", Thickness);
getattribute("geom:curve_tangent_normal", TangentNormal);
}

View File

@@ -161,6 +161,15 @@ vector cross (vector a, vector b) BUILTIN;
float dot (vector a, vector b) BUILTIN;
float length (vector v) BUILTIN;
float distance (point a, point b) BUILTIN;
float distance (point a, point b, point q)
{
vector d = b - a;
float dd = dot(d, d);
if(dd == 0.0)
return distance(q, a);
float t = dot(q - a, d)/dd;
return distance(q, a + clamp(t, 0.0, 1.0)*d);
}
normal normalize (normal v) BUILTIN;
vector normalize (vector v) BUILTIN;
vector faceforward (vector N, vector I, vector Nref) BUILTIN;
@@ -304,7 +313,7 @@ color transformc (string to, color x)
r = color (dot (vector(0.299, 0.587, 0.114), (vector)x),
dot (vector(0.596, -0.275, -0.321), (vector)x),
dot (vector(0.212, -0.523, 0.311), (vector)x));
else if (to == "xyz")
else if (to == "XYZ")
r = color (dot (vector(0.412453, 0.357580, 0.180423), (vector)x),
dot (vector(0.212671, 0.715160, 0.072169), (vector)x),
dot (vector(0.019334, 0.119193, 0.950227), (vector)x));
@@ -366,7 +375,7 @@ color transformc (string from, string to, color x)
r = color (dot (vector(1, 0.9557, 0.6199), (vector)x),
dot (vector(1, -0.2716, -0.6469), (vector)x),
dot (vector(1, -1.1082, 1.7051), (vector)x));
else if (from == "xyz")
else if (from == "XYZ")
r = color (dot (vector( 3.240479, -1.537150, -0.498535), (vector)x),
dot (vector(-0.969256, 1.875991, 0.041556), (vector)x),
dot (vector( 0.055648, -0.204043, 1.057311), (vector)x));
@@ -409,6 +418,8 @@ int startswith (string s, string prefix) BUILTIN;
int endswith (string s, string suffix) BUILTIN;
string substr (string s, int start, int len) BUILTIN;
string substr (string s, int start) { return substr (s, start, strlen(s)); }
float strtof (string str) BUILTIN;
int strtoi (string str) BUILTIN;
// Define concat in terms of shorter concat
string concat (string a, string b, string c) {

View File

@@ -301,6 +301,12 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT
case NODE_PARTICLE_INFO:
svm_node_particle_info(kg, sd, stack, node.y, node.z);
break;
#ifdef __HAIR__
case NODE_HAIR_INFO:
svm_node_hair_info(kg, sd, stack, node.y, node.z);
break;
#endif
#endif
case NODE_CONVERT:
svm_node_convert(sd, stack, node.y, node.z, node.w);

View File

@@ -28,10 +28,15 @@ __device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
/* find attribute by unique id */
uint id = node.y;
uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
#ifdef __HAIR__
attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE;
#endif
uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
while(attr_map.x != id)
attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset);
while(attr_map.x != id) {
attr_offset += ATTR_PRIM_TYPES;
attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
}
/* return result */
*elem = (AttributeElement)attr_map.y;
@@ -61,21 +66,21 @@ __device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uin
/* fetch and store attribute */
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL);
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL);
stack_store_float(stack, out_offset, f);
}
else {
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL);
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
stack_store_float(stack, out_offset, average(f));
}
}
else {
if(mesh_type == NODE_ATTR_FLOAT3) {
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL);
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
stack_store_float3(stack, out_offset, f);
}
else {
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL);
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL);
stack_store_float3(stack, out_offset, make_float3(f, f, f));
}
}
@@ -94,24 +99,24 @@ __device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *st
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
float dx;
float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL);
float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL);
stack_store_float(stack, out_offset, f+dx);
}
else {
float3 dx;
float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL);
float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL);
stack_store_float(stack, out_offset, average(f+dx));
}
}
else {
if(mesh_type == NODE_ATTR_FLOAT3) {
float3 dx;
float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL);
float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL);
stack_store_float3(stack, out_offset, f+dx);
}
else {
float dx;
float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL);
float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL);
stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx));
}
}
@@ -130,24 +135,24 @@ __device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *st
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
float dy;
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy);
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy);
stack_store_float(stack, out_offset, f+dy);
}
else {
float3 dy;
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy);
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy);
stack_store_float(stack, out_offset, average(f+dy));
}
}
else {
if(mesh_type == NODE_ATTR_FLOAT3) {
float3 dy;
float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy);
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy);
stack_store_float3(stack, out_offset, f+dy);
}
else {
float dy;
float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy);
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy);
stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy));
}
}

View File

@@ -28,23 +28,7 @@ __device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stack,
case NODE_GEOM_P: data = sd->P; break;
case NODE_GEOM_N: data = sd->N; break;
#ifdef __DPDU__
case NODE_GEOM_T: {
/* try to create spherical tangent from generated coordinates */
int attr_offset = (sd->object != ~0)? find_attribute(kg, sd, ATTR_STD_GENERATED): ATTR_STD_NOT_FOUND;
if(attr_offset != ATTR_STD_NOT_FOUND) {
data = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL);
data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
object_normal_transform(kg, sd, &data);
data = cross(sd->N, normalize(cross(data, sd->N)));;
}
else {
/* otherwise use surface derivatives */
data = normalize(sd->dPdu);
}
break;
}
case NODE_GEOM_T: data = primitive_tangent(kg, sd); break;
#endif
case NODE_GEOM_I: data = sd->I; break;
case NODE_GEOM_Ng: data = sd->Ng; break;
@@ -160,5 +144,36 @@ __device void svm_node_particle_info(KernelGlobals *kg, ShaderData *sd, float *s
}
}
#ifdef __HAIR__
/* Hair Info */
__device void svm_node_hair_info(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset)
{
float data;
float3 data3;
switch(type) {
case NODE_INFO_CURVE_IS_STRAND: {
data = (sd->segment != ~0);
stack_store_float(stack, out_offset, data);
break;
}
case NODE_INFO_CURVE_INTERCEPT:
break; /* handled as attribute */
case NODE_INFO_CURVE_THICKNESS: {
data = curve_thickness(kg, sd);
stack_store_float(stack, out_offset, data);
break;
}
case NODE_INFO_CURVE_TANGENT_NORMAL: {
data3 = curve_tangent_normal(kg, sd);
stack_store_float3(stack, out_offset, data3);
break;
}
}
}
#endif
CCL_NAMESPACE_END

View File

@@ -248,8 +248,9 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac
}
/* first try to get tangent attribute */
int attr_offset = find_attribute(kg, sd, node.z);
int attr_sign_offset = find_attribute(kg, sd, node.w);
AttributeElement attr_elem, attr_sign_elem;
int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
int attr_sign_offset = find_attribute(kg, sd, node.w, &attr_sign_elem);
if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND) {
stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
@@ -257,8 +258,8 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac
}
/* ensure orthogonal and normalized (interpolation breaks it) */
float3 tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL);
float sign = triangle_attribute_float(kg, sd, ATTR_ELEMENT_CORNER, attr_sign_offset, NULL, NULL);
float3 tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
float sign = primitive_attribute_float(kg, sd, attr_sign_elem, attr_sign_offset, NULL, NULL);
object_normal_transform(kg, sd, &tangent);
tangent = cross(sd->N, normalize(cross(tangent, sd->N)));;
@@ -295,22 +296,24 @@ __device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack,
if(direction_type == NODE_TANGENT_UVMAP) {
/* UV map */
int attr_offset = find_attribute(kg, sd, node.z);
AttributeElement attr_elem;
int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
if(attr_offset == ATTR_STD_NOT_FOUND)
tangent = make_float3(0.0f, 0.0f, 0.0f);
else
tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL);
tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
}
else {
/* radial */
int attr_offset = find_attribute(kg, sd, node.z);
AttributeElement attr_elem;
int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
float3 generated;
if(attr_offset == ATTR_STD_NOT_FOUND)
generated = sd->P;
else
generated = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL);
generated = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
if(axis == NODE_TANGENT_AXIS_X)
tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f));

View File

@@ -97,7 +97,8 @@ typedef enum NodeType {
NODE_CLOSURE_SET_NORMAL,
NODE_CLOSURE_AMBIENT_OCCLUSION,
NODE_TANGENT,
NODE_NORMAL_MAP
NODE_NORMAL_MAP,
NODE_HAIR_INFO
} NodeType;
typedef enum NodeAttributeType {
@@ -132,6 +133,13 @@ typedef enum NodeParticleInfo {
NODE_INFO_PAR_ANGULAR_VELOCITY
} NodeParticleInfo;
typedef enum NodeHairInfo {
NODE_INFO_CURVE_IS_STRAND,
NODE_INFO_CURVE_INTERCEPT,
NODE_INFO_CURVE_THICKNESS,
NODE_INFO_CURVE_TANGENT_NORMAL
} NodeHairInfo;
typedef enum NodeLightPath {
NODE_LP_camera = 0,
NODE_LP_shadow,

View File

@@ -31,6 +31,7 @@ set(SRC
object.cpp
osl.cpp
particles.cpp
curves.cpp
scene.cpp
session.cpp
shader.cpp
@@ -56,6 +57,7 @@ set(SRC_HEADERS
object.h
osl.h
particles.h
curves.h
scene.h
session.h
shader.h

View File

@@ -26,7 +26,7 @@ CCL_NAMESPACE_BEGIN
/* Attribute */
void Attribute::set(ustring name_, TypeDesc type_, Element element_)
void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
{
name = name_;
type = type_;
@@ -39,12 +39,30 @@ void Attribute::set(ustring name_, TypeDesc type_, Element element_)
type == TypeDesc::TypeNormal);
}
void Attribute::reserve(int numverts, int numtris)
void Attribute::reserve(int numverts, int numtris, int numcurves, int numkeys)
{
buffer.resize(buffer_size(numverts, numtris), 0);
buffer.resize(buffer_size(numverts, numtris, numcurves, numkeys), 0);
}
size_t Attribute::data_sizeof()
void Attribute::add(const float& f)
{
char *data = (char*)&f;
size_t size = sizeof(f);
for(size_t i = 0; i < size; i++)
buffer.push_back(data[i]);
}
void Attribute::add(const float3& f)
{
char *data = (char*)&f;
size_t size = sizeof(f);
for(size_t i = 0; i < size; i++)
buffer.push_back(data[i]);
}
size_t Attribute::data_sizeof() const
{
if(type == TypeDesc::TypeFloat)
return sizeof(float);
@@ -52,19 +70,27 @@ size_t Attribute::data_sizeof()
return sizeof(float3);
}
size_t Attribute::element_size(int numverts, int numtris)
size_t Attribute::element_size(int numverts, int numtris, int numcurves, int numkeys) const
{
if(element == VERTEX)
if(element == ATTR_ELEMENT_VALUE)
return 1;
if(element == ATTR_ELEMENT_VERTEX)
return numverts;
else if(element == FACE)
else if(element == ATTR_ELEMENT_FACE)
return numtris;
else
else if(element == ATTR_ELEMENT_CORNER)
return numtris*3;
else if(element == ATTR_ELEMENT_CURVE)
return numcurves;
else if(element == ATTR_ELEMENT_CURVE_KEY)
return numkeys;
return 0;
}
size_t Attribute::buffer_size(int numverts, int numtris)
size_t Attribute::buffer_size(int numverts, int numtris, int numcurves, int numkeys) const
{
return element_size(numverts, numtris)*data_sizeof();
return element_size(numverts, numtris, numcurves, numkeys)*data_sizeof();
}
bool Attribute::same_storage(TypeDesc a, TypeDesc b)
@@ -84,18 +110,51 @@ bool Attribute::same_storage(TypeDesc a, TypeDesc b)
return false;
}
const char *Attribute::standard_name(AttributeStandard std)
{
if(std == ATTR_STD_VERTEX_NORMAL)
return "N";
else if(std == ATTR_STD_FACE_NORMAL)
return "Ng";
else if(std == ATTR_STD_UV)
return "uv";
else if(std == ATTR_STD_GENERATED)
return "generated";
else if(std == ATTR_STD_UV_TANGENT)
return "tangent";
else if(std == ATTR_STD_UV_TANGENT_SIGN)
return "tangent_sign";
else if(std == ATTR_STD_POSITION_UNDEFORMED)
return "undeformed";
else if(std == ATTR_STD_POSITION_UNDISPLACED)
return "undisplaced";
else if(std == ATTR_STD_MOTION_PRE)
return "motion_pre";
else if(std == ATTR_STD_MOTION_POST)
return "motion_post";
else if(std == ATTR_STD_PARTICLE)
return "particle";
else if(std == ATTR_STD_CURVE_TANGENT)
return "curve_tangent";
else if(std == ATTR_STD_CURVE_INTERCEPT)
return "curve_intercept";
return "";
}
/* Attribute Set */
AttributeSet::AttributeSet()
{
mesh = NULL;
triangle_mesh = NULL;
curve_mesh = NULL;
}
AttributeSet::~AttributeSet()
{
}
Attribute *AttributeSet::add(ustring name, TypeDesc type, Attribute::Element element)
Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element)
{
Attribute *attr = find(name);
@@ -111,24 +170,22 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, Attribute::Element ele
attributes.push_back(Attribute());
attr = &attributes.back();
if(element == Attribute::VERTEX)
attr->set(name, type, element);
else if(element == Attribute::FACE)
attr->set(name, type, element);
else if(element == Attribute::CORNER)
attr->set(name, type, element);
if(mesh)
attr->reserve(mesh->verts.size(), mesh->triangles.size());
/* this is weak .. */
if(triangle_mesh)
attr->reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), 0, 0);
if(curve_mesh)
attr->reserve(0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size());
return attr;
}
Attribute *AttributeSet::find(ustring name)
Attribute *AttributeSet::find(ustring name) const
{
foreach(Attribute& attr, attributes)
foreach(const Attribute& attr, attributes)
if(attr.name == name)
return &attr;
return (Attribute*)&attr;
return NULL;
}
@@ -154,41 +211,59 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
Attribute *attr = NULL;
if(name == ustring())
name = attribute_standard_name(std);
name = Attribute::standard_name(std);
if(triangle_mesh) {
if(std == ATTR_STD_VERTEX_NORMAL)
attr = add(name, TypeDesc::TypeNormal, Attribute::VERTEX);
attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX);
else if(std == ATTR_STD_FACE_NORMAL)
attr = add(name, TypeDesc::TypeNormal, Attribute::FACE);
attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE);
else if(std == ATTR_STD_UV)
attr = add(name, TypeDesc::TypePoint, Attribute::CORNER);
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
else if(std == ATTR_STD_UV_TANGENT)
attr = add(name, TypeDesc::TypeVector, Attribute::CORNER);
attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
else if(std == ATTR_STD_UV_TANGENT_SIGN)
attr = add(name, TypeDesc::TypeFloat, Attribute::CORNER);
attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER);
else if(std == ATTR_STD_GENERATED)
attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
else if(std == ATTR_STD_POSITION_UNDEFORMED)
attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
else if(std == ATTR_STD_POSITION_UNDISPLACED)
attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
else if(std == ATTR_STD_MOTION_PRE)
attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
else if(std == ATTR_STD_MOTION_POST)
attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX);
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
else
assert(0);
}
else if(curve_mesh) {
if(std == ATTR_STD_UV)
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
else if(std == ATTR_STD_GENERATED)
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
else if(std == ATTR_STD_MOTION_PRE)
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY);
else if(std == ATTR_STD_MOTION_POST)
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY);
else if(std == ATTR_STD_CURVE_TANGENT)
attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CURVE_KEY);
else if(std == ATTR_STD_CURVE_INTERCEPT)
attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY);
else
assert(0);
}
attr->std = std;
return attr;
}
Attribute *AttributeSet::find(AttributeStandard std)
Attribute *AttributeSet::find(AttributeStandard std) const
{
foreach(Attribute& attr, attributes)
foreach(const Attribute& attr, attributes)
if(attr.std == std)
return &attr;
return (Attribute*)&attr;
return NULL;
}
@@ -217,10 +292,14 @@ Attribute *AttributeSet::find(AttributeRequest& req)
return find(req.std);
}
void AttributeSet::reserve(int numverts, int numtris)
void AttributeSet::reserve()
{
foreach(Attribute& attr, attributes)
attr.reserve(numverts, numtris);
foreach(Attribute& attr, attributes) {
if(triangle_mesh)
attr.reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), 0, 0);
if(curve_mesh)
attr.reserve(0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size());
}
}
void AttributeSet::clear()
@@ -235,9 +314,13 @@ AttributeRequest::AttributeRequest(ustring name_)
name = name_;
std = ATTR_STD_NONE;
type = TypeDesc::TypeFloat;
element = ATTR_ELEMENT_NONE;
offset = 0;
triangle_type = TypeDesc::TypeFloat;
triangle_element = ATTR_ELEMENT_NONE;
triangle_offset = 0;
curve_type = TypeDesc::TypeFloat;
curve_element = ATTR_ELEMENT_NONE;
curve_offset = 0;
}
AttributeRequest::AttributeRequest(AttributeStandard std_)
@@ -245,9 +328,13 @@ AttributeRequest::AttributeRequest(AttributeStandard std_)
name = ustring();
std = std_;
type = TypeDesc::TypeFloat;
element = ATTR_ELEMENT_NONE;
offset = 0;
triangle_type = TypeDesc::TypeFloat;
triangle_element = ATTR_ELEMENT_NONE;
triangle_offset = 0;
curve_type = TypeDesc::TypeFloat;
curve_element = ATTR_ELEMENT_NONE;
curve_offset = 0;
}
/* AttributeRequestSet */

View File

@@ -21,7 +21,6 @@
#include "kernel_types.h"
#include "util_attribute.h"
#include "util_list.h"
#include "util_param.h"
#include "util_types.h"
@@ -42,36 +41,34 @@ class Mesh;
class Attribute {
public:
enum Element {
VERTEX,
FACE,
CORNER
};
ustring name;
AttributeStandard std;
TypeDesc type;
vector<char> buffer;
Element element;
AttributeElement element;
Attribute() {}
void set(ustring name, TypeDesc type, Element element);
void reserve(int numverts, int numfaces);
void set(ustring name, TypeDesc type, AttributeElement element);
void reserve(int numverts, int numfaces, int numcurves, int numkeys);
size_t data_sizeof();
size_t element_size(int numverts, int numfaces);
size_t buffer_size(int numverts, int numfaces);
size_t data_sizeof() const;
size_t element_size(int numverts, int numfaces, int numcurves, int numkeys) const;
size_t buffer_size(int numverts, int numfaces, int numcurves, int numkeys) const;
char *data() { return (buffer.size())? &buffer[0]: NULL; };
float3 *data_float3() { return (float3*)data(); }
float *data_float() { return (float*)data(); }
const char *data() const { return (buffer.size())? &buffer[0]: NULL; }
const float3 *data_float3() const { return (float3*)data(); }
const float *data_float() const { return (float*)data(); }
const float3 *data_float3() const { return (const float3*)data(); }
const float *data_float() const { return (const float*)data(); }
void add(const float& f);
void add(const float3& f);
static bool same_storage(TypeDesc a, TypeDesc b);
static const char *standard_name(AttributeStandard std);
};
/* Attribute Set
@@ -80,23 +77,24 @@ public:
class AttributeSet {
public:
Mesh *mesh;
Mesh *triangle_mesh;
Mesh *curve_mesh;
list<Attribute> attributes;
AttributeSet();
~AttributeSet();
Attribute *add(ustring name, TypeDesc type, Attribute::Element element);
Attribute *find(ustring name);
Attribute *add(ustring name, TypeDesc type, AttributeElement element);
Attribute *find(ustring name) const;
void remove(ustring name);
Attribute *add(AttributeStandard std, ustring name = ustring());
Attribute *find(AttributeStandard std);
Attribute *find(AttributeStandard std) const;
void remove(AttributeStandard std);
Attribute *find(AttributeRequest& req);
void reserve(int numverts, int numfaces);
void reserve();
void clear();
};
@@ -104,7 +102,7 @@ public:
*
* Request from a shader to use a certain attribute, so we can figure out
* which ones we need to export from the host app end store for the kernel.
* The attribute is found either by name or by standard. */
* The attribute is found either by name or by standard attribute type. */
class AttributeRequest {
public:
@@ -112,9 +110,9 @@ public:
AttributeStandard std;
/* temporary variables used by MeshManager */
TypeDesc type;
AttributeElement element;
int offset;
TypeDesc triangle_type, curve_type;
AttributeElement triangle_element, curve_element;
int triangle_offset, curve_offset;
AttributeRequest(ustring name_);
AttributeRequest(AttributeStandard std);

View File

@@ -0,0 +1,160 @@
/*
* 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 "curves.h"
#include "mesh.h"
#include "object.h"
#include "scene.h"
#include "util_foreach.h"
#include "util_map.h"
#include "util_progress.h"
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
/* Hair System Manager */
CurveSystemManager::CurveSystemManager()
{
primitive = CURVE_LINE_SEGMENTS;
line_method = CURVE_CORRECTED;
interpolation = CURVE_CARDINAL;
triangle_method = CURVE_CAMERA;
resolution = 3;
segments = 1;
normalmix = 1.0f;
encasing_ratio = 1.01f;
use_curves = true;
use_smooth = true;
use_cache = true;
use_parents = false;
use_encasing = true;
use_backfacing = false;
use_joined = false;
use_tangent_normal = false;
use_tangent_normal_geometry = false;
use_tangent_normal_correction = false;
need_update = true;
need_mesh_update = false;
}
CurveSystemManager::~CurveSystemManager()
{
}
void CurveSystemManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
if(!need_update)
return;
device_free(device, dscene);
progress.set_status("Updating Hair settings", "Copying Hair settings to device");
KernelCurves *kcurve= &dscene->data.curve_kernel_data;
kcurve->curveflags = 0;
if(primitive == CURVE_SEGMENTS)
kcurve->curveflags |= CURVE_KN_INTERPOLATE;
if(line_method == CURVE_ACCURATE)
kcurve->curveflags |= CURVE_KN_ACCURATE;
if(line_method == CURVE_CORRECTED)
kcurve->curveflags |= CURVE_KN_INTERSECTCORRECTION;
if(line_method == CURVE_POSTCORRECTED)
kcurve->curveflags |= CURVE_KN_POSTINTERSECTCORRECTION;
if(use_tangent_normal)
kcurve->curveflags |= CURVE_KN_TANGENTGNORMAL;
if(use_tangent_normal_correction)
kcurve->curveflags |= CURVE_KN_NORMALCORRECTION;
if(use_tangent_normal_geometry)
kcurve->curveflags |= CURVE_KN_TRUETANGENTGNORMAL;
if(use_joined)
kcurve->curveflags |= CURVE_KN_CURVEDATA;
if(use_backfacing)
kcurve->curveflags |= CURVE_KN_BACKFACING;
if(use_encasing)
kcurve->curveflags |= CURVE_KN_ENCLOSEFILTER;
kcurve->normalmix = normalmix;
kcurve->encasing_ratio = encasing_ratio;
if(progress.get_cancel()) return;
need_update = false;
}
void CurveSystemManager::device_free(Device *device, DeviceScene *dscene)
{
}
bool CurveSystemManager::modified(const CurveSystemManager& CurveSystemManager)
{
return !(line_method == CurveSystemManager.line_method &&
interpolation == CurveSystemManager.interpolation &&
primitive == CurveSystemManager.primitive &&
use_encasing == CurveSystemManager.use_encasing &&
use_tangent_normal == CurveSystemManager.use_tangent_normal &&
use_tangent_normal_correction == CurveSystemManager.use_tangent_normal_correction &&
use_tangent_normal_geometry == CurveSystemManager.use_tangent_normal_geometry &&
encasing_ratio == CurveSystemManager.encasing_ratio &&
use_backfacing == CurveSystemManager.use_backfacing &&
normalmix == CurveSystemManager.normalmix &&
use_cache == CurveSystemManager.use_cache &&
use_smooth == CurveSystemManager.use_smooth &&
triangle_method == CurveSystemManager.triangle_method &&
resolution == CurveSystemManager.resolution &&
use_curves == CurveSystemManager.use_curves &&
use_joined == CurveSystemManager.use_joined &&
segments == CurveSystemManager.segments &&
use_parents == CurveSystemManager.use_parents);
}
bool CurveSystemManager::modified_mesh(const CurveSystemManager& CurveSystemManager)
{
return !(primitive == CurveSystemManager.primitive &&
interpolation == CurveSystemManager.interpolation &&
use_parents == CurveSystemManager.use_parents &&
use_smooth == CurveSystemManager.use_smooth &&
triangle_method == CurveSystemManager.triangle_method &&
resolution == CurveSystemManager.resolution &&
use_curves == CurveSystemManager.use_curves &&
use_joined == CurveSystemManager.use_joined &&
segments == CurveSystemManager.segments &&
use_cache == CurveSystemManager.use_cache);
}
void CurveSystemManager::tag_update(Scene *scene)
{
need_update = true;
}
void CurveSystemManager::tag_update_mesh()
{
need_mesh_update = true;
}
CCL_NAMESPACE_END

View File

@@ -0,0 +1,134 @@
/*
* 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 __CURVES_H__
#define __CURVES_H__
#include "util_types.h"
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
class Device;
class DeviceScene;
class Progress;
class Scene;
typedef enum curve_presets {
CURVE_CUSTOM,
CURVE_TANGENT_SHADING,
CURVE_TRUE_NORMAL,
CURVE_ACCURATE_PRESET
} curve_presets;
typedef enum curve_primitives {
CURVE_TRIANGLES,
CURVE_LINE_SEGMENTS,
CURVE_SEGMENTS
} curve_primitives;
typedef enum curve_triangles {
CURVE_CAMERA,
CURVE_RIBBONS,
CURVE_TESSELATED
} curve_triangles;
typedef enum curve_lines {
CURVE_ACCURATE,
CURVE_CORRECTED,
CURVE_POSTCORRECTED,
CURVE_UNCORRECTED
} curve_lines;
typedef enum curve_interpolation {
CURVE_LINEAR,
CURVE_CARDINAL,
CURVE_BSPLINE
} curve_interpolation;
class ParticleCurveData {
public:
ParticleCurveData();
~ParticleCurveData();
vector<int> psys_firstcurve;
vector<int> psys_curvenum;
vector<int> psys_shader;
vector<float> psys_rootradius;
vector<float> psys_tipradius;
vector<float> psys_shape;
vector<bool> psys_closetip;
vector<int> curve_firstkey;
vector<int> curve_keynum;
vector<float> curve_length;
vector<float3> curve_uv;
vector<float3> curve_vcol;
vector<float3> curvekey_co;
vector<float> curvekey_time;
};
/* HairSystem Manager */
class CurveSystemManager {
public:
int primitive;
int line_method;
int interpolation;
int triangle_method;
int resolution;
int segments;
float normalmix;
float encasing_ratio;
bool use_curves;
bool use_smooth;
bool use_cache;
bool use_parents;
bool use_encasing;
bool use_backfacing;
bool use_tangent_normal;
bool use_tangent_normal_correction;
bool use_tangent_normal_geometry;
bool use_joined;
bool need_update;
bool need_mesh_update;
CurveSystemManager();
~CurveSystemManager();
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
bool modified(const CurveSystemManager& CurveSystemManager);
bool modified_mesh(const CurveSystemManager& CurveSystemManager);
void tag_update(Scene *scene);
void tag_update_mesh();
};
CCL_NAMESPACE_END
#endif /* __CURVES_H__ */

View File

@@ -142,6 +142,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
/* count */
size_t num_lights = scene->lights.size();
size_t num_triangles = 0;
size_t num_curve_segments = 0;
foreach(Object *object, scene->objects) {
Mesh *mesh = object->mesh;
@@ -169,10 +170,19 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
if(shader->sample_as_light && shader->has_surface_emission)
num_triangles++;
}
/* disabled for curves */
#if 0
foreach(Mesh::Curve& curve, mesh->curves) {
Shader *shader = scene->shaders[curve.shader];
if(shader->sample_as_light && shader->has_surface_emission)
num_curve_segments += curve.num_segments();
#endif
}
}
size_t num_distribution = num_triangles;
size_t num_distribution = num_triangles + num_curve_segments;
num_distribution += num_lights;
/* emission area */
@@ -216,7 +226,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
if(shader->sample_as_light && shader->has_surface_emission) {
distribution[offset].x = totarea;
distribution[offset].y = __int_as_float(i + mesh->tri_offset);
distribution[offset].z = 1.0f;
distribution[offset].z = __int_as_float(~0);
distribution[offset].w = __int_as_float(object_id);
offset++;
@@ -234,6 +244,40 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
totarea += triangle_area(p1, p2, p3);
}
}
/*sample as light disabled for strands*/
#if 0
size_t i = 0;
foreach(Mesh::Curve& curve, mesh->curves) {
Shader *shader = scene->shaders[curve.shader];
int first_key = curve.first_key;
if(shader->sample_as_light && shader->has_surface_emission) {
for(int j = 0; j < curve.num_segments(); j++) {
distribution[offset].x = totarea;
distribution[offset].y = __int_as_float(i + mesh->curve_offset); // XXX fix kernel code
distribution[offset].z = __int_as_float(j);
distribution[offset].w = __int_as_float(object_id);
offset++;
float3 p1 = mesh->curve_keys[first_key + j].loc;
float r1 = mesh->curve_keys[first_key + j].radius;
float3 p2 = mesh->curve_keys[first_key + j + 1].loc;
float r2 = mesh->curve_keys[first_key + j + 1].radius;
if(!transform_applied) {
p1 = transform_point(&tfm, p1);
p2 = transform_point(&tfm, p2);
}
totarea += M_PI_F * (r1 + r2) * len(p1 - p2);
}
}
i++;
}
#endif
}
if(progress.get_cancel()) return;

View File

@@ -51,7 +51,11 @@ Mesh::Mesh()
tri_offset = 0;
vert_offset = 0;
attributes.mesh = this;
curve_offset = 0;
curvekey_offset = 0;
attributes.triangle_mesh = this;
curve_attributes.curve_mesh = this;
}
Mesh::~Mesh()
@@ -59,14 +63,18 @@ Mesh::~Mesh()
delete bvh;
}
void Mesh::reserve(int numverts, int numtris)
void Mesh::reserve(int numverts, int numtris, int numcurves, int numcurvekeys)
{
/* reserve space to add verts and triangles later */
verts.resize(numverts);
triangles.resize(numtris);
shader.resize(numtris);
smooth.resize(numtris);
attributes.reserve(numverts, numtris);
curve_keys.resize(numcurvekeys);
curves.resize(numcurves);
attributes.reserve();
curve_attributes.reserve();
}
void Mesh::clear()
@@ -77,7 +85,11 @@ void Mesh::clear()
shader.clear();
smooth.clear();
curve_keys.clear();
curves.clear();
attributes.clear();
curve_attributes.clear();
used_shaders.clear();
transform_applied = false;
@@ -86,24 +98,47 @@ void Mesh::clear()
void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
{
Triangle t;
t.v[0] = v0;
t.v[1] = v1;
t.v[2] = v2;
Triangle tri;
tri.v[0] = v0;
tri.v[1] = v1;
tri.v[2] = v2;
triangles.push_back(t);
triangles.push_back(tri);
shader.push_back(shader_);
smooth.push_back(smooth_);
}
void Mesh::add_curve_key(float3 co, float radius)
{
CurveKey key;
key.co = co;
key.radius = radius;
curve_keys.push_back(key);
}
void Mesh::add_curve(int first_key, int num_keys, int shader)
{
Curve curve;
curve.first_key = first_key;
curve.num_keys = num_keys;
curve.shader = shader;
curves.push_back(curve);
}
void Mesh::compute_bounds()
{
BoundBox bnds = BoundBox::empty;
size_t verts_size = verts.size();
size_t curve_keys_size = curve_keys.size();
for(size_t i = 0; i < verts_size; i++)
bnds.grow(verts[i]);
for(size_t i = 0; i < curve_keys_size; i++)
bnds.grow(curve_keys[i].co, curve_keys[i].radius);
/* happens mostly on empty meshes */
if(!bnds.valid())
bnds.grow(make_float3(0.0f, 0.0f, 0.0f));
@@ -135,7 +170,12 @@ void Mesh::add_face_normals()
float3 v1 = verts_ptr[t.v[1]];
float3 v2 = verts_ptr[t.v[2]];
fN[i] = normalize(cross(v1 - v0, v2 - v0));
float3 norm = cross(v1 - v0, v2 - v0);
float normlen = len(norm);
if(normlen == 0.0f)
fN[i] = make_float3(0.0f, 0.0f, 0.0f);
else
fN[i] = norm / normlen;
if(flip)
fN[i] = -fN[i];
@@ -243,6 +283,43 @@ void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset)
}
}
void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset)
{
size_t curve_keys_size = curve_keys.size();
CurveKey *keys_ptr = NULL;
/* pack curve keys */
if(curve_keys_size) {
keys_ptr = &curve_keys[0];
for(size_t i = 0; i < curve_keys_size; i++) {
float3 p = keys_ptr[i].co;
float radius = keys_ptr[i].radius;
curve_key_co[i] = make_float4(p.x, p.y, p.z, radius);
}
}
/* pack curve segments */
size_t curve_num = curves.size();
if(curve_num) {
Curve *curve_ptr = &curves[0];
int shader_id = 0;
for(size_t i = 0; i < curve_num; i++) {
Curve curve = curve_ptr[i];
shader_id = scene->shader_manager->get_shader_id(curve.shader, this, false);
curve_data[i] = make_float4(
__int_as_float(curve.first_key + curvekey_offset),
__int_as_float(curve.num_keys),
__int_as_float(shader_id),
0.0f);
}
}
}
void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total)
{
if(progress->get_cancel())
@@ -327,7 +404,7 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
og->attribute_map.clear();
og->object_names.clear();
og->attribute_map.resize(scene->objects.size());
og->attribute_map.resize(scene->objects.size()*ATTR_PRIM_TYPES);
for(size_t i = 0; i < scene->objects.size(); i++) {
/* set object name to object index map */
@@ -343,7 +420,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
osl_attr.elem = ATTR_ELEMENT_VALUE;
osl_attr.value = attr;
og->attribute_map[i][attr.name()] = osl_attr;
og->attribute_map[i*ATTR_PRIM_TYPES][attr.name()] = osl_attr;
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr;
}
/* find mesh attributes */
@@ -357,27 +435,46 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
/* set object attributes */
foreach(AttributeRequest& req, attributes.requests) {
if(req.element == ATTR_ELEMENT_NONE)
continue;
OSLGlobals::Attribute osl_attr;
osl_attr.elem = req.element;
osl_attr.offset = req.offset;
if(req.triangle_element != ATTR_ELEMENT_NONE) {
osl_attr.elem = req.triangle_element;
osl_attr.offset = req.triangle_offset;
if(req.type == TypeDesc::TypeFloat)
if(req.triangle_type == TypeDesc::TypeFloat)
osl_attr.type = TypeDesc::TypeFloat;
else
osl_attr.type = TypeDesc::TypeColor;
if(req.std != ATTR_STD_NONE) {
/* if standard attribute, add lookup by geom: name convention */
ustring stdname(string("geom:") + string(attribute_standard_name(req.std)));
og->attribute_map[i][stdname] = osl_attr;
ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
og->attribute_map[i*ATTR_PRIM_TYPES][stdname] = osl_attr;
}
else if(req.name != ustring()) {
/* add lookup by mesh attribute name */
og->attribute_map[i][req.name] = osl_attr;
og->attribute_map[i*ATTR_PRIM_TYPES][req.name] = osl_attr;
}
}
if(req.curve_element != ATTR_ELEMENT_NONE) {
osl_attr.elem = req.curve_element;
osl_attr.offset = req.curve_offset;
if(req.curve_type == TypeDesc::TypeFloat)
osl_attr.type = TypeDesc::TypeFloat;
else
osl_attr.type = TypeDesc::TypeColor;
if(req.std != ATTR_STD_NONE) {
/* if standard attribute, add lookup by geom: name convention */
ustring stdname(string("geom:") + string(Attribute::standard_name(req.std)));
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][stdname] = osl_attr;
}
else if(req.name != ustring()) {
/* add lookup by mesh attribute name */
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr;
}
}
}
}
@@ -393,7 +490,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
int attr_map_stride = 0;
for(size_t i = 0; i < scene->meshes.size(); i++)
attr_map_stride = max(attr_map_stride, mesh_attributes[i].size()+1);
attr_map_stride = max(attr_map_stride, (mesh_attributes[i].size() + 1)*ATTR_PRIM_TYPES);
if(attr_map_stride == 0)
return;
@@ -404,12 +501,13 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
for(size_t i = 0; i < scene->objects.size(); i++) {
Object *object = scene->objects[i];
Mesh *mesh = object->mesh;
/* find mesh attributes */
size_t j;
for(j = 0; j < scene->meshes.size(); j++)
if(scene->meshes[j] == object->mesh)
if(scene->meshes[j] == mesh)
break;
AttributeRequestSet& attributes = mesh_attributes[j];
@@ -425,14 +523,29 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
else
id = scene->shader_manager->get_attribute_id(req.std);
if(mesh->triangles.size()) {
attr_map[index].x = id;
attr_map[index].y = req.element;
attr_map[index].z = as_uint(req.offset);
attr_map[index].y = req.triangle_element;
attr_map[index].z = as_uint(req.triangle_offset);
if(req.type == TypeDesc::TypeFloat)
if(req.triangle_type == TypeDesc::TypeFloat)
attr_map[index].w = NODE_ATTR_FLOAT;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
}
index++;
if(mesh->curves.size()) {
attr_map[index].x = id;
attr_map[index].y = req.curve_element;
attr_map[index].z = as_uint(req.curve_offset);
if(req.curve_type == TypeDesc::TypeFloat)
attr_map[index].w = NODE_ATTR_FLOAT;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
}
index++;
}
@@ -442,6 +555,15 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
attr_map[index].y = 0;
attr_map[index].z = 0;
attr_map[index].w = 0;
index++;
attr_map[index].x = ATTR_STD_NONE;
attr_map[index].y = 0;
attr_map[index].z = 0;
attr_map[index].w = 0;
index++;
}
/* copy to device */
@@ -449,6 +571,60 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
device->tex_alloc("__attributes_map", dscene->attributes_map);
}
static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_float, vector<float4>& attr_float3,
Attribute *mattr, TypeDesc& type, int& offset, AttributeElement& element)
{
if(mattr) {
/* store element and type */
element = mattr->element;
type = mattr->type;
/* store attribute data in arrays */
size_t size = mattr->element_size(
mesh->verts.size(),
mesh->triangles.size(),
mesh->curves.size(),
mesh->curve_keys.size());
if(mattr->type == TypeDesc::TypeFloat) {
float *data = mattr->data_float();
offset = attr_float.size();
attr_float.resize(attr_float.size() + size);
for(size_t k = 0; k < size; k++)
attr_float[offset+k] = data[k];
}
else {
float3 *data = mattr->data_float3();
offset = attr_float3.size();
attr_float3.resize(attr_float3.size() + size);
for(size_t k = 0; k < size; k++)
attr_float3[offset+k] = float3_to_float4(data[k]);
}
/* mesh vertex/curve index is global, not per object, so we sneak
* a correction for that in here */
if(element == ATTR_ELEMENT_VERTEX)
offset -= mesh->vert_offset;
else if(element == ATTR_ELEMENT_FACE)
offset -= mesh->tri_offset;
else if(element == ATTR_ELEMENT_CORNER)
offset -= 3*mesh->tri_offset;
else if(element == ATTR_ELEMENT_CURVE)
offset -= mesh->curve_offset;
else if(element == ATTR_ELEMENT_CURVE_KEY)
offset -= mesh->curvekey_offset;
}
else {
/* attribute not found */
element = ATTR_ELEMENT_NONE;
offset = 0;
}
}
void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
progress.set_status("Updating Mesh", "Computing attributes");
@@ -482,65 +658,23 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
/* todo: we now store std and name attributes from requests even if
* they actually refer to the same mesh attributes, optimize */
foreach(AttributeRequest& req, attributes.requests) {
Attribute *mattr = mesh->attributes.find(req);
Attribute *triangle_mattr = mesh->attributes.find(req);
Attribute *curve_mattr = mesh->curve_attributes.find(req);
/* todo: get rid of this exception */
if(!mattr && req.std == ATTR_STD_GENERATED) {
mattr = mesh->attributes.add(ATTR_STD_GENERATED);
/* todo: get rid of this exception, it's only here for giving some
* working texture coordinate for subdivision as we can't preserve
* any attributes yet */
if(!triangle_mattr && req.std == ATTR_STD_GENERATED) {
triangle_mattr = mesh->attributes.add(ATTR_STD_GENERATED);
if(mesh->verts.size())
memcpy(mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size());
memcpy(triangle_mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size());
}
/* attribute not found */
if(!mattr) {
req.element = ATTR_ELEMENT_NONE;
req.offset = 0;
continue;
}
update_attribute_element_offset(mesh, attr_float, attr_float3, triangle_mattr,
req.triangle_type, req.triangle_offset, req.triangle_element);
/* we abuse AttributeRequest to pass on info like element and
* offset, it doesn't really make sense but is convenient */
/* store element and type */
if(mattr->element == Attribute::VERTEX)
req.element = ATTR_ELEMENT_VERTEX;
else if(mattr->element == Attribute::FACE)
req.element = ATTR_ELEMENT_FACE;
else if(mattr->element == Attribute::CORNER)
req.element = ATTR_ELEMENT_CORNER;
req.type = mattr->type;
/* store attribute data in arrays */
size_t size = mattr->element_size(mesh->verts.size(), mesh->triangles.size());
if(mattr->type == TypeDesc::TypeFloat) {
float *data = mattr->data_float();
req.offset = attr_float.size();
attr_float.resize(attr_float.size() + size);
for(size_t k = 0; k < size; k++)
attr_float[req.offset+k] = data[k];
}
else {
float3 *data = mattr->data_float3();
req.offset = attr_float3.size();
attr_float3.resize(attr_float3.size() + size);
for(size_t k = 0; k < size; k++)
attr_float3[req.offset+k] = float3_to_float4(data[k]);
}
/* mesh vertex/triangle index is global, not per object, so we sneak
* a correction for that in here */
if(req.element == ATTR_ELEMENT_VERTEX)
req.offset -= mesh->vert_offset;
else if(mattr->element == Attribute::FACE)
req.offset -= mesh->tri_offset;
else if(mattr->element == Attribute::CORNER)
req.offset -= 3*mesh->tri_offset;
update_attribute_element_offset(mesh, attr_float, attr_float3, curve_mattr,
req.curve_type, req.curve_offset, req.curve_element);
if(progress.get_cancel()) return;
}
@@ -573,17 +707,24 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
size_t vert_size = 0;
size_t tri_size = 0;
size_t curve_key_size = 0;
size_t curve_size = 0;
foreach(Mesh *mesh, scene->meshes) {
mesh->vert_offset = vert_size;
mesh->tri_offset = tri_size;
mesh->curvekey_offset = curve_key_size;
mesh->curve_offset = curve_size;
vert_size += mesh->verts.size();
tri_size += mesh->triangles.size();
curve_key_size += mesh->curve_keys.size();
curve_size += mesh->curves.size();
}
if(tri_size == 0)
return;
if(tri_size != 0) {
/* normals */
progress.set_status("Updating Mesh", "Computing normals");
@@ -608,6 +749,22 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
device->tex_alloc("__tri_vindex", dscene->tri_vindex);
}
if(curve_size != 0) {
progress.set_status("Updating Mesh", "Copying Strands to device");
float4 *curve_keys = dscene->curve_keys.resize(curve_key_size);
float4 *curves = dscene->curves.resize(curve_size);
foreach(Mesh *mesh, scene->meshes) {
mesh->pack_curves(scene, &curve_keys[mesh->curvekey_offset], &curves[mesh->curve_offset], mesh->curvekey_offset);
if(progress.get_cancel()) return;
}
device->tex_alloc("__curve_keys", dscene->curve_keys);
device->tex_alloc("__curves", dscene->curves);
}
}
void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
/* bvh build */
@@ -642,6 +799,10 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
dscene->tri_woop.reference(&pack.tri_woop[0], pack.tri_woop.size());
device->tex_alloc("__tri_woop", dscene->tri_woop);
}
if(pack.prim_segment.size()) {
dscene->prim_segment.reference((uint*)&pack.prim_segment[0], pack.prim_segment.size());
device->tex_alloc("__prim_segment", dscene->prim_segment);
}
if(pack.prim_visibility.size()) {
dscene->prim_visibility.reference((uint*)&pack.prim_visibility[0], pack.prim_visibility.size());
device->tex_alloc("__prim_visibility", dscene->prim_visibility);
@@ -751,6 +912,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->bvh_nodes);
device->tex_free(dscene->object_node);
device->tex_free(dscene->tri_woop);
device->tex_free(dscene->prim_segment);
device->tex_free(dscene->prim_visibility);
device->tex_free(dscene->prim_index);
device->tex_free(dscene->prim_object);
@@ -758,6 +920,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->tri_vnormal);
device->tex_free(dscene->tri_vindex);
device->tex_free(dscene->tri_verts);
device->tex_free(dscene->curves);
device->tex_free(dscene->curve_keys);
device->tex_free(dscene->attributes_map);
device->tex_free(dscene->attributes_float);
device->tex_free(dscene->attributes_float3);
@@ -765,6 +929,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->bvh_nodes.clear();
dscene->object_node.clear();
dscene->tri_woop.clear();
dscene->prim_segment.clear();
dscene->prim_visibility.clear();
dscene->prim_index.clear();
dscene->prim_object.clear();
@@ -772,6 +937,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->tri_vnormal.clear();
dscene->tri_vindex.clear();
dscene->tri_verts.clear();
dscene->curves.clear();
dscene->curve_keys.clear();
dscene->attributes_map.clear();
dscene->attributes_float.clear();
dscene->attributes_float3.clear();

View File

@@ -50,6 +50,21 @@ public:
int v[3];
};
/* Mesh Curve */
struct Curve {
int first_key;
int num_keys;
uint shader;
uint pad;
int num_segments() { return num_keys - 1; }
};
struct CurveKey {
float3 co;
float radius;
};
/* Displacement */
enum DisplacementMethod {
DISPLACE_BUMP,
@@ -65,8 +80,12 @@ public:
vector<uint> shader;
vector<bool> smooth;
vector<CurveKey> curve_keys;
vector<Curve> curves;
vector<uint> used_shaders;
AttributeSet attributes;
AttributeSet curve_attributes;
BoundBox bounds;
bool transform_applied;
@@ -82,13 +101,18 @@ public:
size_t tri_offset;
size_t vert_offset;
size_t curve_offset;
size_t curvekey_offset;
/* Functions */
Mesh();
~Mesh();
void reserve(int numverts, int numfaces);
void reserve(int numverts, int numfaces, int numcurves, int numcurvekeys);
void clear();
void add_triangle(int v0, int v1, int v2, int shader, bool smooth);
void add_curve_key(float3 loc, float radius);
void add_curve(int first_key, int num_keys, int shader);
void compute_bounds();
void add_face_normals();
@@ -96,6 +120,7 @@ public:
void pack_normals(Scene *scene, float4 *normal, float4 *vnormal);
void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset);
void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset);
void compute_bvh(SceneParams *params, Progress *progress, int n, int total);
bool need_attribute(Scene *scene, AttributeStandard std);

View File

@@ -19,6 +19,7 @@
#include "device.h"
#include "mesh.h"
#include "object.h"
#include "scene.h"
#include "shader.h"
@@ -41,11 +42,24 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p
if(!has_displacement)
return false;
string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
progress.set_status("Updating Mesh", msg);
/* find object index. todo: is arbitrary */
size_t object_index = ~0;
for(size_t i = 0; i < scene->objects.size(); i++) {
if(scene->objects[i]->mesh == mesh) {
object_index = i;
break;
}
}
/* setup input for device task */
vector<bool> done(mesh->verts.size(), false);
device_vector<uint4> d_input;
uint4 *d_input_data = d_input.resize(mesh->verts.size());
size_t d_input_offset = 0;
size_t d_input_size = 0;
for(size_t i = 0; i < mesh->triangles.size(); i++) {
Mesh::Triangle t = mesh->triangles[i];
@@ -61,8 +75,8 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p
done[t.v[j]] = true;
/* set up object, primitive and barycentric coordinates */
/* when used, non-instanced convention: object = -object-1; */
int object = ~0; /* todo */
/* when used, non-instanced convention: object = ~object */
int object = ~object_index;
int prim = mesh->tri_offset + i;
float u, v;
@@ -81,16 +95,16 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p
/* back */
uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v));
d_input_data[d_input_offset++] = in;
d_input_data[d_input_size++] = in;
}
}
if(d_input_offset == 0)
if(d_input_size == 0)
return false;
/* run device task */
device_vector<float4> d_output;
d_output.resize(d_input.size());
d_output.resize(d_input_size);
device->mem_alloc(d_input, MEM_READ_ONLY);
device->mem_copy_to(d_input);
@@ -101,7 +115,7 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p
task.shader_output = d_output.device_pointer;
task.shader_eval_type = SHADER_EVAL_DISPLACE;
task.shader_x = 0;
task.shader_w = d_input.size();
task.shader_w = d_output.size();
device->task_add(task);
device->task_wait();

View File

@@ -2240,6 +2240,63 @@ void ParticleInfoNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_particle_info");
}
/* Hair Info */
HairInfoNode::HairInfoNode()
: ShaderNode("hair_info")
{
add_output("Is Strand", SHADER_SOCKET_FLOAT);
add_output("Intercept", SHADER_SOCKET_FLOAT);
add_output("Thickness", SHADER_SOCKET_FLOAT);
add_output("Tangent Normal", SHADER_SOCKET_NORMAL);
}
void HairInfoNode::attributes(AttributeRequestSet *attributes)
{
ShaderOutput *intercept_out = output("Intercept");
if(!intercept_out->links.empty())
attributes->add(ATTR_STD_CURVE_INTERCEPT);
ShaderNode::attributes(attributes);
}
void HairInfoNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out;
out = output("Is Strand");
if(!out->links.empty()) {
compiler.stack_assign(out);
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, out->stack_offset);
}
out = output("Intercept");
if(!out->links.empty()) {
int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT);
compiler.stack_assign(out);
compiler.add_node(NODE_ATTR, attr, out->stack_offset, NODE_ATTR_FLOAT);
}
out = output("Thickness");
if(!out->links.empty()) {
compiler.stack_assign(out);
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, out->stack_offset);
}
out = output("Tangent Normal");
if(!out->links.empty()) {
compiler.stack_assign(out);
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, out->stack_offset);
}
}
void HairInfoNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_hair_info");
}
/* Value */
ValueNode::ValueNode()

View File

@@ -331,6 +331,13 @@ public:
void attributes(AttributeRequestSet *attributes);
};
class HairInfoNode : public ShaderNode {
public:
SHADER_NODE_CLASS(HairInfoNode)
void attributes(AttributeRequestSet *attributes);
};
class ValueNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ValueNode)

View File

@@ -19,6 +19,7 @@
#include "device.h"
#include "light.h"
#include "mesh.h"
#include "curves.h"
#include "object.h"
#include "scene.h"
@@ -45,6 +46,7 @@ Object::Object()
motion.post = transform_identity();
use_motion = false;
use_holdout = false;
curverender = false;
}
Object::~Object()
@@ -86,6 +88,10 @@ void Object::apply_transform()
for(size_t i = 0; i < mesh->verts.size(); i++)
mesh->verts[i] = transform_point(&tfm, mesh->verts[i]);
for(size_t i = 0; i < mesh->curve_keys.size(); i++)
mesh->curve_keys[i].co = transform_point(&tfm, mesh->curve_keys[i].co);
Attribute *attr_tangent = mesh->curve_attributes.find(ATTR_STD_CURVE_TANGENT);
Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
@@ -110,6 +116,13 @@ void Object::apply_transform()
vN[i] = transform_direction(&ntfm, vN[i]);
}
if(attr_tangent) {
float3 *tangent = attr_tangent->data_float3();
for(size_t i = 0; i < mesh->curve_keys.size(); i++)
tangent[i] = transform_direction(&tfm, tangent[i]);
}
if(bounds.valid()) {
mesh->compute_bounds();
compute_bounds(false, 0.0f);
@@ -133,6 +146,7 @@ void Object::tag_update(Scene *scene)
}
}
scene->curve_system_manager->need_update = true;
scene->mesh_manager->need_update = true;
scene->object_manager->need_update = true;
}
@@ -189,6 +203,20 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
surface_area += triangle_area(p1, p2, p3);
}
foreach(Mesh::Curve& curve, mesh->curves) {
int first_key = curve.first_key;
for(int i = 0; i < curve.num_segments(); i++) {
float3 p1 = mesh->curve_keys[first_key + i].co;
float r1 = mesh->curve_keys[first_key + i].radius;
float3 p2 = mesh->curve_keys[first_key + i + 1].co;
float r2 = mesh->curve_keys[first_key + i + 1].radius;
/* currently ignores segment overlaps*/
surface_area += M_PI_F *(r1 + r2) * len(p1 - p2);
}
}
surface_area_map[mesh] = surface_area;
}
else
@@ -204,6 +232,23 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
surface_area += triangle_area(p1, p2, p3);
}
foreach(Mesh::Curve& curve, mesh->curves) {
int first_key = curve.first_key;
for(int i = 0; i < curve.num_segments(); i++) {
float3 p1 = mesh->curve_keys[first_key + i].co;
float r1 = mesh->curve_keys[first_key + i].radius;
float3 p2 = mesh->curve_keys[first_key + i + 1].co;
float r2 = mesh->curve_keys[first_key + i + 1].radius;
p1 = transform_point(&tfm, p1);
p2 = transform_point(&tfm, p2);
/* currently ignores segment overlaps*/
surface_area += M_PI_F *(r1 + r2) * len(p1 - p2);
}
}
}
/* pack in texture */
@@ -355,6 +400,7 @@ void ObjectManager::apply_static_transforms(Scene *scene, uint *object_flag, Pro
void ObjectManager::tag_update(Scene *scene)
{
need_update = true;
scene->curve_system_manager->need_update = true;
scene->mesh_manager->need_update = true;
scene->light_manager->need_update = true;
}

View File

@@ -48,6 +48,7 @@ public:
MotionTransform motion;
bool use_motion;
bool use_holdout;
bool curverender;
float3 dupli_generated;
float2 dupli_uv;

View File

@@ -29,6 +29,7 @@
#include "mesh.h"
#include "object.h"
#include "particles.h"
#include "curves.h"
#include "scene.h"
#include "svm.h"
#include "osl.h"
@@ -54,6 +55,7 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
integrator = new Integrator();
image_manager = new ImageManager();
particle_system_manager = new ParticleSystemManager();
curve_system_manager = new CurveSystemManager();
/* OSL only works on the CPU */
if(device_info_.type == DEVICE_CPU)
@@ -96,6 +98,7 @@ void Scene::free_memory(bool final)
light_manager->device_free(device, &dscene);
particle_system_manager->device_free(device, &dscene);
curve_system_manager->device_free(device, &dscene);
if(!params.persistent_images || final)
image_manager->device_free(device, &dscene);
@@ -112,6 +115,7 @@ void Scene::free_memory(bool final)
delete shader_manager;
delete light_manager;
delete particle_system_manager;
delete curve_system_manager;
delete image_manager;
}
else {
@@ -165,6 +169,11 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel()) return;
progress.set_status("Updating Hair Systems");
curve_system_manager->device_update(device, &dscene, this, progress);
if(progress.get_cancel()) return;
progress.set_status("Updating Meshes");
mesh_manager->device_update(device, &dscene, this, progress);
@@ -242,7 +251,8 @@ bool Scene::need_reset()
|| filter->need_update
|| integrator->need_update
|| shader_manager->need_update
|| particle_system_manager->need_update);
|| particle_system_manager->need_update
|| curve_system_manager->need_update);
}
void Scene::reset()

View File

@@ -25,7 +25,6 @@
#include "kernel_types.h"
#include "util_attribute.h"
#include "util_param.h"
#include "util_string.h"
#include "util_thread.h"
@@ -50,6 +49,7 @@ class Object;
class ObjectManager;
class ParticleSystemManager;
class ParticleSystem;
class CurveSystemManager;
class Shader;
class ShaderManager;
class Progress;
@@ -62,6 +62,7 @@ public:
device_vector<float4> bvh_nodes;
device_vector<uint> object_node;
device_vector<float4> tri_woop;
device_vector<uint> prim_segment;
device_vector<uint> prim_visibility;
device_vector<uint> prim_index;
device_vector<uint> prim_object;
@@ -72,6 +73,9 @@ public:
device_vector<float4> tri_vindex;
device_vector<float4> tri_verts;
device_vector<float4> curves;
device_vector<float4> curve_keys;
/* objects */
device_vector<float4> objects;
device_vector<float4> objects_vector;
@@ -170,6 +174,7 @@ public:
MeshManager *mesh_manager;
ObjectManager *object_manager;
ParticleSystemManager *particle_system_manager;
CurveSystemManager *curve_system_manager;
/* default shaders */
int default_surface;

View File

@@ -357,7 +357,7 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile)
tile_lock.unlock();
/* in case of a permant buffer, return it, otherwise we will allocate
/* in case of a permanent buffer, return it, otherwise we will allocate
* a new temporary buffer */
if(!params.background) {
tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride);
@@ -411,6 +411,12 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile)
rtile.rgba = 0;
rtile.buffers = tilebuffers;
/* this will tag tile as IN PROGRESS in blender-side render pipeline,
* which is needed to highlight currently rendering tile before first
* sample was processed for it
*/
update_tile_sample(rtile);
return true;
}

View File

@@ -47,7 +47,7 @@ void EdgeDice::reserve(int num_verts, int num_tris)
vert_offset = mesh->verts.size();
tri_offset = mesh->triangles.size();
mesh->reserve(vert_offset + num_verts, tri_offset + num_tris);
mesh->reserve(vert_offset + num_verts, tri_offset + num_tris, 0, 0);
Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);

View File

@@ -9,7 +9,6 @@ set(INC_SYS
)
set(SRC
util_attribute.cpp
util_cache.cpp
util_cuda.cpp
util_dynlib.cpp
@@ -33,7 +32,6 @@ endif()
set(SRC_HEADERS
util_algorithm.h
util_args.h
util_attribute.h
util_boundbox.h
util_cache.h
util_cuda.h

View File

@@ -1,51 +0,0 @@
/*
* 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 "util_attribute.h"
CCL_NAMESPACE_BEGIN
const char *attribute_standard_name(AttributeStandard std)
{
if(std == ATTR_STD_VERTEX_NORMAL)
return "N";
else if(std == ATTR_STD_FACE_NORMAL)
return "Ng";
else if(std == ATTR_STD_UV)
return "uv";
else if(std == ATTR_STD_GENERATED)
return "generated";
else if(std == ATTR_STD_UV_TANGENT)
return "tangent";
else if(std == ATTR_STD_UV_TANGENT_SIGN)
return "tangent_sign";
else if(std == ATTR_STD_POSITION_UNDEFORMED)
return "undeformed";
else if(std == ATTR_STD_POSITION_UNDISPLACED)
return "undisplaced";
else if(std == ATTR_STD_MOTION_PRE)
return "motion_pre";
else if(std == ATTR_STD_MOTION_POST)
return "motion_post";
else if(std == ATTR_STD_PARTICLE)
return "particle";
return "";
}
CCL_NAMESPACE_END

View File

@@ -65,6 +65,13 @@ public:
max = ccl::max(max, pt);
}
__forceinline void grow(const float3& pt, float border)
{
float3 shift = {border, border, border, 0.0f};
min = ccl::min(min, pt - shift);
max = ccl::max(max, pt + shift);
}
__forceinline void grow(const BoundBox& bbox)
{
grow(bbox.min);

View File

@@ -448,24 +448,6 @@ __device_inline int4 make_int4(const float3& f)
#endif
typedef enum AttributeStandard {
ATTR_STD_NONE = 0,
ATTR_STD_VERTEX_NORMAL,
ATTR_STD_FACE_NORMAL,
ATTR_STD_UV,
ATTR_STD_UV_TANGENT,
ATTR_STD_UV_TANGENT_SIGN,
ATTR_STD_GENERATED,
ATTR_STD_POSITION_UNDEFORMED,
ATTR_STD_POSITION_UNDISPLACED,
ATTR_STD_MOTION_PRE,
ATTR_STD_MOTION_POST,
ATTR_STD_PARTICLE,
ATTR_STD_NUM,
ATTR_STD_NOT_FOUND = ~0
} AttributeStandard;
CCL_NAMESPACE_END
#endif /* __UTIL_TYPES_H__ */

View File

@@ -1579,7 +1579,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
case NSScrollWheel:
{
if (!m_hasMultiTouchTrackpad) {
int momentum = 0;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
m_hasMultiTouchTrackpad = 0;
momentum = [event momentumPhase] || [event phase];
#endif
/* standard scrollwheel case */
if (!m_hasMultiTouchTrackpad && momentum == 0) {
GHOST_TInt32 delta;
double deltaF = [event deltaY];
@@ -1593,9 +1599,18 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
else {
NSPoint mousePos = [cocoawindow mouseLocationOutsideOfEventStream];
GHOST_TInt32 x, y;
double dx = [event deltaX];
double dy = -[event deltaY];
double dx;
double dy;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
/* with 10.7 nice scrolling deltas are supported */
dx = [event scrollingDeltaX];
dy = [event scrollingDeltaY];
#else
/* trying to pretend you have nice scrolls... */
dx = [event deltaX];
dy = -[event deltaY];
const double deltaMax = 50.0;
if ((dx == 0) && (dy == 0)) break;
@@ -1613,8 +1628,9 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
if (dy < -deltaMax) dy= -deltaMax;
else if (dy > deltaMax) dy= deltaMax;
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
dy = -dy;
#endif
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000, window, GHOST_kTrackpadEventScroll, x, y, dx, dy));
}

View File

@@ -595,6 +595,11 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
[m_window setAcceptsMouseMovedEvents:YES];
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
NSView *view = [m_window contentView];
[view setAcceptsTouchEvents:YES];
#endif
[m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
NSStringPboardType, NSTIFFPboardType, nil]];

View File

@@ -57,11 +57,12 @@ void bl_locale_set(const char *locale)
gen.add_messages_domain(default_domain);
//gen.set_default_messages_domain(default_domain);
try {
if (locale && locale[0]) {
std::locale::global(gen(locale));
}
else {
#if defined (__APPLE__)
#ifdef __APPLE__
// workaround to get osx system locale from user defaults
FILE *fp;
std::string locale_osx = "";
@@ -91,6 +92,10 @@ void bl_locale_set(const char *locale)
}
// Note: boost always uses "C" LC_NUMERIC by default!
}
catch(std::exception const &e) {
std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n";
}
}
const char *bl_locale_pgettext(const char *msgctxt, const char *msgid)
{
@@ -107,7 +112,7 @@ const char* bl_locale_pgettext(const char *msgctxt, const char *msgid)
return msgid;
}
catch(std::exception const &e) {
// std::cout << "boost_locale_pgettext: " << e.what() << " \n";
// std::cout << "bl_locale_pgettext(" << msgctxt << ", " << msgid << "): " << e.what() << " \n";
return msgid;
}
}

View File

@@ -29,7 +29,7 @@ set(INC
)
set(INC_SYS
../../extern/bullet2/src
${BULLET_INCLUDE_DIRS}
${PNG_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS}
)

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 3.9 MiB

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 KiB

After

Width:  |  Height:  |  Size: 563 KiB

View File

@@ -81,6 +81,8 @@ LANGUAGES = (
(35, "Esperanto (Esperanto)", "eo"),
(36, "Spanish from Spain (Español de España)", "es_ES"),
(37, "Amharic (አማርኛ)", "am_ET"),
(38, "Uzbek (Oʻzbek)", "uz_UZ"),
(39, "Uzbek Cyrillic (Ўзбек)", "uz_UZ@cyrillic"),
)
# Name of language file used by Blender to generate translations' menu.
@@ -91,7 +93,7 @@ LANGUAGES_FILE = "languages"
IMPORT_MIN_LEVEL = -1
# Languages in /branches we do not want to import in /trunk currently...
IMPORT_LANGUAGES_SKIP = {'bg', 'ca', 'fi', 'el', 'ko', 'ne', 'pl', 'ro'}
IMPORT_LANGUAGES_SKIP = {'am', 'bg', 'fi', 'el', 'et', 'ko', 'ne', 'pl', 'ro', 'uz', 'uz@cyrillic'}
# The comment prefix used in generated messages.txt file.
COMMENT_PREFIX = "#~ "

View File

@@ -188,6 +188,7 @@ dict_uimsgs = {
"occluder",
"passepartout",
"perspectively",
"pixelate",
"polygonization",
"selectability",
"slurph",
@@ -195,7 +196,7 @@ dict_uimsgs = {
"symmetrize",
"trackability",
"transmissivity",
"rasterized", "rasterization",
"rasterized", "rasterization", "rasterizer",
"renderer", "renderable", "renderability",
# Abbreviations
@@ -380,6 +381,7 @@ dict_uimsgs = {
"texface",
"timeline", "timelines",
"tosphere",
"uilist",
"vcol", "vcols",
"vgroup", "vgroups",
"vinterlace",

View File

@@ -30,6 +30,9 @@ __all__ = (
"display_name",
"display_name_from_filepath",
"ensure_ext",
"extensions_image",
"extensions_movie",
"extensions_audio",
"is_subdir",
"module_names",
"relpath",
@@ -39,6 +42,10 @@ __all__ = (
import bpy as _bpy
import os as _os
from _bpy_path import (extensions_audio,
extensions_movie,
extensions_image,
)
def abspath(path, start=None, library=None):
"""

View File

@@ -16,7 +16,7 @@
#
# ##### END GPL LICENSE BLOCK #####
# <pep8-80 compliant>
# <pep8 compliant>
__all__ = (
"bake_action",
@@ -52,7 +52,7 @@ def bake_action(frame_start,
:type do_pose: bool
:arg do_object: Bake objects.
:type do_object: bool
:arg do_constraint_clear: Remove constraints.
:arg do_constraint_clear: Remove constraints (and do 'visual keying').
:type do_constraint_clear: bool
:arg do_clean: Remove redundant keyframes after baking.
:type do_clean: bool
@@ -65,61 +65,20 @@ def bake_action(frame_start,
"""
# -------------------------------------------------------------------------
# Helper Functions
# Helper Functions and vars
def pose_frame_info(obj):
from mathutils import Matrix
def pose_frame_info(obj, do_visual_keying):
matrix = {}
for name, pbone in obj.pose.bones.items():
if do_visual_keying:
# Get the final transform of the bone in its own local space...
matrix[name] = obj.convert_space(pbone, pbone.matrix, 'POSE', 'LOCAL')
else:
matrix[name] = pbone.matrix_basis.copy()
return matrix
info = {}
pose = obj.pose
pose_items = pose.bones.items()
for name, pbone in pose_items:
binfo = {}
bone = pbone.bone
binfo["parent"] = getattr(bone.parent, "name", None)
binfo["bone"] = bone
binfo["pbone"] = pbone
binfo["matrix_local"] = bone.matrix_local.copy()
try:
binfo["matrix_local_inv"] = binfo["matrix_local"].inverted()
except:
binfo["matrix_local_inv"] = Matrix()
binfo["matrix"] = bone.matrix.copy()
binfo["matrix_pose"] = pbone.matrix.copy()
try:
binfo["matrix_pose_inv"] = binfo["matrix_pose"].inverted()
except:
binfo["matrix_pose_inv"] = Matrix()
info[name] = binfo
for name, pbone in pose_items:
binfo = info[name]
binfo_parent = binfo.get("parent", None)
if binfo_parent:
binfo_parent = info[binfo_parent]
matrix = binfo["matrix_pose"]
rest_matrix = binfo["matrix_local"]
if binfo_parent:
matrix = binfo_parent["matrix_pose_inv"] * matrix
rest_matrix = binfo_parent["matrix_local_inv"] * rest_matrix
binfo["matrix_key"] = rest_matrix.inverted() * matrix
return info
def obj_frame_info(obj):
info = {}
# parent = obj.parent
info["matrix_key"] = obj.matrix_local.copy()
return info
def obj_frame_info(obj, do_visual_keying):
return obj.matrix_local.copy() if do_visual_keying else obj.matrix_basis.copy()
# -------------------------------------------------------------------------
# Setup the Context
@@ -127,33 +86,30 @@ def bake_action(frame_start,
# TODO, pass data rather then grabbing from the context!
scene = bpy.context.scene
obj = bpy.context.object
pose = obj.pose
frame_back = scene.frame_current
if pose is None:
if obj.pose is None:
do_pose = False
if do_pose is None and do_object is None:
if not (do_pose or do_object):
return None
pose_info = []
obj_info = []
options = {'INSERTKEY_NEEDED'}
frame_range = range(frame_start, frame_end + 1, frame_step)
# -------------------------------------------------------------------------
# Collect transformations
# could speed this up by applying steps here too...
for f in frame_range:
scene.frame_set(f)
if do_pose:
pose_info.append(pose_frame_info(obj))
pose_info.append(pose_frame_info(obj, do_constraint_clear))
if do_object:
obj_info.append(obj_frame_info(obj))
f += 1
obj_info.append(obj_frame_info(obj, do_constraint_clear))
# -------------------------------------------------------------------------
# Create action
@@ -164,16 +120,12 @@ def bake_action(frame_start,
action = bpy.data.actions.new("Action")
atd.action = action
if do_pose:
pose_items = pose.bones.items()
else:
pose_items = [] # skip
# -------------------------------------------------------------------------
# Apply transformations to action
# pose
for name, pbone in (pose_items if do_pose else ()):
if do_pose:
for name, pbone in obj.pose.bones.items():
if only_selected and not pbone.bone.select:
continue
@@ -184,37 +136,28 @@ def bake_action(frame_start,
# create compatible eulers
euler_prev = None
for f in frame_range:
f_step = (f - frame_start) // frame_step
matrix = pose_info[f_step][name]["matrix_key"]
for (f, matrix) in zip(frame_range, pose_info):
pbone.matrix_basis = matrix[name].copy()
# pbone.location = matrix.to_translation()
# pbone.rotation_quaternion = matrix.to_quaternion()
pbone.matrix_basis = matrix
pbone.keyframe_insert("location", -1, f, name)
pbone.keyframe_insert("location", -1, f, name, options)
rotation_mode = pbone.rotation_mode
if rotation_mode == 'QUATERNION':
pbone.keyframe_insert("rotation_quaternion", -1, f, name)
pbone.keyframe_insert("rotation_quaternion", -1, f, name, options)
elif rotation_mode == 'AXIS_ANGLE':
pbone.keyframe_insert("rotation_axis_angle", -1, f, name)
pbone.keyframe_insert("rotation_axis_angle", -1, f, name, options)
else: # euler, XYZ, ZXY etc
if euler_prev is not None:
euler = pbone.rotation_euler.copy()
euler.make_compatible(euler_prev)
pbone.rotation_euler = euler
euler_prev = euler
del euler
pbone.keyframe_insert("rotation_euler", -1, f, name)
if euler_prev is None:
else:
euler_prev = pbone.rotation_euler.copy()
pbone.keyframe_insert("rotation_euler", -1, f, name, options)
pbone.keyframe_insert("scale", -1, f, name)
pbone.keyframe_insert("scale", -1, f, name, options)
# object. TODO. multiple objects
if do_object:
@@ -225,18 +168,16 @@ def bake_action(frame_start,
# create compatible eulers
euler_prev = None
for f in frame_range:
matrix = obj_info[(f - frame_start) // frame_step]["matrix_key"]
obj.matrix_local = matrix
for (f, matrix) in zip(frame_range, obj_info):
obj.matrix_basis = matrix[name]
obj.keyframe_insert("location", -1, f)
obj.keyframe_insert("location", -1, f, options)
rotation_mode = obj.rotation_mode
if rotation_mode == 'QUATERNION':
obj.keyframe_insert("rotation_quaternion", -1, f)
obj.keyframe_insert("rotation_quaternion", -1, f, options)
elif rotation_mode == 'AXIS_ANGLE':
obj.keyframe_insert("rotation_axis_angle", -1, f)
obj.keyframe_insert("rotation_axis_angle", -1, f, options)
else: # euler, XYZ, ZXY etc
if euler_prev is not None:
euler = obj.rotation_euler.copy()
@@ -244,15 +185,11 @@ def bake_action(frame_start,
obj.rotation_euler = euler
euler_prev = euler
del euler
obj.keyframe_insert("rotation_euler", -1, f)
if euler_prev is None:
else:
euler_prev = obj.rotation_euler.copy()
obj.keyframe_insert("rotation_euler", -1, f, options)
obj.keyframe_insert("scale", -1, f)
scene.frame_set(frame_back)
obj.keyframe_insert("scale", -1, f, options)
# -------------------------------------------------------------------------
# Clean
@@ -271,4 +208,6 @@ def bake_action(frame_start,
else:
i += 1
scene.frame_set(frame_back)
return action

View File

@@ -26,7 +26,6 @@ __all__ = (
import bpy
import mathutils
from bpy.props import BoolProperty, FloatVectorProperty
@@ -80,7 +79,7 @@ def add_object_align_init(context, operator):
rotation = space_data.region_3d.view_matrix.to_3x3().inverted()
rotation.resize_4x4()
else:
rotation = mathutils.Matrix()
rotation = Matrix()
# set the operator properties
if operator:

Some files were not shown because too many files have changed in this diff Show More