1
1

Compare commits

...

329 Commits

Author SHA1 Message Date
99e17c236e GPencil: Cleanup - Rename function for better naming
The old function name was not clear enough
2016-08-12 15:55:03 +02:00
5355c40dd1 GPencil: Move polygon to back only if something was drawn
If the user enable polygon draw and press ESC before drawing something,
the last stroke must not be moved back.
2016-08-12 15:55:03 +02:00
3fd807c088 Cycles: Remove set but unused variable 2016-08-12 15:55:03 +02:00
Julian Eisel
0082017833 Cycles: Quiet warning with WITH_OPENSUBDIV disabled
Checked with @maiself, for now going with this simple solution.
2016-08-12 15:55:03 +02:00
a109b289dc Cycles: fix objects disappearing when starting or stopping movement.
Another issue with the modified particle motion blur fix: since
pre and post are used as validity markers, they must be set even
if there is no actual motion, like the original bool flags were.
Otherwise an object starting to move or stopping is interpreted
as having invalid blur data and hidden.
2016-08-12 15:55:03 +02:00
Julian Eisel
24f1b91259 Fix local view editing broken after changing object's layer from non-local view
Wasn't copying back local view bytes to object after changing layer.

Steps to reproduce were:
* Split 3D view in default startup.blend
* Enter local view in one of the 3D views
* Move default cube to different layer *in the other 3D view* (the one that's not in local view)
* Try transforming object from 3D View that's in local view (should lag)
2016-08-12 15:55:03 +02:00
58b1887934 Cycles microdisplacement: Move displacement options from mesh to material settings
Displacement is now a per material setting, which means old files will have to
be updated if they had used displacement. Cool side effect of this change is
material previews now show displacement.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D2140
2016-08-12 15:55:03 +02:00
bef2fd9218 Set WIN32_WINNT for all windows platforms, not just x64 2016-08-12 15:55:03 +02:00
808e153179 Cycles microdisplacement: Support for Catmull-Clark subdivision via OpenSubdiv
Enables Catmull-Clark subdivision meshes with support for creases and attribute
subdivision. Still waiting on OpenSubdiv to fully support face varying
interpolation for subdividing uv coordinates tho. Also there may be some
inconsistencies with Blender's subdivision which will be resolved at a
later time.

Code for reading patch tables and creating patch maps is borrowed
from OpenSubdiv.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D2111
2016-08-12 15:55:03 +02:00
856c30675a GPencil: Handle drawing on back for polygons
The polygons must move the stroke to back only when polygon is complete
2016-08-12 15:55:03 +02:00
ddfa59d164 GPencil: Add option to draw new strokes on back of layer
For artist point of view is very useful to have an option to draw by
default the new strokes on back of all strokes in the layer.
2016-08-12 15:55:03 +02:00
5e8ba041c6 GPencil: Fix error in arrange strokes
During code review a field was renamed, but one line was missing.
2016-08-12 15:55:03 +02:00
07efe1119e Don't hide on/off buttons of the Softbody modifier when there's Collision.
From source code history, it seems this behavior is a relic of a very
old limitation when the same object couldn't be both a Softbody and a
Collision object. In those times if somehow both modifiers were added
to an object, Softbody auto-disabled itself and buttons were hidden.

Now however there is no problem having both modifiers on an object,
so there is no point hiding the buttons. The same exact buttons are
available on the physics tab in any case.
2016-08-12 15:55:03 +02:00
9febb30b40 Particles: don't output nonsense UV data for Grid distribution particles.
As reported in T48928, From Dupli UV is not supported for grid
distribution, and running the normal code as usual simply produces
nonsense data, because fuv is used to hold orco instead of
interpolation factors for uv, and num is zero.

Since support won't be added in 2.78, just stop outputting nonsense.
2016-08-12 15:55:03 +02:00
ccf39d5aa0 Fix pretty stupid mistake in last 'append fix' commit (rB50c017b6eabd). 2016-08-12 15:55:03 +02:00
369292de61 Cleanup: add missing ID types to BKE_library_idtype_can_use_idtype(). 2016-08-12 15:55:03 +02:00
b182c0dd30 Fix T49028: crash when copying a scene without grease pencil data. 2016-08-12 15:55:03 +02:00
c21d63ff3e Cleanup: better not split UI strings when possible... 2016-08-12 15:55:03 +02:00
e22e1a486d Cleanup some new gpencil rna functions names.
Convention for properties callback names is to prefix them with a version of the RNA struct name.
2016-08-12 15:55:03 +02:00
c710815881 Basic Alembic support
All in all, this patch adds an Alembic importer, an Alembic exporter,
and a new CacheFile data block which, for now, wraps around an Alembic
archive. This data block is made available through a new modifier ("Mesh
Sequence Cache") as well as a new constraint ("Transform Cache") to
somewhat properly support respectively geometric and transformation data
streaming from alembic caches.

A more in-depth documentation is to be found on the wiki, as well as a
 guide to compile alembic: https://wiki.blender.org/index.php/
User:Kevindietrich/AlembicBasicIo.

Many thanks to everyone involved in this little project, and huge shout
out to "cgstrive" for the thorough testings with Maya, 3ds Max, Houdini
and Realflow as well as @fjuhec, @jensverwiebe and @jasperge for the
custom builds and compile fixes.

Reviewers: sergey, campbellbarton, mont29

Reviewed By: sergey, campbellbarton, mont29

Differential Revision: https://developer.blender.org/D2060
2016-08-12 15:55:03 +02:00
a1f9ca9135 Add the collision group option to the UI for boid particle physics.
The option already works, just missing from the ui since it
has completely different option set from newtonian and fluid.
2016-08-12 15:55:03 +02:00
96e628d6f7 Fix T26658: particles stopped or bounced by 100% permeability colliders.
There were two issues here. One is that the fix done originally for this
bug only checks for colliding with the same face as the single preceeding
hit. If the particle hits an edge or vertex of the collider, it in fact
hits two or more faces, so the loop ends up cycling between first two
of them and reaches the max collision limit.

The fix is to disable the collider for the sim step once a permeability
roll succeeds, by adding it to a skip list. Skipping just one face causes
some particles to bounce at odd angles in case of partial permeability.

The second problem was that the collider bounced back a small percentage
of particles, and the cause seemed to be that the code was set to flip
the velocity if the particle was just past the collider but still within
collision distance. Inverting both values causes a half permeable collider
to stop particles, so it seems that this if branch shouldn't bounce at all.

Test file: {F327322}

Reviewers: lukastoenne, brecht

Reviewed By: brecht

Subscribers: brecht, #physics

Maniphest Tasks: T26658

Differential Revision: https://developer.blender.org/D2120
2016-08-12 15:55:03 +02:00
Julian Eisel
10b6cada7f Fix wrong property type usage
Prints error on startup.
2016-08-12 15:55:03 +02:00
883f9cdd1b Cycles: Add AttributeDescriptor
Adds a descriptor for attributes that can easily be passed around and extended
to contain more data. Will be used for attributes on subdivision meshes.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D2110
2016-08-12 15:55:03 +02:00
1dc6bd1060 Fix for Cycles particle motion blur hiding fix.
My mistake in modifying the patch.
2016-08-12 15:55:03 +02:00
354e75f160 Fix T49023: Segfault when switching brushes while renaming another brush.
rna_GPencilBrush_name_set() was trying to use a mere bGPDbrush as a complete ToolSettings,
was doomed to fail...
2016-08-12 15:55:03 +02:00
a0e3fdfc47 GPencil: Tweaks to layout to try and get the spacing a bit nicer
Currently, the lack of spacing (or rather, odd spacing/clumping) in places
seemed a bit off.
2016-08-12 15:55:03 +02:00
9f6f24edec GPencil: Various UI name fixes
* "Flip direction" -> "Flip Direction"
* "Show drawing direction" -> "Show Directions"
* "Grease Pencil Curves" -> "Brush Curves"
  (I was considering "Brush Response Curves" instead, but that seemed like too much
   of a mouthful)
* "X" for removing a palette. The UI there was more similar to a standard datablock
  selector, so it should use the "+X" combo instead of "+-" combo for consistency.
  (Note though, presets tend to use "+-" instead - e.g. see the Render Settings)
2016-08-12 15:55:03 +02:00
8de596cdad GPencil: Added Ctrl-J hotkey for Joining strokes
(Ctrl-Shift-J is for "Join and Copy")
2016-08-12 15:55:03 +02:00
ba2300904f GPencil: "Join Strokes" tool doesn't leave gaps by default now
Previously, it would insert "invisible" points after the endpoints of the strokes,
so that they wouldn't appear to be joined, but that behaviour could also get quite
confusing as you wouldn't be sure whether the strokes were really joined or not.

To keep the previous behaviour, simply enable the "Leave Gaps" option on the operator
after running it. This setting will get saved between runs of the operator.
2016-08-12 15:55:03 +02:00
c6ebbf2b8c Fix T49022: Crash in BKE_libblock_remap_locked.
Previous check to skip non-linkable IDs resulted in not clearing those skipped ID's newid member,
wich lead to try to remap it later in code.
2016-08-12 15:55:03 +02:00
1cfe61bf18 Cleanup: add missing entries to library_query.c ID types switch case. 2016-08-12 15:55:03 +02:00
351201ef18 Fix T48366: Freestyle will unnecessary exclude some linked objects.
Group membership testing for including/excluding feature lines was not
accounting for object names possibly further qualified by library file
paths.

Also fixed a few potential (but unlikely) references of uninitialized
variables.

A big thank to Bastien Montagne for the insight on the cause of the
problem and how to fix it.
2016-08-12 15:55:03 +02:00
208514114d Freestyle: minor code cleanup (whites pace). 2016-08-12 15:55:03 +02:00
67f4191277 Fix T49014: Append does not work in some cases.
There were actually two issues, one in recent changes and one existing... forever?

I) id_make_local() would never proceed over indirectly linked data, which is required in specific 'append' context.
II) BKE_image_copy() was not setting id->newid pointer of newly copied ID.

About II: don't really know why image copy does its own cooking instead of using generaic ID copy helpers.
Think this should be changed, but that would be after 2.78 now.
2016-08-12 15:55:03 +02:00
12a1a280af Cycles: Fix embarrassing typo
Spotted by Mai Lavelle, thanks!
2016-08-12 15:55:03 +02:00
f313329862 Cycles: Correction to previous commit
The change didn't fix difference render result on CUDA as i've hoped,
so reverting change for GPU rendering for now.

Sorry for the noise.
2016-08-12 15:55:03 +02:00
085eef1d15 Cycles: Fix/workaround for wrong/noise render results with GCC6 2016-08-12 15:55:03 +02:00
2aabbd9fb6 Curve Fitting: fix off by one error
In practice this wasn't likely to cause problems, but better fix.
2016-08-12 15:55:03 +02:00
ea51099303 VSE sound strips: draw either the waveform or text label, not both.
Drawing both text and the wave onto a sound strip makes both hard to read,
which is a concrete issue for Hjalti at the moment. This was the simplest
fix I could think of to give him control over what he sees.
2016-08-12 15:55:03 +02:00
65936b9217 Cycles: hide particles with broken motion blur traces.
Currently cycles cannot correctly render motion blur for objects that appear or
disappear during the shutter window. Until that can be fixed properly, it may be
better to hide such particles rather than let them render as if they were
stationary for half of the frame.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D2125
2016-08-12 15:55:03 +02:00
1c57069a0f Fix python error when OSL file has wrong extension. 2016-08-12 15:55:03 +02:00
5c335e9b89 Add upstream information to curve_fit_nd library 2016-08-12 15:55:03 +02:00
749ee40690 Curve Fitting: sync with upstream
Correct accidental float use
2016-08-12 15:55:03 +02:00
Julian Eisel
c0f4975ecb Cleanup: Use BKE_gpencil prefix
This is a good point to change this as grease-pencil-v2 branch was just merged, so I hope merge conflicts with other branches are minimal.
2016-08-12 15:55:03 +02:00
107083a6a9 Cycles: copy shader node names over in the blender sync code.
This makes constant folding logs with --debug-cycles more meaningful.
A tiny fix is needed in OSL generator to match recent node refactoring.
2016-08-12 15:55:03 +02:00
9adc5c5e19 Cycles: Report human-readable string of compilation error code
It is possible that compilation will fail without giving anything in the
log buffer. For this cases giving a tip about error code will be really
handy.

Patch by @Ilia, thanks!
2016-08-12 15:55:03 +02:00
195e80e94c Do not disable continuous drawing if click out of drawing area 2016-08-05 17:57:08 +02:00
db3ea8cfc4 Merged last version from master 2016-08-04 08:53:12 +02:00
c0b9e97675 Cleanup: Text case 2016-08-03 23:00:28 +02:00
175aea121c Cleanup: Text case 2016-08-03 22:46:46 +02:00
b209d7c553 Cleanup: Replace text 2016-08-03 22:46:46 +02:00
Julian Eisel
3c411830da Cleanup: Code style 2016-08-03 22:41:56 +02:00
e266147495 Cleanup: Update index value for better code reading 2016-08-03 22:12:59 +02:00
Julian Eisel
ed70a2a4fc Cleanup: Line length 2016-08-03 22:03:52 +02:00
Julian Eisel
9e1a1eafaa Use proper default prop values, add asserts for prop usage 2016-08-03 21:41:14 +02:00
6067f0e62b Cleanup: Remove unused fields 2016-08-03 21:25:14 +02:00
Julian Eisel
a1f6562c5d Fix palette reordering broken after recent cleanups
Also added assert.
2016-08-03 21:20:54 +02:00
Julian Eisel
ea7c408d7e Quiet warning, cleanup whitespace in macro 2016-08-03 21:05:10 +02:00
df23ee1bc2 Use default color from user preferences when create a new color
Also remove an old wrong comment line
2016-08-03 19:41:26 +02:00
c060112a12 Cleanup: Replace use of layer color in onion skin
The layer color is not used anymore, so by default use the user
preferences color.
2016-08-03 19:34:19 +02:00
584f378a09 Cleanup: Change field comments 2016-08-03 19:20:25 +02:00
95badd1e2c Fix bug in selection if active frame is NULL 2016-08-03 18:04:19 +02:00
17565a6249 Rename operator GPENCIL_OT_hideselect_toggle to GPENCIL_OT_selection_opacity_toggle 2016-08-03 17:21:13 +02:00
4be3f122e1 Do not disable continuous drawing when press Enter o ESC
This line was related to previous commits and now can be removed.
2016-08-03 16:52:45 +02:00
952754bd6a Cleanup: Use iterator macro for layers and strokes 2016-08-01 16:49:55 +02:00
23bea89248 Cleanup: Replace by matrix multiplication 2016-08-01 16:28:44 +02:00
bd5cc1d4c8 Cleanup: Create Macro for loop layer and strokes 2016-08-01 11:21:25 +02:00
6d7cc47be5 Cleanup: Remove unused field 2016-08-01 11:09:14 +02:00
099dd3eb2b Replace for loop with layer iterator 2016-07-31 22:48:34 +02:00
e090dcff21 Make start visual point bigger than end point 2016-07-31 19:35:34 +02:00
5679ebc255 Use angle in radians internally 2016-07-31 19:21:51 +02:00
f73cfb49e6 Cleanup: Better tooltip text 2016-07-31 19:08:30 +02:00
a5a504e8f6 Cleanup: Style 2016-07-31 19:07:55 +02:00
d1d3bc711e Fix arrange parameter after revert text commit 2016-07-31 18:51:41 +02:00
5f392593ce Revert arrange options text 2016-07-31 18:49:51 +02:00
7512aa553a Revert "Fix missing pie menu changes after rename arrange parameter in previous commit"
This reverts commit a1d6a21915.
2016-07-31 18:44:44 +02:00
00c7713047 Cleanup: Use copy_v4_v4 instead of set array 2016-07-31 18:42:40 +02:00
f75005d34c Cleanup: Rename function 2016-07-31 18:37:31 +02:00
cca3c0061e Cleanup: Replace lines by matrix multiplication 2016-07-31 18:33:13 +02:00
6ab0e48333 Cleanup: Remove unused function 2016-07-31 18:20:00 +02:00
8e1b5a28fc Remove unused function 2016-07-31 18:03:40 +02:00
033491d7a6 Fix operator name after rename 2016-07-31 18:01:58 +02:00
93686646e3 Cleanup: Fix comment 2016-07-30 11:32:02 +02:00
a1d6a21915 Fix missing pie menu changes after rename arrange parameter in previous commit 2016-07-30 10:45:25 +02:00
bf03f3e8aa Cleanup: Fix comment 2016-07-30 10:28:46 +02:00
4f488ca6a3 Change operator thickness_apply to use only active layer 2016-07-30 10:28:14 +02:00
3606cd41e7 Cleanup: Rename property is_closed to draw_cyclic 2016-07-30 10:17:33 +02:00
743558f000 Cleanup: Remone unused code 2016-07-30 09:06:02 +02:00
Julian Eisel
cfaa3cf25e Add DNA_struct_elem_find check
Other devs can now safely add own stuff to 2.77.3 version patch.
Also minor whitespace cleanup.
2016-07-30 03:03:39 +02:00
Julian Eisel
991d39f1e0 Fix memory leak when joining strokes
Wasn't freeing arrays.
2016-07-30 02:41:32 +02:00
Julian Eisel
e640f2a7c6 Cleanup: Unneeded flag check, shorten if/else block 2016-07-30 02:27:37 +02:00
Julian Eisel
52af4ec289 Remove unneeded BLI_listbase_count call
BLI_findlink returns NULL if index is higher than number of links.
2016-07-30 02:13:35 +02:00
Julian Eisel
b1640a2ee2 Reduce number of padding dummy variables 2016-07-30 02:08:46 +02:00
Julian Eisel
fcb0a2ef42 Cleanup: Group keymap item definitions together 2016-07-30 01:16:48 +02:00
Julian Eisel
76bfe05ff6 Cleanup: Operator names, descriptions, whitespace, ... 2016-07-30 01:10:54 +02:00
Julian Eisel
7340a1ea3e Random Cleanup: Whitespace, style, UI descriptions, ... 2016-07-29 23:23:00 +02:00
Julian Eisel
00d45628f8 Fix unused var warnings 2016-07-29 21:14:38 +02:00
Julian Eisel
58b0216510 Correct wrong changes in do_versions 2016-07-29 21:14:15 +02:00
93d7efa3a2 Merge branch 'master' into grease-pencil-v2 2016-07-29 18:53:33 +02:00
Julian Eisel
093c524a65 Minor (uberpicky) optimization to new GPencil freeing functions 2016-07-29 18:33:02 +02:00
ae9f4872af Add Join&Copy button to UI panel 2016-07-29 18:20:53 +02:00
40e60e718b Hide layer colors in dope sheet
This colors are not used anymore. Maybe in the future an icon can be
added.
2016-07-29 18:04:32 +02:00
Julian Eisel
13f9c856d4 Use ED_ prefix for externally used editor functions 2016-07-29 17:58:46 +02:00
Julian Eisel
3445c728e3 Minor UI Cleanup
* Avoid unintuitive operator menus, use default operator
* Don't expand GPencil sculpt tool menu to avoid scrolling madness
* Rename OP name: "Delete..." -> "Delete"
2016-07-29 16:56:10 +02:00
Julian Eisel
a46a0a1686 Cleanup stroke_cyclic_toggle OP 2016-07-29 15:55:10 +02:00
Julian Eisel
ec9115cab9 Cleanup: Unused var 2016-07-29 15:33:40 +02:00
Julian Eisel
b2186f8b9a Use GHash in GP merge OP to avoid O(n^2) lookups 2016-07-29 15:28:56 +02:00
Julian Eisel
3ac871100d Fix compiling Blenderplayer 2016-07-29 15:28:29 +02:00
a68aab494d Cleanup: Rename and recode arrange stroke operator
Rename for clearer name and recode partially in order to make it faster
and cleaner.
2016-07-29 13:44:05 +02:00
0b87985661 Fix error when joining strokes in different layers 2016-07-28 21:54:43 +02:00
603962bb86 Cleanup: Use editable_gpencil_layer context iterator in flip strokes operator 2016-07-28 19:23:39 +02:00
faad153ad9 Cleanup: Use editable_gpencil_layer context iterator in join strokes operator 2016-07-28 19:12:56 +02:00
2e37142e19 Rename close operator and rewrite to use cyclic drawing instead of inserting new points
This operator is only available in 3dView
2016-07-28 19:06:16 +02:00
a786a1c0f4 Merge branch 'master' into grease-pencil-v2 2016-07-28 12:11:31 +02:00
4db2748b58 Cleanup: Rename field for clarity 2016-07-28 11:55:46 +02:00
11eda64b59 Cleanup: Replace comment 2016-07-28 11:46:58 +02:00
f0be1d9312 Create new fields for tint color and opacity and do not reuse old fields 2016-07-28 11:43:52 +02:00
40d8ac24ea Cleanup: Use the editable_gpencil_layers context iterator instead of manually iterating over layers 2016-07-27 23:49:30 +02:00
8d971635b9 Cleanup: Rename brush info to brush name 2016-07-27 22:54:13 +02:00
e3a239b99f Cleanup: Rename palette info to palette name 2016-07-27 21:26:50 +02:00
d1bac1bdc3 Cleanup: Style 2016-07-27 21:05:57 +02:00
d6dcf63961 Cleanup: Reorder enum for Strength sculpt brush 2016-07-27 21:03:13 +02:00
cea7c27cec Cleanup: Fix merge error in initialization code removing duplicate code 2016-07-27 20:55:43 +02:00
78c5e17ac8 Cleanup: Rename function gpencil_brush_crt_presets to gpencil_brush_init_presets 2016-07-27 20:33:20 +02:00
86a6bbae7c Cleanup: Remove line not used anymore 2016-07-27 20:08:40 +02:00
a5915f6fc6 Move Close stroke operator 2016-07-27 20:07:22 +02:00
8a64b75d86 Remove duplicate code by merge error 2016-07-27 20:05:30 +02:00
2bb9435a88 Hide parent options if not 3D view 2016-07-27 19:59:47 +02:00
0adb60af03 Remove space in layers panel if parent to bone 2016-07-27 19:57:06 +02:00
1a7ba05969 Change layers panel design 2016-07-27 19:51:12 +02:00
3e6859f838 Merge branch 'master' into grease-pencil-v2 2016-07-27 11:51:00 +02:00
56d65b5564 Cleanup: Replace custom code by standard function BLI_movelisttolist 2016-07-26 19:18:16 +02:00
dba4f58383 Remove operator to create RenderLayers from GP layers
After some code review, this option has been removed because need to be
redesigned to integrate better in the current rendering workflow.
2016-07-26 13:00:08 +02:00
75d2892a2b If render animation, too many passes are created with same name 2016-07-26 12:54:59 +02:00
880af3de17 Remove Hide/Unhide selected points button and RNA property
Now, the hide and unhide is controlled by alpha factor only. The Ctrl+H
can toggle alpha between 0 and 1 to speed up artist drawing session.
2016-07-25 23:23:06 +02:00
3facf573ba Revert writelist. THe writestruct generates a bug 2016-07-25 12:08:40 +02:00
08d91813cd Cleanup: Remove debug line 2016-07-24 23:22:42 +02:00
4844e4cfd5 Remove disable continuous drawing with D
Artist find better to avoid this option
2016-07-24 16:21:49 +02:00
be054a9c20 Cleanup: Replace code by predefined function 2016-07-23 23:09:38 +02:00
b4755f900a Replace len_v3v3 with len_squared_v3v3 to avoid sqrtf call 2016-07-23 23:04:20 +02:00
050800c168 Do not enable continuous drawing when press draw button 2016-07-23 15:55:22 +02:00
f276e5c23c Remove custom cursor for GP drawing
After some test, the cursor is intrusive and need a better solution. We
add the topic to whishlist
2016-07-22 22:02:59 +02:00
c1e2c164e0 Remove palette colors panel if no active layer 2016-07-22 19:00:59 +02:00
8001ccd90a Cleanup: Use BLI_findstring instead of custom search loop 2016-07-22 18:52:30 +02:00
bb349ccf7a Cleanup: Replace function to avoid multiple calls to BLI_remlink 2016-07-22 18:35:47 +02:00
6ded42943e Cleanup: Remove giant if block and replace by continue 2016-07-22 18:24:26 +02:00
e721659845 Cleanup: Remove redundant calls to gpencil_stroke_getcolor 2016-07-22 17:46:48 +02:00
b74123edec Cleanup: Restore comment removed by error 2016-07-22 17:27:27 +02:00
0b7c331de8 Cleanup: Rename function for temp points 2016-07-22 17:25:46 +02:00
361b9cd8d7 Cleanup: Add helper functions for point color 2016-07-22 17:19:46 +02:00
eb5210bcc4 Cleanup: Remove redundant loop 2016-07-22 16:54:33 +02:00
4bde6672fa Cleanup: Remove unused field 2016-07-22 16:45:03 +02:00
18ecea939a Cleanup: Style and remove redundant call to set color 2016-07-22 12:19:26 +02:00
69e56bb96e Cleanup: Replace ARRAY_SET_ITEMS by matrix multiplication 2016-07-22 12:13:07 +02:00
040d562485 Cleanup: Remove debug printf line 2016-07-22 12:07:18 +02:00
bdaa221b5b Cleanup: Style 2016-07-22 12:06:15 +02:00
f3931e8ff5 Cleanup: Remove redundant characters in function call 2016-07-22 12:04:05 +02:00
adaf74e8d4 Cleanup: Replace wrong comment 2016-07-22 11:57:50 +02:00
83b0ef02e6 Cleanup: Replace loop by BLI_freelistN 2016-07-22 11:56:41 +02:00
6a10ae7c5f Cleanup: Replace definitions by inline definition 2016-07-22 11:50:53 +02:00
b8a8b9a049 Renamed GPENCIL_STRENGHT_LOWEST to GPENCIL_STRENGTH_MIN 2016-07-22 11:38:48 +02:00
5d72e40db9 Change GP drawing cursor size and style 2016-07-21 23:51:26 +02:00
85b5ebf321 Remove D keymap. Conflict with pie menus 2016-07-21 23:06:36 +02:00
799eedcd89 Change GP drawing cursor 2016-07-21 21:32:11 +02:00
e7cb47c5b7 Change the way continuous drawing is enabled
Now for using GP. Press D...draw...press D to finish. Always continuous
is enabled. No more keep D key pressed.
2016-07-21 13:42:07 +02:00
51e4d291a0 Add D keymap for GP drawing button 2016-07-21 13:04:32 +02:00
75bda9aefc Remove continuous icon indicator in viewport 2016-07-21 13:03:58 +02:00
9f379b7c2b When copy palette color use original name as base name 2016-07-20 23:07:39 +02:00
a308fa78c2 Move options to submenu to keep UI consistency 2016-07-20 22:29:24 +02:00
cbc60576f7 Change Delete operator to drop list in UI panel 2016-07-20 16:12:46 +02:00
a53520ebfd Relocate Mirror option in edit panel 2016-07-20 13:32:30 +02:00
1bbda801cf Rename sensibility field to sensitivity 2016-07-20 13:29:11 +02:00
49cc48a7d9 Fix memory leak when duplicate GP drawing brushes 2016-07-19 19:48:58 +02:00
374c3e73c3 Fix error deleting parent object
The if comparision was wrong. Better compare objects, not names
2016-07-19 13:52:52 +02:00
178aaef081 Cleanup: Length of names set to 64
A length of 128 is not necessary and can be problematic in UI panels
2016-07-19 13:45:36 +02:00
ad88ffbebd Custom interpolate functions works inverse of old custom function 2016-07-19 13:40:42 +02:00
241c7b9f87 Clenaup: Remove redundant check 2016-07-19 13:30:58 +02:00
304f0d97d5 Cleanup: Replace ARRAY_SET_ITEMS by matrix multiplication 2016-07-19 13:17:50 +02:00
6c2856e4d0 Cleanup: Replace custom interpolate function by standard function 2016-07-19 13:11:49 +02:00
1435825efc Cleanup: Python changes by review comments
Small changes based on code review to fit all standards
2016-07-19 12:56:31 +02:00
ab2db63e28 Remove redundant poll function 2016-07-19 20:54:03 +10:00
0277e3c140 Merge branch 'master' into grease-pencil-v2 2016-07-19 10:37:47 +10:00
8a443f005e Cleanup: style 2016-07-19 10:06:42 +10:00
7b9c3faad5 Merge branch 'master' into grease-pencil-v2 2016-07-19 10:03:09 +10:00
81205e9fc8 Cleanup: Remove not required RNA functions 2016-07-18 23:16:42 +02:00
96c786bc82 Cleanup: use const qualifier 2016-07-19 07:19:56 +10:00
81c9ffbfd2 Cleanup: rename vars to be more clear 2016-07-19 07:12:08 +10:00
8ed6712cc7 Cleanup: minor Python edits 2016-07-19 06:58:44 +10:00
922a55ac40 Merge branch 'master' into grease-pencil-v2 2016-07-19 06:46:11 +10:00
9db699177f Cleanup: warnings on Linux 2016-07-19 06:42:28 +10:00
c9d4c2781e Change comment 2016-07-18 20:09:35 +02:00
0655496eab Clean up code: Remove fields not used anymore at layer level. 2016-07-18 20:08:57 +02:00
c5862517b7 Rename layer property alpha to opacity 2016-07-18 18:06:35 +02:00
2cb474cba8 Expose stroke colorname to python and update internal values 2016-07-18 16:39:25 +02:00
513cca249e Change operator poll to reuse existing gp_stroke_edit_poll 2016-07-17 17:36:35 +02:00
dcd64c2b8c Clean up code 2016-07-17 17:07:23 +02:00
4b9241b613 Include new sculpt options in pie menu 2016-07-16 16:44:14 +02:00
3cbcc3153d Enable mid activation if the user start pressing draw button
Simulate the user pressed D key if the drawing is started with draw
button instead of D key.
2016-07-16 16:35:44 +02:00
af09470d48 Enable one sculpt option by default if none selected 2016-07-16 16:22:03 +02:00
09ca2d9cc8 Small fixes after rebase 2016-07-13 18:41:30 +02:00
285324e39a Improve Randomize brush to affect Strength and Thickness 2016-07-13 18:08:50 +02:00
81d2c9455d Move options near of radius section in the UI panel 2016-07-13 18:08:50 +02:00
086629d33c Change of UI panel to include new sculpt options 2016-07-13 18:08:50 +02:00
fd8e94bc66 Improve smooth sculpt brush to affect strength and line thickness 2016-07-13 18:08:50 +02:00
c0095b7a74 Include an icon if the layer is parented 2016-07-13 18:08:50 +02:00
b6bd62b75c Filter SceneRenderLayer list using SCE_LAY_DISABLE flag 2016-07-13 18:08:50 +02:00
442de0c64a Replace error with bit flag 2016-07-13 18:08:50 +02:00
212e2f30c1 Do not check if the layer is empty 2016-07-13 18:08:50 +02:00
4210691885 Change Edit Strokes Panel to get more compact design 2016-07-13 18:08:50 +02:00
b7af14448a Clean up code 2016-07-13 18:08:50 +02:00
1d18126d9d Invert GP keymaps "F" and "CTRL+F" to make consistent with sculpt keymaps
Now, F adjust brush size and CTRL+F adjust eraser size. Use CTRL+F to
adjust the brush size was inconsistent with sculpt brushes.
2016-07-13 18:08:50 +02:00
81bc5f71aa New operator: Select drawing brush with number key
Only in edit mode, the drawing brush can be selected using the keys
(0-9). 1 is the 1st and 0 is the 10th brush.
2016-07-13 18:08:50 +02:00
495f8f6084 New operator: Enable CTRL+H for hide/unhide points selected
Hide the orange dots to make viewport less intrusive during detailed
drawing session
2016-07-13 18:08:50 +02:00
26d1976d19 New functions for Hide GP selected points 2016-07-13 18:08:50 +02:00
d3e149f360 Be sure continuous drawing is disabled in all exits 2016-07-13 18:08:50 +02:00
f93a8d60b7 Improve continuous drawing
Now the continuous drawing is enabled using double D key. This improve
the workflow between draw and sculpt.
2016-07-13 18:08:50 +02:00
de5648f9db New operator: Copy drawing brush 2016-07-13 18:08:50 +02:00
9ed9028e0b Fix null pointer error 2016-07-13 18:08:50 +02:00
7768aa76bd Fix error: merge layers gets infinite loop 2016-07-13 18:08:50 +02:00
a92cd80bc1 Create a basic drawing brush, and enable it by default
This brush is similar to the old grease pencil and is more compatible
with add-ons that do not require artistic features.
2016-07-13 18:08:50 +02:00
1f2449a252 The parenting remap must be for new scene only 2016-07-13 18:08:50 +02:00
2e95634897 Remap parent objects after full scene copy 2016-07-13 18:08:50 +02:00
1aeb069146 Change layer isolate icon 2016-07-13 18:08:50 +02:00
e1ae7b2d93 Change randomness icon 2016-07-13 18:08:50 +02:00
16d1355d5d Make subdivision randomness less sensitive 2016-07-13 18:08:50 +02:00
b1d054cb0c Change parameter tooltip 2016-07-13 18:08:50 +02:00
eb4d211ae2 Change icon for isolate palette colors 2016-07-13 18:08:50 +02:00
6a94ddfdec Change parameter label to fit better in narrow panels 2016-07-13 18:08:50 +02:00
7ce5ab3942 Make opengl renderlayers more automatic
Now the user do not need to select the check for generating exr layers.
The system detect if necessary using the SceneREnderLayers
2016-07-13 18:08:50 +02:00
55dce81ae7 Improve create renderlayers from gpencil operator
Make the list to keep same list of gp layers and remove not used.
2016-07-13 18:08:50 +02:00
625ac94c3a Fix error on RNA_main_api.c
Fix error due a mistake in merge
2016-07-13 18:08:50 +02:00
f3904ac307 New operator: Create renderlayers
Create automatically all SceneRenderLayers from visible grease pencil
layers
2016-07-13 18:08:50 +02:00
6f4964529e Remove renderlayer from GP panel
These options have been moved to new panel in render panels
2016-07-13 18:08:50 +02:00
d635362078 New poll for grease pencil out of drawing context
This pool verify the gp block in scene.
2016-07-13 18:08:50 +02:00
2a8cd6cf4e Remove property for SceneRenderLayers. Not used, replaced by operator 2016-07-13 18:08:50 +02:00
2f4313b1e6 Remove SceneRenderLayer creation and check null pointers 2016-07-13 18:08:50 +02:00
c1a95c839c Set default RenderLayer values 2016-07-13 18:08:50 +02:00
92afda6375 Fix rebase errors
After doing a rebase, fix some mistakes.
2016-07-13 18:08:50 +02:00
b36e144fd8 Fix error iin panel draw f gp is None 2016-07-13 18:08:50 +02:00
fdddabc2a7 Add renderlayer for grease pencil composition
Now, the compositor can use the output of the opengl render. For each
visible GP layer, a new renderlayer with a combined renderpass is
created. THis can exported as EXR multilayer
2016-07-13 18:08:50 +02:00
662ed5a125 Copy and Paste on the same layer
The old copy mpaste is now copy merge. The new one copy the strokes in
the same layer, not all in the active layer
2016-07-13 18:08:50 +02:00
43c4b57a14 Use Ctrl or Alt Key for straight drawing 2016-07-13 18:08:50 +02:00
cd808e2ddb If press CTRL draw straight lines
If press the key, the stroke will be horizontal or vertical only. Relase
key and the stroke can go on free.
2016-07-13 18:08:50 +02:00
781bcd8050 Draw drawing direction with green and red points
For doing a stroke join with filling is good to see the direction to
flip the stroke if necessary.
2016-07-13 18:08:50 +02:00
9d8b092084 New operator: Flip stroke direction
Flip the start and end point of strokes to use in joins
2016-07-13 18:08:50 +02:00
0019350af8 Fix error drawing in 2D
In 2D drawing, the stroke disappears after finish stroke
2016-07-13 18:08:50 +02:00
5dc6d10a81 New operator: Copy Color
Duplicate active palette color
2016-07-13 18:08:50 +02:00
da17bffcdb Clean up python code
Remove not used UIList template
2016-07-13 18:08:50 +02:00
15f0eda528 Remove palette panel and integrate in palettecolor panel
Now the palette is selected using a dropdown list instead of a separated
panel with a UIlist
2016-07-13 18:08:50 +02:00
29cb000aea Create a set of predefined drawing brushes
The infraestructure was created in a previous commit. This commit only
defines the values of the parameters.
2016-07-13 18:08:50 +02:00
9891ea0239 Fix include file removed by mistake 2016-07-13 18:08:50 +02:00
51f0632a17 Parented to bones requires apply armature matrix
The matrix is the result of Armature Matrix x Bone Matrix
2016-07-13 18:08:50 +02:00
5849f7a117 Parent strokes to bones
Parent layer to object or bones
2016-07-13 18:08:50 +02:00
1c9bc8910a New icons dat files 2016-07-13 18:08:50 +02:00
85e96d1716 Add two new icons for color lock 2016-07-13 18:08:50 +02:00
b756f84e41 New operator: Select strokes by color 2016-07-13 18:08:50 +02:00
2bb9db6155 Set limits to stroke thickness 2016-07-13 18:08:50 +02:00
be7b8a5b3e New operator infrastructure for creating a set of default brushes
The presets are pending, but this provides the infrastructure to create
the brushes.
2016-07-13 18:08:50 +02:00
8ecb55f550 Fix error when convert files and no color is active
If no color is active, the first color is activated by default to avoid
GPF.
2016-07-13 18:08:50 +02:00
b7e7fe09d5 Add new loading routines for 277.3 2016-07-13 18:08:50 +02:00
e7d9f18fe7 Change version number to 277.3 due new requirements loading files 2016-07-13 18:08:50 +02:00
409de3b263 Change drawing brushes loading 2016-07-13 18:08:50 +02:00
6937d59860 Verify brush not null before drawing
Instead of create brush, only verify exist
2016-07-13 18:08:50 +02:00
9d9b7a5c89 Duplicate Drawing Brushes when copy Scene 2016-07-13 18:08:50 +02:00
39cb55efca Mobe Drawing Brushes to ToollSettings and fix loading files error
Fixed the problem loading files with the brushes defined in ToolSettings
moving the listbase link to direct_link_scene()
2016-07-13 18:08:50 +02:00
4bfad73897 First prototype of drawing brushes in Toolsettings 2016-07-13 18:08:50 +02:00
e3d544fe79 Change operator text from Merge Layer to Merge Down 2016-07-13 18:08:50 +02:00
20b2db0398 Add UNDO flag 2016-07-13 18:08:50 +02:00
9ad6dc1605 New operator for join strokes and replace Blend text for Tint 2016-07-13 18:08:50 +02:00
3f4fac464d Fix memory GPF when load a new file
The curvemapping tables need to be initializate when load a new file.
2016-07-13 18:08:50 +02:00
17c89b4896 Use different random factors and replace by jitter
Using the same randomness factor for all areas of the brush was weird,
so the factors have been splitted.
2016-07-13 18:08:50 +02:00
791130a187 Fix memory leaks and improve scene copy
When copy a scene, some data was not copied and fix some memory leaks
with curves.
2016-07-13 18:08:50 +02:00
d163b566a2 Add curves to control pressure and fix some memory issues 2016-07-13 18:08:50 +02:00
b61016779b Add new operator for moving brushes up/down in the list 2016-07-13 18:08:50 +02:00
aa2a8891f5 Improve brushes with more randomness
Added new options to get more control
2016-07-13 18:08:50 +02:00
dad591b1c6 New random and anle brush properties
Add parameters to simulate different types of pens, including pastel and
rectangulas pens that change with angle
2016-07-13 18:08:50 +02:00
da036fa5a3 Initialize tot_triangles variable reading new files 2016-07-13 18:08:50 +02:00
4df7c734fd Remove RNA properties moved to palette colors and brushes
The options removed are not used in layer anymore.
2016-07-13 18:08:50 +02:00
6d1d3cafe9 Remove properties not used
Remove the properties not used and rename old to better names
2016-07-13 18:08:50 +02:00
d0086da2e5 Fix error applying rebase master
Fix errors merging master branch
2016-07-13 18:08:50 +02:00
d53b9ea13b Fix text mistake 2016-07-13 18:08:50 +02:00
2f6a369d8d Improve pie menus
Now is possible to select the brush from PIe menu and the strenght brush
appears in the pie options.
2016-07-13 18:08:50 +02:00
6ccb0770d0 Add strength to pie menu 2016-07-13 18:08:50 +02:00
fbbc10165b Limit strength brush between 0.0f and 1.0f 2016-07-13 18:08:50 +02:00
c8273fda20 Fix close stroke error with strength 2016-07-13 18:08:50 +02:00
fd4448bddc Move blending color in UI panel 2016-07-13 18:08:50 +02:00
b1a7fc2ae9 Improve feedback during drawing for color strength
Before the color was solid during drawing and the feedback was wrong.
2016-07-13 18:08:50 +02:00
02d535107d Include color strength and new sculpt brush
Now is possible to get different alpha factors of the current color
using the pressure of the tablet.
2016-07-13 18:08:50 +02:00
f004714ec2 Fix problem with rotations
In some situations the stroke moved away of the drawing position. THis
was related to the way the parent inverse matrix was calculated. Now the
calculation is very simple: inverse of diff_matrix
2016-07-13 18:08:50 +02:00
7cbc0138c0 If delete parent, keep strokes in last location
If the parent is cleared, the stroke keeps the transformation and don't
back to the original position because the user don't understand why the
stroke move back.
2016-07-13 18:08:50 +02:00
286f152988 Apply parent transformation to conversion to Mesh 2016-07-13 18:08:50 +02:00
21e30b40f2 When delete an object, must clear parent 2016-07-13 18:08:50 +02:00
6f87e59468 Snap operators
Change snap operators to use parent and move some functions to utils
module.
2016-07-13 18:07:16 +02:00
09c335a82a Apply parent transformation to Lines and Polygons 2016-07-13 18:07:16 +02:00
e4a4a7f8ac Clean code
Use copy_v3_v3 instead of manual copy
2016-07-13 18:07:16 +02:00
f46132a1d4 Apply parent to standard transformations
Apply the parent to the standard transformations using matrix.
2016-07-13 18:07:16 +02:00
74ee5907a1 Fix eraser
Apply the parent rotation to eraser
2016-07-13 18:07:16 +02:00
2c4abb3c69 Change manipulator
Make the manipulator uses parent transform data
2016-07-13 18:07:16 +02:00
bcc3434d51 First changes to incluye parent to layer
A lot of things pending
2016-07-13 18:07:16 +02:00
a02c2a1390 Move the buttons to right side of the list
After some testing is better to put all buttons on the same side
2016-07-13 18:07:16 +02:00
a98d2bcafa New operator Palette_lock_layer. Some text description changed.
LOck and Hide any non used color in the layer. Some changes in the
descriptions too
2016-07-13 18:07:16 +02:00
cb1ef606c7 Color Blending 2016-07-13 18:07:16 +02:00
fdc4b63982 Fix description warning 2016-07-13 18:07:16 +02:00
3cf309b420 Clean code
Centralize edit color lock control
2016-07-13 18:07:16 +02:00
2a0d92797c New operator to reorganize colors and avoid erase if color is locked 2016-07-13 18:07:16 +02:00
1077a0e7ae New Close Stroke operator 2016-07-13 18:07:16 +02:00
a4a2cd7450 Publish stroke data
This data can be used by add-ons
2016-07-13 18:07:16 +02:00
31fc56b8f6 Fix error if create a layer ano brushes
The layer needs one brush. Created automatically.
2016-07-13 18:07:16 +02:00
e7fe7e6fa4 Avoid editing if color is hide 2016-07-13 18:07:16 +02:00
c97caa15c3 Improve and separate UI panels 2016-07-13 18:07:16 +02:00
b111706dff Remove layer color from outliner 2016-07-13 18:07:16 +02:00
1207efaadc New operator MERGE layers 2016-07-13 18:07:16 +02:00
e4aa70ee9a New operators Bring to Front and Send to Back strokes 2016-07-13 18:07:16 +02:00
fb0182e0fa New apply thickness operator 2016-07-13 18:07:16 +02:00
476afefd0e Basic GP Brushes
Basic grease pencil brush object created. Now need to use the brushes in
strokes.
2016-07-13 18:07:16 +02:00
43c88b4465 Change to version 277.2 and optimize code
The last buildbot is 277.1 and there is something new, so move version
2016-07-13 18:07:16 +02:00
3d56b9edc8 Old files conversion
Convert old files to use palettes
2016-07-13 18:07:16 +02:00
bf3dc5e092 New operators and onion skinning 2016-07-13 18:07:16 +02:00
65d0110235 New change stroke color operator y Layer opacity 2016-07-13 18:07:16 +02:00
b228e027f4 Basic palettes and colors working
Need more test and new operators
2016-07-13 18:07:16 +02:00
2f1d55d9ce New structure and operators
Working the basic functions to create/remove palettes and colors
2016-07-13 18:05:35 +02:00
421d7a21af Undo Palette changes 2016-07-13 18:03:54 +02:00
4421c27b78 Redo all and undo the Palette module changes 2016-07-13 18:03:54 +02:00
35802276f6 Before remove the palette from bGPdata
Remove the palette from bGPdata because it looks is not used
2016-07-13 18:03:54 +02:00
740e29a76a Edition and lock working in alpha
Basic editing functions working
2016-07-13 17:49:49 +02:00
fcfc6c6dbf Basic palettes and colors
Running the basic creation of palettes and draw
2016-07-13 17:49:49 +02:00
e7f240568f Disable pressure factor for smooth
It is getting strange result, so disabled while get better solution
2016-07-13 17:49:49 +02:00
50eeb6a5cb Apply smooth iterations patch 2016-07-13 17:49:49 +02:00
213 changed files with 12372 additions and 956 deletions

View File

@@ -323,6 +323,10 @@ option(WITH_CODEC_AVI "Enable Blenders own AVI file support (raw/jpeg)
option(WITH_CODEC_FFMPEG "Enable FFMPeg Support (http://ffmpeg.org)" ${_init_CODEC_FFMPEG})
option(WITH_CODEC_SNDFILE "Enable libsndfile Support (http://www.mega-nerd.com/libsndfile)" OFF)
# Alembic support
option(WITH_ALEMBIC "Enable Alembic Support" OFF)
option(WITH_ALEMBIC_HDF5 "Enable Legacy Alembic Support (not officially supported)" OFF)
if(APPLE)
option(WITH_CODEC_QUICKTIME "Enable Quicktime Support" ON)
endif()
@@ -393,6 +397,7 @@ option(WITH_CYCLES "Enable Cycles Render Engine" ON)
option(WITH_CYCLES_STANDALONE "Build Cycles standalone application" OFF)
option(WITH_CYCLES_STANDALONE_GUI "Build Cycles standalone with GUI" OFF)
option(WITH_CYCLES_OSL "Build Cycles with OSL support" ${_init_CYCLES_OSL})
option(WITH_CYCLES_OPENSUBDIV "Build Cycles with OpenSubdiv support" ON)
option(WITH_CYCLES_CUDA_BINARIES "Build Cycles CUDA binaries" OFF)
set(CYCLES_CUDA_BINARIES_ARCH sm_20 sm_21 sm_30 sm_35 sm_37 sm_50 sm_52 CACHE STRING "CUDA architectures to build binaries for")
mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH)
@@ -720,6 +725,11 @@ if(WITH_OPENIMAGEIO)
set(WITH_IMAGE_TIFF ON)
endif()
# auto enable alembic linking dependencies
if(WITH_ALEMBIC)
set(WITH_IMAGE_OPENEXR ON)
endif()
# don't store paths to libs for portable distribution
if(WITH_INSTALL_PORTABLE)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
@@ -1091,6 +1101,21 @@ if(UNIX AND NOT APPLE)
endif()
endif()
if(WITH_ALEMBIC)
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
find_package_wrapper(Alembic)
if(WITH_ALEMBIC_HDF5)
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
find_package_wrapper(HDF5)
endif()
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
set(WITH_ALEMBIC OFF)
set(WITH_ALEMBIC_HDF5 OFF)
endif()
endif()
if(WITH_BOOST)
# uses in build instructions to override include and library variables
if(NOT BOOST_CUSTOM)
@@ -1326,10 +1351,8 @@ elseif(WIN32)
# MSVC11 needs _ALLOW_KEYWORD_MACROS to build
add_definitions(-D_ALLOW_KEYWORD_MACROS)
if(CMAKE_CL_64)
# We want to support Vista level ABI for x64
add_definitions(-D_WIN32_WINNT=0x600)
endif()
# We want to support Vista level ABI
add_definitions(-D_WIN32_WINNT=0x600)
# Make cmake find the msvc redistributables
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
@@ -1660,6 +1683,21 @@ elseif(WIN32)
set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
endif()
if(WITH_ALEMBIC)
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
find_package(Alembic)
if(WITH_ALEMBIC_HDF5)
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
find_package(HDF5)
endif()
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
set(WITH_ALEMBIC OFF)
set(WITH_ALEMBIC_HDF5 OFF)
endif()
endif()
if(WITH_MOD_CLOTH_ELTOPO)
set(LAPACK ${LIBDIR}/lapack)
# set(LAPACK_INCLUDE_DIR ${LAPACK}/include)
@@ -1959,6 +1997,21 @@ elseif(WIN32)
set(OPENVDB_DEFINITIONS)
endif()
if(WITH_ALEMBIC)
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
find_package_wrapper(Alembic)
if(WITH_ALEMBIC_HDF5)
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
find_package_wrapper(HDF5)
endif()
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
set(WITH_ALEMBIC OFF)
set(WITH_ALEMBIC_HDF5 OFF)
endif()
endif()
set(PLATFORM_LINKFLAGS "-Xlinker --stack=2097152")
## DISABLE - causes linking errors
@@ -2043,6 +2096,20 @@ elseif(APPLE)
endif()
endif()
if(WITH_ALEMBIC)
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
find_package(Alembic)
if(WITH_ALEMBIC_HDF5)
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
find_package(HDF5)
endif()
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
set(WITH_ALEMBIC OFF)
set(WITH_ALEMBIC_HDF5 OFF)
endif()
endif()
if(WITH_OPENSUBDIV)
set(OPENSUBDIV ${LIBDIR}/opensubdiv)
set(OPENSUBDIV_LIBPATH ${OPENSUBDIV}/lib)
@@ -2452,6 +2519,11 @@ if(WITH_CYCLES)
)
endif()
endif()
if(WITH_CYCLES_OPENSUBDIV AND NOT WITH_OPENSUBDIV)
message(STATUS "WITH_CYCLES_OPENSUBDIV requires WITH_OPENSUBDIV to be ON, turning OFF")
set(WITH_CYCLES_OPENSUBDIV OFF)
endif()
endif()
if(WITH_INTERNATIONAL)
@@ -3215,6 +3287,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_FREESTYLE)
info_cfg_option(WITH_OPENCOLORIO)
info_cfg_option(WITH_OPENVDB)
info_cfg_option(WITH_ALEMBIC)
info_cfg_text("Compiler Options:")
info_cfg_option(WITH_BUILDINFO)

View File

@@ -29,13 +29,13 @@ getopt \
ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,\
force-all,force-python,force-numpy,force-boost,\
force-ocio,force-openexr,force-oiio,force-llvm,force-osl,force-osd,force-openvdb,\
force-ffmpeg,force-opencollada,\
force-ffmpeg,force-opencollada,force-alembic,\
build-all,build-python,build-numpy,build-boost,\
build-ocio,build-openexr,build-oiio,build-llvm,build-osl,build-osd,build-openvdb,\
build-ffmpeg,build-opencollada,\
build-ffmpeg,build-opencollada,build-alembic,\
skip-python,skip-numpy,skip-boost,\
skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-osd,skip-openvdb,\
skip-ffmpeg,skip-opencollada \
skip-ffmpeg,skip-opencollada,skip-alembic \
-- "$@" \
)
@@ -167,6 +167,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--build-openvdb
Force the build of OpenVDB.
--build-alembic
Force the build of Alembic.
--build-opencollada
Force the build of OpenCOLLADA.
@@ -216,6 +219,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--force-openvdb
Force the rebuild of OpenVDB.
--force-alembic
Force the rebuild of Alembic.
--force-opencollada
Force the rebuild of OpenCOLLADA.
@@ -258,6 +264,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--skip-openvdb
Unconditionally skip OpenVDB installation/building.
--skip-alembic
Unconditionally skip Alembic installation/building.
--skip-opencollada
Unconditionally skip OpenCOLLADA installation/building.
@@ -343,6 +352,13 @@ OPENVDB_FORCE_BUILD=false
OPENVDB_FORCE_REBUILD=false
OPENVDB_SKIP=false
# Alembic needs to be compiled for now
ALEMBIC_VERSION="1.6.0"
ALEMBIC_VERSION_MIN=$ALEMBIC_VERSION
ALEMBIC_FORCE_BUILD=false
ALEMBIC_FORCE_REBUILD=false
ALEMBIC_SKIP=false
# Version??
OPENCOLLADA_VERSION="1.3"
OPENCOLLADA_FORCE_BUILD=false
@@ -525,6 +541,7 @@ while true; do
OPENVDB_FORCE_BUILD=true
OPENCOLLADA_FORCE_BUILD=true
FFMPEG_FORCE_BUILD=true
ALEMBIC_FORCE_BUILD=true
shift; continue
;;
--build-python)
@@ -567,6 +584,9 @@ while true; do
--build-ffmpeg)
FFMPEG_FORCE_BUILD=true; shift; continue
;;
--build-alembic)
ALEMBIC_FORCE_BUILD=true; shift; continue
;;
--force-all)
PYTHON_FORCE_REBUILD=true
NUMPY_FORCE_REBUILD=true
@@ -580,6 +600,7 @@ while true; do
OPENVDB_FORCE_REBUILD=true
OPENCOLLADA_FORCE_REBUILD=true
FFMPEG_FORCE_REBUILD=true
ALEMBIC_FORCE_REBUILD=true
shift; continue
;;
--force-python)
@@ -620,6 +641,9 @@ while true; do
--force-ffmpeg)
FFMPEG_FORCE_REBUILD=true; shift; continue
;;
--force-alembic)
ALEMBIC_FORCE_REBUILD=true; shift; continue
;;
--skip-python)
PYTHON_SKIP=true; shift; continue
;;
@@ -656,6 +680,9 @@ while true; do
--skip-ffmpeg)
FFMPEG_SKIP=true; shift; continue
;;
--skip-alembic)
ALEMBIC_SKIP=true; shift; continue
;;
--)
# no more arguments to parse
break
@@ -683,7 +710,7 @@ NUMPY_SOURCE=( "http://sourceforge.net/projects/numpy/files/NumPy/$NUMPY_VERSION
_boost_version_nodots=`echo "$BOOST_VERSION" | sed -r 's/\./_/g'`
BOOST_SOURCE=( "http://sourceforge.net/projects/boost/files/boost/$BOOST_VERSION/boost_$_boost_version_nodots.tar.bz2/download" )
BOOST_BUILD_MODULES="--with-system --with-filesystem --with-thread --with-regex --with-locale --with-date_time --with-wave --with-iostreams"
BOOST_BUILD_MODULES="--with-system --with-filesystem --with-thread --with-regex --with-locale --with-date_time --with-wave --with-iostreams --with-python --with-program_options"
OCIO_SOURCE=( "https://github.com/imageworks/OpenColorIO/tarball/v$OCIO_VERSION" )
@@ -727,6 +754,12 @@ OPENVDB_SOURCE=( "https://github.com/dreamworksanimation/openvdb/archive/v${OPEN
#~ OPENVDB_SOURCE_REPO_UID="404659fffa659da075d1c9416e4fc939139a84ee"
#~ OPENVDB_SOURCE_REPO_BRANCH="dev"
ALEMBIC_USE_REPO=false
ALEMBIC_SOURCE=( "https://github.com/alembic/alembic/archive/${ALEMBIC_VERSION}.tar.gz" )
# ALEMBIC_SOURCE_REPO=( "https://github.com/alembic/alembic.git" )
# ALEMBIC_SOURCE_REPO_UID="e6c90d4faa32c4550adeaaf3f556dad4b73a92bb"
# ALEMBIC_SOURCE_REPO_BRANCH="master"
OPENCOLLADA_SOURCE=( "https://github.com/KhronosGroup/OpenCOLLADA.git" )
OPENCOLLADA_REPO_UID="3335ac164e68b2512a40914b14c74db260e6ff7d"
OPENCOLLADA_REPO_BRANCH="master"
@@ -767,7 +800,8 @@ You may also want to build them yourself (optional ones are [between brackets]):
* [OpenShadingLanguage $OSL_VERSION_MIN] (from $OSL_SOURCE_REPO, branch $OSL_SOURCE_REPO_BRANCH, commit $OSL_SOURCE_REPO_UID).
* [OpenSubDiv $OSD_VERSION_MIN] (from $OSD_SOURCE_REPO, branch $OSD_SOURCE_REPO_BRANCH, commit $OSD_SOURCE_REPO_UID).
* [OpenVDB $OPENVDB_VERSION_MIN] (from $OPENVDB_SOURCE), [Blosc $OPENVDB_BLOSC_VERSION] (from $OPENVDB_BLOSC_SOURCE).
* [OpenCollada] (from $OPENCOLLADA_SOURCE, branch $OPENCOLLADA_REPO_BRANCH, commit $OPENCOLLADA_REPO_UID).\""
* [OpenCollada] (from $OPENCOLLADA_SOURCE, branch $OPENCOLLADA_REPO_BRANCH, commit $OPENCOLLADA_REPO_UID).
* [Alembic $ALEMBIC_VERSION] (from $ALEMBIC_SOURCE).\""
if [ "$DO_SHOW_DEPS" = true ]; then
PRINT ""
@@ -1118,7 +1152,7 @@ compile_Boost() {
fi
# To be changed each time we make edits that would modify the compiled result!
boost_magic=10
boost_magic=11
_init_boost
@@ -2138,6 +2172,102 @@ compile_OPENVDB() {
run_ldconfig "openvdb"
}
#### Build Alembic ####
_init_alembic() {
_src=$SRC/alembic-$ALEMBIC_VERSION
_git=false
_inst=$INST/alembic-$ALEMBIC_VERSION
_inst_shortcut=$INST/alembic
}
clean_ALEMBIC() {
_init_alembic
_clean
}
compile_ALEMBIC() {
if [ "$NO_BUILD" = true ]; then
WARNING "--no-build enabled, Alembic will not be compiled!"
return
fi
compile_HDF5
PRINT ""
# To be changed each time we make edits that would modify the compiled result!
alembic_magic=2
_init_alembic
# Clean install if needed!
magic_compile_check alembic-$ALEMBIC_VERSION $alembic_magic
if [ $? -eq 1 -o "$ALEMBIC_FORCE_REBUILD" = true ]; then
clean_ALEMBIC
fi
if [ ! -d $_inst ]; then
INFO "Building Alembic-$ALEMBIC_VERSION"
prepare_opt
if [ ! -d $_src -o true ]; then
mkdir -p $SRC
download ALEMBIC_SOURCE[@] "$_src.tar.gz"
INFO "Unpacking Alembic-$ALEMBIC_VERSION"
tar -C $SRC -xf $_src.tar.gz
fi
cd $_src
cmake_d="-D CMAKE_INSTALL_PREFIX=$_inst"
if [ -d $INST/boost ]; then
cmake_d="$cmake_d -D BOOST_ROOT=$INST/boost"
cmake_d="$cmake_d -D USE_STATIC_BOOST=ON"
else
cmake_d="$cmake_d -D USE_STATIC_BOOST=OFF"
fi
if [ "$_with_built_openexr" = true ]; then
cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr"
cmake_d="$cmake_d -D USE_ARNOLD=OFF"
cmake_d="$cmake_d -D USE_BINARIES=OFF"
cmake_d="$cmake_d -D USE_EXAMPLES=OFF"
cmake_d="$cmake_d -D USE_HDF5=OFF"
cmake_d="$cmake_d -D USE_MAYA=OFF"
cmake_d="$cmake_d -D USE_PRMAN=OFF"
cmake_d="$cmake_d -D USE_PYALEMBIC=OFF"
cmake_d="$cmake_d -D USE_STATIC_HDF5=OFF"
cmake_d="$cmake_d -D ALEMBIC_ILMBASE_LINK_STATIC=OFF"
cmake_d="$cmake_d -D ALEMBIC_SHARED_LIBS=OFF"
cmake_d="$cmake_d -D ALEMBIC_LIB_USES_BOOST=ON"
cmake_d="$cmake_d -D ALEMBIC_LIB_USES_TR1=OFF"
INFO "ILMBASE_ROOT=$INST/openexr"
fi
cmake $cmake_d ./
make -j$THREADS install
make clean
if [ -d $_inst ]; then
_create_inst_shortcut
else
ERROR "Alembic-$ALEMBIC_VERSION failed to compile, exiting"
exit 1
fi
magic_compile_set alembic-$ALEMBIC_VERSION $alembic_magic
cd $CWD
INFO "Done compiling Alembic-$ALEMBIC_VERSION!"
else
INFO "Own Alembic-$ALEMBIC_VERSION is up to date, nothing to do!"
INFO "If you want to force rebuild of this lib, use the --force-alembic option."
fi
run_ldconfig "alembic"
}
#### Build OpenCOLLADA ####
_init_opencollada() {
_src=$SRC/OpenCOLLADA-$OPENCOLLADA_VERSION
@@ -2746,6 +2876,17 @@ install_DEB() {
fi
fi
PRINT ""
if [ "$ALEMBIC_SKIP" = true ]; then
WARNING "Skipping Alembic installation, as requested..."
elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
INFO "Forced Alembic building, as requested..."
compile_ALEMBIC
else
# No package currently, only HDF5!
compile_ALEMBIC
fi
if [ "$WITH_OPENCOLLADA" = true ]; then
_do_compile_collada=false
@@ -3283,6 +3424,17 @@ install_RPM() {
compile_OPENVDB
fi
PRINT ""
if [ "$ALEMBIC_SKIP" = true ]; then
WARNING "Skipping Alembic installation, as requested..."
elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
INFO "Forced Alembic building, as requested..."
compile_ALEMBIC
else
# No package currently!
compile_ALEMBIC
fi
if [ "$WITH_OPENCOLLADA" = true ]; then
PRINT ""
@@ -3693,6 +3845,16 @@ install_ARCH() {
fi
fi
PRINT ""
if [ "$ALEMBIC_SKIP" = true ]; then
WARNING "Skipping Alembic installation, as requested..."
elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
INFO "Forced Alembic building, as requested..."
compile_ALEMBIC
else
compile_ALEMBIC
fi
if [ "$WITH_OPENCOLLADA" = true ]; then
PRINT ""
@@ -4000,7 +4162,7 @@ print_info() {
_buildargs="-U *SNDFILE* -U *PYTHON* -U *BOOST* -U *Boost*"
_buildargs="$_buildargs -U *OPENCOLORIO* -U *OPENEXR* -U *OPENIMAGEIO* -U *LLVM* -U *CYCLES*"
_buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *COLLADA* -U *FFMPEG*"
_buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *COLLADA* -U *FFMPEG* -U *ALEMBIC*"
_1="-D WITH_CODEC_SNDFILE=ON"
PRINT " $_1"
@@ -4106,6 +4268,17 @@ print_info() {
_buildargs="$_buildargs $_1"
fi
if [ "$ALEMBIC_SKIP" = false ]; then
_1="-D WITH_ALEMBIC=ON"
PRINT " $_1"
_buildargs="$_buildargs $_1"
if [ -d $INST/alembic ]; then
_1="-D ALEMBIC_ROOT_DIR=$INST/alembic"
PRINT " $_1"
_buildargs="$_buildargs $_1"
fi
fi
if [ "$NO_SYSTEM_GLEW" = true ]; then
_1="-D WITH_SYSTEM_GLEW=OFF"
PRINT " $_1"

View File

@@ -0,0 +1,70 @@
# - Find Alembic library
# Find the native Alembic includes and libraries
# This module defines
# ALEMBIC_INCLUDE_DIRS, where to find Alembic headers, Set when
# ALEMBIC_INCLUDE_DIR is found.
# ALEMBIC_LIBRARIES, libraries to link against to use Alembic.
# ALEMBIC_ROOT_DIR, The base directory to search for Alembic.
# This can also be an environment variable.
# ALEMBIC_FOUND, If false, do not try to use Alembic.
#
#=============================================================================
# Copyright 2016 Blender Foundation.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# If ALEMBIC_ROOT_DIR was defined in the environment, use it.
IF(NOT ALEMBIC_ROOT_DIR AND NOT $ENV{ALEMBIC_ROOT_DIR} STREQUAL "")
SET(ALEMBIC_ROOT_DIR $ENV{ALEMBIC_ROOT_DIR})
ENDIF()
SET(_alembic_SEARCH_DIRS
${ALEMBIC_ROOT_DIR}
/usr/local
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt/lib/alembic
)
FIND_PATH(ALEMBIC_INCLUDE_DIR
NAMES
Alembic/Abc/All.h
HINTS
${_alembic_SEARCH_DIRS}
PATH_SUFFIXES
include
)
FIND_LIBRARY(ALEMBIC_LIBRARY
NAMES
Alembic
HINTS
${_alembic_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib lib/static
)
# handle the QUIETLY and REQUIRED arguments and set ALEMBIC_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ALEMBIC DEFAULT_MSG ALEMBIC_LIBRARY ALEMBIC_INCLUDE_DIR)
IF(ALEMBIC_FOUND)
SET(ALEMBIC_LIBRARIES ${ALEMBIC_LIBRARY})
SET(ALEMBIC_INCLUDE_DIRS ${ALEMBIC_INCLUDE_DIR})
ENDIF(ALEMBIC_FOUND)
MARK_AS_ADVANCED(
ALEMBIC_INCLUDE_DIR
ALEMBIC_LIBRARY
)
UNSET(_alembic_SEARCH_DIRS)

View File

@@ -0,0 +1,69 @@
# - Find HDF5 library
# Find the native HDF5 includes and libraries
# This module defines
# HDF5_INCLUDE_DIRS, where to find hdf5.h, Set when HDF5_INCLUDE_DIR is found.
# HDF5_LIBRARIES, libraries to link against to use HDF5.
# HDF5_ROOT_DIR, The base directory to search for HDF5.
# This can also be an environment variable.
# HDF5_FOUND, If false, do not try to use HDF5.
#
#=============================================================================
# Copyright 2016 Blender Foundation.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# If HDF5_ROOT_DIR was defined in the environment, use it.
IF(NOT HDF5_ROOT_DIR AND NOT $ENV{HDF5_ROOT_DIR} STREQUAL "")
SET(HDF5_ROOT_DIR $ENV{HDF5_ROOT_DIR})
ENDIF()
SET(_hdf5_SEARCH_DIRS
${HDF5_ROOT_DIR}
/usr/local
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt/lib/hdf5
)
FIND_LIBRARY(HDF5_LIBRARY
NAMES
hdf5
HINTS
${_hdf5_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
FIND_PATH(HDF5_INCLUDE_DIR
NAMES
hdf5.h
HINTS
${_hdf5_SEARCH_DIRS}
PATH_SUFFIXES
include
)
# handle the QUIETLY and REQUIRED arguments and set HDF5_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(HDF5 DEFAULT_MSG HDF5_LIBRARY HDF5_INCLUDE_DIR)
IF(HDF5_FOUND)
SET(HDF5_LIBRARIES ${HDF5_LIBRARY})
SET(HDF5_INCLUDE_DIRS ${HDF5_INCLUDE_DIR})
ENDIF(HDF5_FOUND)
MARK_AS_ADVANCED(
HDF5_INCLUDE_DIR
HDF5_LIBRARY
)
UNSET(_hdf5_SEARCH_DIRS)

View File

@@ -4,6 +4,7 @@
# cmake -C../blender/build_files/cmake/config/blender_full.cmake ../blender
#
set(WITH_ALEMBIC ON CACHE BOOL "" FORCE)
set(WITH_BUILDINFO ON CACHE BOOL "" FORCE)
set(WITH_BULLET ON CACHE BOOL "" FORCE)
set(WITH_CODEC_AVI ON CACHE BOOL "" FORCE)

View File

@@ -8,6 +8,7 @@
set(WITH_INSTALL_PORTABLE ON CACHE BOOL "" FORCE)
set(WITH_SYSTEM_GLEW ON CACHE BOOL "" FORCE)
set(WITH_ALEMBIC OFF CACHE BOOL "" FORCE)
set(WITH_BUILDINFO OFF CACHE BOOL "" FORCE)
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_AVI OFF CACHE BOOL "" FORCE)

View File

@@ -32,3 +32,4 @@ set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE)
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
set(WITH_ALEMBIC OFF CACHE BOOL "" FORCE)

View File

@@ -333,6 +333,11 @@ function(SETUP_LIBDIRS)
link_directories(${LLVM_LIBPATH})
endif()
if(WITH_ALEMBIC)
link_directories(${ALEMBIC_LIBPATH})
link_directories(${HDF5_LIBPATH})
endif()
if(WIN32 AND NOT UNIX)
link_directories(${PTHREADS_LIBPATH})
endif()
@@ -434,6 +439,9 @@ function(setup_liblinks
endif()
endif()
target_link_libraries(${target} ${JPEG_LIBRARIES})
if(WITH_ALEMBIC)
target_link_libraries(${target} ${ALEMBIC_LIBRARIES} ${HDF5_LIBRARIES})
endif()
if(WITH_IMAGE_OPENEXR)
target_link_libraries(${target} ${OPENEXR_LIBRARIES})
endif()
@@ -607,6 +615,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
bf_imbuf_openimageio
bf_imbuf_dds
bf_collada
bf_alembic
bf_intern_elbeem
bf_intern_memutil
bf_intern_guardedalloc

5
extern/curve_fit_nd/README.blender vendored Normal file
View File

@@ -0,0 +1,5 @@
Project: Curve-Fit-nD
URL: https://github.com/ideasman42/curve-fit-nd
License: BSD 3-Clause
Upstream version: Unknown (Last Release)
Local modifications: None

View File

@@ -614,7 +614,7 @@ static void cubic_from_points_offset_fallback(
double dists[2] = {0, 0};
const double *pt = points_offset;
const double *pt = &points_offset[dims];
for (uint i = 1; i < points_offset_len - 1; i++, pt += dims) {
for (uint k = 0; k < 2; k++) {
sub_vn_vnvn(tmp, p0, pt, dims);
@@ -623,13 +623,13 @@ static void cubic_from_points_offset_fallback(
}
}
float alpha_l = (dists[0] / 0.75) / dot_vnvn(tan_l, a[0], dims);
float alpha_r = (dists[1] / 0.75) / -dot_vnvn(tan_r, a[1], dims);
double alpha_l = (dists[0] / 0.75) / dot_vnvn(tan_l, a[0], dims);
double alpha_r = (dists[1] / 0.75) / -dot_vnvn(tan_r, a[1], dims);
if (!(alpha_l > 0.0f)) {
if (!(alpha_l > 0.0)) {
alpha_l = dir_dist / 3.0;
}
if (!(alpha_r > 0.0f)) {
if (!(alpha_r > 0.0)) {
alpha_r = dir_dist / 3.0;
}
@@ -896,7 +896,7 @@ static double points_calc_coord_length(
}
assert(!is_almost_zero(r_u[points_offset_len - 1]));
const double w = r_u[points_offset_len - 1];
for (uint i = 0; i < points_offset_len; i++) {
for (uint i = 1; i < points_offset_len; i++) {
r_u[i] /= w;
}
return w;

View File

@@ -146,6 +146,14 @@ if(WITH_CYCLES_OSL)
)
endif()
if(WITH_CYCLES_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
include_directories(
SYSTEM
${OPENSUBDIV_INCLUDE_DIR}
)
endif()
set(WITH_CYCLES_DEVICE_OPENCL TRUE)
set(WITH_CYCLES_DEVICE_CUDA TRUE)
set(WITH_CYCLES_DEVICE_MULTI TRUE)

View File

@@ -41,6 +41,8 @@ def update_script_node(node, report):
import shutil
import tempfile
oso_file_remove = False
if node.mode == 'EXTERNAL':
# compile external script file
script_path = bpy.path.abspath(node.filepath, library=node.id_data.library)
@@ -49,7 +51,6 @@ def update_script_node(node, report):
if script_ext == ".oso":
# it's a .oso file, no need to compile
ok, oso_path = True, script_path
oso_file_remove = False
elif script_ext == ".osl":
# compile .osl file
ok, oso_path = osl_compile(script_path, report)
@@ -65,7 +66,6 @@ def update_script_node(node, report):
elif os.path.dirname(node.filepath) == "":
# module in search path
oso_path = node.filepath
oso_file_remove = False
ok = True
else:
# unknown
@@ -88,12 +88,10 @@ def update_script_node(node, report):
osl_file.close()
ok, oso_path = osl_compile(osl_file.name, report)
oso_file_remove = False
os.remove(osl_file.name)
else:
# compile text datablock from disk directly
ok, oso_path = osl_compile(osl_path, report)
oso_file_remove = False
if ok:
# read bytecode

View File

@@ -775,6 +775,13 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup):
default='LINEAR',
)
cls.displacement_method = EnumProperty(
name="Displacement Method",
description="Method to use for the displacement",
items=enum_displacement_methods,
default='BUMP',
)
@classmethod
def unregister(cls):
del bpy.types.Material.cycles
@@ -952,13 +959,6 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
type=cls,
)
cls.displacement_method = EnumProperty(
name="Displacement Method",
description="Method to use for the displacement",
items=enum_displacement_methods,
default='BUMP',
)
@classmethod
def unregister(cls):
del bpy.types.Mesh.cycles

View File

@@ -674,40 +674,6 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
split.separator()
class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
bl_label = "Displacement"
bl_context = "data"
@classmethod
def poll(cls, context):
if CyclesButtonsPanel.poll(context):
if context.mesh or context.curve or context.meta_ball:
if context.scene.cycles.feature_set == 'EXPERIMENTAL':
return True
return False
def draw(self, context):
layout = self.layout
mesh = context.mesh
curve = context.curve
mball = context.meta_ball
if mesh:
cdata = mesh.cycles
elif curve:
cdata = curve.cycles
elif mball:
cdata = mball.cycles
split = layout.split()
col = split.column()
sub = col.column(align=True)
sub.label(text="Displacement:")
sub.prop(cdata, "displacement_method", text="")
class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel):
bl_label = "Motion Blur"
bl_context = "object"
@@ -1219,6 +1185,11 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
col.prop(cmat, "sample_as_light", text="Multiple Importance")
col.prop(cmat, "use_transparent_shadow")
if context.scene.cycles.feature_set == 'EXPERIMENTAL':
col.separator()
col.label(text="Displacement:")
col.prop(cmat, "displacement_method", text="")
col = split.column()
col.label(text="Volume:")
sub = col.column()

View File

@@ -409,7 +409,8 @@ static void attr_create_uv_map(Scene *scene,
BL::Mesh& b_mesh,
const vector<int>& nverts,
const vector<int>& face_flags,
bool subdivision)
bool subdivision,
bool subdivide_uvs)
{
if(subdivision) {
BL::Mesh::uv_layers_iterator l;
@@ -429,6 +430,10 @@ static void attr_create_uv_map(Scene *scene,
else
attr = mesh->subd_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
if(subdivide_uvs) {
attr->flags |= ATTR_SUBDIVIDED;
}
BL::Mesh::polygons_iterator p;
float3 *fdata = attr->data_float3();
@@ -592,7 +597,8 @@ static void create_mesh(Scene *scene,
Mesh *mesh,
BL::Mesh& b_mesh,
const vector<Shader*>& used_shaders,
bool subdivision=false)
bool subdivision=false,
bool subdivide_uvs=true)
{
/* count vertices and faces */
int numverts = b_mesh.vertices.length();
@@ -638,6 +644,7 @@ static void create_mesh(Scene *scene,
/* create generated coordinates from undeformed coordinates */
if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
Attribute *attr = attributes.add(ATTR_STD_GENERATED);
attr->flags |= ATTR_SUBDIVIDED;
float3 loc, size;
mesh_texture_space(b_mesh, loc, size);
@@ -746,7 +753,7 @@ static void create_mesh(Scene *scene,
* The calculate functions will check whether they're needed or not.
*/
attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision);
attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision);
attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision, subdivide_uvs);
/* for volume objects, create a matrix to transform from object space to
* mesh texture space. this does not work with deformations but that can
@@ -770,8 +777,35 @@ static void create_subd_mesh(Scene *scene,
float dicing_rate,
int max_subdivisions)
{
create_mesh(scene, mesh, b_mesh, used_shaders, true);
BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length()-1]);
bool subdivide_uvs = subsurf_mod.use_subsurf_uv();
create_mesh(scene, mesh, b_mesh, used_shaders, true, subdivide_uvs);
/* export creases */
size_t num_creases = 0;
BL::Mesh::edges_iterator e;
for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
if(e->crease() != 0.0f) {
num_creases++;
}
}
mesh->subd_creases.resize(num_creases);
Mesh::SubdEdgeCrease* crease = mesh->subd_creases.data();
for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
if(e->crease() != 0.0f) {
crease->v[0] = e->vertices()[0];
crease->v[1] = e->vertices()[1];
crease->crease = e->crease();
crease++;
}
}
/* set subd params */
SubdParams sdparams(mesh);
PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
@@ -903,8 +937,6 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
mesh_synced.insert(mesh);
/* create derived mesh */
PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
array<int> oldtriangle = mesh->triangles;
/* compares curve_keys rather than strands in order to handle quick hair
@@ -974,21 +1006,6 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
}
mesh->geometry_flags = requested_geometry_flags;
/* displacement method */
if(cmesh.data) {
const int method = get_enum(cmesh,
"displacement_method",
Mesh::DISPLACE_NUM_METHODS,
Mesh::DISPLACE_BUMP);
if(method == 0 || !experimental)
mesh->displacement_method = Mesh::DISPLACE_BUMP;
else if(method == 1)
mesh->displacement_method = Mesh::DISPLACE_TRUE;
else
mesh->displacement_method = Mesh::DISPLACE_BOTH;
}
/* fluid motion */
sync_mesh_fluid_motion(b_ob, scene, mesh);

View File

@@ -329,16 +329,18 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
/* object transformation */
if(tfm != object->tfm) {
VLOG(1) << "Object " << b_ob.name() << " motion detected.";
if(motion_time == -1.0f) {
object->motion.pre = tfm;
object->use_motion = true;
}
else if(motion_time == 1.0f) {
object->motion.post = tfm;
if(motion_time == -1.0f || motion_time == 1.0f) {
object->use_motion = true;
}
}
if(motion_time == -1.0f) {
object->motion.pre = tfm;
}
else if(motion_time == 1.0f) {
object->motion.post = tfm;
}
/* mesh deformation */
if(object->mesh)
sync_mesh_motion(b_ob, object, motion_time);
@@ -395,8 +397,8 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
object->name = b_ob.name().c_str();
object->pass_id = b_ob.pass_index();
object->tfm = tfm;
object->motion.pre = tfm;
object->motion.post = tfm;
object->motion.pre = transform_empty();
object->motion.post = transform_empty();
object->use_motion = false;
/* motion blur */

View File

@@ -64,6 +64,14 @@ static VolumeInterpolation get_volume_interpolation(PointerRNA& ptr)
VOLUME_INTERPOLATION_LINEAR);
}
static DisplacementMethod get_displacement_method(PointerRNA& ptr)
{
return (DisplacementMethod)get_enum(ptr,
"displacement_method",
DISPLACE_NUM_METHODS,
DISPLACE_BUMP);
}
static int validate_enum_value(int value, int num_values, int default_value)
{
if(value >= num_values) {
@@ -837,8 +845,10 @@ static ShaderNode *add_node(Scene *scene,
}
}
if(node)
if(node) {
node->name = b_node.name();
graph->add(node);
}
return node;
}
@@ -1180,6 +1190,7 @@ void BlenderSync::sync_materials(bool update_all)
shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume");
shader->volume_sampling_method = get_volume_sampling(cmat);
shader->volume_interpolation_method = get_volume_interpolation(cmat);
shader->displacement_method = (experimental) ? get_displacement_method(cmat) : DISPLACE_BUMP;
shader->set_graph(graph);
shader->tag_update(scene);

View File

@@ -875,6 +875,7 @@ public:
if(ciErr != CL_SUCCESS) {
opencl_error("OpenCL build failed: errors in console");
fprintf(stderr, "Build error: %s\n", clewErrorString(ciErr));
return false;
}

View File

@@ -162,6 +162,7 @@ set(SRC_GEOM_HEADERS
geom/geom_motion_curve.h
geom/geom_motion_triangle.h
geom/geom_object.h
geom/geom_patch.h
geom/geom_primitive.h
geom/geom_subd_triangle.h
geom/geom_triangle.h

View File

@@ -144,7 +144,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg,
return label;
}
#ifndef __KERNEL_CUDS__
#ifndef __KERNEL_CUDA__
ccl_device
#else
ccl_device_inline

View File

@@ -17,6 +17,7 @@
#include "geom_attribute.h"
#include "geom_object.h"
#include "geom_patch.h"
#include "geom_triangle.h"
#include "geom_subd_triangle.h"
#include "geom_triangle_intersect.h"

View File

@@ -43,12 +43,19 @@ ccl_device_inline uint attribute_primitive_type(KernelGlobals *kg, const ShaderD
}
}
ccl_device_inline AttributeDescriptor attribute_not_found()
{
const AttributeDescriptor desc = {ATTR_ELEMENT_NONE, (NodeAttributeType)0, 0, ATTR_STD_NOT_FOUND};
return desc;
}
/* Find attribute based on ID */
ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
{
if(ccl_fetch(sd, object) == PRIM_NONE)
return (int)ATTR_STD_NOT_FOUND;
if(ccl_fetch(sd, object) == PRIM_NONE) {
return attribute_not_found();
}
/* for SVM, find attribute by unique id */
uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride;
@@ -57,31 +64,37 @@ ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, ui
while(attr_map.x != id) {
if(UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
return ATTR_STD_NOT_FOUND;
return attribute_not_found();
}
attr_offset += ATTR_PRIM_TYPES;
attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
}
*elem = (AttributeElement)attr_map.y;
AttributeDescriptor desc;
desc.element = (AttributeElement)attr_map.y;
if(ccl_fetch(sd, prim) == PRIM_NONE && (AttributeElement)attr_map.y != ATTR_ELEMENT_MESH)
return ATTR_STD_NOT_FOUND;
if(ccl_fetch(sd, prim) == PRIM_NONE && desc.element != ATTR_ELEMENT_MESH) {
return attribute_not_found();
}
/* return result */
return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
desc.offset = (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
desc.type = (NodeAttributeType)(attr_map.w & 0xff);
desc.flags = (AttributeFlag)(attr_map.w >> 8);
return desc;
}
/* Transform matrix attribute on meshes */
ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderData *sd, int offset)
ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc)
{
Transform tfm;
tfm.x = kernel_tex_fetch(__attributes_float3, offset + 0);
tfm.y = kernel_tex_fetch(__attributes_float3, offset + 1);
tfm.z = kernel_tex_fetch(__attributes_float3, offset + 2);
tfm.w = kernel_tex_fetch(__attributes_float3, offset + 3);
tfm.x = kernel_tex_fetch(__attributes_float3, desc.offset + 0);
tfm.y = kernel_tex_fetch(__attributes_float3, desc.offset + 1);
tfm.z = kernel_tex_fetch(__attributes_float3, desc.offset + 2);
tfm.w = kernel_tex_fetch(__attributes_float3, desc.offset + 3);
return tfm;
}

View File

@@ -24,23 +24,23 @@ CCL_NAMESPACE_BEGIN
/* Reading attributes on various curve elements */
ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
{
if(elem == ATTR_ELEMENT_CURVE) {
if(desc.element == ATTR_ELEMENT_CURVE) {
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = 0.0f;
if(dy) *dy = 0.0f;
#endif
return kernel_tex_fetch(__attributes_float, offset + ccl_fetch(sd, prim));
return kernel_tex_fetch(__attributes_float, desc.offset + ccl_fetch(sd, prim));
}
else if(elem == ATTR_ELEMENT_CURVE_KEY || elem == ATTR_ELEMENT_CURVE_KEY_MOTION) {
else if(desc.element == ATTR_ELEMENT_CURVE_KEY || desc.element == ATTR_ELEMENT_CURVE_KEY_MOTION) {
float4 curvedata = kernel_tex_fetch(__curves, ccl_fetch(sd, prim));
int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(ccl_fetch(sd, type));
int k1 = k0 + 1;
float f0 = kernel_tex_fetch(__attributes_float, offset + k0);
float f1 = kernel_tex_fetch(__attributes_float, offset + k1);
float f0 = kernel_tex_fetch(__attributes_float, desc.offset + k0);
float f1 = kernel_tex_fetch(__attributes_float, desc.offset + k1);
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*(f1 - f0);
@@ -59,9 +59,9 @@ ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd,
}
}
ccl_device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
ccl_device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
{
if(elem == ATTR_ELEMENT_CURVE) {
if(desc.element == 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
@@ -71,15 +71,15 @@ ccl_device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
#endif
return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + ccl_fetch(sd, prim)));
return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + ccl_fetch(sd, prim)));
}
else if(elem == ATTR_ELEMENT_CURVE_KEY || elem == ATTR_ELEMENT_CURVE_KEY_MOTION) {
else if(desc.element == ATTR_ELEMENT_CURVE_KEY || desc.element == ATTR_ELEMENT_CURVE_KEY_MOTION) {
float4 curvedata = kernel_tex_fetch(__curves, ccl_fetch(sd, prim));
int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(ccl_fetch(sd, type));
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));
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + k0));
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + k1));
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*(f1 - f0);

View File

@@ -292,6 +292,18 @@ ccl_device_inline void object_motion_info(KernelGlobals *kg, int object, int *nu
*numverts = __float_as_int(f.w);
}
/* Offset to an objects patch map */
ccl_device_inline uint object_patch_map_offset(KernelGlobals *kg, int object)
{
if(object == OBJECT_NONE)
return 0;
int offset = object*OBJECT_SIZE + 11;
float4 f = kernel_tex_fetch(__objects, offset);
return __float_as_uint(f.x);
}
/* Pass ID for shader */
ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd)

View File

@@ -0,0 +1,343 @@
/*
* Based on code from OpenSubdiv released under this license:
*
* Copyright 2013 Pixar
*
* Licensed under the Apache License, Version 2.0 (the "Apache License")
* with the following modification; you may not use this file except in
* compliance with the Apache License and the following modification to it:
* Section 6. Trademarks. is deleted and replaced with:
*
* 6. Trademarks. This License does not grant permission to use the trade
* names, trademarks, service marks, or product names of the Licensor
* and its affiliates, except as required to comply with Section 4(c) of
* the License and to reproduce the content of the NOTICE file.
*
* You may obtain a copy of the Apache License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Apache License with the above modification is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the Apache License for the specific
* language governing permissions and limitations under the Apache License.
*
*/
CCL_NAMESPACE_BEGIN
typedef struct PatchHandle {
int array_index, patch_index, vert_index;
} PatchHandle;
ccl_device_inline int patch_map_resolve_quadrant(float median, float *u, float *v)
{
int quadrant = -1;
if(*u < median) {
if(*v < median) {
quadrant = 0;
}
else {
quadrant = 1;
*v -= median;
}
}
else {
if(*v < median) {
quadrant = 3;
}
else {
quadrant = 2;
*v -= median;
}
*u -= median;
}
return quadrant;
}
/* retrieve PatchHandle from patch coords */
ccl_device_inline PatchHandle patch_map_find_patch(KernelGlobals *kg, int object, int patch, float u, float v)
{
PatchHandle handle;
kernel_assert((u >= 0.0f) && (u <= 1.0f) && (v >= 0.0f) && (v <= 1.0f));
int node = (object_patch_map_offset(kg, object) + patch)/2;
float median = 0.5f;
for(int depth = 0; depth < 0xff; depth++) {
float delta = median * 0.5f;
int quadrant = patch_map_resolve_quadrant(median, &u, &v);
kernel_assert(quadrant >= 0);
uint child = kernel_tex_fetch(__patches, node + quadrant);
/* is the quadrant a hole? */
if(!(child & PATCH_MAP_NODE_IS_SET)) {
handle.array_index = -1;
return handle;
}
uint index = child & PATCH_MAP_NODE_INDEX_MASK;
if(child & PATCH_MAP_NODE_IS_LEAF) {
handle.array_index = kernel_tex_fetch(__patches, index + 0);
handle.patch_index = kernel_tex_fetch(__patches, index + 1);
handle.vert_index = kernel_tex_fetch(__patches, index + 2);
return handle;
} else {
node = index;
}
median = delta;
}
/* no leaf found */
kernel_assert(0);
handle.array_index = -1;
return handle;
}
ccl_device_inline void patch_eval_bspline_weights(float t, float *point, float *deriv)
{
/* The four uniform cubic B-Spline basis functions evaluated at t */
float inv_6 = 1.0f / 6.0f;
float t2 = t * t;
float t3 = t * t2;
point[0] = inv_6 * (1.0f - 3.0f*(t - t2) - t3);
point[1] = inv_6 * (4.0f - 6.0f*t2 + 3.0f*t3);
point[2] = inv_6 * (1.0f + 3.0f*(t + t2 - t3));
point[3] = inv_6 * t3;
/* Derivatives of the above four basis functions at t */
deriv[0] = -0.5f*t2 + t - 0.5f;
deriv[1] = 1.5f*t2 - 2.0f*t;
deriv[2] = -1.5f*t2 + t + 0.5f;
deriv[3] = 0.5f*t2;
}
ccl_device_inline void patch_eval_adjust_boundary_weights(uint bits, float *s, float *t)
{
int boundary = ((bits >> 8) & 0xf);
if(boundary & 1) {
t[2] -= t[0];
t[1] += 2*t[0];
t[0] = 0;
}
if(boundary & 2) {
s[1] -= s[3];
s[2] += 2*s[3];
s[3] = 0;
}
if(boundary & 4) {
t[1] -= t[3];
t[2] += 2*t[3];
t[3] = 0;
}
if(boundary & 8) {
s[2] -= s[0];
s[1] += 2*s[0];
s[0] = 0;
}
}
ccl_device_inline int patch_eval_depth(uint patch_bits)
{
return (patch_bits & 0xf);
}
ccl_device_inline float patch_eval_param_fraction(uint patch_bits)
{
bool non_quad_root = (patch_bits >> 4) & 0x1;
int depth = patch_eval_depth(patch_bits);
if(non_quad_root) {
return 1.0f / (float)(1 << (depth-1));
}
else {
return 1.0f / (float)(1 << depth);
}
}
ccl_device_inline void patch_eval_normalize_coords(uint patch_bits, float *u, float *v)
{
float frac = patch_eval_param_fraction(patch_bits);
int iu = (patch_bits >> 22) & 0x3ff;
int iv = (patch_bits >> 12) & 0x3ff;
/* top left corner */
float pu = (float)iu*frac;
float pv = (float)iv*frac;
/* normalize uv coordinates */
*u = (*u - pu) / frac;
*v = (*v - pv) / frac;
}
/* retrieve patch control indices */
ccl_device_inline int patch_eval_indices(KernelGlobals *kg, const PatchHandle *handle, int channel,
int indices[PATCH_MAX_CONTROL_VERTS])
{
int index_base = kernel_tex_fetch(__patches, handle->array_index + 2) + handle->vert_index;
/* XXX: regular patches only */
for(int i = 0; i < 16; i++) {
indices[i] = kernel_tex_fetch(__patches, index_base + i);
}
return 16;
}
/* evaluate patch basis functions */
ccl_device_inline void patch_eval_basis(KernelGlobals *kg, const PatchHandle *handle, float u, float v,
float weights[PATCH_MAX_CONTROL_VERTS],
float weights_du[PATCH_MAX_CONTROL_VERTS],
float weights_dv[PATCH_MAX_CONTROL_VERTS])
{
uint patch_bits = kernel_tex_fetch(__patches, handle->patch_index + 1); /* read patch param */
float d_scale = 1 << patch_eval_depth(patch_bits);
bool non_quad_root = (patch_bits >> 4) & 0x1;
if(non_quad_root) {
d_scale *= 0.5f;
}
patch_eval_normalize_coords(patch_bits, &u, &v);
/* XXX: regular patches only for now. */
float s[4], t[4], ds[4], dt[4];
patch_eval_bspline_weights(u, s, ds);
patch_eval_bspline_weights(v, t, dt);
patch_eval_adjust_boundary_weights(patch_bits, s, t);
patch_eval_adjust_boundary_weights(patch_bits, ds, dt);
for(int k = 0; k < 4; k++) {
for(int l = 0; l < 4; l++) {
weights[4*k+l] = s[l] * t[k];
weights_du[4*k+l] = ds[l] * t[k] * d_scale;
weights_dv[4*k+l] = s[l] * dt[k] * d_scale;
}
}
}
/* generic function for evaluating indices and weights from patch coords */
ccl_device_inline int patch_eval_control_verts(KernelGlobals *kg, int object, int patch, float u, float v, int channel,
int indices[PATCH_MAX_CONTROL_VERTS],
float weights[PATCH_MAX_CONTROL_VERTS],
float weights_du[PATCH_MAX_CONTROL_VERTS],
float weights_dv[PATCH_MAX_CONTROL_VERTS])
{
PatchHandle handle = patch_map_find_patch(kg, object, patch, u, v);
kernel_assert(handle.array_index >= 0);
int num_control = patch_eval_indices(kg, &handle, channel, indices);
patch_eval_basis(kg, &handle, u, v, weights, weights_du, weights_dv);
return num_control;
}
/* functions for evaluating attributes on patches */
ccl_device float patch_eval_float(KernelGlobals *kg, const ShaderData *sd, int offset,
int patch, float u, float v, int channel,
float *du, float* dv)
{
int indices[PATCH_MAX_CONTROL_VERTS];
float weights[PATCH_MAX_CONTROL_VERTS];
float weights_du[PATCH_MAX_CONTROL_VERTS];
float weights_dv[PATCH_MAX_CONTROL_VERTS];
int num_control = patch_eval_control_verts(kg, ccl_fetch(sd, object), patch, u, v, channel,
indices, weights, weights_du, weights_dv);
float val = 0.0f;
if(du) *du = 0.0f;
if(dv) *dv = 0.0f;
for(int i = 0; i < num_control; i++) {
float v = kernel_tex_fetch(__attributes_float, offset + indices[i]);
val += v * weights[i];
if(du) *du += v * weights_du[i];
if(dv) *dv += v * weights_dv[i];
}
return val;
}
ccl_device float3 patch_eval_float3(KernelGlobals *kg, const ShaderData *sd, int offset,
int patch, float u, float v, int channel,
float3 *du, float3 *dv)
{
int indices[PATCH_MAX_CONTROL_VERTS];
float weights[PATCH_MAX_CONTROL_VERTS];
float weights_du[PATCH_MAX_CONTROL_VERTS];
float weights_dv[PATCH_MAX_CONTROL_VERTS];
int num_control = patch_eval_control_verts(kg, ccl_fetch(sd, object), patch, u, v, channel,
indices, weights, weights_du, weights_dv);
float3 val = make_float3(0.0f, 0.0f, 0.0f);
if(du) *du = make_float3(0.0f, 0.0f, 0.0f);
if(dv) *dv = make_float3(0.0f, 0.0f, 0.0f);
for(int i = 0; i < num_control; i++) {
float3 v = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + indices[i]));
val += v * weights[i];
if(du) *du += v * weights_du[i];
if(dv) *dv += v * weights_dv[i];
}
return val;
}
ccl_device float3 patch_eval_uchar4(KernelGlobals *kg, const ShaderData *sd, int offset,
int patch, float u, float v, int channel,
float3 *du, float3 *dv)
{
int indices[PATCH_MAX_CONTROL_VERTS];
float weights[PATCH_MAX_CONTROL_VERTS];
float weights_du[PATCH_MAX_CONTROL_VERTS];
float weights_dv[PATCH_MAX_CONTROL_VERTS];
int num_control = patch_eval_control_verts(kg, ccl_fetch(sd, object), patch, u, v, channel,
indices, weights, weights_du, weights_dv);
float3 val = make_float3(0.0f, 0.0f, 0.0f);
if(du) *du = make_float3(0.0f, 0.0f, 0.0f);
if(dv) *dv = make_float3(0.0f, 0.0f, 0.0f);
for(int i = 0; i < num_control; i++) {
float3 v = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, offset + indices[i]));
val += v * weights[i];
if(du) *du += v * weights_du[i];
if(dv) *dv += v * weights_dv[i];
}
return val;
}
CCL_NAMESPACE_END

View File

@@ -25,24 +25,23 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline float primitive_attribute_float(KernelGlobals *kg,
const ShaderData *sd,
AttributeElement elem,
int offset,
const AttributeDescriptor desc,
float *dx, float *dy)
{
if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) {
if(subd_triangle_patch(kg, sd) == ~0)
return triangle_attribute_float(kg, sd, elem, offset, dx, dy);
return triangle_attribute_float(kg, sd, desc, dx, dy);
else
return subd_triangle_attribute_float(kg, sd, elem, offset, dx, dy);
return subd_triangle_attribute_float(kg, sd, desc, dx, dy);
}
#ifdef __HAIR__
else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
return curve_attribute_float(kg, sd, elem, offset, dx, dy);
return curve_attribute_float(kg, sd, desc, dx, dy);
}
#endif
#ifdef __VOLUME__
else if(ccl_fetch(sd, object) != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) {
return volume_attribute_float(kg, sd, elem, offset, dx, dy);
else if(ccl_fetch(sd, object) != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
return volume_attribute_float(kg, sd, desc, dx, dy);
}
#endif
else {
@@ -54,25 +53,23 @@ ccl_device_inline float primitive_attribute_float(KernelGlobals *kg,
ccl_device_inline float3 primitive_attribute_float3(KernelGlobals *kg,
const ShaderData *sd,
AttributeElement elem,
int offset,
float3 *dx,
float3 *dy)
const AttributeDescriptor desc,
float3 *dx, float3 *dy)
{
if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) {
if(subd_triangle_patch(kg, sd) == ~0)
return triangle_attribute_float3(kg, sd, elem, offset, dx, dy);
return triangle_attribute_float3(kg, sd, desc, dx, dy);
else
return subd_triangle_attribute_float3(kg, sd, elem, offset, dx, dy);
return subd_triangle_attribute_float3(kg, sd, desc, dx, dy);
}
#ifdef __HAIR__
else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
return curve_attribute_float3(kg, sd, elem, offset, dx, dy);
return curve_attribute_float3(kg, sd, desc, dx, dy);
}
#endif
#ifdef __VOLUME__
else if(ccl_fetch(sd, object) != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) {
return volume_attribute_float3(kg, sd, elem, offset, dx, dy);
else if(ccl_fetch(sd, object) != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
return volume_attribute_float3(kg, sd, desc, dx, dy);
}
#endif
else {
@@ -86,13 +83,12 @@ ccl_device_inline float3 primitive_attribute_float3(KernelGlobals *kg,
ccl_device_inline float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
{
AttributeElement elem_uv;
int offset_uv = find_attribute(kg, sd, ATTR_STD_UV, &elem_uv);
const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_UV);
if(offset_uv == ATTR_STD_NOT_FOUND)
if(desc.offset == 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);
float3 uv = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
uv.z = 1.0f;
return uv;
}
@@ -102,15 +98,14 @@ ccl_device_inline float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
ccl_device bool primitive_ptex(KernelGlobals *kg, ShaderData *sd, float2 *uv, int *face_id)
{
/* storing ptex data as attributes is not memory efficient but simple for tests */
AttributeElement elem_face_id, elem_uv;
int offset_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID, &elem_face_id);
int offset_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV, &elem_uv);
const AttributeDescriptor desc_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID);
const AttributeDescriptor desc_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV);
if(offset_face_id == ATTR_STD_NOT_FOUND || offset_uv == ATTR_STD_NOT_FOUND)
if(desc_face_id.offset == ATTR_STD_NOT_FOUND || desc_uv.offset == ATTR_STD_NOT_FOUND)
return false;
float3 uv3 = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL);
float face_id_f = primitive_attribute_float(kg, sd, elem_face_id, offset_face_id, NULL, NULL);
float3 uv3 = primitive_attribute_float3(kg, sd, desc_uv, NULL, NULL);
float face_id_f = primitive_attribute_float(kg, sd, desc_face_id, NULL, NULL);
*uv = make_float2(uv3.x, uv3.y);
*face_id = (int)face_id_f;
@@ -132,11 +127,10 @@ ccl_device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
#endif
/* try to create spherical tangent from generated coordinates */
AttributeElement attr_elem;
int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED, &attr_elem);
const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED);
if(attr_offset != ATTR_STD_NOT_FOUND) {
float3 data = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
if(desc.offset != ATTR_STD_NOT_FOUND) {
float3 data = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
object_normal_transform(kg, sd, &data);
return cross(ccl_fetch(sd, N), normalize(cross(data, ccl_fetch(sd, N))));
@@ -173,19 +167,18 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
float3 motion_pre = center, motion_post = center;
/* deformation motion */
AttributeElement elem;
int offset = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION, &elem);
AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION);
if(offset != ATTR_STD_NOT_FOUND) {
if(desc.offset != ATTR_STD_NOT_FOUND) {
/* get motion info */
int numverts, numkeys;
object_motion_info(kg, ccl_fetch(sd, object), NULL, &numverts, &numkeys);
/* lookup attributes */
int offset_next = (ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE)? offset + numverts: offset + numkeys;
motion_pre = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
motion_pre = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
motion_post = primitive_attribute_float3(kg, sd, elem, offset_next, NULL, NULL);
desc.offset += (ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE)? numverts: numkeys;
motion_post = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
#ifdef __HAIR__
if(is_curve_primitive && (ccl_fetch(sd, flag) & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {

View File

@@ -97,36 +97,78 @@ ccl_device_inline void subd_triangle_patch_corners(KernelGlobals *kg, int patch,
/* Reading attributes on various subdivision triangle elements */
ccl_device float subd_triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
{
int patch = subd_triangle_patch(kg, sd);
if(elem == ATTR_ELEMENT_FACE) {
if(desc.flags & ATTR_SUBDIVIDED) {
float2 uv[3];
subd_triangle_patch_uv(kg, sd, uv);
float2 dpdu = uv[0] - uv[2];
float2 dpdv = uv[1] - uv[2];
/* p is [s, t] */
float2 p = dpdu * ccl_fetch(sd, u) + dpdv * ccl_fetch(sd, v) + uv[2];
float a, dads, dadt;
a = patch_eval_float(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
#ifdef __RAY_DIFFERENTIALS__
if(dx || dy) {
float dsdu = dpdu.x;
float dtdu = dpdu.y;
float dsdv = dpdv.x;
float dtdv = dpdv.y;
if(dx) {
float dudx = ccl_fetch(sd, du).dx;
float dvdx = ccl_fetch(sd, dv).dx;
float dsdx = dsdu*dudx + dsdv*dvdx;
float dtdx = dtdu*dudx + dtdv*dvdx;
*dx = dads*dsdx + dadt*dtdx;
}
if(dy) {
float dudy = ccl_fetch(sd, du).dy;
float dvdy = ccl_fetch(sd, dv).dy;
float dsdy = dsdu*dudy + dsdv*dvdy;
float dtdy = dtdu*dudy + dtdv*dvdy;
*dy = dads*dsdy + dadt*dtdy;
}
}
#endif
return a;
}
else if(desc.element == ATTR_ELEMENT_FACE) {
if(dx) *dx = 0.0f;
if(dy) *dy = 0.0f;
return kernel_tex_fetch(__attributes_float, offset + subd_triangle_patch_face(kg, patch));
return kernel_tex_fetch(__attributes_float, desc.offset + subd_triangle_patch_face(kg, patch));
}
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
float2 uv[3];
subd_triangle_patch_uv(kg, sd, uv);
uint4 v = subd_triangle_patch_indices(kg, patch);
float a, b, c;
float f0 = kernel_tex_fetch(__attributes_float, offset + v.x);
float f1 = kernel_tex_fetch(__attributes_float, offset + v.y);
float f2 = kernel_tex_fetch(__attributes_float, offset + v.z);
float f3 = kernel_tex_fetch(__attributes_float, offset + v.w);
float f0 = kernel_tex_fetch(__attributes_float, desc.offset + v.x);
float f1 = kernel_tex_fetch(__attributes_float, desc.offset + v.y);
float f2 = kernel_tex_fetch(__attributes_float, desc.offset + v.z);
float f3 = kernel_tex_fetch(__attributes_float, desc.offset + v.w);
if(subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1+f0)*0.5f;
f3 = (f3+f0)*0.5f;
}
a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;
@@ -135,28 +177,26 @@ ccl_device float subd_triangle_attribute_float(KernelGlobals *kg, const ShaderDa
return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c;
}
else if(elem == ATTR_ELEMENT_CORNER) {
int corners[4];
subd_triangle_patch_corners(kg, patch, corners);
else if(desc.element == ATTR_ELEMENT_CORNER) {
float2 uv[3];
subd_triangle_patch_uv(kg, sd, uv);
float a, b, c;
int corners[4];
subd_triangle_patch_corners(kg, patch, corners);
float f0 = kernel_tex_fetch(__attributes_float, corners[0] + offset);
float f1 = kernel_tex_fetch(__attributes_float, corners[1] + offset);
float f2 = kernel_tex_fetch(__attributes_float, corners[2] + offset);
float f3 = kernel_tex_fetch(__attributes_float, corners[3] + offset);
float f0 = kernel_tex_fetch(__attributes_float, corners[0] + desc.offset);
float f1 = kernel_tex_fetch(__attributes_float, corners[1] + desc.offset);
float f2 = kernel_tex_fetch(__attributes_float, corners[2] + desc.offset);
float f3 = kernel_tex_fetch(__attributes_float, corners[3] + desc.offset);
if(subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1+f0)*0.5f;
f3 = (f3+f0)*0.5f;
}
a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;
@@ -173,36 +213,84 @@ ccl_device float subd_triangle_attribute_float(KernelGlobals *kg, const ShaderDa
}
}
ccl_device float3 subd_triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
{
int patch = subd_triangle_patch(kg, sd);
if(elem == ATTR_ELEMENT_FACE) {
if(desc.flags & ATTR_SUBDIVIDED) {
float2 uv[3];
subd_triangle_patch_uv(kg, sd, uv);
float2 dpdu = uv[0] - uv[2];
float2 dpdv = uv[1] - uv[2];
/* p is [s, t] */
float2 p = dpdu * ccl_fetch(sd, u) + dpdv * ccl_fetch(sd, v) + uv[2];
float3 a, dads, dadt;
if(desc.element == ATTR_ELEMENT_CORNER_BYTE) {
a = patch_eval_uchar4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
}
else {
a = patch_eval_float3(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
}
#ifdef __RAY_DIFFERENTIALS__
if(dx || dy) {
float dsdu = dpdu.x;
float dtdu = dpdu.y;
float dsdv = dpdv.x;
float dtdv = dpdv.y;
if(dx) {
float dudx = ccl_fetch(sd, du).dx;
float dvdx = ccl_fetch(sd, dv).dx;
float dsdx = dsdu*dudx + dsdv*dvdx;
float dtdx = dtdu*dudx + dtdv*dvdx;
*dx = dads*dsdx + dadt*dtdx;
}
if(dy) {
float dudy = ccl_fetch(sd, du).dy;
float dvdy = ccl_fetch(sd, dv).dy;
float dsdy = dsdu*dudy + dsdv*dvdy;
float dtdy = dtdu*dudy + dtdv*dvdy;
*dy = dads*dsdy + dadt*dtdy;
}
}
#endif
return a;
}
else if(desc.element == ATTR_ELEMENT_FACE) {
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + subd_triangle_patch_face(kg, patch)));
return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + subd_triangle_patch_face(kg, patch)));
}
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
float2 uv[3];
subd_triangle_patch_uv(kg, sd, uv);
uint4 v = subd_triangle_patch_indices(kg, patch);
float3 a, b, c;
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.x));
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.y));
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.z));
float3 f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.w));
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.x));
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.y));
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.z));
float3 f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.w));
if(subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1+f0)*0.5f;
f3 = (f3+f0)*0.5f;
}
a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;
@@ -211,27 +299,26 @@ ccl_device float3 subd_triangle_attribute_float3(KernelGlobals *kg, const Shader
return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c;
}
else if(elem == ATTR_ELEMENT_CORNER || elem == ATTR_ELEMENT_CORNER_BYTE) {
int corners[4];
subd_triangle_patch_corners(kg, patch, corners);
else if(desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
float2 uv[3];
subd_triangle_patch_uv(kg, sd, uv);
float3 a, b, c;
int corners[4];
subd_triangle_patch_corners(kg, patch, corners);
float3 f0, f1, f2, f3;
if(elem == ATTR_ELEMENT_CORNER) {
f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + offset));
f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + offset));
f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + offset));
f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + offset));
if(desc.element == ATTR_ELEMENT_CORNER) {
f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset));
f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset));
f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset));
f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset));
}
else {
f0 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[0] + offset));
f1 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[1] + offset));
f2 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[2] + offset));
f3 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[3] + offset));
f0 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[0] + desc.offset));
f1 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[1] + desc.offset));
f2 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[2] + desc.offset));
f3 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[3] + desc.offset));
}
if(subd_triangle_patch_num_corners(kg, patch) != 4) {
@@ -239,9 +326,9 @@ ccl_device float3 subd_triangle_attribute_float3(KernelGlobals *kg, const Shader
f3 = (f3+f0)*0.5f;
}
a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;

View File

@@ -105,20 +105,20 @@ ccl_device_inline void triangle_dPdudv(KernelGlobals *kg, int prim, ccl_addr_spa
/* Reading attributes on various triangle elements */
ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
{
if(elem == ATTR_ELEMENT_FACE) {
if(desc.element == ATTR_ELEMENT_FACE) {
if(dx) *dx = 0.0f;
if(dy) *dy = 0.0f;
return kernel_tex_fetch(__attributes_float, offset + ccl_fetch(sd, prim));
return kernel_tex_fetch(__attributes_float, desc.offset + ccl_fetch(sd, prim));
}
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
float f0 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.x);
float f1 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.y);
float f2 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.z);
float f0 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.x);
float f1 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.y);
float f2 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.z);
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
@@ -127,8 +127,8 @@ ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *s
return ccl_fetch(sd, u)*f0 + ccl_fetch(sd, v)*f1 + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*f2;
}
else if(elem == ATTR_ELEMENT_CORNER) {
int tri = offset + ccl_fetch(sd, prim)*3;
else if(desc.element == ATTR_ELEMENT_CORNER) {
int tri = desc.offset + ccl_fetch(sd, prim)*3;
float f0 = kernel_tex_fetch(__attributes_float, tri + 0);
float f1 = kernel_tex_fetch(__attributes_float, tri + 1);
float f2 = kernel_tex_fetch(__attributes_float, tri + 2);
@@ -148,20 +148,20 @@ ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *s
}
}
ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
{
if(elem == ATTR_ELEMENT_FACE) {
if(desc.element == ATTR_ELEMENT_FACE) {
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + ccl_fetch(sd, prim)));
return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + ccl_fetch(sd, prim)));
}
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x));
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y));
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z));
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.x));
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.y));
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.z));
#ifdef __RAY_DIFFERENTIALS__
if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
@@ -170,11 +170,11 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData
return ccl_fetch(sd, u)*f0 + ccl_fetch(sd, v)*f1 + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*f2;
}
else if(elem == ATTR_ELEMENT_CORNER || elem == ATTR_ELEMENT_CORNER_BYTE) {
int tri = offset + ccl_fetch(sd, prim)*3;
else if(desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
int tri = desc.offset + ccl_fetch(sd, prim)*3;
float3 f0, f1, f2;
if(elem == ATTR_ELEMENT_CORNER) {
if(desc.element == ATTR_ELEMENT_CORNER) {
f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0));
f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1));
f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2));

View File

@@ -50,36 +50,35 @@ ccl_device_inline float3 volume_normalized_position(KernelGlobals *kg,
{
/* todo: optimize this so it's just a single matrix multiplication when
* possible (not motion blur), or perhaps even just translation + scale */
AttributeElement attr_elem;
int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM, &attr_elem);
const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM);
object_inverse_position_transform(kg, sd, &P);
if(attr_offset != ATTR_STD_NOT_FOUND) {
Transform tfm = primitive_attribute_matrix(kg, sd, attr_offset);
if(desc.offset != ATTR_STD_NOT_FOUND) {
Transform tfm = primitive_attribute_matrix(kg, sd, desc);
P = transform_point(&tfm, P);
}
return P;
}
ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int id, float *dx, float *dy)
ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
{
float3 P = volume_normalized_position(kg, sd, sd->P);
#ifdef __KERNEL_GPU__
# if __CUDA_ARCH__ >= 300
CUtexObject tex = kernel_tex_fetch(__bindless_mapping, id);
CUtexObject tex = kernel_tex_fetch(__bindless_mapping, desc.offset);
float f = kernel_tex_image_interp_3d_float(tex, P.x, P.y, P.z);
float4 r = make_float4(f, f, f, 1.0);
# else
float4 r = volume_image_texture_3d(id, P.x, P.y, P.z);
float4 r = volume_image_texture_3d(desc.offset, P.x, P.y, P.z);
# endif
#else
float4 r;
if(sd->flag & SD_VOLUME_CUBIC)
r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
r = kernel_tex_image_interp_3d_ex(desc.offset, P.x, P.y, P.z, INTERPOLATION_CUBIC);
else
r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
r = kernel_tex_image_interp_3d(desc.offset, P.x, P.y, P.z);
#endif
if(dx) *dx = 0.0f;
@@ -88,22 +87,22 @@ ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd,
return average(float4_to_float3(r));
}
ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int id, float3 *dx, float3 *dy)
ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
{
float3 P = volume_normalized_position(kg, sd, sd->P);
#ifdef __KERNEL_GPU__
# if __CUDA_ARCH__ >= 300
CUtexObject tex = kernel_tex_fetch(__bindless_mapping, id);
CUtexObject tex = kernel_tex_fetch(__bindless_mapping, desc.offset);
float4 r = kernel_tex_image_interp_3d_float4(tex, P.x, P.y, P.z);
# else
float4 r = volume_image_texture_3d(id, P.x, P.y, P.z);
float4 r = volume_image_texture_3d(desc.offset, P.x, P.y, P.z);
# endif
#else
float4 r;
if(sd->flag & SD_VOLUME_CUBIC)
r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
r = kernel_tex_image_interp_3d_ex(desc.offset, P.x, P.y, P.z, INTERPOLATION_CUBIC);
else
r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
r = kernel_tex_image_interp_3d(desc.offset, P.x, P.y, P.z);
#endif
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);

View File

@@ -149,7 +149,7 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
/* ShaderData setup from BSSRDF scatter */
#ifdef __SUBSURFACE__
# ifndef __KERNEL_CUDS__
# ifndef __KERNEL_CUDA__
ccl_device
# else
ccl_device_inline
@@ -539,7 +539,7 @@ ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg,
#endif
#ifndef __KERNEL_CUDS__
#ifndef __KERNEL_CUDA__
ccl_device
#else
ccl_device_inline

View File

@@ -86,7 +86,7 @@ ccl_device ShaderClosure *subsurface_scatter_pick_closure(KernelGlobals *kg, Sha
}
#ifndef __KERNEL_GPU__
ccl_device
ccl_device_noinline
#else
ccl_device_inline
#endif

View File

@@ -34,7 +34,7 @@
CCL_NAMESPACE_BEGIN
/* constants */
#define OBJECT_SIZE 11
#define OBJECT_SIZE 12
#define OBJECT_VECTOR_SIZE 6
#define LIGHT_SIZE 5
#define FILTER_TABLE_SIZE 1024
@@ -624,6 +624,18 @@ typedef enum AttributeStandard {
ATTR_STD_NOT_FOUND = ~0
} AttributeStandard;
typedef enum AttributeFlag {
ATTR_FINAL_SIZE = (1 << 0),
ATTR_SUBDIVIDED = (1 << 1),
} AttributeFlag;
typedef struct AttributeDescriptor {
AttributeElement element;
NodeAttributeType type;
uint flags; /* see enum AttributeFlag */
int offset;
} AttributeDescriptor;
/* Closure data */
#ifdef __MULTI_CLOSURE__
@@ -1239,6 +1251,16 @@ enum RayState {
#define REMOVE_RAY_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] = (ray_state[ray_index] & (~flag)))
#define IS_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] & flag)
/* Patches */
#define PATCH_MAX_CONTROL_VERTS 16
/* Patch map node flags */
#define PATCH_MAP_NODE_IS_SET (1 << 30)
#define PATCH_MAP_NODE_IS_LEAF (1 << 31)
#define PATCH_MAP_NODE_INDEX_MASK (~(PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF))
CCL_NAMESPACE_END
#endif /* __KERNEL_TYPES_H__ */

View File

@@ -59,8 +59,7 @@ struct OSLGlobals {
/* attributes */
struct Attribute {
TypeDesc type;
AttributeElement elem;
int offset;
AttributeDescriptor desc;
ParamValue value;
};

View File

@@ -554,13 +554,13 @@ static bool get_mesh_element_attribute(KernelGlobals *kg, const ShaderData *sd,
attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
{
float3 fval[3];
fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset,
fval[0] = primitive_attribute_float3(kg, sd, attr.desc,
(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] = primitive_attribute_float(kg, sd, attr.elem, attr.offset,
fval[0] = primitive_attribute_float(kg, sd, attr.desc,
(derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float(fval, type, derivatives, val);
}
@@ -573,7 +573,7 @@ static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OS
const TypeDesc& type, bool derivatives, void *val)
{
if(attr.type == TypeDesc::TypeMatrix) {
Transform tfm = primitive_attribute_matrix(kg, sd, attr.offset);
Transform tfm = primitive_attribute_matrix(kg, sd, attr.desc);
return set_attribute_matrix(tfm, type, val);
}
else {
@@ -815,7 +815,7 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring
if(it != attribute_map.end()) {
const OSLGlobals::Attribute& attr = it->second;
if(attr.elem != ATTR_ELEMENT_OBJECT) {
if(attr.desc.element != ATTR_ELEMENT_OBJECT) {
/* triangle and vertex attributes */
if(get_mesh_element_attribute(kg, sd, attr, type, derivatives, val))
return true;

View File

@@ -334,7 +334,7 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderConte
/* Attributes */
int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeDescriptor *desc)
{
/* for OSL, a hash map is used to lookup the attribute by name. */
int object = sd->object*ATTR_PRIM_TYPES;
@@ -348,16 +348,23 @@ int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id,
if(it != attr_map.end()) {
const OSLGlobals::Attribute &osl_attr = it->second;
*elem = osl_attr.elem;
*desc = osl_attr.desc;
if(sd->prim == PRIM_NONE && (AttributeElement)osl_attr.elem != ATTR_ELEMENT_MESH)
if(sd->prim == PRIM_NONE && (AttributeElement)osl_attr.desc.element != ATTR_ELEMENT_MESH) {
desc->offset = ATTR_STD_NOT_FOUND;
return ATTR_STD_NOT_FOUND;
}
/* return result */
return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
if(osl_attr.desc.element == ATTR_ELEMENT_NONE) {
desc->offset = ATTR_STD_NOT_FOUND;
}
return desc->offset;
}
else
else {
desc->offset = ATTR_STD_NOT_FOUND;
return (int)ATTR_STD_NOT_FOUND;
}
}
CCL_NAMESPACE_END

View File

@@ -59,7 +59,7 @@ public:
static void eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx);
/* attributes */
static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem);
static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeDescriptor *desc);
};
CCL_NAMESPACE_END

View File

@@ -18,117 +18,101 @@ CCL_NAMESPACE_BEGIN
/* Attribute Node */
ccl_device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
ccl_device AttributeDescriptor svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
uint4 node, NodeAttributeType *type,
NodeAttributeType *mesh_type, AttributeElement *elem, int *offset, uint *out_offset)
uint *out_offset)
{
*out_offset = node.z;
*type = (NodeAttributeType)node.w;
if(ccl_fetch(sd, object) != OBJECT_NONE) {
/* find attribute by unique id */
uint id = node.y;
uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride;
attr_offset += attribute_primitive_type(kg, sd);
uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
while(attr_map.x != id) {
if(UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
*elem = ATTR_ELEMENT_NONE;
*offset = 0;
*mesh_type = (NodeAttributeType)node.w;
return;
}
attr_offset += ATTR_PRIM_TYPES;
attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
}
/* return result */
*elem = (AttributeElement)attr_map.y;
*offset = as_int(attr_map.z);
*mesh_type = (NodeAttributeType)attr_map.w;
AttributeDescriptor desc;
if(ccl_fetch(sd, object) != OBJECT_NONE) {
desc = find_attribute(kg, sd, node.y);
if(desc.offset == ATTR_STD_NOT_FOUND) {
desc.element = ATTR_ELEMENT_NONE;
desc.offset = 0;
desc.type = (NodeAttributeType)node.w;
}
}
else {
/* background */
*elem = ATTR_ELEMENT_NONE;
*offset = 0;
*mesh_type = (NodeAttributeType)node.w;
desc.element = ATTR_ELEMENT_NONE;
desc.offset = 0;
desc.type = (NodeAttributeType)node.w;
}
return desc;
}
ccl_device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
{
NodeAttributeType type, mesh_type;
AttributeElement elem;
NodeAttributeType type;
uint out_offset;
int offset;
svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
/* fetch and store attribute */
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL);
if(desc.type == NODE_ATTR_FLOAT) {
float f = primitive_attribute_float(kg, sd, desc, NULL, NULL);
stack_store_float(stack, out_offset, f);
}
else {
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
float3 f = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
stack_store_float(stack, out_offset, average(f));
}
}
else {
if(mesh_type == NODE_ATTR_FLOAT3) {
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
if(desc.type == NODE_ATTR_FLOAT3) {
float3 f = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
stack_store_float3(stack, out_offset, f);
}
else {
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL);
float f = primitive_attribute_float(kg, sd, desc, NULL, NULL);
stack_store_float3(stack, out_offset, make_float3(f, f, f));
}
}
}
#ifndef __KERNEL_CUDS__
#ifndef __KERNEL_CUDA__
ccl_device
#else
ccl_device_noinline
#endif
void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
{
NodeAttributeType type, mesh_type;
AttributeElement elem;
NodeAttributeType type;
uint out_offset;
int offset;
svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
/* fetch and store attribute */
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
if(desc.type == NODE_ATTR_FLOAT) {
float dx;
float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL);
float f = primitive_attribute_float(kg, sd, desc, &dx, NULL);
stack_store_float(stack, out_offset, f+dx);
}
else {
float3 dx;
float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL);
float3 f = primitive_attribute_float3(kg, sd, desc, &dx, NULL);
stack_store_float(stack, out_offset, average(f+dx));
}
}
else {
if(mesh_type == NODE_ATTR_FLOAT3) {
if(desc.type == NODE_ATTR_FLOAT3) {
float3 dx;
float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL);
float3 f = primitive_attribute_float3(kg, sd, desc, &dx, NULL);
stack_store_float3(stack, out_offset, f+dx);
}
else {
float dx;
float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL);
float f = primitive_attribute_float(kg, sd, desc, &dx, NULL);
stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx));
}
}
}
#ifndef __KERNEL_CUDS__
#ifndef __KERNEL_CUDA__
ccl_device
#else
ccl_device_noinline
@@ -138,35 +122,32 @@ void svm_node_attr_bump_dy(KernelGlobals *kg,
float *stack,
uint4 node)
{
NodeAttributeType type, mesh_type;
AttributeElement elem;
NodeAttributeType type;
uint out_offset;
int offset;
svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
/* fetch and store attribute */
if(type == NODE_ATTR_FLOAT) {
if(mesh_type == NODE_ATTR_FLOAT) {
if(desc.type == NODE_ATTR_FLOAT) {
float dy;
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy);
float f = primitive_attribute_float(kg, sd, desc, NULL, &dy);
stack_store_float(stack, out_offset, f+dy);
}
else {
float3 dy;
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy);
float3 f = primitive_attribute_float3(kg, sd, desc, NULL, &dy);
stack_store_float(stack, out_offset, average(f+dy));
}
}
else {
if(mesh_type == NODE_ATTR_FLOAT3) {
if(desc.type == NODE_ATTR_FLOAT3) {
float3 dy;
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy);
float3 f = primitive_attribute_float3(kg, sd, desc, NULL, &dy);
stack_store_float3(stack, out_offset, f+dy);
}
else {
float dy;
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy);
float f = primitive_attribute_float(kg, sd, desc, NULL, &dy);
stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy));
}
}

View File

@@ -287,23 +287,22 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
}
/* first try to get tangent attribute */
AttributeElement attr_elem, attr_sign_elem, attr_normal_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);
int attr_normal_offset = find_attribute(kg, sd, ATTR_STD_VERTEX_NORMAL, &attr_normal_elem);
const AttributeDescriptor attr = find_attribute(kg, sd, node.z);
const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.w);
const AttributeDescriptor attr_normal = find_attribute(kg, sd, ATTR_STD_VERTEX_NORMAL);
if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND || attr_normal_offset == ATTR_STD_NOT_FOUND) {
if(attr.offset == ATTR_STD_NOT_FOUND || attr_sign.offset == ATTR_STD_NOT_FOUND || attr_normal.offset == ATTR_STD_NOT_FOUND) {
stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
return;
}
/* get _unnormalized_ interpolated normal and tangent */
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);
float3 tangent = primitive_attribute_float3(kg, sd, attr, NULL, NULL);
float sign = primitive_attribute_float(kg, sd, attr_sign, NULL, NULL);
float3 normal;
if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL) {
normal = primitive_attribute_float3(kg, sd, attr_normal_elem, attr_normal_offset, NULL, NULL);
normal = primitive_attribute_float3(kg, sd, attr_normal, NULL, NULL);
}
else {
normal = ccl_fetch(sd, Ng);
@@ -356,24 +355,22 @@ ccl_device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack
if(direction_type == NODE_TANGENT_UVMAP) {
/* UV map */
AttributeElement attr_elem;
int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
const AttributeDescriptor desc = find_attribute(kg, sd, node.z);
if(attr_offset == ATTR_STD_NOT_FOUND)
if(desc.offset == ATTR_STD_NOT_FOUND)
tangent = make_float3(0.0f, 0.0f, 0.0f);
else
tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
tangent = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
}
else {
/* radial */
AttributeElement attr_elem;
int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
const AttributeDescriptor desc = find_attribute(kg, sd, node.z);
float3 generated;
if(attr_offset == ATTR_STD_NOT_FOUND)
if(desc.offset == ATTR_STD_NOT_FOUND)
generated = ccl_fetch(sd, P);
else
generated = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
generated = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
if(axis == NODE_TANGENT_AXIS_X)
tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f));

View File

@@ -44,6 +44,7 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
type = type_;
element = element_;
std = ATTR_STD_NONE;
flags = 0;
/* string and matrix not supported! */
assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
@@ -61,6 +62,11 @@ void Attribute::resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only)
}
}
void Attribute::resize(size_t num_elements)
{
buffer.resize(num_elements * data_sizeof(), 0);
}
void Attribute::add(const float& f)
{
char *data = (char*)&f;
@@ -130,6 +136,10 @@ size_t Attribute::data_sizeof() const
size_t Attribute::element_size(Mesh *mesh, AttributePrimitive prim) const
{
if(flags & ATTR_FINAL_SIZE) {
return buffer.size() / data_sizeof();
}
size_t size;
switch(element) {
@@ -517,16 +527,19 @@ AttributeRequest::AttributeRequest(ustring name_)
std = ATTR_STD_NONE;
triangle_type = TypeDesc::TypeFloat;
triangle_element = ATTR_ELEMENT_NONE;
triangle_offset = 0;
triangle_desc.element = ATTR_ELEMENT_NONE;
triangle_desc.offset = 0;
triangle_desc.type = NODE_ATTR_FLOAT;
curve_type = TypeDesc::TypeFloat;
curve_element = ATTR_ELEMENT_NONE;
curve_offset = 0;
curve_desc.element = ATTR_ELEMENT_NONE;
curve_desc.offset = 0;
curve_desc.type = NODE_ATTR_FLOAT;
subd_type = TypeDesc::TypeFloat;
subd_element = ATTR_ELEMENT_NONE;
subd_offset = 0;
subd_desc.element = ATTR_ELEMENT_NONE;
subd_desc.offset = 0;
subd_desc.type = NODE_ATTR_FLOAT;
}
AttributeRequest::AttributeRequest(AttributeStandard std_)
@@ -535,16 +548,19 @@ AttributeRequest::AttributeRequest(AttributeStandard std_)
std = std_;
triangle_type = TypeDesc::TypeFloat;
triangle_element = ATTR_ELEMENT_NONE;
triangle_offset = 0;
triangle_desc.element = ATTR_ELEMENT_NONE;
triangle_desc.offset = 0;
triangle_desc.type = NODE_ATTR_FLOAT;
curve_type = TypeDesc::TypeFloat;
curve_element = ATTR_ELEMENT_NONE;
curve_offset = 0;
curve_desc.element = ATTR_ELEMENT_NONE;
curve_desc.offset = 0;
curve_desc.type = NODE_ATTR_FLOAT;
subd_type = TypeDesc::TypeFloat;
subd_element = ATTR_ELEMENT_NONE;
subd_offset = 0;
subd_desc.element = ATTR_ELEMENT_NONE;
subd_desc.offset = 0;
subd_desc.type = NODE_ATTR_FLOAT;
}
/* AttributeRequestSet */

View File

@@ -54,11 +54,13 @@ public:
TypeDesc type;
vector<char> buffer;
AttributeElement element;
uint flags; /* enum AttributeFlag */
Attribute() {}
~Attribute();
void set(ustring name, TypeDesc type, AttributeElement element);
void resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only);
void resize(size_t num_elements);
size_t data_sizeof() const;
size_t element_size(Mesh *mesh, AttributePrimitive prim) const;
@@ -135,8 +137,7 @@ public:
/* temporary variables used by MeshManager */
TypeDesc triangle_type, curve_type, subd_type;
AttributeElement triangle_element, curve_element, subd_element;
int triangle_offset, curve_offset, subd_offset;
AttributeDescriptor triangle_desc, curve_desc, subd_desc;
explicit AttributeRequest(ustring name_);
explicit AttributeRequest(AttributeStandard std);

View File

@@ -30,6 +30,8 @@
#include "osl_globals.h"
#include "subd_patch_table.h"
#include "util_foreach.h"
#include "util_logging.h"
#include "util_progress.h"
@@ -112,19 +114,12 @@ float3 Mesh::SubdFace::normal(const Mesh *mesh) const
return safe_normalize(cross(v1 - v0, v2 - v0));
}
/* Mesh */
NODE_DEFINE(Mesh)
{
NodeType* type = NodeType::add("mesh", create);
static NodeEnum displacement_method_enum;
displacement_method_enum.insert("bump", DISPLACE_BUMP);
displacement_method_enum.insert("true", DISPLACE_TRUE);
displacement_method_enum.insert("both", DISPLACE_BOTH);
SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
SOCKET_UINT(motion_steps, "Motion Steps", 3);
SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false);
@@ -177,11 +172,14 @@ Mesh::Mesh()
num_ngons = 0;
subdivision_type = SUBDIVISION_NONE;
patch_table = NULL;
}
Mesh::~Mesh()
{
delete bvh;
delete patch_table;
}
void Mesh::resize_mesh(int numverts, int numtris)
@@ -274,6 +272,8 @@ void Mesh::clear()
num_subd_verts = 0;
subd_creases.clear();
attributes.clear();
curve_attributes.clear();
subd_attributes.clear();
@@ -283,6 +283,9 @@ void Mesh::clear()
transform_negative_scaled = false;
transform_normal = transform_identity();
geometry_flags = GEOMETRY_NONE;
delete patch_table;
patch_table = NULL;
}
int Mesh::split_vertex(int vertex)
@@ -705,7 +708,6 @@ void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, ui
}
}
void Mesh::compute_bvh(DeviceScene *dscene,
SceneParams *params,
Progress *progress,
@@ -779,6 +781,17 @@ bool Mesh::has_motion_blur() const
curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)));
}
bool Mesh::has_true_displacement() const
{
foreach(Shader *shader, used_shaders) {
if(shader->has_displacement && shader->displacement_method != DISPLACE_BUMP) {
return true;
}
}
return false;
}
bool Mesh::need_build_bvh() const
{
return !transform_applied || has_surface_bssrdf;
@@ -831,9 +844,10 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
OSLGlobals::Attribute osl_attr;
osl_attr.type = attr.type();
osl_attr.elem = ATTR_ELEMENT_OBJECT;
osl_attr.desc.element = ATTR_ELEMENT_OBJECT;
osl_attr.value = attr;
osl_attr.offset = 0;
osl_attr.desc.offset = 0;
osl_attr.desc.flags = 0;
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][attr.name()] = osl_attr;
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr;
@@ -853,9 +867,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
foreach(AttributeRequest& req, attributes.requests) {
OSLGlobals::Attribute osl_attr;
if(req.triangle_element != ATTR_ELEMENT_NONE) {
osl_attr.elem = req.triangle_element;
osl_attr.offset = req.triangle_offset;
if(req.triangle_desc.element != ATTR_ELEMENT_NONE) {
osl_attr.desc = req.triangle_desc;
if(req.triangle_type == TypeDesc::TypeFloat)
osl_attr.type = TypeDesc::TypeFloat;
@@ -875,9 +888,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
}
}
if(req.curve_element != ATTR_ELEMENT_NONE) {
osl_attr.elem = req.curve_element;
osl_attr.offset = req.curve_offset;
if(req.curve_desc.element != ATTR_ELEMENT_NONE) {
osl_attr.desc = req.curve_desc;
if(req.curve_type == TypeDesc::TypeFloat)
osl_attr.type = TypeDesc::TypeFloat;
@@ -897,9 +909,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
}
}
if(req.subd_element != ATTR_ELEMENT_NONE) {
osl_attr.elem = req.subd_element;
osl_attr.offset = req.subd_offset;
if(req.subd_desc.element != ATTR_ELEMENT_NONE) {
osl_attr.desc = req.subd_desc;
if(req.subd_type == TypeDesc::TypeFloat)
osl_attr.type = TypeDesc::TypeFloat;
@@ -971,8 +982,8 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
if(mesh->num_triangles()) {
attr_map[index].x = id;
attr_map[index].y = req.triangle_element;
attr_map[index].z = as_uint(req.triangle_offset);
attr_map[index].y = req.triangle_desc.element;
attr_map[index].z = as_uint(req.triangle_desc.offset);
if(req.triangle_type == TypeDesc::TypeFloat)
attr_map[index].w = NODE_ATTR_FLOAT;
@@ -980,14 +991,16 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
attr_map[index].w = NODE_ATTR_MATRIX;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
attr_map[index].w |= req.triangle_desc.flags << 8;
}
index++;
if(mesh->num_curves()) {
attr_map[index].x = id;
attr_map[index].y = req.curve_element;
attr_map[index].z = as_uint(req.curve_offset);
attr_map[index].y = req.curve_desc.element;
attr_map[index].z = as_uint(req.curve_desc.offset);
if(req.curve_type == TypeDesc::TypeFloat)
attr_map[index].w = NODE_ATTR_FLOAT;
@@ -995,14 +1008,16 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
attr_map[index].w = NODE_ATTR_MATRIX;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
attr_map[index].w |= req.curve_desc.flags << 8;
}
index++;
if(mesh->subd_faces.size()) {
attr_map[index].x = id;
attr_map[index].y = req.subd_element;
attr_map[index].z = as_uint(req.subd_offset);
attr_map[index].y = req.subd_desc.element;
attr_map[index].z = as_uint(req.subd_desc.offset);
if(req.subd_type == TypeDesc::TypeFloat)
attr_map[index].w = NODE_ATTR_FLOAT;
@@ -1010,6 +1025,8 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
attr_map[index].w = NODE_ATTR_MATRIX;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
attr_map[index].w |= req.subd_desc.flags << 8;
}
index++;
@@ -1069,17 +1086,20 @@ static void update_attribute_element_offset(Mesh *mesh,
Attribute *mattr,
AttributePrimitive prim,
TypeDesc& type,
int& offset,
AttributeElement& element)
AttributeDescriptor& desc)
{
if(mattr) {
/* store element and type */
element = mattr->element;
desc.element = mattr->element;
desc.flags = mattr->flags;
type = mattr->type;
/* store attribute data in arrays */
size_t size = mattr->element_size(mesh, prim);
AttributeElement& element = desc.element;
int& offset = desc.offset;
if(mattr->element == ATTR_ELEMENT_VOXEL) {
/* store slot in offset value */
VoxelAttribute *voxel_data = mattr->data_voxel();
@@ -1128,7 +1148,11 @@ static void update_attribute_element_offset(Mesh *mesh,
/* mesh vertex/curve index is global, not per object, so we sneak
* a correction for that in here */
if(element == ATTR_ELEMENT_VERTEX)
if(mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && desc.flags & ATTR_SUBDIVIDED) {
/* indices for subdivided attributes are retrieved
* from patch table so no need for correction here*/
}
else if(element == ATTR_ELEMENT_VERTEX)
offset -= mesh->vert_offset;
else if(element == ATTR_ELEMENT_VERTEX_MOTION)
offset -= mesh->vert_offset;
@@ -1153,8 +1177,8 @@ static void update_attribute_element_offset(Mesh *mesh,
}
else {
/* attribute not found */
element = ATTR_ELEMENT_NONE;
offset = 0;
desc.element = ATTR_ELEMENT_NONE;
desc.offset = 0;
}
}
@@ -1243,8 +1267,7 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
triangle_mattr,
ATTR_PRIM_TRIANGLE,
req.triangle_type,
req.triangle_offset,
req.triangle_element);
req.triangle_desc);
update_attribute_element_offset(mesh,
attr_float, attr_float_offset,
@@ -1253,8 +1276,7 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
curve_mattr,
ATTR_PRIM_CURVE,
req.curve_type,
req.curve_offset,
req.curve_element);
req.curve_desc);
update_attribute_element_offset(mesh,
attr_float, attr_float_offset,
@@ -1263,8 +1285,7 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
subd_mattr,
ATTR_PRIM_SUBD,
req.subd_type,
req.subd_offset,
req.subd_element);
req.subd_desc);
if(progress.get_cancel()) return;
}
@@ -1327,6 +1348,12 @@ void MeshManager::mesh_calc_offset(Scene *scene)
if(mesh->subd_faces.size()) {
Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-1];
patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
/* patch tables are stored in same array so include them in patch_size */
if(mesh->patch_table) {
mesh->patch_table_offset = patch_size;
patch_size += mesh->patch_table->total_size();
}
}
face_size += mesh->subd_faces.size();
corner_size += mesh->subd_face_corners.size();
@@ -1358,6 +1385,12 @@ void MeshManager::device_update_mesh(Device *device,
if(mesh->subd_faces.size()) {
Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-1];
patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
/* patch tables are stored in same array so include them in patch_size */
if(mesh->patch_table) {
mesh->patch_table_offset = patch_size;
patch_size += mesh->patch_table->total_size();
}
}
}
@@ -1440,6 +1473,11 @@ void MeshManager::device_update_mesh(Device *device,
foreach(Mesh *mesh, scene->meshes) {
mesh->pack_patches(&patch_data[mesh->patch_offset], mesh->vert_offset, mesh->face_offset, mesh->corner_offset);
if(mesh->patch_table) {
mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], mesh->patch_table_offset);
}
if(progress.get_cancel()) return;
}
@@ -1626,7 +1664,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
bool old_need_object_flags_update = false;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update &&
mesh->displacement_method != Mesh::DISPLACE_BUMP)
mesh->has_true_displacement())
{
true_displacement_used = true;
break;
@@ -1652,6 +1690,10 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
}
if(progress.get_cancel()) return;
/* after mesh data has been copied to device memory we need to update
* offsets for patch tables as this can't be known before hand */
scene->object_manager->device_update_patch_map_offsets(device, dscene, scene);
device_update_attributes(device, dscene, scene, progress);
if(progress.get_cancel()) return;

View File

@@ -40,6 +40,7 @@ class Scene;
class SceneParams;
class AttributeRequest;
class DiagSplit;
struct PackedPatchTable;
/* Mesh */
@@ -110,13 +111,9 @@ public:
int num_ptex_faces() const { return num_corners == 4 ? 1 : num_corners; }
};
/* Displacement */
enum DisplacementMethod {
DISPLACE_BUMP = 0,
DISPLACE_TRUE = 1,
DISPLACE_BOTH = 2,
DISPLACE_NUM_METHODS,
struct SubdEdgeCrease {
int v[2];
float crease;
};
enum SubdivisionType {
@@ -157,6 +154,8 @@ public:
array<int> subd_face_corners;
int num_ngons;
array<SubdEdgeCrease> subd_creases;
vector<Shader*> used_shaders;
AttributeSet attributes;
AttributeSet curve_attributes;
@@ -166,7 +165,8 @@ public:
bool transform_applied;
bool transform_negative_scaled;
Transform transform_normal;
DisplacementMethod displacement_method;
PackedPatchTable *patch_table;
uint motion_steps;
bool use_motion_blur;
@@ -184,6 +184,7 @@ public:
size_t curvekey_offset;
size_t patch_offset;
size_t patch_table_offset;
size_t face_offset;
size_t corner_offset;
@@ -234,6 +235,7 @@ public:
void tag_update(Scene *scene, bool rebuild);
bool has_motion_blur() const;
bool has_true_displacement() const;
/* Check whether the mesh should have own BVH built separately. Briefly,
* own BVH is needed for mesh, if:

View File

@@ -26,19 +26,27 @@
CCL_NAMESPACE_BEGIN
static float3 compute_face_normal(const Mesh::Triangle& t, float3 *verts)
{
float3 v0 = verts[t.v[0]];
float3 v1 = verts[t.v[1]];
float3 v2 = verts[t.v[2]];
float3 norm = cross(v1 - v0, v2 - v0);
float normlen = len(norm);
if(normlen == 0.0f)
return make_float3(1.0f, 0.0f, 0.0f);
return norm / normlen;
}
bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress)
{
/* verify if we have a displacement shader */
bool has_displacement = false;
if(mesh->displacement_method != Mesh::DISPLACE_BUMP) {
foreach(Shader *shader, mesh->used_shaders)
if(shader->has_displacement)
has_displacement = true;
}
if(!has_displacement)
if(!mesh->has_true_displacement()) {
return false;
}
string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
progress.set_status("Updating Mesh", msg);
@@ -67,8 +75,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] : scene->default_surface;
if(!shader->has_displacement)
if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
continue;
}
for(int j = 0; j < 3; j++) {
if(done[t.v[j]])
@@ -153,8 +162,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] : scene->default_surface;
if(!shader->has_displacement)
if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
continue;
}
for(int j = 0; j < 3; j++) {
if(!done[t.v[j]]) {
@@ -178,9 +188,131 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
mesh->add_face_normals();
if(mesh->displacement_method == Mesh::DISPLACE_TRUE) {
mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
mesh->add_vertex_normals();
bool need_recompute_vertex_normals = false;
foreach(Shader *shader, mesh->used_shaders) {
if(shader->has_displacement && shader->displacement_method == DISPLACE_TRUE) {
need_recompute_vertex_normals = true;
break;
}
}
if(need_recompute_vertex_normals) {
bool flip = mesh->transform_negative_scaled;
vector<bool> tri_has_true_disp(num_triangles, false);
for(size_t i = 0; i < num_triangles; i++) {
int shader_index = mesh->shader[i];
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] : scene->default_surface;
tri_has_true_disp[i] = shader->has_displacement && shader->displacement_method == DISPLACE_TRUE;
}
/* static vertex normals */
/* get attributes */
Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
float3 *fN = attr_fN->data_float3();
float3 *vN = attr_vN->data_float3();
/* compute vertex normals */
/* zero vertex normals on triangles with true displacement */
for(size_t i = 0; i < num_triangles; i++) {
if(tri_has_true_disp[i]) {
for(size_t j = 0; j < 3; j++) {
vN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f);
}
}
}
/* add face normals to vertex normals */
for(size_t i = 0; i < num_triangles; i++) {
if(tri_has_true_disp[i]) {
for(size_t j = 0; j < 3; j++) {
vN[mesh->get_triangle(i).v[j]] += fN[i];
}
}
}
/* normalize vertex normals */
done.clear();
done.resize(num_verts, false);
for(size_t i = 0; i < num_triangles; i++) {
if(tri_has_true_disp[i]) {
for(size_t j = 0; j < 3; j++) {
int vert = mesh->get_triangle(i).v[j];
if(done[vert]) {
continue;
}
vN[vert] = normalize(vN[vert]);
if(flip)
vN[vert] = -vN[vert];
done[vert] = true;
}
}
}
/* motion vertex normals */
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
if(mesh->has_motion_blur() && attr_mP && attr_mN) {
for(int step = 0; step < mesh->motion_steps - 1; step++) {
float3 *mP = attr_mP->data_float3() + step*mesh->verts.size();
float3 *mN = attr_mN->data_float3() + step*mesh->verts.size();
/* compute */
/* zero vertex normals on triangles with true displacement */
for(size_t i = 0; i < num_triangles; i++) {
if(tri_has_true_disp[i]) {
for(size_t j = 0; j < 3; j++) {
mN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f);
}
}
}
/* add face normals to vertex normals */
for(size_t i = 0; i < num_triangles; i++) {
if(tri_has_true_disp[i]) {
for(size_t j = 0; j < 3; j++) {
float3 fN = compute_face_normal(mesh->get_triangle(i), mP);
mN[mesh->get_triangle(i).v[j]] += fN;
}
}
}
/* normalize vertex normals */
done.clear();
done.resize(num_verts, false);
for(size_t i = 0; i < num_triangles; i++) {
if(tri_has_true_disp[i]) {
for(size_t j = 0; j < 3; j++) {
int vert = mesh->get_triangle(i).v[j];
if(done[vert]) {
continue;
}
mN[vert] = normalize(mN[vert]);
if(flip)
mN[vert] = -mN[vert];
done[vert] = true;
}
}
}
}
}
}
return true;

View File

@@ -19,13 +19,302 @@
#include "subd_split.h"
#include "subd_patch.h"
#include "subd_patch_table.h"
#include "util_foreach.h"
CCL_NAMESPACE_BEGIN
#ifdef WITH_OPENSUBDIV
CCL_NAMESPACE_END
#include <opensubdiv/far/topologyRefinerFactory.h>
#include <opensubdiv/far/primvarRefiner.h>
#include <opensubdiv/far/patchTableFactory.h>
#include <opensubdiv/far/patchMap.h>
/* specializations of TopologyRefinerFactory for ccl::Mesh */
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Far {
template<>
bool TopologyRefinerFactory<ccl::Mesh>::resizeComponentTopology(TopologyRefiner& refiner, ccl::Mesh const& mesh)
{
setNumBaseVertices(refiner, mesh.verts.size());
setNumBaseFaces(refiner, mesh.subd_faces.size());
ccl::Mesh::SubdFace* face = &mesh.subd_faces[0];
for(int i = 0; i < mesh.subd_faces.size(); i++, face++) {
setNumBaseFaceVertices(refiner, i, face->num_corners);
}
return true;
}
template<>
bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTopology(TopologyRefiner& refiner, ccl::Mesh const& mesh)
{
ccl::Mesh::SubdFace* face = &mesh.subd_faces[0];
for(int i = 0; i < mesh.subd_faces.size(); i++, face++) {
IndexArray face_verts = getBaseFaceVertices(refiner, i);
int* corner = &mesh.subd_face_corners[face->start_corner];
for(int j = 0; j < face->num_corners; j++, corner++) {
face_verts[j] = *corner;
}
}
return true;
}
template<>
bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTags(TopologyRefiner& refiner, ccl::Mesh const& mesh)
{
const ccl::Mesh::SubdEdgeCrease* crease = mesh.subd_creases.data();
for(int i = 0; i < mesh.subd_creases.size(); i++, crease++) {
Index edge = findBaseEdge(refiner, crease->v[0], crease->v[1]);
if(edge != INDEX_INVALID) {
setBaseEdgeSharpness(refiner, edge, crease->crease * 10.0f);
}
}
for(int i = 0; i < mesh.verts.size(); i++) {
ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i);
if(vert_edges.size() == 2) {
float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]);
sharpness = std::min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1]));
setBaseVertexSharpness(refiner, i, sharpness);
}
}
return true;
}
template<>
bool TopologyRefinerFactory<ccl::Mesh>::assignFaceVaryingTopology(TopologyRefiner& /*refiner*/, ccl::Mesh const& /*mesh*/)
{
return true;
}
template<>
void TopologyRefinerFactory<ccl::Mesh>::reportInvalidTopology(TopologyError /*err_code*/,
char const */*msg*/, ccl::Mesh const& /*mesh*/)
{
}
} /* namespace Far */
} /* namespace OPENSUBDIV_VERSION */
} /* namespace OpenSubdiv */
CCL_NAMESPACE_BEGIN
using namespace OpenSubdiv;
/* struct that implements OpenSubdiv's vertex interface */
template<typename T>
struct OsdValue {
T value;
OsdValue() {}
void Clear(void* = 0) {
memset(&value, 0, sizeof(T));
}
void AddWithWeight(OsdValue<T> const& src, float weight) {
value += src.value * weight;
}
};
template<>
void OsdValue<uchar4>::AddWithWeight(OsdValue<uchar4> const& src, float weight)
{
for(int i = 0; i < 4; i++) {
value[i] += (uchar)(src.value[i] * weight);
}
}
/* class for holding OpenSubdiv data used during tessellation */
class OsdData {
Mesh* mesh;
vector<OsdValue<float3> > verts;
Far::TopologyRefiner* refiner;
Far::PatchTable* patch_table;
Far::PatchMap* patch_map;
public:
OsdData() : mesh(NULL), refiner(NULL), patch_table(NULL), patch_map(NULL) {}
~OsdData()
{
delete refiner;
delete patch_table;
delete patch_map;
}
void build_from_mesh(Mesh* mesh_)
{
mesh = mesh_;
/* type and options */
Sdc::SchemeType type = Sdc::SCHEME_CATMARK;
Sdc::Options options;
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
/* create refiner */
refiner = Far::TopologyRefinerFactory<Mesh>::Create(*mesh,
Far::TopologyRefinerFactory<Mesh>::Options(type, options));
/* adaptive refinement */
int max_isolation = 10;
refiner->RefineAdaptive(Far::TopologyRefiner::AdaptiveOptions(max_isolation));
/* create patch table */
Far::PatchTableFactory::Options patch_options;
patch_options.endCapType = Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
patch_table = Far::PatchTableFactory::Create(*refiner, patch_options);
/* interpolate verts */
int num_refiner_verts = refiner->GetNumVerticesTotal();
int num_local_points = patch_table->GetNumLocalPoints();
verts.resize(num_refiner_verts + num_local_points);
for(int i = 0; i < mesh->verts.size(); i++) {
verts[i].value = mesh->verts[i];
}
OsdValue<float3>* src = &verts[0];
for(int i = 0; i < refiner->GetMaxLevel(); i++) {
OsdValue<float3>* dest = src + refiner->GetLevel(i).GetNumVertices();
Far::PrimvarRefiner(*refiner).Interpolate(i+1, src, dest);
src = dest;
}
patch_table->ComputeLocalPointValues(&verts[0], &verts[num_refiner_verts]);
/* create patch map */
patch_map = new Far::PatchMap(*patch_table);
}
void subdivide_attribute(Attribute& attr)
{
Far::PrimvarRefiner primvar_refiner(*refiner);
if(attr.element == ATTR_ELEMENT_VERTEX) {
int num_refiner_verts = refiner->GetNumVerticesTotal();
int num_local_points = patch_table->GetNumLocalPoints();
attr.resize(num_refiner_verts + num_local_points);
attr.flags |= ATTR_FINAL_SIZE;
char* src = &attr.buffer[0];
for(int i = 0; i < refiner->GetMaxLevel(); i++) {
char* dest = src + refiner->GetLevel(i).GetNumVertices() * attr.data_sizeof();
if(attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
primvar_refiner.Interpolate(i+1, (OsdValue<float>*)src, (OsdValue<float>*&)dest);
}
else {
primvar_refiner.Interpolate(i+1, (OsdValue<float4>*)src, (OsdValue<float4>*&)dest);
}
src = dest;
}
if(attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
patch_table->ComputeLocalPointValues((OsdValue<float>*)&attr.buffer[0],
(OsdValue<float>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
}
else {
patch_table->ComputeLocalPointValues((OsdValue<float4>*)&attr.buffer[0],
(OsdValue<float4>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
}
}
else if(attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
// TODO(mai): fvar interpolation
}
}
friend struct OsdPatch;
friend class Mesh;
};
/* ccl::Patch implementation that uses OpenSubdiv for eval */
struct OsdPatch : Patch {
OsdData* osd_data;
OsdPatch(OsdData* data) : osd_data(data) {}
void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
{
const Far::PatchTable::PatchHandle* handle = osd_data->patch_map->FindPatch(patch_index, u, v);
assert(handle);
float p_weights[20], du_weights[20], dv_weights[20];
osd_data->patch_table->EvaluateBasis(*handle, u, v, p_weights, du_weights, dv_weights);
Far::ConstIndexArray cv = osd_data->patch_table->GetPatchVertices(*handle);
float3 du, dv;
if(P) *P = make_float3(0.0f, 0.0f, 0.0f);
du = make_float3(0.0f, 0.0f, 0.0f);
dv = make_float3(0.0f, 0.0f, 0.0f);
for(int i = 0; i < cv.size(); i++) {
float3 p = osd_data->verts[cv[i]].value;
if(P) *P += p * p_weights[i];
du += p * du_weights[i];
dv += p * dv_weights[i];
}
if(dPdu) *dPdu = du;
if(dPdv) *dPdv = dv;
if(N) *N = normalize(cross(du, dv));
}
BoundBox bound() { return BoundBox::empty; }
};
#endif
void Mesh::tessellate(DiagSplit *split)
{
#ifdef WITH_OPENSUBDIV
OsdData osd_data;
bool need_packed_patch_table = false;
if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
osd_data.build_from_mesh(this);
}
else
#endif
{
/* force linear subdivision if OpenSubdiv is unavailable to avoid
* falling into catmull-clark code paths by accident
*/
subdivision_type = SUBDIVISION_LINEAR;
/* force disable attribute subdivision for same reason as above */
foreach(Attribute& attr, subd_attributes.attributes) {
attr.flags &= ~ATTR_SUBDIVIDED;
}
}
int num_faces = subd_faces.size();
Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL);
@@ -36,98 +325,33 @@ void Mesh::tessellate(DiagSplit *split)
if(face.is_quad()) {
/* quad */
LinearQuadPatch patch;
float3 *hull = patch.hull;
float3 *normals = patch.normals;
patch.patch_index = face.ptex_offset;
patch.shader = face.shader;
for(int i = 0; i < 4; i++) {
hull[i] = verts[subd_face_corners[face.start_corner+i]];
}
if(face.smooth) {
for(int i = 0; i < 4; i++) {
normals[i] = vN[subd_face_corners[face.start_corner+i]];
}
}
else {
float3 N = face.normal(this);
for(int i = 0; i < 4; i++) {
normals[i] = N;
}
}
swap(hull[2], hull[3]);
swap(normals[2], normals[3]);
/* Quad faces need to be split at least once to line up with split ngons, we do this
* here in this manner because if we do it later edge factors may end up slightly off.
*/
QuadDice::SubPatch subpatch;
subpatch.patch = &patch;
subpatch.P00 = make_float2(0.0f, 0.0f);
subpatch.P10 = make_float2(0.5f, 0.0f);
subpatch.P01 = make_float2(0.0f, 0.5f);
subpatch.P11 = make_float2(0.5f, 0.5f);
split->split_quad(&patch, &subpatch);
LinearQuadPatch quad_patch;
#ifdef WITH_OPENSUBDIV
OsdPatch osd_patch(&osd_data);
subpatch.P00 = make_float2(0.5f, 0.0f);
subpatch.P10 = make_float2(1.0f, 0.0f);
subpatch.P01 = make_float2(0.5f, 0.5f);
subpatch.P11 = make_float2(1.0f, 0.5f);
split->split_quad(&patch, &subpatch);
if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
osd_patch.patch_index = face.ptex_offset;
subpatch.P00 = make_float2(0.0f, 0.5f);
subpatch.P10 = make_float2(0.5f, 0.5f);
subpatch.P01 = make_float2(0.0f, 1.0f);
subpatch.P11 = make_float2(0.5f, 1.0f);
split->split_quad(&patch, &subpatch);
subpatch.P00 = make_float2(0.5f, 0.5f);
subpatch.P10 = make_float2(1.0f, 0.5f);
subpatch.P01 = make_float2(0.5f, 1.0f);
subpatch.P11 = make_float2(1.0f, 1.0f);
split->split_quad(&patch, &subpatch);
}
else {
/* ngon */
float3 center_vert = make_float3(0.0f, 0.0f, 0.0f);
float3 center_normal = make_float3(0.0f, 0.0f, 0.0f);
float inv_num_corners = 1.0f/float(face.num_corners);
for(int corner = 0; corner < face.num_corners; corner++) {
center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
subpatch.patch = &osd_patch;
}
else
#endif
{
float3 *hull = quad_patch.hull;
float3 *normals = quad_patch.normals;
for(int corner = 0; corner < face.num_corners; corner++) {
LinearQuadPatch patch;
float3 *hull = patch.hull;
float3 *normals = patch.normals;
quad_patch.patch_index = face.ptex_offset;
patch.patch_index = face.ptex_offset + corner;
patch.shader = face.shader;
hull[0] = verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
hull[1] = verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
hull[2] = verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
hull[3] = center_vert;
hull[1] = (hull[1] + hull[0]) * 0.5;
hull[2] = (hull[2] + hull[0]) * 0.5;
for(int i = 0; i < 4; i++) {
hull[i] = verts[subd_face_corners[face.start_corner+i]];
}
if(face.smooth) {
normals[0] = vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
normals[1] = vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
normals[2] = vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
normals[3] = center_normal;
normals[1] = (normals[1] + normals[0]) * 0.5;
normals[2] = (normals[2] + normals[0]) * 0.5;
for(int i = 0; i < 4; i++) {
normals[i] = vN[subd_face_corners[face.start_corner+i]];
}
}
else {
float3 N = face.normal(this);
@@ -136,13 +360,123 @@ void Mesh::tessellate(DiagSplit *split)
}
}
split->split_quad(&patch);
swap(hull[2], hull[3]);
swap(normals[2], normals[3]);
subpatch.patch = &quad_patch;
}
subpatch.patch->shader = face.shader;
/* Quad faces need to be split at least once to line up with split ngons, we do this
* here in this manner because if we do it later edge factors may end up slightly off.
*/
subpatch.P00 = make_float2(0.0f, 0.0f);
subpatch.P10 = make_float2(0.5f, 0.0f);
subpatch.P01 = make_float2(0.0f, 0.5f);
subpatch.P11 = make_float2(0.5f, 0.5f);
split->split_quad(subpatch.patch, &subpatch);
subpatch.P00 = make_float2(0.5f, 0.0f);
subpatch.P10 = make_float2(1.0f, 0.0f);
subpatch.P01 = make_float2(0.5f, 0.5f);
subpatch.P11 = make_float2(1.0f, 0.5f);
split->split_quad(subpatch.patch, &subpatch);
subpatch.P00 = make_float2(0.0f, 0.5f);
subpatch.P10 = make_float2(0.5f, 0.5f);
subpatch.P01 = make_float2(0.0f, 1.0f);
subpatch.P11 = make_float2(0.5f, 1.0f);
split->split_quad(subpatch.patch, &subpatch);
subpatch.P00 = make_float2(0.5f, 0.5f);
subpatch.P10 = make_float2(1.0f, 0.5f);
subpatch.P01 = make_float2(0.5f, 1.0f);
subpatch.P11 = make_float2(1.0f, 1.0f);
split->split_quad(subpatch.patch, &subpatch);
}
else {
/* ngon */
#ifdef WITH_OPENSUBDIV
if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
OsdPatch patch(&osd_data);
patch.shader = face.shader;
for(int corner = 0; corner < face.num_corners; corner++) {
patch.patch_index = face.ptex_offset + corner;
split->split_quad(&patch);
}
}
else
#endif
{
float3 center_vert = make_float3(0.0f, 0.0f, 0.0f);
float3 center_normal = make_float3(0.0f, 0.0f, 0.0f);
float inv_num_corners = 1.0f/float(face.num_corners);
for(int corner = 0; corner < face.num_corners; corner++) {
center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
}
for(int corner = 0; corner < face.num_corners; corner++) {
LinearQuadPatch patch;
float3 *hull = patch.hull;
float3 *normals = patch.normals;
patch.patch_index = face.ptex_offset + corner;
patch.shader = face.shader;
hull[0] = verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
hull[1] = verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
hull[2] = verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
hull[3] = center_vert;
hull[1] = (hull[1] + hull[0]) * 0.5;
hull[2] = (hull[2] + hull[0]) * 0.5;
if(face.smooth) {
normals[0] = vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
normals[1] = vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
normals[2] = vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
normals[3] = center_normal;
normals[1] = (normals[1] + normals[0]) * 0.5;
normals[2] = (normals[2] + normals[0]) * 0.5;
}
else {
float3 N = face.normal(this);
for(int i = 0; i < 4; i++) {
normals[i] = N;
}
}
split->split_quad(&patch);
}
}
}
}
/* interpolate center points for attributes */
foreach(Attribute& attr, subd_attributes.attributes) {
#ifdef WITH_OPENSUBDIV
if(subdivision_type == SUBDIVISION_CATMULL_CLARK && attr.flags & ATTR_SUBDIVIDED) {
if(attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
/* keep subdivision for corner attributes disabled for now */
attr.flags &= ~ATTR_SUBDIVIDED;
}
else {
osd_data.subdivide_attribute(attr);
need_packed_patch_table = true;
continue;
}
}
#endif
char* data = attr.data();
size_t stride = attr.data_sizeof();
int ngons = 0;
@@ -218,6 +552,15 @@ void Mesh::tessellate(DiagSplit *split)
default: break;
}
}
#ifdef WITH_OPENSUBDIV
/* pack patch tables */
if(need_packed_patch_table) {
delete patch_table;
patch_table = new PackedPatchTable;
patch_table->pack(osd_data.patch_table);
}
#endif
}
CCL_NAMESPACE_END

View File

@@ -29,6 +29,8 @@
#include "util_progress.h"
#include "util_vector.h"
#include "subd_patch_table.h"
CCL_NAMESPACE_BEGIN
/* Object */
@@ -55,9 +57,9 @@ Object::Object()
particle_system = NULL;
particle_index = 0;
bounds = BoundBox::empty;
motion.pre = transform_identity();
motion.mid = transform_identity();
motion.post = transform_identity();
motion.pre = transform_empty();
motion.mid = transform_empty();
motion.post = transform_empty();
use_motion = false;
}
@@ -70,19 +72,28 @@ void Object::compute_bounds(bool motion_blur)
BoundBox mbounds = mesh->bounds;
if(motion_blur && use_motion) {
DecompMotionTransform decomp;
transform_motion_decompose(&decomp, &motion, &tfm);
if(motion.pre == transform_empty() ||
motion.post == transform_empty()) {
/* Hide objects that have no valid previous or next transform, for
* example particle that stop existing. TODO: add support for this
* case in the kernel so we don't get render artifacts. */
bounds = BoundBox::empty;
}
else {
DecompMotionTransform decomp;
transform_motion_decompose(&decomp, &motion, &tfm);
bounds = BoundBox::empty;
bounds = BoundBox::empty;
/* todo: this is really terrible. according to pbrt there is a better
* way to find this iteratively, but did not find implementation yet
* or try to implement myself */
for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
Transform ttfm;
/* todo: this is really terrible. according to pbrt there is a better
* way to find this iteratively, but did not find implementation yet
* or try to implement myself */
for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
Transform ttfm;
transform_motion_interpolate(&ttfm, &decomp, t);
bounds.grow(mbounds.transformed(&ttfm));
transform_motion_interpolate(&ttfm, &decomp, t);
bounds.grow(mbounds.transformed(&ttfm));
}
}
}
else {
@@ -228,7 +239,7 @@ vector<float> Object::motion_times()
bool Object::is_traceable()
{
/* Mesh itself can be empty,can skip all such objects. */
if (bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
if (!bounds.valid() || bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
return false;
}
/* TODO(sergey): Check for mesh vertices/curves. visibility flags. */
@@ -337,6 +348,15 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
Transform mtfm_pre = ob->motion.pre;
Transform mtfm_post = ob->motion.post;
/* In case of missing motion information for previous/next frame,
* assume there is no motion. */
if(!ob->use_motion || mtfm_pre == transform_empty()) {
mtfm_pre = ob->tfm;
}
if(!ob->use_motion || mtfm_post == transform_empty()) {
mtfm_post = ob->tfm;
}
if(!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
mtfm_pre = mtfm_pre * itfm;
mtfm_post = mtfm_post * itfm;
@@ -589,6 +609,37 @@ void ObjectManager::device_update_flags(Device *device,
device->tex_alloc("__object_flag", dscene->object_flag);
}
void ObjectManager::device_update_patch_map_offsets(Device *device, DeviceScene *dscene, Scene *scene)
{
uint4* objects = (uint4*)dscene->objects.get_data();
bool update = false;
int object_index = 0;
foreach(Object *object, scene->objects) {
int offset = object_index*OBJECT_SIZE + 11;
Mesh* mesh = object->mesh;
if(mesh->patch_table) {
uint patch_map_offset = 2*(mesh->patch_table_offset + mesh->patch_table->total_size() -
mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - mesh->patch_offset;
if(objects[offset].x != patch_map_offset) {
objects[offset].x = patch_map_offset;
update = true;
}
}
object_index++;
}
if(update) {
device->tex_free(dscene->objects);
device->tex_alloc("__objects", dscene->objects);
}
}
void ObjectManager::device_free(Device *device, DeviceScene *dscene)
{
device->tex_free(dscene->objects);
@@ -638,7 +689,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
* Could be solved by moving reference counter to Mesh.
*/
if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) &&
object->mesh->displacement_method == Mesh::DISPLACE_BUMP)
!object->mesh->has_true_displacement())
{
if(!(motion_blur && object->use_motion)) {
if(!object->mesh->transform_applied) {

View File

@@ -97,6 +97,8 @@ public:
Scene *scene,
Progress& progress,
bool bounds_valid = true);
void device_update_patch_map_offsets(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);

View File

@@ -549,7 +549,7 @@ string OSLCompiler::id(ShaderNode *node)
{
/* assign layer unique name based on pointer address + bump mode */
stringstream stream;
stream << "node_" << node->name << "_" << node;
stream << "node_" << node->type->name << "_" << node;
return stream.str();
}

View File

@@ -150,6 +150,12 @@ NODE_DEFINE(Shader)
volume_interpolation_method_enum.insert("cubic", VOLUME_INTERPOLATION_CUBIC);
SOCKET_ENUM(volume_interpolation_method, "Volume Interpolation Method", volume_interpolation_method_enum, VOLUME_INTERPOLATION_LINEAR);
static NodeEnum displacement_method_enum;
displacement_method_enum.insert("bump", DISPLACE_BUMP);
displacement_method_enum.insert("true", DISPLACE_TRUE);
displacement_method_enum.insert("both", DISPLACE_BOTH);
SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
return type;
}
@@ -173,6 +179,8 @@ Shader::Shader()
has_object_dependency = false;
has_integrator_dependency = false;
displacement_method = DISPLACE_BUMP;
id = -1;
used = false;
@@ -310,7 +318,7 @@ int ShaderManager::get_shader_id(Shader *shader, Mesh *mesh, bool smooth)
int id = shader->id*2;
/* index depends bump since this setting is not in the shader */
if(mesh && mesh->displacement_method != Mesh::DISPLACE_TRUE)
if(mesh && shader->displacement_method != DISPLACE_TRUE)
id += 1;
/* smooth flag */
if(smooth)

View File

@@ -66,6 +66,14 @@ enum VolumeInterpolation {
VOLUME_NUM_INTERPOLATION,
};
enum DisplacementMethod {
DISPLACE_BUMP = 0,
DISPLACE_TRUE = 1,
DISPLACE_BOTH = 2,
DISPLACE_NUM_METHODS,
};
/* Shader describing the appearance of a Mesh, Light or Background.
*
* While there is only a single shader graph, it has three outputs: surface,
@@ -110,6 +118,9 @@ public:
bool has_object_dependency;
bool has_integrator_dependency;
/* displacement */
DisplacementMethod displacement_method;
/* requested mesh attributes */
AttributeRequestSet attributes;

View File

@@ -16,6 +16,7 @@ set(SRC
subd_dice.cpp
subd_patch.cpp
subd_split.cpp
subd_patch_table.cpp
)
set(SRC_HEADERS
@@ -24,10 +25,6 @@ set(SRC_HEADERS
subd_split.h
)
if(WITH_CYCLES_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})

View File

@@ -0,0 +1,297 @@
/*
* Based on code from OpenSubdiv released under this license:
*
* Copyright 2014 DreamWorks Animation LLC.
*
* Licensed under the Apache License, Version 2.0 (the "Apache License")
* with the following modification; you may not use this file except in
* compliance with the Apache License and the following modification to it:
* Section 6. Trademarks. is deleted and replaced with:
*
* 6. Trademarks. This License does not grant permission to use the trade
* names, trademarks, service marks, or product names of the Licensor
* and its affiliates, except as required to comply with Section 4(c) of
* the License and to reproduce the content of the NOTICE file.
*
* You may obtain a copy of the Apache License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Apache License with the above modification is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the Apache License for the specific
* language governing permissions and limitations under the Apache License.
*
*/
#include "subd_patch_table.h"
#include "kernel_types.h"
#include "util_math.h"
#ifdef WITH_OPENSUBDIV
#include <opensubdiv/far/patchTable.h>
#endif
CCL_NAMESPACE_BEGIN
#ifdef WITH_OPENSUBDIV
using namespace OpenSubdiv;
/* functions for building patch maps */
struct PatchMapQuadNode {
/* sets all the children to point to the patch of index */
void set_child(int index)
{
for (int i = 0; i < 4; i++) {
children[i] = index | PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF;
}
}
/* sets the child in quadrant to point to the node or patch of the given index */
void set_child(unsigned char quadrant, int index, bool is_leaf=true)
{
assert(quadrant < 4);
children[quadrant] = index | PATCH_MAP_NODE_IS_SET | (is_leaf ? PATCH_MAP_NODE_IS_LEAF : 0);
}
uint children[4];
};
template<class T>
static int resolve_quadrant(T& median, T& u, T& v)
{
int quadrant = -1;
if(u < median) {
if(v < median) {
quadrant = 0;
}
else {
quadrant = 1;
v -= median;
}
}
else {
if(v < median) {
quadrant = 3;
}
else {
quadrant = 2;
v -= median;
}
u -= median;
}
return quadrant;
}
static void build_patch_map(PackedPatchTable& table, OpenSubdiv::Far::PatchTable* patch_table, int offset)
{
int num_faces = 0;
for(int array = 0; array < table.num_arrays; array++) {
Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
for(int j = 0; j < patch_table->GetNumPatches(array); j++) {
num_faces = max(num_faces, (int)params[j].GetFaceId());
}
}
num_faces++;
vector<PatchMapQuadNode> quadtree;
quadtree.reserve(num_faces + table.num_patches);
quadtree.resize(num_faces);
/* adjust offsets to make indices relative to the table */
int handle_index = -(table.num_patches * PATCH_HANDLE_SIZE);
offset += table.total_size();
/* populate the quadtree from the FarPatchArrays sub-patches */
for(int array = 0; array < table.num_arrays; array++) {
Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
for(int i = 0; i < patch_table->GetNumPatches(array); i++, handle_index += PATCH_HANDLE_SIZE) {
const Far::PatchParam& param = params[i];
unsigned short depth = param.GetDepth();
PatchMapQuadNode* node = &quadtree[params[i].GetFaceId()];
if(depth == (param.NonQuadRoot() ? 1 : 0)) {
/* special case : regular BSpline face w/ no sub-patches */
node->set_child(handle_index + offset);
continue;
}
int u = param.GetU();
int v = param.GetV();
int pdepth = param.NonQuadRoot() ? depth-2 : depth-1;
int half = 1 << pdepth;
for(int j = 0; j < depth; j++) {
int delta = half >> 1;
int quadrant = resolve_quadrant(half, u, v);
assert(quadrant >= 0);
half = delta;
if(j == pdepth) {
/* we have reached the depth of the sub-patch : add a leaf */
assert(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET));
node->set_child(quadrant, handle_index + offset, true);
break;
}
else {
/* travel down the child node of the corresponding quadrant */
if(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET)) {
/* create a new branch in the quadrant */
quadtree.push_back(PatchMapQuadNode());
int idx = (int)quadtree.size() - 1;
node->set_child(quadrant, idx*4 + offset, false);
node = &quadtree[idx];
}
else {
/* travel down an existing branch */
uint idx = node->children[quadrant] & PATCH_MAP_NODE_INDEX_MASK;
node = &(quadtree[(idx - offset)/4]);
}
}
}
}
}
/* copy into table */
assert(table.table.size() == table.total_size());
uint map_offset = table.total_size();
table.num_nodes = quadtree.size() * 4;
table.table.resize(table.total_size());
uint* data = &table.table[map_offset];
for(int i = 0; i < quadtree.size(); i++) {
for(int j = 0; j < 4; j++) {
assert(quadtree[i].children[j] & PATCH_MAP_NODE_IS_SET);
*(data++) = quadtree[i].children[j];
}
}
}
#endif
/* packed patch table functions */
size_t PackedPatchTable::total_size()
{
return num_arrays * PATCH_ARRAY_SIZE +
num_indices +
num_patches * (PATCH_PARAM_SIZE + PATCH_HANDLE_SIZE) +
num_nodes * PATCH_NODE_SIZE;
}
void PackedPatchTable::pack(Far::PatchTable* patch_table, int offset)
{
num_arrays = 0;
num_patches = 0;
num_indices = 0;
num_nodes = 0;
#ifdef WITH_OPENSUBDIV
num_arrays = patch_table->GetNumPatchArrays();
for(int i = 0; i < num_arrays; i++) {
int patches = patch_table->GetNumPatches(i);
int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
num_patches += patches;
num_indices += patches * num_control;
}
table.resize(total_size());
uint* data = &table[0];
uint* array = data;
uint* index = array + num_arrays * PATCH_ARRAY_SIZE;
uint* param = index + num_indices;
uint* handle = param + num_patches * PATCH_PARAM_SIZE;
uint current_param = 0;
for(int i = 0; i < num_arrays; i++) {
*(array++) = patch_table->GetPatchArrayDescriptor(i).GetType();
*(array++) = patch_table->GetNumPatches(i);
*(array++) = (index - data) + offset;
*(array++) = (param - data) + offset;
Far::ConstIndexArray indices = patch_table->GetPatchArrayVertices(i);
for(int j = 0; j < indices.size(); j++) {
*(index++) = indices[j];
}
const Far::PatchParamTable& param_table = patch_table->GetPatchParamTable();
int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
int patches = patch_table->GetNumPatches(i);
for(int j = 0; j < patches; j++, current_param++) {
*(param++) = param_table[current_param].field0;
*(param++) = param_table[current_param].field1;
*(handle++) = (array - data) - PATCH_ARRAY_SIZE + offset;
*(handle++) = (param - data) - PATCH_PARAM_SIZE + offset;
*(handle++) = j * num_control;
}
}
build_patch_map(*this, patch_table, offset);
#else
(void)patch_table;
(void)offset;
#endif
}
void PackedPatchTable::copy_adjusting_offsets(uint* dest, int doffset)
{
uint* src = &table[0];
/* arrays */
for(int i = 0; i < num_arrays; i++) {
*(dest++) = *(src++);
*(dest++) = *(src++);
*(dest++) = *(src++) + doffset;
*(dest++) = *(src++) + doffset;
}
/* indices */
for(int i = 0; i < num_indices; i++) {
*(dest++) = *(src++);
}
/* params */
for(int i = 0; i < num_patches; i++) {
*(dest++) = *(src++);
*(dest++) = *(src++);
}
/* handles */
for(int i = 0; i < num_patches; i++) {
*(dest++) = *(src++) + doffset;
*(dest++) = *(src++) + doffset;
*(dest++) = *(src++);
}
/* nodes */
for(int i = 0; i < num_nodes; i++) {
*(dest++) = *(src++) + doffset;
}
}
CCL_NAMESPACE_END

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2011-2016 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SUBD_PATCH_TABLE_H__
#define __SUBD_PATCH_TABLE_H__
#include "util_types.h"
#include "util_vector.h"
#ifdef WITH_OPENSUBDIV
#ifdef _MSC_VER
# include "iso646.h"
#endif
#include <opensubdiv/far/patchTable.h>
#endif
CCL_NAMESPACE_BEGIN
#ifdef WITH_OPENSUBDIV
using namespace OpenSubdiv;
#else
/* forward declare for when OpenSubdiv is unavailable */
namespace Far { struct PatchTable; }
#endif
#define PATCH_ARRAY_SIZE 4
#define PATCH_PARAM_SIZE 2
#define PATCH_HANDLE_SIZE 3
#define PATCH_NODE_SIZE 1
struct PackedPatchTable {
vector<uint> table;
size_t num_arrays;
size_t num_indices;
size_t num_patches;
size_t num_nodes;
/* calculated size from num_* members */
size_t total_size();
void pack(Far::PatchTable* patch_table, int offset = 0);
void copy_adjusting_offsets(uint* dest, int doffset);
};
CCL_NAMESPACE_END
#endif /* __SUBD_PATCH_TABLE_H__ */

View File

@@ -323,6 +323,15 @@ ccl_device_inline Transform transform_clear_scale(const Transform& tfm)
return ntfm;
}
ccl_device_inline Transform transform_empty()
{
return make_transform(
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0);
}
#endif
/* Motion Transform */

View File

@@ -222,6 +222,11 @@ public:
return datasize_;
}
T* data()
{
return data_;
}
const T* data() const
{
return data_;

View File

@@ -914,14 +914,25 @@ class QuantitativeInvisibilityRangeUP1D(UnaryPredicate1D):
return self.qi_start <= qi <= self.qi_end
def getQualifiedObjectName(ob):
if ob.library is not None:
return ob.library.filepath + '/' + ob.name
return ob.name
class ObjectNamesUP1D(UnaryPredicate1D):
def __init__(self, names, negative):
UnaryPredicate1D.__init__(self)
self.names = names
self.negative = negative
def getViewShapeName(self, vs):
if vs.library_path is not None:
return vs.library_path + '/' + vs.name
return vs.name
def __call__(self, viewEdge):
found = viewEdge.viewshape.name in self.names
found = self.getViewShapeName(viewEdge.viewshape) in self.names
if self.negative:
return not found
return found
@@ -1256,7 +1267,7 @@ def process(layer_name, lineset_name):
# prepare selection criteria by group of objects
if lineset.select_by_group:
if lineset.group is not None:
names = {ob.name: True for ob in lineset.group.objects}
names = {getQualifiedObjectName(ob): True for ob in lineset.group.objects}
upred = ObjectNamesUP1D(names, lineset.group_negation == 'EXCLUSIVE')
selection_criteria.append(upred)
# prepare selection criteria by image border

View File

@@ -158,6 +158,13 @@ def write_sysinfo(filepath):
else:
output.write("Blender was built without OpenVDB support\n")
alembic = bpy.app.alembic
output.write("Alembic: ")
if alembic.supported:
output.write("%s\n" % alembic.version_string)
else:
output.write("Blender was built without Alembic support\n")
if not bpy.app.build_options.sdl:
output.write("SDL: Blender was built without SDL support\n")

View File

@@ -880,6 +880,19 @@ class ConstraintButtonsPanel:
layout.operator("clip.constraint_to_fcurve")
def TRANSFORM_CACHE(self, context, layout, con):
layout.label(text="Cache File Properties:")
box = layout.box()
box.template_cache_file(con, "cache_file")
cache_file = con.cache_file
layout.label(text="Constraint Properties:")
box = layout.box()
if cache_file is not None:
box.prop_search(con, "object_path", cache_file, "object_paths")
def SCRIPT(self, context, layout, con):
layout.label("Blender 2.6 doesn't support python constraints yet")

View File

@@ -181,6 +181,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
layout.prop(md, "cache_format")
layout.prop(md, "filepath")
if md.cache_format == 'ABC':
layout.prop(md, "sub_object")
layout.label(text="Evaluation:")
layout.prop(md, "factor", slider=True)
layout.prop(md, "deform_mode")
@@ -215,6 +218,22 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
row = split.row()
row.prop(md, "flip_axis")
def MESH_SEQUENCE_CACHE(self, layout, ob, md):
layout.label(text="Cache File Properties:")
box = layout.box()
box.template_cache_file(md, "cache_file")
cache_file = md.cache_file
layout.label(text="Modifier Properties:")
box = layout.box()
if cache_file is not None:
box.prop_search(md, "object_path", cache_file, "object_paths")
if ob.type == 'MESH':
box.row().prop(md, "read_data")
def CAST(self, layout, ob, md):
split = layout.split(percentage=0.25)

View File

@@ -80,6 +80,7 @@ class GreasePencilDrawingToolsPanel:
sub = col.column(align=True)
sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing")
sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing")
sub.prop(context.tool_settings, "use_gpencil_draw_onback", text="Draw on Back")
col.separator()
col.separator()
@@ -190,11 +191,11 @@ class GreasePencilStrokeEditPanel:
col = layout.column(align=True)
col.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
col.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
col.operator("gpencil.stroke_flip", text="Flip direction")
col.operator("gpencil.stroke_flip", text="Flip Direction")
gpd = context.gpencil_data
if gpd:
col.prop(gpd, "show_stroke_direction", text="Show drawing direction")
col.prop(gpd, "show_stroke_direction", text="Show Directions")
class GreasePencilBrushPanel:
@@ -326,7 +327,7 @@ class GreasePencilStrokeSculptPanel:
class GreasePencilBrushCurvesPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
bl_label = "Grease Pencil Curves"
bl_label = "Brush Curves"
bl_category = "Grease Pencil"
bl_region_type = 'TOOLS'
bl_options = {'DEFAULT_CLOSED'}
@@ -821,33 +822,32 @@ class GreasePencilDataPanel:
def draw_layer(self, context, layout, gpl):
row = layout.row(align=True)
row.prop(gpl, "opacity", text="Opacity", slider=True)
# layer settings
# Layer options
split = layout.split(percentage=0.5)
split.active = not gpl.lock
# Options
split.prop(gpl, "show_x_ray")
split.prop(gpl, "show_points")
# Offsets + Parenting (where available)
split = layout.split(percentage=0.5)
col = split.column(align=True)
col.active = not gpl.lock
col.prop(gpl, "show_x_ray")
split.active = not gpl.lock
col.label("Tint")
col.prop(gpl, "tint_color", text="")
col.prop(gpl, "tint_factor", text="Factor", slider=True)
# Offsets - Color Tint
col = split.column()
subcol = col.column(align=True)
subcol.label("Tint")
subcol.prop(gpl, "tint_color", text="")
subcol.prop(gpl, "tint_factor", text="Factor", slider=True)
col = split.column(align=True)
col.active = not gpl.lock
col.prop(gpl, "show_points", text="Points")
# Full-Row - Parent
'''
row = layout.row()
if context.area.type == 'VIEW_3D' and not gpl.lock:
row.enabled = True
else:
row.enabled = False
'''
# Offsets - Thickness
row = col.row(align=True)
row.prop(gpl, "line_change", text="Thickness Change", slider=True)
row.operator("gpencil.stroke_apply_thickness", icon='STYLUS_PRESSURE', text="")
# col = row.column()
# Parenting
if context.space_data.type == 'VIEW_3D':
col = split.column(align=True)
col.label(text="Parent:")
col.prop(gpl, "parent", text="")
@@ -857,11 +857,7 @@ class GreasePencilDataPanel:
if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
sub.prop_search(gpl, "parent_bone", parent.data, "bones", text="")
# Full-Row - Thickness
row = layout.row(align=True)
row.active = not gpl.lock
row.prop(gpl, "line_change", text="Thickness change", slider=True)
row.operator("gpencil.stroke_apply_thickness", icon='STYLUS_PRESSURE', text="")
layout.separator()
# Full-Row - Frame Locking (and Delete Frame)
row = layout.row(align=True)
@@ -875,6 +871,8 @@ class GreasePencilDataPanel:
row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED')
row.operator("gpencil.active_frame_delete", text="", icon='X')
layout.separator()
# Onion skinning
col = layout.column(align=True)
col.active = not gpl.lock
@@ -925,7 +923,7 @@ class GreasePencilPaletteColorPanel:
row.operator_menu_enum("gpencil.palette_change", "palette", text="", icon='COLOR')
row.prop(palette, "name", text="")
row.operator("gpencil.palette_add", icon='ZOOMIN', text="")
row.operator("gpencil.palette_remove", icon='ZOOMOUT', text="")
row.operator("gpencil.palette_remove", icon='X', text="")
# Palette colors
row = layout.row()

View File

@@ -716,6 +716,8 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
col.prop(boids, "land_personal_space")
col.prop(boids, "land_stick_force")
layout.prop(part, "collision_group")
split = layout.split()
col = split.column(align=True)

View File

@@ -158,6 +158,8 @@ class INFO_MT_file_import(Menu):
def draw(self, context):
if bpy.app.build_options.collada:
self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)")
if bpy.app.build_options.alembic:
self.layout.operator("wm.alembic_import", text="Alembic (.abc)")
class INFO_MT_file_export(Menu):
@@ -167,6 +169,8 @@ class INFO_MT_file_export(Menu):
def draw(self, context):
if bpy.app.build_options.collada:
self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)")
if bpy.app.build_options.alembic:
self.layout.operator("wm.alembic_export", text="Alembic (.abc)")
class INFO_MT_file_external_data(Menu):

View File

@@ -31,6 +31,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_boid_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cachefile_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cloth_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_color_types.h
@@ -153,3 +154,6 @@ if(WITH_FREESTYLE)
add_subdirectory(freestyle)
endif()
if(WITH_ALEMBIC)
add_subdirectory(alembic)
endif()

View File

@@ -0,0 +1,110 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __ABC_ALEMBIC_H__
#define __ABC_ALEMBIC_H__
#ifdef __cplusplus
extern "C" {
#endif
struct bContext;
struct DerivedMesh;
struct ListBase;
struct Object;
struct Scene;
typedef struct AbcArchiveHandle AbcArchiveHandle;
enum {
ABC_ARCHIVE_OGAWA = 0,
ABC_ARCHIVE_HDF5 = 1,
};
int ABC_get_version(void);
struct AlembicExportParams {
double frame_start;
double frame_end;
double frame_step_xform;
double frame_step_shape;
double shutter_open;
double shutter_close;
/* bools */
unsigned int selected_only : 1;
unsigned int uvs : 1;
unsigned int normals : 1;
unsigned int vcolors : 1;
unsigned int apply_subdiv : 1;
unsigned int flatten_hierarchy : 1;
unsigned int visible_layers_only : 1;
unsigned int renderable_only : 1;
unsigned int face_sets : 1;
unsigned int use_subdiv_schema : 1;
unsigned int packuv : 1;
unsigned int compression_type : 1;
float global_scale;
};
void ABC_export(
struct Scene *scene,
struct bContext *C,
const char *filepath,
const struct AlembicExportParams *params);
void ABC_import(struct bContext *C,
const char *filepath,
float scale,
bool is_sequence,
bool set_frame_range,
int sequence_len,
int offset,
bool validate_meshes);
AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths);
void ABC_free_handle(AbcArchiveHandle *handle);
void ABC_get_transform(AbcArchiveHandle *handle,
struct Object *ob,
const char *object_path,
float r_mat[4][4],
float time,
float scale);
struct DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle,
struct Object *ob,
struct DerivedMesh *dm,
const char *object_path,
const float time,
const char **err_str,
int flags);
#ifdef __cplusplus
}
#endif
#endif /* __ABC_ALEMBIC_H__ */

View File

@@ -0,0 +1,81 @@
# ***** 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.
#
# The Original Code is Copyright (C) 2006, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Kevin Dietrich.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
../blenkernel
../blenlib
../blenloader
../editors/include
../makesdna
../makesrna
../windowmanager
../../../intern/guardedalloc
)
set(INC_SYS
${ALEMBIC_INCLUDE_DIRS}
${HDF5_INCLUDE_DIRS}
${OPENEXR_INCLUDE_DIRS}
)
if(APPLE)
list(APPEND INC_SYS
${BOOST_INCLUDE_DIR}
)
endif()
set(SRC
intern/abc_camera.cc
intern/abc_customdata.cc
intern/abc_curves.cc
intern/abc_exporter.cc
intern/abc_hair.cc
intern/abc_mesh.cc
intern/abc_nurbs.cc
intern/abc_object.cc
intern/abc_points.cc
intern/abc_transform.cc
intern/abc_util.cc
intern/alembic_capi.cc
ABC_alembic.h
intern/abc_camera.h
intern/abc_customdata.h
intern/abc_curves.h
intern/abc_exporter.h
intern/abc_hair.h
intern/abc_mesh.h
intern/abc_nurbs.h
intern/abc_object.h
intern/abc_points.h
intern/abc_transform.h
intern/abc_util.h
)
if(WITH_ALEMBIC_HDF5)
add_definitions(-DWITH_ALEMBIC_HDF5)
endif()
blender_add_lib(bf_alembic "${SRC}" "${INC}" "${INC_SYS}")

View File

@@ -0,0 +1,162 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "abc_camera.h"
#include "abc_transform.h"
#include "abc_util.h"
extern "C" {
#include "DNA_camera_types.h"
#include "DNA_object_types.h"
#include "BKE_camera.h"
#include "BKE_object.h"
#include "BLI_math.h"
#include "BLI_string.h"
}
using Alembic::AbcGeom::ICamera;
using Alembic::AbcGeom::ICompoundProperty;
using Alembic::AbcGeom::IFloatProperty;
using Alembic::AbcGeom::ISampleSelector;
using Alembic::AbcGeom::OCamera;
using Alembic::AbcGeom::OFloatProperty;
using Alembic::AbcGeom::CameraSample;
using Alembic::AbcGeom::kWrapExisting;
/* ************************************************************************** */
AbcCameraWriter::AbcCameraWriter(Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
{
OCamera camera(parent->alembicXform(), m_name, m_time_sampling);
m_camera_schema = camera.getSchema();
m_custom_data_container = m_camera_schema.getUserProperties();
m_stereo_distance = OFloatProperty(m_custom_data_container, "stereoDistance", m_time_sampling);
m_eye_separation = OFloatProperty(m_custom_data_container, "eyeSeparation", m_time_sampling);
}
void AbcCameraWriter::do_write()
{
Camera *cam = static_cast<Camera *>(m_object->data);
m_stereo_distance.set(cam->stereo.convergence_distance);
m_eye_separation.set(cam->stereo.interocular_distance);
const double apperture_x = cam->sensor_x / 10.0;
const double apperture_y = cam->sensor_y / 10.0;
const double film_aspect = apperture_x / apperture_y;
m_camera_sample.setFocalLength(cam->lens);
m_camera_sample.setHorizontalAperture(apperture_x);
m_camera_sample.setVerticalAperture(apperture_y);
m_camera_sample.setHorizontalFilmOffset(apperture_x * cam->shiftx);
m_camera_sample.setVerticalFilmOffset(apperture_y * cam->shifty * film_aspect);
m_camera_sample.setNearClippingPlane(cam->clipsta);
m_camera_sample.setFarClippingPlane(cam->clipend);
if (cam->dof_ob) {
Imath::V3f v(m_object->loc[0] - cam->dof_ob->loc[0],
m_object->loc[1] - cam->dof_ob->loc[1],
m_object->loc[2] - cam->dof_ob->loc[2]);
m_camera_sample.setFocusDistance(v.length());
}
else {
m_camera_sample.setFocusDistance(cam->gpu_dof.focus_distance);
}
/* Blender camera does not have an fstop param, so try to find a custom prop
* instead. */
m_camera_sample.setFStop(cam->gpu_dof.fstop);
m_camera_sample.setLensSqueezeRatio(1.0);
m_camera_schema.set(m_camera_sample);
}
/* ************************************************************************** */
AbcCameraReader::AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
ICamera abc_cam(m_iobject, kWrapExisting);
m_schema = abc_cam.getSchema();
get_min_max_time(m_schema, m_min_time, m_max_time);
}
bool AbcCameraReader::valid() const
{
return m_schema.valid();
}
void AbcCameraReader::readObjectData(Main *bmain, float time)
{
Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, "abc_camera"));
ISampleSelector sample_sel(time);
CameraSample cam_sample;
m_schema.get(cam_sample, sample_sel);
ICompoundProperty customDataContainer = m_schema.getUserProperties();
if (customDataContainer.valid() &&
customDataContainer.getPropertyHeader("stereoDistance") &&
customDataContainer.getPropertyHeader("eyeSeparation"))
{
IFloatProperty convergence_plane(customDataContainer, "stereoDistance");
IFloatProperty eye_separation(customDataContainer, "eyeSeparation");
bcam->stereo.interocular_distance = eye_separation.getValue(sample_sel);
bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel);
}
const float lens = cam_sample.getFocalLength();
const float apperture_x = cam_sample.getHorizontalAperture();
const float apperture_y = cam_sample.getVerticalAperture();
const float h_film_offset = cam_sample.getHorizontalFilmOffset();
const float v_film_offset = cam_sample.getVerticalFilmOffset();
const float film_aspect = apperture_x / apperture_y;
bcam->lens = lens;
bcam->sensor_x = apperture_x * 10;
bcam->sensor_y = apperture_y * 10;
bcam->shiftx = h_film_offset / apperture_x;
bcam->shifty = v_film_offset / apperture_y / film_aspect;
bcam->clipsta = max_ff(0.1f, cam_sample.getNearClippingPlane());
bcam->clipend = cam_sample.getFarClippingPlane();
bcam->gpu_dof.focus_distance = cam_sample.getFocusDistance();
bcam->gpu_dof.fstop = cam_sample.getFStop();
BLI_strncpy(bcam->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1);
m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str());
m_object->data = bcam;
}

View File

@@ -0,0 +1,61 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __ABC_CAMERA_H__
#define __ABC_CAMERA_H__
#include "abc_object.h"
/* ************************************************************************** */
class AbcCameraWriter : public AbcObjectWriter {
Alembic::AbcGeom::OCameraSchema m_camera_schema;
Alembic::AbcGeom::CameraSample m_camera_sample;
Alembic::AbcGeom::OCompoundProperty m_custom_data_container;
Alembic::AbcGeom::OFloatProperty m_stereo_distance;
Alembic::AbcGeom::OFloatProperty m_eye_separation;
public:
AbcCameraWriter(Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
private:
virtual void do_write();
};
/* ************************************************************************** */
class AbcCameraReader : public AbcObjectReader {
Alembic::AbcGeom::ICameraSchema m_schema;
public:
AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
void readObjectData(Main *bmain, float time);
};
#endif /* __ABC_CAMERA_H__ */

View File

@@ -0,0 +1,355 @@
/*
* ***** 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.
*
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
* All rights reserved.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
#include "abc_curves.h"
#include <cstdio>
#include "abc_transform.h"
#include "abc_util.h"
extern "C" {
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "BLI_listbase.h"
#include "BKE_curve.h"
#include "BKE_object.h"
#include "ED_curve.h"
}
using Alembic::Abc::IInt32ArrayProperty;
using Alembic::Abc::Int32ArraySamplePtr;
using Alembic::Abc::FloatArraySamplePtr;
using Alembic::Abc::P3fArraySamplePtr;
using Alembic::Abc::UcharArraySamplePtr;
using Alembic::AbcGeom::ICurves;
using Alembic::AbcGeom::ICurvesSchema;
using Alembic::AbcGeom::IFloatGeomParam;
using Alembic::AbcGeom::ISampleSelector;
using Alembic::AbcGeom::kWrapExisting;
using Alembic::AbcGeom::CurvePeriodicity;
using Alembic::AbcGeom::OCurves;
using Alembic::AbcGeom::OCurvesSchema;
using Alembic::AbcGeom::ON3fGeomParam;
using Alembic::AbcGeom::OV2fGeomParam;
/* ************************************************************************** */
AbcCurveWriter::AbcCurveWriter(Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
{
OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
m_schema = curves.getSchema();
}
void AbcCurveWriter::do_write()
{
Curve *curve = static_cast<Curve *>(m_object->data);
std::vector<Imath::V3f> verts;
std::vector<int32_t> vert_counts;
std::vector<float> widths;
std::vector<float> weights;
std::vector<float> knots;
std::vector<uint8_t> orders;
Imath::V3f temp_vert;
Alembic::AbcGeom::BasisType curve_basis;
Alembic::AbcGeom::CurveType curve_type;
Alembic::AbcGeom::CurvePeriodicity periodicity;
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
for (; nurbs; nurbs = nurbs->next) {
if (nurbs->bp) {
curve_basis = Alembic::AbcGeom::kNoBasis;
curve_type = Alembic::AbcGeom::kLinear;
const int totpoint = nurbs->pntsu * nurbs->pntsv;
const BPoint *point = nurbs->bp;
for (int i = 0; i < totpoint; ++i, ++point) {
copy_zup_yup(temp_vert.getValue(), point->vec);
verts.push_back(temp_vert);
weights.push_back(point->vec[3]);
widths.push_back(point->radius);
}
}
else if (nurbs->bezt) {
curve_basis = Alembic::AbcGeom::kBezierBasis;
curve_type = Alembic::AbcGeom::kCubic;
const int totpoint = nurbs->pntsu;
const BezTriple *bezier = nurbs->bezt;
/* TODO(kevin): store info about handles, Alembic doesn't have this. */
for (int i = 0; i < totpoint; ++i, ++bezier) {
copy_zup_yup(temp_vert.getValue(), bezier->vec[1]);
verts.push_back(temp_vert);
widths.push_back(bezier->radius);
}
}
if ((nurbs->flagu & CU_NURB_ENDPOINT) != 0) {
periodicity = Alembic::AbcGeom::kNonPeriodic;
}
else if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) {
periodicity = Alembic::AbcGeom::kPeriodic;
/* Duplicate the start points to indicate that the curve is actually
* cyclic since other software need those.
*/
for (int i = 0; i < nurbs->orderu; ++i) {
verts.push_back(verts[i]);
}
}
if (nurbs->knotsu != NULL) {
const size_t num_knots = KNOTSU(nurbs);
/* Add an extra knot at the beggining and end of the array since most apps
* require/expect them. */
knots.resize(num_knots + 2);
for (int i = 0; i < num_knots; ++i) {
knots[i + 1] = nurbs->knotsu[i];
}
if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) {
knots[0] = nurbs->knotsu[0];
knots[num_knots - 1] = nurbs->knotsu[num_knots - 1];
}
else {
knots[0] = (2.0f * nurbs->knotsu[0] - nurbs->knotsu[1]);
knots[num_knots - 1] = (2.0f * nurbs->knotsu[num_knots - 1] - nurbs->knotsu[num_knots - 2]);
}
}
orders.push_back(nurbs->orderu + 1);
vert_counts.push_back(verts.size());
}
Alembic::AbcGeom::OFloatGeomParam::Sample width_sample;
width_sample.setVals(widths);
m_sample = OCurvesSchema::Sample(verts,
vert_counts,
curve_type,
periodicity,
width_sample,
OV2fGeomParam::Sample(), /* UVs */
ON3fGeomParam::Sample(), /* normals */
curve_basis,
weights,
orders,
knots);
m_sample.setSelfBounds(bounds());
m_schema.set(m_sample);
}
/* ************************************************************************** */
AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
ICurves abc_curves(object, kWrapExisting);
m_curves_schema = abc_curves.getSchema();
get_min_max_time(m_curves_schema, m_min_time, m_max_time);
}
bool AbcCurveReader::valid() const
{
return m_curves_schema.valid();
}
void AbcCurveReader::readObjectData(Main *bmain, float time)
{
Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVE);
cu->flag |= CU_DEFORM_FILL | CU_3D;
cu->actvert = CU_ACT_NONE;
m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str());
m_object->data = cu;
read_curve_sample(cu, m_curves_schema, time);
if (has_animations(m_curves_schema, m_settings)) {
addCacheModifier();
}
}
/* ************************************************************************** */
void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
{
const ISampleSelector sample_sel(time);
ICurvesSchema::Sample smp = schema.getValue(sample_sel);
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
const P3fArraySamplePtr positions = smp.getPositions();
const FloatArraySamplePtr weights = smp.getPositionWeights();
const FloatArraySamplePtr knots = smp.getKnots();
const CurvePeriodicity periodicity = smp.getWrap();
const UcharArraySamplePtr orders = smp.getOrders();
const IFloatGeomParam widths_param = schema.getWidthsParam();
FloatArraySamplePtr radiuses;
if (widths_param.valid()) {
IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
radiuses = wsample.getVals();
}
int knot_offset = 0;
size_t idx = 0;
for (size_t i = 0; i < num_vertices->size(); ++i) {
const int num_verts = (*num_vertices)[i];
Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
nu->resolu = cu->resolu;
nu->resolv = cu->resolv;
nu->pntsu = num_verts;
nu->pntsv = 1;
nu->flag |= CU_SMOOTH;
nu->orderu = num_verts;
if (smp.getType() == Alembic::AbcGeom::kCubic) {
nu->orderu = 3;
}
else if (orders && orders->size() > i) {
nu->orderu = static_cast<short>((*orders)[i] - 1);
}
if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
nu->flagu |= CU_NURB_ENDPOINT;
}
else if (periodicity == Alembic::AbcGeom::kPeriodic) {
nu->flagu |= CU_NURB_CYCLIC;
/* Check the number of points which overlap, we don't have
* overlapping points in Blender, but other software do use them to
* indicate that a curve is actually cyclic. Usually the number of
* overlapping points is equal to the order/degree of the curve.
*/
const int start = idx;
const int end = idx + num_verts;
int overlap = 0;
for (int j = start, k = end - nu->orderu; j < nu->orderu; ++j, ++k) {
const Imath::V3f &p1 = (*positions)[j];
const Imath::V3f &p2 = (*positions)[k];
if (p1 != p2) {
break;
}
++overlap;
}
/* TODO: Special case, need to figure out how it coincides with knots. */
if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
overlap = 1;
}
/* There is no real cycles. */
if (overlap == 0) {
nu->flagu &= ~CU_NURB_CYCLIC;
nu->flagu |= CU_NURB_ENDPOINT;
}
nu->pntsu -= overlap;
}
const bool do_weights = (weights != NULL) && (weights->size() > 1);
float weight = 1.0f;
const bool do_radius = (radiuses != NULL) && (radiuses->size() > 1);
float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f;
nu->type = CU_NURBS;
nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb"));
BPoint *bp = nu->bp;
for (int j = 0; j < nu->pntsu; ++j, ++bp, ++idx) {
const Imath::V3f &pos = (*positions)[idx];
if (do_radius) {
radius = (*radiuses)[idx];
}
if (do_weights) {
weight = (*weights)[idx];
}
copy_yup_zup(bp->vec, pos.getValue());
bp->vec[3] = weight;
bp->f1 = SELECT;
bp->radius = radius;
bp->weight = 1.0f;
}
if (knots && knots->size() != 0) {
nu->knotsu = static_cast<float *>(MEM_callocN(KNOTSU(nu) * sizeof(float), "abc_setsplineknotsu"));
/* TODO: second check is temporary, for until the check for cycles is rock solid. */
if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) {
/* Skip first and last knots. */
for (size_t i = 1; i < knots->size() - 1; ++i) {
nu->knotsu[i - 1] = (*knots)[knot_offset + i];
}
}
else {
/* TODO: figure out how to use the knots array from other
* software in this case. */
BKE_nurb_knot_calc_u(nu);
}
knot_offset += knots->size();
}
else {
BKE_nurb_knot_calc_u(nu);
}
BLI_addtail(BKE_curve_nurbs_get(cu), nu);
}
}

View File

@@ -0,0 +1,65 @@
/*
* ***** 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.
*
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
* All rights reserved.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
#ifndef __ABC_CURVES_H__
#define __ABC_CURVES_H__
#include "abc_object.h"
struct Curve;
/* ************************************************************************** */
class AbcCurveWriter : public AbcObjectWriter {
Alembic::AbcGeom::OCurvesSchema m_schema;
Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
public:
AbcCurveWriter(Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
void do_write();
};
/* ************************************************************************** */
class AbcCurveReader : public AbcObjectReader {
Alembic::AbcGeom::ICurvesSchema m_curves_schema;
public:
AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
void readObjectData(Main *bmain, float time);
};
/* ************************************************************************** */
void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time);
#endif /* __ABC_CURVES_H__ */

View File

@@ -0,0 +1,379 @@
/*
* ***** 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.
*
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
* All rights reserved.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
#include "abc_customdata.h"
#include <Alembic/AbcGeom/All.h>
#include <algorithm>
extern "C" {
#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_customdata.h"
}
/* NOTE: for now only UVs and Vertex Colors are supported for streaming.
* Although Alembic only allows for a single UV layer per {I|O}Schema, and does
* not have a vertex color concept, there is a convention between DCCs to write
* such data in a way that lets other DCC know what they are for. See comments
* in the write code for the conventions. */
using Alembic::AbcGeom::kVertexScope;
using Alembic::AbcGeom::kFacevaryingScope;
using Alembic::Abc::C4fArraySample;
using Alembic::Abc::UInt32ArraySample;
using Alembic::Abc::V2fArraySample;
using Alembic::AbcGeom::OV2fGeomParam;
using Alembic::AbcGeom::OC4fGeomParam;
static void get_uvs(const CDStreamConfig &config,
std::vector<Imath::V2f> &uvs,
std::vector<uint32_t> &uvidx,
void *cd_data)
{
MLoopUV *mloopuv_array = static_cast<MLoopUV *>(cd_data);
if (!mloopuv_array) {
return;
}
const int num_poly = config.totpoly;
MPoly *polygons = config.mpoly;
if (!config.pack_uvs) {
int cnt = 0;
uvidx.resize(config.totloop);
uvs.resize(config.totloop);
for (int i = 0; i < num_poly; ++i) {
MPoly &current_poly = polygons[i];
MLoopUV *loopuvpoly = mloopuv_array + current_poly.loopstart + current_poly.totloop;
for (int j = 0; j < current_poly.totloop; ++j, ++cnt) {
--loopuvpoly;
uvidx[cnt] = cnt;
uvs[cnt][0] = loopuvpoly->uv[0];
uvs[cnt][1] = loopuvpoly->uv[1];
}
}
}
else {
for (int i = 0; i < num_poly; ++i) {
MPoly &current_poly = polygons[i];
MLoopUV *loopuvpoly = mloopuv_array + current_poly.loopstart + current_poly.totloop;
for (int j = 0; j < current_poly.totloop; ++j) {
loopuvpoly--;
Imath::V2f uv(loopuvpoly->uv[0], loopuvpoly->uv[1]);
std::vector<Imath::V2f>::iterator it = std::find(uvs.begin(), uvs.end(), uv);
if (it == uvs.end()) {
uvidx.push_back(uvs.size());
uvs.push_back(uv);
}
else {
uvidx.push_back(std::distance(uvs.begin(), it));
}
}
}
}
}
const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data)
{
const int active_uvlayer = CustomData_get_active_layer(data, CD_MLOOPUV);
if (active_uvlayer < 0) {
return "";
}
void *cd_data = CustomData_get_layer_n(data, CD_MLOOPUV, active_uvlayer);
get_uvs(config, sample.uvs, sample.indices, cd_data);
return CustomData_get_layer_name(data, CD_MLOOPUV, active_uvlayer);
}
/* Convention to write UVs:
* - V2fGeomParam on the arbGeomParam
* - set scope as face varying
* - (optional due to its behaviour) tag as UV using Alembic::AbcGeom::SetIsUV
*/
static void write_uv(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name)
{
std::vector<uint32_t> indices;
std::vector<Imath::V2f> uvs;
get_uvs(config, uvs, indices, data);
if (indices.empty() || uvs.empty()) {
return;
}
OV2fGeomParam param(prop, name, true, kFacevaryingScope, 1);
OV2fGeomParam::Sample sample(
V2fArraySample(&uvs.front(), uvs.size()),
UInt32ArraySample(&indices.front(), indices.size()),
kFacevaryingScope);
param.set(sample);
}
/* Convention to write Vertex Colors:
* - C3fGeomParam/C4fGeomParam on the arbGeomParam
* - set scope as vertex varying
*/
static void write_mcol(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name)
{
const float cscale = 1.0f / 255.0f;
MPoly *polys = config.mpoly;
MLoop *mloops = config.mloop;
MCol *cfaces = static_cast<MCol *>(data);
std::vector<Imath::C4f> buffer(config.totvert);
Imath::C4f col;
for (int i = 0; i < config.totpoly; ++i) {
MPoly *p = &polys[i];
MCol *cface = &cfaces[p->loopstart + p->totloop];
MLoop *mloop = &mloops[p->loopstart + p->totloop];
for (int j = 0; j < p->totloop; ++j) {
cface--;
mloop--;
col[0] = cface->a * cscale;
col[1] = cface->r * cscale;
col[2] = cface->g * cscale;
col[3] = cface->b * cscale;
buffer[mloop->v] = col;
}
}
OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1);
OC4fGeomParam::Sample sample(
C4fArraySample(&buffer.front(), buffer.size()),
kVertexScope);
param.set(sample);
}
void write_custom_data(const OCompoundProperty &prop, const CDStreamConfig &config, CustomData *data, int data_type)
{
CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
if (!CustomData_has_layer(data, cd_data_type)) {
return;
}
const int active_layer = CustomData_get_active_layer(data, cd_data_type);
const int tot_layers = CustomData_number_of_layers(data, cd_data_type);
for (int i = 0; i < tot_layers; ++i) {
void *cd_data = CustomData_get_layer_n(data, cd_data_type, i);
const char *name = CustomData_get_layer_name(data, cd_data_type, i);
if (cd_data_type == CD_MLOOPUV) {
/* Already exported. */
if (i == active_layer) {
continue;
}
write_uv(prop, config, cd_data, name);
}
else if (cd_data_type == CD_MLOOPCOL) {
write_mcol(prop, config, cd_data, name);
}
}
}
/* ************************************************************************** */
using Alembic::Abc::C3fArraySamplePtr;
using Alembic::Abc::C4fArraySamplePtr;
using Alembic::Abc::PropertyHeader;
using Alembic::AbcGeom::IC3fGeomParam;
using Alembic::AbcGeom::IC4fGeomParam;
using Alembic::AbcGeom::IV2fGeomParam;
static void read_mcols(const CDStreamConfig &config, void *data,
const C3fArraySamplePtr &c3f_ptr, const C4fArraySamplePtr &c4f_ptr)
{
MCol *cfaces = static_cast<MCol *>(data);
MPoly *polys = config.mpoly;
MLoop *mloops = config.mloop;
if (c3f_ptr) {
for (int i = 0; i < config.totpoly; ++i) {
MPoly *p = &polys[i];
MCol *cface = &cfaces[p->loopstart + p->totloop];
MLoop *mloop = &mloops[p->loopstart + p->totloop];
for (int j = 0; j < p->totloop; ++j) {
cface--;
mloop--;
const Imath::C3f &color = (*c3f_ptr)[mloop->v];
cface->a = FTOCHAR(color[0]);
cface->r = FTOCHAR(color[1]);
cface->g = FTOCHAR(color[2]);
cface->b = 255;
}
}
}
else if (c4f_ptr) {
for (int i = 0; i < config.totpoly; ++i) {
MPoly *p = &polys[i];
MCol *cface = &cfaces[p->loopstart + p->totloop];
MLoop *mloop = &mloops[p->loopstart + p->totloop];
for (int j = 0; j < p->totloop; ++j) {
cface--;
mloop--;
const Imath::C4f &color = (*c4f_ptr)[mloop->v];
cface->a = FTOCHAR(color[0]);
cface->r = FTOCHAR(color[1]);
cface->g = FTOCHAR(color[2]);
cface->b = FTOCHAR(color[3]);
}
}
}
}
static void read_uvs(const CDStreamConfig &config, void *data,
const Alembic::AbcGeom::V2fArraySamplePtr &uvs,
const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
{
MPoly *mpolys = config.mpoly;
MLoopUV *mloopuvs = static_cast<MLoopUV *>(data);
unsigned int uv_index, loop_index;
for (int i = 0; i < config.totpoly; ++i) {
MPoly &poly = mpolys[i];
for (int f = 0; f < poly.totloop; ++f) {
loop_index = poly.loopstart + f;
uv_index = (*indices)[loop_index];
const Imath::V2f &uv = (*uvs)[uv_index];
MLoopUV &loopuv = mloopuvs[loop_index];
loopuv.uv[0] = uv[0];
loopuv.uv[1] = uv[1];
}
}
}
static void read_custom_data_ex(const ICompoundProperty &prop,
const PropertyHeader &prop_header,
const CDStreamConfig &config,
const Alembic::Abc::ISampleSelector &iss,
int data_type)
{
if (data_type == CD_MLOOPCOL) {
C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr();
C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr();
if (IC3fGeomParam::matches(prop_header)) {
IC3fGeomParam color_param(prop, prop_header.getName());
IC3fGeomParam::Sample sample;
color_param.getIndexed(sample, iss);
c3f_ptr = sample.getVals();
}
else if (IC4fGeomParam::matches(prop_header)) {
IC4fGeomParam color_param(prop, prop_header.getName());
IC4fGeomParam::Sample sample;
color_param.getIndexed(sample, iss);
c4f_ptr = sample.getVals();
}
void *cd_data = config.add_customdata_cb(config.user_data,
prop_header.getName().c_str(),
data_type);
read_mcols(config, cd_data, c3f_ptr, c4f_ptr);
}
else if (data_type == CD_MLOOPUV) {
IV2fGeomParam uv_param(prop, prop_header.getName());
IV2fGeomParam::Sample sample;
uv_param.getIndexed(sample, iss);
if (uv_param.getScope() != kFacevaryingScope) {
return;
}
void *cd_data = config.add_customdata_cb(config.user_data,
prop_header.getName().c_str(),
data_type);
read_uvs(config, cd_data, sample.getVals(), sample.getIndices());
}
}
void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
{
if (!prop.valid()) {
return;
}
int num_uvs = 0;
int num_colors = 0;
const size_t num_props = prop.getNumProperties();
for (size_t i = 0; i < num_props; ++i) {
const Alembic::Abc::PropertyHeader &prop_header = prop.getPropertyHeader(i);
/* Read UVs according to convention. */
if (IV2fGeomParam::matches(prop_header) && Alembic::AbcGeom::isUV(prop_header)) {
if (++num_uvs > MAX_MTFACE) {
continue;
}
read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPUV);
continue;
}
/* Read vertex colors according to convention. */
if (IC3fGeomParam::matches(prop_header) || IC4fGeomParam::matches(prop_header)) {
if (++num_colors > MAX_MCOL) {
continue;
}
read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPCOL);
continue;
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* ***** 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.
*
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
* All rights reserved.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
#ifndef __ABC_CUSTOMDATA_H__
#define __ABC_CUSTOMDATA_H__
#include <Alembic/Abc/All.h>
struct CustomData;
struct MLoop;
struct MLoopUV;
struct MPoly;
struct MVert;
using Alembic::Abc::ICompoundProperty;
using Alembic::Abc::OCompoundProperty;
struct UVSample {
std::vector<Imath::V2f> uvs;
std::vector<uint32_t> indices;
};
struct CDStreamConfig {
MLoop *mloop;
int totloop;
MPoly *mpoly;
int totpoly;
MVert *mvert;
int totvert;
MLoopUV *mloopuv;
CustomData *loopdata;
bool pack_uvs;
/* TODO(kevin): might need a better way to handle adding and/or updating
* custom datas such that it updates the custom data holder and its pointers
* properly. */
void *user_data;
void *(*add_customdata_cb)(void *user_data, const char *name, int data_type);
CDStreamConfig()
: mloop(NULL)
, totloop(0)
, mpoly(NULL)
, totpoly(0)
, totvert(0)
, pack_uvs(false)
, user_data(NULL)
, add_customdata_cb(NULL)
{}
};
/* Get the UVs for the main UV property on a OSchema.
* Returns the name of the UV layer.
*
* For now the active layer is used, maybe needs a better way to choose this. */
const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data);
void write_custom_data(const OCompoundProperty &prop,
const CDStreamConfig &config,
CustomData *data,
int data_type);
void read_custom_data(const ICompoundProperty &prop,
const CDStreamConfig &config,
const Alembic::Abc::ISampleSelector &iss);
#endif /* __ABC_CUSTOMDATA_H__ */

View File

@@ -0,0 +1,600 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "abc_exporter.h"
#include <cmath>
#ifdef WITH_ALEMBIC_HDF5
# include <Alembic/AbcCoreHDF5/All.h>
#endif
#include <Alembic/AbcCoreOgawa/All.h>
#include "abc_camera.h"
#include "abc_curves.h"
#include "abc_hair.h"
#include "abc_mesh.h"
#include "abc_nurbs.h"
#include "abc_points.h"
#include "abc_transform.h"
#include "abc_util.h"
extern "C" {
#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
#include "DNA_space_types.h" /* for FILE_MAX */
#include "BLI_string.h"
#ifdef WIN32
/* needed for MSCV because of snprintf from BLI_string */
# include "BLI_winstuff.h"
#endif
#include "BKE_anim.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
}
using Alembic::Abc::TimeSamplingPtr;
using Alembic::Abc::OBox3dProperty;
/* ************************************************************************** */
ExportSettings::ExportSettings()
: scene(NULL)
, selected_only(false)
, visible_layers_only(false)
, renderable_only(false)
, frame_start(1)
, frame_end(1)
, frame_step_xform(1)
, frame_step_shape(1)
, shutter_open(0.0)
, shutter_close(1.0)
, global_scale(1.0f)
, flatten_hierarchy(false)
, export_normals(false)
, export_uvs(false)
, export_vcols(false)
, export_face_sets(false)
, export_vweigths(false)
, apply_subdiv(false)
, use_subdiv_schema(false)
, export_child_hairs(true)
, export_ogawa(true)
, pack_uv(false)
, do_convert_axis(false)
{}
static bool object_is_smoke_sim(Object *ob)
{
ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
if (md) {
SmokeModifierData *smd = reinterpret_cast<SmokeModifierData *>(md);
return (smd->type == MOD_SMOKE_TYPE_DOMAIN);
}
return false;
}
static bool object_is_shape(Object *ob)
{
switch (ob->type) {
case OB_MESH:
if (object_is_smoke_sim(ob)) {
return false;
}
return true;
case OB_CURVE:
case OB_SURF:
case OB_CAMERA:
return true;
default:
return false;
}
}
static bool export_object(const ExportSettings * const settings, Object *ob)
{
if (settings->selected_only && !parent_selected(ob)) {
return false;
}
if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) {
return false;
}
if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) {
return false;
}
return true;
}
/* ************************************************************************** */
AbcExporter::AbcExporter(Scene *scene, const char *filename, ExportSettings &settings)
: m_settings(settings)
, m_filename(filename)
, m_trans_sampling_index(0)
, m_shape_sampling_index(0)
, m_scene(scene)
{}
AbcExporter::~AbcExporter()
{
std::map<std::string, AbcTransformWriter*>::iterator it, e;
for (it = m_xforms.begin(), e = m_xforms.end(); it != e; ++it) {
delete it->second;
}
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
delete m_shapes[i];
}
}
void AbcExporter::getShutterSamples(double step, bool time_relative,
std::vector<double> &samples)
{
samples.clear();
const double time_factor = time_relative ? m_scene->r.frs_sec : 1.0;
const double shutter_open = m_settings.shutter_open;
const double shutter_close = m_settings.shutter_close;
/* sample all frame */
if (shutter_open == 0.0 && shutter_close == 1.0) {
for (double t = 0; t < 1.0; t += step) {
samples.push_back(t / time_factor);
}
}
else {
/* sample between shutter open & close */
const int nsamples = std::max((1.0 / step) - 1.0, 1.0);
const double time_inc = (shutter_close - shutter_open) / nsamples;
for (double t = shutter_open; t <= shutter_close; t += time_inc) {
samples.push_back(t / time_factor);
}
}
}
Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step)
{
TimeSamplingPtr time_sampling;
std::vector<double> samples;
if (m_settings.frame_start == m_settings.frame_end) {
time_sampling.reset(new Alembic::Abc::TimeSampling());
return time_sampling;
}
getShutterSamples(step, true, samples);
Alembic::Abc::TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / m_scene->r.frs_sec);
time_sampling.reset(new Alembic::Abc::TimeSampling(ts, samples));
return time_sampling;
}
void AbcExporter::getFrameSet(double step, std::set<double> &frames)
{
frames.clear();
std::vector<double> shutter_samples;
getShutterSamples(step, false, shutter_samples);
for (int frame = m_settings.frame_start; frame <= m_settings.frame_end; ++frame) {
for (int j = 0, e = shutter_samples.size(); j < e; ++j) {
frames.insert(frame + shutter_samples[j]);
}
}
}
void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
{
std::string scene_name;
if (bmain->name[0] != '\0') {
char scene_file_name[FILE_MAX];
BLI_strncpy(scene_file_name, bmain->name, FILE_MAX);
scene_name = scene_file_name;
}
else {
scene_name = "untitled";
}
Scene *scene = m_scene;
const int fps = FPS;
char buf[16];
snprintf(buf, 15, "%d", fps);
const std::string str_fps = buf;
Alembic::AbcCoreAbstract::MetaData md;
md.set("FramesPerTimeUnit", str_fps);
Alembic::Abc::Argument arg(md);
#ifdef WITH_ALEMBIC_HDF5
if (!m_settings.export_ogawa) {
m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreHDF5::WriteArchive(),
m_filename,
"Blender",
scene_name,
Alembic::Abc::ErrorHandler::kThrowPolicy,
arg);
}
else
#endif
{
m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreOgawa::WriteArchive(),
m_filename,
"Blender",
scene_name,
Alembic::Abc::ErrorHandler::kThrowPolicy,
arg);
}
/* Create time samplings for transforms and shapes. */
TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_step_xform);
m_trans_sampling_index = m_archive.addTimeSampling(*trans_time);
TimeSamplingPtr shape_time;
if ((m_settings.frame_step_shape == m_settings.frame_step_xform) ||
(m_settings.frame_start == m_settings.frame_end))
{
shape_time = trans_time;
m_shape_sampling_index = m_trans_sampling_index;
}
else {
shape_time = createTimeSampling(m_settings.frame_step_shape);
m_shape_sampling_index = m_archive.addTimeSampling(*shape_time);
}
OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_archive, m_trans_sampling_index);
if (m_settings.flatten_hierarchy) {
createTransformWritersFlat();
}
else {
createTransformWritersHierarchy(bmain->eval_ctx);
}
createShapeWriters(bmain->eval_ctx);
/* Make a list of frames to export. */
std::set<double> xform_frames;
getFrameSet(m_settings.frame_step_xform, xform_frames);
std::set<double> shape_frames;
getFrameSet(m_settings.frame_step_shape, shape_frames);
/* Merge all frames needed. */
std::set<double> frames(xform_frames);
frames.insert(shape_frames.begin(), shape_frames.end());
/* Export all frames. */
std::set<double>::const_iterator begin = frames.begin();
std::set<double>::const_iterator end = frames.end();
const float size = static_cast<float>(frames.size());
size_t i = 0;
for (; begin != end; ++begin) {
progress = (++i / size);
if (G.is_break) {
was_canceled = true;
break;
}
double f = *begin;
setCurrentFrame(bmain, f);
if (shape_frames.count(f) != 0) {
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
m_shapes[i]->write();
}
}
if (xform_frames.count(f) == 0) {
continue;
}
std::map<std::string, AbcTransformWriter *>::iterator xit, xe;
for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
xit->second->write();
}
/* Save the archive 's bounding box. */
Imath::Box3d bounds;
for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
Imath::Box3d box = xit->second->bounds();
bounds.extendBy(box);
}
archive_bounds_prop.set(bounds);
}
}
void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx)
{
Base *base = static_cast<Base *>(m_scene->base.first);
while (base) {
Object *ob = base->object;
if (export_object(&m_settings, ob)) {
switch(ob->type) {
case OB_LAMP:
case OB_LATTICE:
case OB_MBALL:
case OB_SPEAKER:
/* We do not export transforms for objects of these classes. */
break;
default:
exploreTransform(eval_ctx, ob, ob->parent, NULL);
}
}
base = base->next;
}
}
void AbcExporter::createTransformWritersFlat()
{
Base *base = static_cast<Base *>(m_scene->base.first);
while (base) {
Object *ob = base->object;
if (export_object(&m_settings, ob) && object_is_shape(ob)) {
std::string name = get_id_name(ob);
m_xforms[name] = new AbcTransformWriter(ob, m_archive.getTop(), 0, m_trans_sampling_index, m_settings);
}
base = base->next;
}
}
void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent)
{
createTransformWriter(ob, parent, dupliObParent);
ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
if (lb) {
DupliObject *link = static_cast<DupliObject *>(lb->first);
Object *dupli_ob = NULL;
Object *dupli_parent = NULL;
while (link) {
if (link->type == OB_DUPLIGROUP) {
dupli_ob = link->ob;
dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob;
exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob);
}
link = link->next;
}
}
free_object_duplilist(lb);
}
void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
{
const std::string name = get_object_dag_path_name(ob, dupliObParent);
/* check if we have already created a transform writer for this object */
if (m_xforms.find(name) != m_xforms.end()){
std::cerr << "xform " << name << " already exists\n";
return;
}
AbcTransformWriter *parent_xform = NULL;
if (parent) {
const std::string parentname = get_object_dag_path_name(parent, dupliObParent);
parent_xform = getXForm(parentname);
if (!parent_xform) {
if (parent->parent) {
createTransformWriter(parent, parent->parent, dupliObParent);
}
else {
createTransformWriter(parent, dupliObParent, dupliObParent);
}
parent_xform = getXForm(parentname);
}
}
if (parent_xform) {
m_xforms[name] = new AbcTransformWriter(ob, parent_xform->alembicXform(), parent_xform, m_trans_sampling_index, m_settings);
m_xforms[name]->setParent(parent);
}
else {
m_xforms[name] = new AbcTransformWriter(ob, m_archive.getTop(), NULL, m_trans_sampling_index, m_settings);
}
}
void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx)
{
Base *base = static_cast<Base *>(m_scene->base.first);
while (base) {
Object *ob = base->object;
exploreObject(eval_ctx, ob, NULL);
base = base->next;
}
}
void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent)
{
ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
createShapeWriter(ob, dupliObParent);
if (lb) {
DupliObject *dupliob = static_cast<DupliObject *>(lb->first);
while (dupliob) {
if (dupliob->type == OB_DUPLIGROUP) {
exploreObject(eval_ctx, dupliob->ob, ob);
}
dupliob = dupliob->next;
}
}
free_object_duplilist(lb);
}
void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
{
if (!object_is_shape(ob)) {
return;
}
if (!export_object(&m_settings, ob)) {
return;
}
std::string name;
if (m_settings.flatten_hierarchy) {
name = get_id_name(ob);
}
else {
name = get_object_dag_path_name(ob, dupliObParent);
}
AbcTransformWriter *xform = getXForm(name);
if (!xform) {
std::cerr << __func__ << ": xform " << name << " is NULL\n";
return;
}
ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first);
for (; psys; psys = psys->next) {
if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) {
continue;
}
if (psys->part->type == PART_HAIR) {
m_settings.export_child_hairs = true;
m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
}
else if (psys->part->type == PART_EMITTER) {
m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
}
}
switch(ob->type) {
case OB_MESH:
{
Mesh *me = static_cast<Mesh *>(ob->data);
if (!me || me->totvert == 0) {
return;
}
m_shapes.push_back(new AbcMeshWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
break;
}
case OB_SURF:
{
Curve *cu = static_cast<Curve *>(ob->data);
if (!cu) {
return;
}
m_shapes.push_back(new AbcNurbsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
break;
}
case OB_CURVE:
{
Curve *cu = static_cast<Curve *>(ob->data);
if (!cu) {
return;
}
m_shapes.push_back(new AbcCurveWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
break;
}
case OB_CAMERA:
{
Camera *cam = static_cast<Camera *>(ob->data);
if (cam->type == CAM_PERSP) {
m_shapes.push_back(new AbcCameraWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
}
break;
}
}
}
AbcTransformWriter *AbcExporter::getXForm(const std::string &name)
{
std::map<std::string, AbcTransformWriter *>::iterator it = m_xforms.find(name);
if (it == m_xforms.end()) {
return NULL;
}
return it->second;
}
void AbcExporter::setCurrentFrame(Main *bmain, double t)
{
m_scene->r.cfra = std::floor(t);
m_scene->r.subframe = t - m_scene->r.cfra;
BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay);
}

View File

@@ -0,0 +1,112 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __ABC_EXPORTER_H__
#define __ABC_EXPORTER_H__
#include <Alembic/Abc/All.h>
#include <map>
#include <set>
#include <vector>
class AbcObjectWriter;
class AbcTransformWriter;
struct EvaluationContext;
struct Main;
struct Object;
struct Scene;
struct ExportSettings {
ExportSettings();
Scene *scene;
bool selected_only;
bool visible_layers_only;
bool renderable_only;
double frame_start, frame_end;
double frame_step_xform;
double frame_step_shape;
double shutter_open;
double shutter_close;
float global_scale;
bool flatten_hierarchy;
bool export_normals;
bool export_uvs;
bool export_vcols;
bool export_face_sets;
bool export_vweigths;
bool apply_subdiv;
bool use_subdiv_schema;
bool export_child_hairs;
bool export_ogawa;
bool pack_uv;
bool do_convert_axis;
float convert_matrix[3][3];
};
class AbcExporter {
ExportSettings &m_settings;
const char *m_filename;
Alembic::Abc::OArchive m_archive;
unsigned int m_trans_sampling_index, m_shape_sampling_index;
Scene *m_scene;
std::map<std::string, AbcTransformWriter *> m_xforms;
std::vector<AbcObjectWriter *> m_shapes;
public:
AbcExporter(Scene *scene, const char *filename, ExportSettings &settings);
~AbcExporter();
void operator()(Main *bmain, float &progress, bool &was_canceled);
private:
void getShutterSamples(double step, bool time_relative, std::vector<double> &samples);
Alembic::Abc::TimeSamplingPtr createTimeSampling(double step);
void getFrameSet(double step, std::set<double> &frames);
void createTransformWritersHierarchy(EvaluationContext *eval_ctx);
void createTransformWritersFlat();
void createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
void exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent = NULL);
void exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent);
void createShapeWriters(EvaluationContext *eval_ctx);
void createShapeWriter(Object *ob, Object *dupliObParent);
AbcTransformWriter *getXForm(const std::string &name);
void setCurrentFrame(Main *bmain, double t);
};
#endif /* __ABC_EXPORTER_H__ */

View File

@@ -0,0 +1,290 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "abc_hair.h"
#include <cstdio>
#include "abc_transform.h"
#include "abc_util.h"
extern "C" {
#include "MEM_guardedalloc.h"
#include "DNA_modifier_types.h"
#include "BLI_listbase.h"
#include "BLI_math_geom.h"
#include "BKE_DerivedMesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
}
using Alembic::Abc::P3fArraySamplePtr;
using Alembic::AbcGeom::OCurves;
using Alembic::AbcGeom::OCurvesSchema;
using Alembic::AbcGeom::ON3fGeomParam;
using Alembic::AbcGeom::OV2fGeomParam;
/* ************************************************************************** */
AbcHairWriter::AbcHairWriter(Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
ParticleSystem *psys)
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
{
m_psys = psys;
OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
m_schema = curves.getSchema();
}
void AbcHairWriter::do_write()
{
if (!m_psys) {
return;
}
ParticleSystemModifierData *psmd = psys_get_modifier(m_object, m_psys);
if (!psmd->dm_final) {
return;
}
DerivedMesh *dm = mesh_create_derived_view(m_scene, m_object, CD_MASK_MESH);
DM_ensure_tessface(dm);
DM_update_tessface_data(dm);
std::vector<Imath::V3f> verts;
std::vector<int32_t> hvertices;
std::vector<Imath::V2f> uv_values;
std::vector<Imath::V3f> norm_values;
if (m_psys->pathcache) {
ParticleSettings *part = m_psys->part;
write_hair_sample(dm, part, verts, norm_values, uv_values, hvertices);
if (m_settings.export_child_hairs && m_psys->childcache) {
write_hair_child_sample(dm, part, verts, norm_values, uv_values, hvertices);
}
}
dm->release(dm);
Alembic::Abc::P3fArraySample iPos(verts);
m_sample = OCurvesSchema::Sample(iPos, hvertices);
m_sample.setBasis(Alembic::AbcGeom::kNoBasis);
m_sample.setType(Alembic::AbcGeom::kLinear);
m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic);
if (!uv_values.empty()) {
OV2fGeomParam::Sample uv_smp;
uv_smp.setVals(uv_values);
m_sample.setUVs(uv_smp);
}
if (!norm_values.empty()) {
ON3fGeomParam::Sample norm_smp;
norm_smp.setVals(norm_values);
m_sample.setNormals(norm_smp);
}
m_sample.setSelfBounds(bounds());
m_schema.set(m_sample);
}
void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
ParticleSettings *part,
std::vector<Imath::V3f> &verts,
std::vector<Imath::V3f> &norm_values,
std::vector<Imath::V2f> &uv_values,
std::vector<int32_t> &hvertices)
{
/* Get untransformed vertices, there's a xform under the hair. */
float inv_mat[4][4];
invert_m4_m4_safe(inv_mat, m_object->obmat);
MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
MFace *mface = dm->getTessFaceArray(dm);
MVert *mverts = dm->getVertArray(dm);
if (!mtface || !mface) {
std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
}
ParticleData * pa = m_psys->particles;
int k;
ParticleCacheKey **cache = m_psys->pathcache;
ParticleCacheKey *path;
float normal[3];
Imath::V3f tmp_nor;
for (int p = 0; p < m_psys->totpart; ++p, ++pa) {
/* underlying info for faces-only emission */
path = cache[p];
if (part->from == PART_FROM_FACE && mtface) {
const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num;
if (num < dm->getNumTessFaces(dm)) {
MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
MTFace *tface = mtface + num;
if (mface) {
float r_uv[2], mapfw[4], vec[3];
psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv);
uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL, NULL);
copy_zup_yup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
}
}
else {
std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, dm->getNumTessFaces(dm));
}
}
else if (part->from == PART_FROM_VERT && mtface) {
/* vertex id */
const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num;
/* iterate over all faces to find a corresponding underlying UV */
for (int n = 0; n < dm->getNumTessFaces(dm); ++n) {
MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, n, CD_MFACE));
MTFace *tface = mtface + n;
unsigned int vtx[4];
vtx[0] = face->v1;
vtx[1] = face->v2;
vtx[2] = face->v3;
vtx[3] = face->v4;
bool found = false;
for (int o = 0; o < 4; ++o) {
if (o > 2 && vtx[o] == 0) {
break;
}
if (vtx[o] == num) {
uv_values.push_back(Imath::V2f(tface->uv[o][0], tface->uv[o][1]));
MVert *mv = mverts + vtx[o];
normal_short_to_float_v3(normal, mv->no);
copy_zup_yup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
found = true;
break;
}
}
if (found) {
break;
}
}
}
int steps = path->segments + 1;
hvertices.push_back(steps);
for (k = 0; k < steps; ++k) {
float vert[3];
copy_v3_v3(vert, path->co);
mul_m4_v3(inv_mat, vert);
/* Convert Z-up to Y-up. */
verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
++path;
}
}
}
void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
ParticleSettings *part,
std::vector<Imath::V3f> &verts,
std::vector<Imath::V3f> &norm_values,
std::vector<Imath::V2f> &uv_values,
std::vector<int32_t> &hvertices)
{
/* Get untransformed vertices, there's a xform under the hair. */
float inv_mat[4][4];
invert_m4_m4_safe(inv_mat, m_object->obmat);
MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
MFace *mface = dm->getTessFaceArray(dm);
MVert *mverts = dm->getVertArray(dm);
if (!mtface || !mface) {
std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
}
ParticleCacheKey **cache = m_psys->childcache;
ParticleCacheKey *path;
ChildParticle *pc = m_psys->child;
for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
path = cache[p];
if (part->from == PART_FROM_FACE) {
const int num = pc->num;
MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
MTFace *tface = mtface + num;
if (mface && mtface) {
float r_uv[2], tmpnor[3], mapfw[4], vec[3];
psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL, NULL);
/* Convert Z-up to Y-up. */
norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
}
}
int steps = path->segments + 1;
hvertices.push_back(steps);
for (int k = 0; k < steps; ++k) {
float vert[3];
copy_v3_v3(vert, path->co);
mul_m4_v3(inv_mat, vert);
/* Convert Z-up to Y-up. */
verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
++path;
}
}
}

View File

@@ -0,0 +1,66 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __ABC_HAIR_H__
#define __ABC_HAIR_H__
#include "abc_object.h"
struct DerivedMesh;
struct ParticleSettings;
struct ParticleSystem;
/* ************************************************************************** */
class AbcHairWriter : public AbcObjectWriter {
ParticleSystem *m_psys;
Alembic::AbcGeom::OCurvesSchema m_schema;
Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
public:
AbcHairWriter(Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
ParticleSystem *psys);
private:
virtual void do_write();
void write_hair_sample(DerivedMesh *dm,
ParticleSettings *part,
std::vector<Imath::V3f> &verts,
std::vector<Imath::V3f> &norm_values,
std::vector<Imath::V2f> &uv_values,
std::vector<int32_t> &hvertices);
void write_hair_child_sample(DerivedMesh *dm,
ParticleSettings *part,
std::vector<Imath::V3f> &verts,
std::vector<Imath::V3f> &norm_values,
std::vector<Imath::V2f> &uv_values,
std::vector<int32_t> &hvertices);
};
#endif /* __ABC_HAIR_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __ABC_MESH_H__
#define __ABC_MESH_H__
#include "abc_customdata.h"
#include "abc_object.h"
struct DerivedMesh;
struct Mesh;
struct ModifierData;
/* ************************************************************************** */
class AbcMeshWriter : public AbcObjectWriter {
Alembic::AbcGeom::OPolyMeshSchema m_mesh_schema;
Alembic::AbcGeom::OPolyMeshSchema::Sample m_mesh_sample;
Alembic::AbcGeom::OSubDSchema m_subdiv_schema;
Alembic::AbcGeom::OSubDSchema::Sample m_subdiv_sample;
bool m_has_per_face_materials;
Alembic::AbcGeom::OFaceSet m_face_set;
Alembic::Abc::OArrayProperty m_mat_indices;
bool m_is_animated;
ModifierData *m_subsurf_mod;
CDStreamConfig m_custom_data_config;
bool m_is_liquid;
bool m_is_subd;
public:
AbcMeshWriter(Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
~AbcMeshWriter();
private:
virtual void do_write();
bool isAnimated() const;
void writeMesh(DerivedMesh *dm);
void writeSubD(DerivedMesh *dm);
void getMeshInfo(DerivedMesh *dm, std::vector<float> &points,
std::vector<int32_t> &facePoints,
std::vector<int32_t> &faceCounts,
std::vector<int32_t> &creaseIndices,
std::vector<int32_t> &creaseLengths,
std::vector<float> &creaseSharpness);
DerivedMesh *getFinalMesh();
void freeMesh(DerivedMesh *dm);
void getMaterialIndices(DerivedMesh *dm, std::vector<int32_t> &indices);
void writeArbGeoParams(DerivedMesh *dm);
void getGeoGroups(DerivedMesh *dm, std::map<std::string, std::vector<int32_t> > &geoGroups);
/* fluid surfaces support */
void getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels);
template <typename Schema>
void writeCommonData(DerivedMesh *dm, Schema &schema);
};
/* ************************************************************************** */
class AbcMeshReader : public AbcObjectReader {
Alembic::AbcGeom::IPolyMeshSchema m_schema;
CDStreamConfig m_mesh_data;
public:
AbcMeshReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
void readObjectData(Main *bmain, float time);
private:
void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
const Alembic::AbcGeom::ISampleSelector &sample_sel);
};
void read_mesh_sample(ImportSettings *settings,
const Alembic::AbcGeom::IPolyMeshSchema &schema,
const Alembic::AbcGeom::ISampleSelector &selector,
CDStreamConfig &config,
bool &do_normals);
/* ************************************************************************** */
class AbcSubDReader : public AbcObjectReader {
Alembic::AbcGeom::ISubDSchema m_schema;
CDStreamConfig m_mesh_data;
public:
AbcSubDReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
void readObjectData(Main *bmain, float time);
};
void read_subd_sample(ImportSettings *settings,
const Alembic::AbcGeom::ISubDSchema &schema,
const Alembic::AbcGeom::ISampleSelector &selector,
CDStreamConfig &config);
/* ************************************************************************** */
namespace utils {
void mesh_add_verts(struct Mesh *mesh, size_t len);
}
void read_mverts(MVert *mverts,
const Alembic::AbcGeom::P3fArraySamplePtr &positions,
const Alembic::AbcGeom::N3fArraySamplePtr &normals);
CDStreamConfig create_config(Mesh *mesh);
#endif /* __ABC_MESH_H__ */

View File

@@ -0,0 +1,367 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "abc_nurbs.h"
#include "abc_transform.h"
#include "abc_util.h"
extern "C" {
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BKE_curve.h"
#include "BKE_object.h"
}
using Alembic::AbcGeom::bool_t;
using Alembic::AbcGeom::FloatArraySample;
using Alembic::AbcGeom::FloatArraySamplePtr;
using Alembic::AbcGeom::MetaData;
using Alembic::AbcGeom::P3fArraySamplePtr;
using Alembic::AbcGeom::kWrapExisting;
using Alembic::AbcGeom::IBoolProperty;
using Alembic::AbcGeom::ICompoundProperty;
using Alembic::AbcGeom::INuPatch;
using Alembic::AbcGeom::INuPatchSchema;
using Alembic::AbcGeom::IObject;
using Alembic::AbcGeom::ISampleSelector;
using Alembic::AbcGeom::OBoolProperty;
using Alembic::AbcGeom::OCompoundProperty;
using Alembic::AbcGeom::ONuPatch;
using Alembic::AbcGeom::ONuPatchSchema;
/* ************************************************************************** */
AbcNurbsWriter::AbcNurbsWriter(Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
{
m_is_animated = isAnimated();
/* if the object is static, use the default static time sampling */
if (!m_is_animated) {
m_time_sampling = 0;
}
Curve *curve = static_cast<Curve *>(m_object->data);
size_t numNurbs = BLI_listbase_count(&curve->nurb);
for (size_t i = 0; i < numNurbs; ++i) {
std::stringstream str;
str << m_name << '_' << i;
while (parent->alembicXform().getChildHeader(str.str())) {
str << "_";
}
ONuPatch nurbs(parent->alembicXform(), str.str().c_str(), m_time_sampling);
m_nurbs_schema.push_back(nurbs.getSchema());
}
}
bool AbcNurbsWriter::isAnimated() const
{
/* check if object has shape keys */
Curve *cu = static_cast<Curve *>(m_object->data);
return (cu->key != NULL);
}
static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_knots)
{
if (num_knots <= 1) {
return;
}
/* Add an extra knot at the beggining and end of the array since most apps
* require/expect them. */
knots.reserve(num_knots + 2);
knots.push_back(0.0f);
for (int i = 0; i < num_knots; ++i) {
knots.push_back(nu_knots[i]);
}
knots[0] = 2.0f * knots[1] - knots[2];
knots.push_back(2.0f * knots[num_knots] - knots[num_knots - 1]);
}
void AbcNurbsWriter::do_write()
{
/* we have already stored a sample for this object. */
if (!m_first_frame && !m_is_animated) {
return;
}
if (!ELEM(m_object->type, OB_SURF, OB_CURVE)) {
return;
}
Curve *curve = static_cast<Curve *>(m_object->data);
ListBase *nulb;
if (m_object->curve_cache->deformed_nurbs.first != NULL) {
nulb = &m_object->curve_cache->deformed_nurbs;
}
else {
nulb = BKE_curve_nurbs_get(curve);
}
size_t count = 0;
for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, ++count) {
std::vector<float> knotsU;
get_knots(knotsU, KNOTSU(nu), nu->knotsu);
std::vector<float> knotsV;
get_knots(knotsV, KNOTSV(nu), nu->knotsv);
const int size = nu->pntsu * nu->pntsv;
std::vector<Imath::V3f> positions(size);
std::vector<float> weights(size);
const BPoint *bp = nu->bp;
for (int i = 0; i < size; ++i, ++bp) {
copy_zup_yup(positions[i].getValue(), bp->vec);
weights[i] = bp->vec[3];
}
ONuPatchSchema::Sample sample;
sample.setUOrder(nu->orderu + 1);
sample.setVOrder(nu->orderv + 1);
sample.setPositions(positions);
sample.setPositionWeights(weights);
sample.setUKnot(FloatArraySample(knotsU));
sample.setVKnot(FloatArraySample(knotsV));
sample.setNu(nu->pntsu);
sample.setNv(nu->pntsv);
/* TODO(kevin): to accomodate other software we should duplicate control
* points to indicate that a NURBS is cyclic. */
OCompoundProperty user_props = m_nurbs_schema[count].getUserProperties();
if ((nu->flagu & CU_NURB_ENDPOINT) != 0) {
OBoolProperty prop(user_props, "endpoint_u");
prop.set(true);
}
if ((nu->flagv & CU_NURB_ENDPOINT) != 0) {
OBoolProperty prop(user_props, "endpoint_v");
prop.set(true);
}
if ((nu->flagu & CU_NURB_CYCLIC) != 0) {
OBoolProperty prop(user_props, "cyclic_u");
prop.set(true);
}
if ((nu->flagv & CU_NURB_CYCLIC) != 0) {
OBoolProperty prop(user_props, "cyclic_v");
prop.set(true);
}
m_nurbs_schema[count].set(sample);
}
}
/* ************************************************************************** */
AbcNurbsReader::AbcNurbsReader(const IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
getNurbsPatches(m_iobject);
get_min_max_time(m_schemas[0].first, m_min_time, m_max_time);
}
bool AbcNurbsReader::valid() const
{
if (m_schemas.empty()) {
return false;
}
std::vector< std::pair<INuPatchSchema, IObject> >::const_iterator it;
for (it = m_schemas.begin(); it != m_schemas.end(); ++it) {
const INuPatchSchema &schema = it->first;
if (!schema.valid()) {
return false;
}
}
return true;
}
static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
{
if (!knots || knots->size() == 0) {
return false;
}
/* Skip first and last knots, as they are used for padding. */
const size_t num_knots = knots->size() - 2;
nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), "abc_setsplineknotsu"));
for (size_t i = 0; i < num_knots; ++i) {
nu_knots[i] = (*knots)[i + 1];
}
return true;
}
void AbcNurbsReader::readObjectData(Main *bmain, float time)
{
Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, "abc_curve", OB_SURF));
cu->actvert = CU_ACT_NONE;
std::vector< std::pair<INuPatchSchema, IObject> >::iterator it;
for (it = m_schemas.begin(); it != m_schemas.end(); ++it) {
Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
nu->flag = CU_SMOOTH;
nu->type = CU_NURBS;
nu->resolu = cu->resolu;
nu->resolv = cu->resolv;
const ISampleSelector sample_sel(time);
const INuPatchSchema &schema = it->first;
const INuPatchSchema::Sample smp = schema.getValue(sample_sel);
nu->orderu = smp.getUOrder() - 1;
nu->orderv = smp.getVOrder() - 1;
nu->pntsu = smp.getNumU();
nu->pntsv = smp.getNumV();
/* Read positions and weights. */
const P3fArraySamplePtr positions = smp.getPositions();
const FloatArraySamplePtr weights = smp.getPositionWeights();
const size_t num_points = positions->size();
nu->bp = static_cast<BPoint *>(MEM_callocN(num_points * sizeof(BPoint), "abc_setsplinetype"));
BPoint *bp = nu->bp;
float posw_in = 1.0f;
for (int i = 0; i < num_points; ++i, ++bp) {
const Imath::V3f &pos_in = (*positions)[i];
if (weights) {
posw_in = (*weights)[i];
}
copy_yup_zup(bp->vec, pos_in.getValue());
bp->vec[3] = posw_in;
bp->f1 = SELECT;
bp->radius = 1.0f;
bp->weight = 1.0f;
}
/* Read knots. */
if (!set_knots(smp.getUKnot(), nu->knotsu)) {
BKE_nurb_knot_calc_u(nu);
}
if (!set_knots(smp.getVKnot(), nu->knotsv)) {
BKE_nurb_knot_calc_v(nu);
}
/* Read flags. */
ICompoundProperty user_props = schema.getUserProperties();
if (has_property(user_props, "enpoint_u")) {
nu->flagu |= CU_NURB_ENDPOINT;
}
if (has_property(user_props, "enpoint_v")) {
nu->flagv |= CU_NURB_ENDPOINT;
}
if (has_property(user_props, "cyclic_u")) {
nu->flagu |= CU_NURB_CYCLIC;
}
if (has_property(user_props, "cyclic_v")) {
nu->flagv |= CU_NURB_CYCLIC;
}
BLI_addtail(BKE_curve_nurbs_get(cu), nu);
}
BLI_strncpy(cu->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1);
m_object = BKE_object_add_only_object(bmain, OB_SURF, m_object_name.c_str());
m_object->data = cu;
}
void AbcNurbsReader::getNurbsPatches(const IObject &obj)
{
if (!obj.valid()) {
return;
}
const int num_children = obj.getNumChildren();
if (num_children == 0) {
INuPatch abc_nurb(obj, kWrapExisting);
INuPatchSchema schem = abc_nurb.getSchema();
m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, obj));
return;
}
for (int i = 0; i < num_children; ++i) {
bool ok = true;
IObject child(obj, obj.getChildHeader(i).getName());
if (!m_name.empty() && child.valid() && !begins_with(child.getFullName(), m_name)) {
ok = false;
}
if (!child.valid()) {
continue;
}
const MetaData &md = child.getMetaData();
if (INuPatch::matches(md) && ok) {
INuPatch abc_nurb(child, kWrapExisting);
INuPatchSchema schem = abc_nurb.getSchema();
m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, child));
}
getNurbsPatches(child);
}
}

View File

@@ -0,0 +1,63 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __ABC_NURBS_H__
#define __ABC_NURBS_H__
#include "abc_object.h"
/* ************************************************************************** */
class AbcNurbsWriter : public AbcObjectWriter {
std::vector<Alembic::AbcGeom::ONuPatchSchema> m_nurbs_schema;
bool m_is_animated;
public:
AbcNurbsWriter(Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
private:
virtual void do_write();
bool isAnimated() const;
};
/* ************************************************************************** */
class AbcNurbsReader : public AbcObjectReader {
std::vector< std::pair<Alembic::AbcGeom::INuPatchSchema, Alembic::Abc::IObject> > m_schemas;
public:
AbcNurbsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
void readObjectData(Main *bmain, float time);
private:
void getNurbsPatches(const Alembic::Abc::IObject &obj);
};
#endif /* __ABC_NURBS_H__ */

View File

@@ -0,0 +1,238 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "abc_object.h"
#include "abc_util.h"
extern "C" {
#include "DNA_cachefile_types.h"
#include "DNA_constraint_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h" /* for FILE_MAX */
#include "BKE_constraint.h"
#include "BKE_depsgraph.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
}
using Alembic::AbcGeom::IObject;
using Alembic::AbcGeom::IXform;
using Alembic::AbcGeom::IXformSchema;
using Alembic::AbcGeom::OCompoundProperty;
using Alembic::AbcGeom::ODoubleArrayProperty;
using Alembic::AbcGeom::ODoubleProperty;
using Alembic::AbcGeom::OFloatArrayProperty;
using Alembic::AbcGeom::OFloatProperty;
using Alembic::AbcGeom::OInt32ArrayProperty;
using Alembic::AbcGeom::OInt32Property;
using Alembic::AbcGeom::OStringArrayProperty;
using Alembic::AbcGeom::OStringProperty;
/* ************************************************************************** */
AbcObjectWriter::AbcObjectWriter(Scene *scene,
Object *ob,
uint32_t time_sampling,
ExportSettings &settings,
AbcObjectWriter *parent)
: m_object(ob)
, m_settings(settings)
, m_scene(scene)
, m_time_sampling(time_sampling)
, m_first_frame(true)
{
m_name = get_id_name(m_object) + "Shape";
if (parent) {
parent->addChild(this);
}
}
AbcObjectWriter::~AbcObjectWriter()
{}
void AbcObjectWriter::addChild(AbcObjectWriter *child)
{
m_children.push_back(child);
}
Imath::Box3d AbcObjectWriter::bounds()
{
BoundBox *bb = BKE_object_boundbox_get(this->m_object);
if (!bb) {
if (this->m_object->type != OB_CAMERA) {
std::cerr << "Boundbox is null!\n";
}
return Imath::Box3d();
}
/* Convert Z-up to Y-up. */
this->m_bounds.min.x = bb->vec[0][0];
this->m_bounds.min.y = bb->vec[0][2];
this->m_bounds.min.z = -bb->vec[0][1];
this->m_bounds.max.x = bb->vec[6][0];
this->m_bounds.max.y = bb->vec[6][2];
this->m_bounds.max.z = -bb->vec[6][1];
return this->m_bounds;
}
void AbcObjectWriter::write()
{
do_write();
m_first_frame = false;
}
/* ************************************************************************** */
AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings)
: m_name("")
, m_object_name("")
, m_data_name("")
, m_object(NULL)
, m_iobject(object)
, m_settings(&settings)
, m_min_time(std::numeric_limits<chrono_t>::max())
, m_max_time(std::numeric_limits<chrono_t>::min())
{
m_name = object.getFullName();
std::vector<std::string> parts;
split(m_name, '/', parts);
if (parts.size() >= 2) {
m_object_name = parts[parts.size() - 2];
m_data_name = parts[parts.size() - 1];
}
else {
m_object_name = m_data_name = parts[parts.size() - 1];
}
}
AbcObjectReader::~AbcObjectReader()
{}
const IObject &AbcObjectReader::iobject() const
{
return m_iobject;
}
Object *AbcObjectReader::object() const
{
return m_object;
}
void AbcObjectReader::readObjectMatrix(const float time)
{
IXform ixform;
bool has_alembic_parent = false;
/* Check that we have an empty object (locator, bone head/tail...). */
if (IXform::matches(m_iobject.getMetaData())) {
ixform = IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
/* See comment below. */
has_alembic_parent = m_iobject.getParent().getParent().valid();
}
/* Check that we have an object with actual data. */
else if (IXform::matches(m_iobject.getParent().getMetaData())) {
ixform = IXform(m_iobject.getParent(), Alembic::AbcGeom::kWrapExisting);
/* This is a bit hackish, but we need to make sure that extra
* transformations added to the matrix (rotation/scale) are only applied
* to root objects. The way objects and their hierarchy are created will
* need to be revisited at some point but for now this seems to do the
* trick.
*
* Explanation of the trick:
* The first getParent() will return this object's transformation matrix.
* The second getParent() will get the parent of the transform, but this
* might be the archive root ('/') which is valid, so we go passed it to
* make sure that there is no parent.
*/
has_alembic_parent = m_iobject.getParent().getParent().getParent().valid();
}
/* Should not happen. */
else {
return;
}
const IXformSchema &schema(ixform.getSchema());
if (!schema.valid()) {
return;
}
Alembic::AbcGeom::ISampleSelector sample_sel(time);
Alembic::AbcGeom::XformSample xs;
schema.get(xs, sample_sel);
create_input_transform(sample_sel, ixform, m_object, m_object->obmat, m_settings->scale, has_alembic_parent);
invert_m4_m4(m_object->imat, m_object->obmat);
BKE_object_apply_mat4(m_object, m_object->obmat, false, false);
if (!schema.isConstant()) {
bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE);
bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
data->cache_file = m_settings->cache_file;
id_us_plus(&data->cache_file->id);
}
}
void AbcObjectReader::addCacheModifier() const
{
ModifierData *md = modifier_new(eModifierType_MeshSequenceCache);
BLI_addtail(&m_object->modifiers, md);
MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
mcmd->cache_file = m_settings->cache_file;
id_us_plus(&mcmd->cache_file->id);
BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
}
chrono_t AbcObjectReader::minTime() const
{
return m_min_time;
}
chrono_t AbcObjectReader::maxTime() const
{
return m_max_time;
}

View File

@@ -0,0 +1,169 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __ABC_OBJECT_H__
#define __ABC_OBJECT_H__
#include <Alembic/Abc/All.h>
#include <Alembic/AbcGeom/All.h>
#include "abc_exporter.h"
extern "C" {
#include "DNA_ID.h"
}
class AbcTransformWriter;
struct Main;
struct Object;
/* ************************************************************************** */
class AbcObjectWriter {
protected:
Object *m_object;
ExportSettings &m_settings;
Scene *m_scene;
uint32_t m_time_sampling;
Imath::Box3d m_bounds;
std::vector<AbcObjectWriter *> m_children;
std::vector< std::pair<std::string, IDProperty *> > m_props;
bool m_first_frame;
std::string m_name;
public:
AbcObjectWriter(Scene *scene,
Object *ob,
uint32_t time_sampling,
ExportSettings &settings,
AbcObjectWriter *parent = NULL);
virtual ~AbcObjectWriter();
void addChild(AbcObjectWriter *child);
virtual Imath::Box3d bounds();
void write();
private:
virtual void do_write() = 0;
};
/* ************************************************************************** */
class CacheFile;
struct ImportSettings {
bool do_convert_mat;
float conversion_mat[4][4];
int from_up;
int from_forward;
float scale;
bool is_sequence;
bool set_frame_range;
/* Length and frame offset of file sequences. */
int sequence_len;
int offset;
/* From MeshSeqCacheModifierData.read_flag */
int read_flag;
bool validate_meshes;
CacheFile *cache_file;
ImportSettings()
: do_convert_mat(false)
, from_up(0)
, from_forward(0)
, scale(1.0f)
, is_sequence(false)
, set_frame_range(false)
, sequence_len(1)
, offset(0)
, read_flag(0)
, validate_meshes(false)
, cache_file(NULL)
{}
};
template <typename Schema>
static bool has_animations(Schema &schema, ImportSettings *settings)
{
if (settings->is_sequence) {
return true;
}
if (!schema.isConstant()) {
return true;
}
return false;
}
/* ************************************************************************** */
using Alembic::AbcCoreAbstract::chrono_t;
class AbcObjectReader {
protected:
std::string m_name;
std::string m_object_name;
std::string m_data_name;
Object *m_object;
Alembic::Abc::IObject m_iobject;
ImportSettings *m_settings;
chrono_t m_min_time;
chrono_t m_max_time;
public:
explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
virtual ~AbcObjectReader();
const Alembic::Abc::IObject &iobject() const;
Object *object() const;
virtual bool valid() const = 0;
virtual void readObjectData(Main *bmain, float time) = 0;
void readObjectMatrix(const float time);
void addCacheModifier() const;
chrono_t minTime() const;
chrono_t maxTime() const;
};
#endif /* __ABC_OBJECT_H__ */

View File

@@ -0,0 +1,198 @@
/*
* ***** 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.
*
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
* All rights reserved.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
#include "abc_points.h"
#include "abc_mesh.h"
#include "abc_transform.h"
#include "abc_util.h"
extern "C" {
#include "DNA_mesh_types.h"
#include "BKE_lattice.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BLI_math.h"
}
using Alembic::AbcGeom::kVertexScope;
using Alembic::AbcGeom::kWrapExisting;
using Alembic::AbcGeom::P3fArraySamplePtr;
using Alembic::AbcGeom::N3fArraySamplePtr;
using Alembic::AbcGeom::ICompoundProperty;
using Alembic::AbcGeom::IN3fArrayProperty;
using Alembic::AbcGeom::IPoints;
using Alembic::AbcGeom::IPointsSchema;
using Alembic::AbcGeom::ISampleSelector;
using Alembic::AbcGeom::OPoints;
using Alembic::AbcGeom::OPointsSchema;
/* ************************************************************************** */
AbcPointsWriter::AbcPointsWriter(Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
ParticleSystem *psys)
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
{
m_psys = psys;
OPoints points(parent->alembicXform(), m_name, m_time_sampling);
m_schema = points.getSchema();
}
void AbcPointsWriter::do_write()
{
if (!m_psys) {
return;
}
std::vector<Imath::V3f> points;
std::vector<Imath::V3f> velocities;
std::vector<float> widths;
std::vector<uint64_t> ids;
ParticleKey state;
ParticleSimulationData sim;
sim.scene = m_scene;
sim.ob = m_object;
sim.psys = m_psys;
m_psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
uint64_t index = 0;
for (int p = 0; p < m_psys->totpart; p++) {
float pos[3], vel[3];
if (m_psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
continue;
}
state.time = BKE_scene_frame_get(m_scene);
if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
continue;
}
/* location */
mul_v3_m4v3(pos, m_object->imat, state.co);
/* velocity */
sub_v3_v3v3(vel, state.co, m_psys->particles[p].prev_state.co);
/* Convert Z-up to Y-up. */
points.push_back(Imath::V3f(pos[0], pos[2], -pos[1]));
velocities.push_back(Imath::V3f(vel[0], vel[2], -vel[1]));
widths.push_back(m_psys->particles[p].size);
ids.push_back(index++);
}
if (m_psys->lattice_deform_data) {
end_latt_deform(m_psys->lattice_deform_data);
m_psys->lattice_deform_data = NULL;
}
Alembic::Abc::P3fArraySample psample(points);
Alembic::Abc::UInt64ArraySample idsample(ids);
Alembic::Abc::V3fArraySample vsample(velocities);
Alembic::Abc::FloatArraySample wsample_array(widths);
Alembic::AbcGeom::OFloatGeomParam::Sample wsample(wsample_array, kVertexScope);
m_sample = OPointsSchema::Sample(psample, idsample, vsample, wsample);
m_sample.setSelfBounds(bounds());
m_schema.set(m_sample);
}
/* ************************************************************************** */
AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
IPoints ipoints(m_iobject, kWrapExisting);
m_schema = ipoints.getSchema();
get_min_max_time(m_schema, m_min_time, m_max_time);
}
bool AbcPointsReader::valid() const
{
return m_schema.valid();
}
void AbcPointsReader::readObjectData(Main *bmain, float time)
{
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
const ISampleSelector sample_sel(time);
m_sample = m_schema.getValue(sample_sel);
const P3fArraySamplePtr &positions = m_sample.getPositions();
utils::mesh_add_verts(mesh, positions->size());
CDStreamConfig config = create_config(mesh);
read_points_sample(m_schema, sample_sel, config, time);
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
}
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
if (has_animations(m_schema, m_settings)) {
addCacheModifier();
}
}
void read_points_sample(const IPointsSchema &schema,
const ISampleSelector &selector,
CDStreamConfig &config,
float time)
{
Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
const P3fArraySamplePtr &positions = sample.getPositions();
ICompoundProperty prop = schema.getArbGeomParams();
N3fArraySamplePtr vnormals;
if (has_property(prop, "N")) {
const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", time);
if (normals_prop) {
vnormals = normals_prop.getValue(selector);
}
}
read_mverts(config.mvert, positions, vnormals);
}

View File

@@ -0,0 +1,70 @@
/*
* ***** 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.
*
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
* All rights reserved.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
#ifndef __ABC_POINTS_H__
#define __ABC_POINTS_H__
#include "abc_object.h"
#include "abc_customdata.h"
class ParticleSystem;
/* ************************************************************************** */
class AbcPointsWriter : public AbcObjectWriter {
Alembic::AbcGeom::OPointsSchema m_schema;
Alembic::AbcGeom::OPointsSchema::Sample m_sample;
ParticleSystem *m_psys;
public:
AbcPointsWriter(Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
ParticleSystem *psys);
void do_write();
};
/* ************************************************************************** */
class AbcPointsReader : public AbcObjectReader {
Alembic::AbcGeom::IPointsSchema m_schema;
Alembic::AbcGeom::IPointsSchema::Sample m_sample;
public:
AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
void readObjectData(Main *bmain, float time);
};
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
const Alembic::AbcGeom::ISampleSelector &selector,
CDStreamConfig &config,
float time);
#endif /* __ABC_POINTS_H__ */

View File

@@ -0,0 +1,152 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "abc_transform.h"
#include <OpenEXR/ImathBoxAlgo.h>
#include "abc_util.h"
extern "C" {
#include "DNA_object_types.h"
#include "BLI_math.h"
#include "BKE_object.h"
}
using Alembic::AbcGeom::OObject;
using Alembic::AbcGeom::OXform;
/* ************************************************************************** */
static bool has_parent_camera(Object *ob)
{
if (!ob->parent) {
return false;
}
Object *parent = ob->parent;
if (parent->type == OB_CAMERA) {
return true;
}
return has_parent_camera(parent);
}
/* ************************************************************************** */
AbcTransformWriter::AbcTransformWriter(Object *ob,
const OObject &abc_parent,
AbcTransformWriter *parent,
unsigned int time_sampling,
ExportSettings &settings)
: AbcObjectWriter(NULL, ob, time_sampling, settings, parent)
{
m_is_animated = hasAnimation(m_object);
m_parent = NULL;
if (!m_is_animated) {
time_sampling = 0;
}
m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling);
m_schema = m_xform.getSchema();
}
void AbcTransformWriter::do_write()
{
if (m_first_frame) {
m_visibility = Alembic::AbcGeom::CreateVisibilityProperty(m_xform, m_xform.getSchema().getTimeSampling());
}
m_visibility.set(!(m_object->restrictflag & OB_RESTRICT_VIEW));
if (!m_first_frame && !m_is_animated) {
return;
}
float mat[4][4];
create_transform_matrix(m_object, mat);
/* Only apply rotation to root camera, parenting will propagate it. */
if (m_object->type == OB_CAMERA && !has_parent_camera(m_object)) {
float rot_mat[4][4];
unit_m4(rot_mat);
rotate_m4(rot_mat, 'X', -M_PI_2);
mul_m4_m4m4(mat, mat, rot_mat);
}
if (!m_object->parent) {
/* Only apply scaling to root objects, parenting will propagate it. */
float scale_mat[4][4];
scale_m4_fl(scale_mat, m_settings.global_scale);
mul_m4_m4m4(mat, mat, scale_mat);
mul_v3_fl(mat[3], m_settings.global_scale);
}
m_matrix = convert_matrix(mat);
m_sample.setMatrix(m_matrix);
m_schema.set(m_sample);
}
Imath::Box3d AbcTransformWriter::bounds()
{
Imath::Box3d bounds;
for (int i = 0; i < m_children.size(); ++i) {
Imath::Box3d box(m_children[i]->bounds());
bounds.extendBy(box);
}
return Imath::transform(bounds, m_matrix);
}
bool AbcTransformWriter::hasAnimation(Object */*ob*/) const
{
/* TODO(kevin): implement this. */
return true;
}
/* ************************************************************************** */
AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
: AbcObjectReader(object, settings)
{
Alembic::AbcGeom::IXform xform(object, Alembic::AbcGeom::kWrapExisting);
m_schema = xform.getSchema();
get_min_max_time(m_schema, m_min_time, m_max_time);
}
bool AbcEmptyReader::valid() const
{
return m_schema.valid();
}
void AbcEmptyReader::readObjectData(Main *bmain, float /*time*/)
{
m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str());
m_object->data = NULL;
}

View File

@@ -0,0 +1,73 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __ABC_TRANSFORM_H__
#define __ABC_TRANSFORM_H__
#include "abc_object.h"
#include <Alembic/AbcGeom/All.h>
/* ************************************************************************** */
class AbcTransformWriter : public AbcObjectWriter {
Alembic::AbcGeom::OXform m_xform;
Alembic::AbcGeom::OXformSchema m_schema;
Alembic::AbcGeom::XformSample m_sample;
Alembic::AbcGeom::OVisibilityProperty m_visibility;
Alembic::Abc::M44d m_matrix;
bool m_is_animated;
Object *m_parent;
bool m_visible;
public:
AbcTransformWriter(Object *ob,
const Alembic::AbcGeom::OObject &abc_parent,
AbcTransformWriter *parent,
unsigned int time_sampling,
ExportSettings &settings);
Alembic::AbcGeom::OXform &alembicXform() { return m_xform;}
virtual Imath::Box3d bounds();
void setParent(Object *p) { m_parent = p; }
private:
virtual void do_write();
bool hasAnimation(Object *ob) const;
};
/* ************************************************************************** */
class AbcEmptyReader : public AbcObjectReader {
Alembic::AbcGeom::IXformSchema m_schema;
public:
AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
bool valid() const;
void readObjectData(Main *bmain, float time);
};
#endif /* __ABC_TRANSFORM_H__ */

View File

@@ -0,0 +1,437 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "abc_util.h"
#include <algorithm>
extern "C" {
#include "DNA_object_types.h"
#include "BLI_math.h"
}
std::string get_id_name(Object *ob)
{
if (!ob) {
return "";
}
return get_id_name(&ob->id);
}
std::string get_id_name(ID *id)
{
std::string name(id->name + 2);
std::replace(name.begin(), name.end(), ' ', '_');
std::replace(name.begin(), name.end(), '.', '_');
std::replace(name.begin(), name.end(), ':', '_');
return name;
}
std::string get_object_dag_path_name(Object *ob, Object *dupli_parent)
{
std::string name = get_id_name(ob);
Object *p = ob->parent;
while (p) {
name = get_id_name(p) + "/" + name;
p = p->parent;
}
if (dupli_parent && (ob != dupli_parent)) {
name = get_id_name(dupli_parent) + "/" + name;
}
return name;
}
bool object_selected(Object *ob)
{
return ob->flag & SELECT;
}
bool parent_selected(Object *ob)
{
if (object_selected(ob)) {
return true;
}
bool do_export = false;
Object *parent = ob->parent;
while (parent != NULL) {
if (object_selected(parent)) {
do_export = true;
break;
}
parent = parent->parent;
}
return do_export;
}
Imath::M44d convert_matrix(float mat[4][4])
{
Imath::M44d m;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
m[i][j] = mat[i][j];
}
}
return m;
}
void split(const std::string &s, const char delim, std::vector<std::string> &tokens)
{
tokens.clear();
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
if (!item.empty()) {
tokens.push_back(item);
}
}
}
/* Create a rotation matrix for each axis from euler angles.
* Euler angles are swaped to change coordinate system. */
static void create_rotation_matrix(
float rot_x_mat[3][3], float rot_y_mat[3][3],
float rot_z_mat[3][3], const float euler[3], const bool to_yup)
{
const float rx = euler[0];
const float ry = (to_yup) ? euler[2] : -euler[2];
const float rz = (to_yup) ? -euler[1] : euler[1];
unit_m3(rot_x_mat);
unit_m3(rot_y_mat);
unit_m3(rot_z_mat);
rot_x_mat[1][1] = cos(rx);
rot_x_mat[2][1] = -sin(rx);
rot_x_mat[1][2] = sin(rx);
rot_x_mat[2][2] = cos(rx);
rot_y_mat[2][2] = cos(ry);
rot_y_mat[0][2] = -sin(ry);
rot_y_mat[2][0] = sin(ry);
rot_y_mat[0][0] = cos(ry);
rot_z_mat[0][0] = cos(rz);
rot_z_mat[1][0] = -sin(rz);
rot_z_mat[0][1] = sin(rz);
rot_z_mat[1][1] = cos(rz);
}
/* Recompute transform matrix of object in new coordinate system
* (from Y-Up to Z-Up). */
void create_transform_matrix(float r_mat[4][4])
{
float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], transform_mat[4][4];
float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
float loc[3], scale[3], euler[3];
zero_v3(loc);
zero_v3(scale);
zero_v3(euler);
unit_m3(rot);
unit_m3(rot_mat);
unit_m4(scale_mat);
unit_m4(transform_mat);
unit_m4(invmat);
/* Compute rotation matrix. */
/* Extract location, rotation, and scale from matrix. */
mat4_to_loc_rot_size(loc, rot, scale, r_mat);
/* Get euler angles from rotation matrix. */
mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
/* Create X, Y, Z rotation matrices from euler angles. */
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, false);
/* Concatenate rotation matrices. */
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
/* Add rotation matrix to transformation matrix. */
copy_m4_m3(transform_mat, rot_mat);
/* Add translation to transformation matrix. */
copy_yup_zup(transform_mat[3], loc);
/* Create scale matrix. */
scale_mat[0][0] = scale[0];
scale_mat[1][1] = scale[2];
scale_mat[2][2] = scale[1];
/* Add scale to transformation matrix. */
mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
copy_m4_m4(r_mat, transform_mat);
}
void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
const Alembic::AbcGeom::IXform &ixform, Object *ob,
float r_mat[4][4], float scale, bool has_alembic_parent)
{
const Alembic::AbcGeom::IXformSchema &ixform_schema = ixform.getSchema();
Alembic::AbcGeom::XformSample xs;
ixform_schema.get(xs, sample_sel);
const Imath::M44d &xform = xs.getMatrix();
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
r_mat[i][j] = xform[i][j];
}
}
if (ob->type == OB_CAMERA) {
float cam_to_yup[4][4];
unit_m4(cam_to_yup);
rotate_m4(cam_to_yup, 'X', M_PI_2);
mul_m4_m4m4(r_mat, r_mat, cam_to_yup);
}
create_transform_matrix(r_mat);
if (ob->parent) {
mul_m4_m4m4(r_mat, ob->parent->obmat, r_mat);
}
/* TODO(kevin) */
else if (!has_alembic_parent) {
/* Only apply scaling to root objects, parenting will propagate it. */
float scale_mat[4][4];
scale_m4_fl(scale_mat, scale);
mul_m4_m4m4(r_mat, r_mat, scale_mat);
mul_v3_fl(r_mat[3], scale);
}
}
/* Recompute transform matrix of object in new coordinate system (from Z-Up to Y-Up). */
void create_transform_matrix(Object *obj, float transform_mat[4][4])
{
float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], mat[4][4];
float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
float loc[3], scale[3], euler[3];
zero_v3(loc);
zero_v3(scale);
zero_v3(euler);
unit_m3(rot);
unit_m3(rot_mat);
unit_m4(scale_mat);
unit_m4(transform_mat);
unit_m4(invmat);
unit_m4(mat);
/* get local matrix. */
if (obj->parent) {
invert_m4_m4(invmat, obj->parent->obmat);
mul_m4_m4m4(mat, invmat, obj->obmat);
}
else {
copy_m4_m4(mat, obj->obmat);
}
/* Compute rotation matrix. */
switch (obj->rotmode) {
case ROT_MODE_AXISANGLE:
{
/* Get euler angles from axis angle rotation. */
axis_angle_to_eulO(euler, ROT_MODE_XYZ, obj->rotAxis, obj->rotAngle);
/* Create X, Y, Z rotation matrices from euler angles. */
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
/* Concatenate rotation matrices. */
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
/* Extract location and scale from matrix. */
mat4_to_loc_rot_size(loc, rot, scale, mat);
break;
}
case ROT_MODE_QUAT:
{
float q[4];
copy_v4_v4(q, obj->quat);
/* Swap axis. */
q[2] = obj->quat[3];
q[3] = -obj->quat[2];
/* Compute rotation matrix from quaternion. */
quat_to_mat3(rot_mat, q);
/* Extract location and scale from matrix. */
mat4_to_loc_rot_size(loc, rot, scale, mat);
break;
}
case ROT_MODE_XYZ:
{
/* Extract location, rotation, and scale form matrix. */
mat4_to_loc_rot_size(loc, rot, scale, mat);
/* Get euler angles from rotation matrix. */
mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
/* Create X, Y, Z rotation matrices from euler angles. */
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
/* Concatenate rotation matrices. */
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
break;
}
case ROT_MODE_XZY:
{
/* Extract location, rotation, and scale form matrix. */
mat4_to_loc_rot_size(loc, rot, scale, mat);
/* Get euler angles from rotation matrix. */
mat3_to_eulO(euler, ROT_MODE_XZY, rot);
/* Create X, Y, Z rotation matrices from euler angles. */
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
/* Concatenate rotation matrices. */
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
break;
}
case ROT_MODE_YXZ:
{
/* Extract location, rotation, and scale form matrix. */
mat4_to_loc_rot_size(loc, rot, scale, mat);
/* Get euler angles from rotation matrix. */
mat3_to_eulO(euler, ROT_MODE_YXZ, rot);
/* Create X, Y, Z rotation matrices from euler angles. */
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
/* Concatenate rotation matrices. */
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
break;
}
case ROT_MODE_YZX:
{
/* Extract location, rotation, and scale form matrix. */
mat4_to_loc_rot_size(loc, rot, scale, mat);
/* Get euler angles from rotation matrix. */
mat3_to_eulO(euler, ROT_MODE_YZX, rot);
/* Create X, Y, Z rotation matrices from euler angles. */
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
/* Concatenate rotation matrices. */
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
break;
}
case ROT_MODE_ZXY:
{
/* Extract location, rotation, and scale form matrix. */
mat4_to_loc_rot_size(loc, rot, scale, mat);
/* Get euler angles from rotation matrix. */
mat3_to_eulO(euler, ROT_MODE_ZXY, rot);
/* Create X, Y, Z rotation matrices from euler angles. */
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
/* Concatenate rotation matrices. */
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
break;
}
case ROT_MODE_ZYX:
{
/* Extract location, rotation, and scale form matrix. */
mat4_to_loc_rot_size(loc, rot, scale, mat);
/* Get euler angles from rotation matrix. */
mat3_to_eulO(euler, ROT_MODE_ZYX, rot);
/* Create X, Y, Z rotation matrices from euler angles. */
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
/* Concatenate rotation matrices. */
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
break;
}
}
/* Add rotation matrix to transformation matrix. */
copy_m4_m3(transform_mat, rot_mat);
/* Add translation to transformation matrix. */
copy_zup_yup(transform_mat[3], loc);
/* Create scale matrix. */
scale_mat[0][0] = scale[0];
scale_mat[1][1] = scale[2];
scale_mat[2][2] = scale[1];
/* Add scale to transformation matrix. */
mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
}
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
{
if (!prop.valid()) {
return false;
}
return prop.getPropertyHeader(name) != NULL;
}

View File

@@ -0,0 +1,125 @@
/*
* ***** 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.
*
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __ABC_UTIL_H__
#define __ABC_UTIL_H__
#include <Alembic/Abc/All.h>
#include <Alembic/AbcGeom/All.h>
#ifdef _MSC_VER
# define ABC_INLINE static __forceinline
#else
# define ABC_INLINE static inline
#endif
using Alembic::Abc::chrono_t;
class ImportSettings;
struct ID;
struct Object;
std::string get_id_name(ID *id);
std::string get_id_name(Object *ob);
std::string get_object_dag_path_name(Object *ob, Object *dupli_parent);
bool object_selected(Object *ob);
bool parent_selected(Object *ob);
Imath::M44d convert_matrix(float mat[4][4]);
void create_transform_matrix(float r_mat[4][4]);
void create_transform_matrix(Object *obj, float transform_mat[4][4]);
void split(const std::string &s, const char delim, std::vector<std::string> &tokens);
template<class TContainer>
bool begins_with(const TContainer &input, const TContainer &match)
{
return input.size() >= match.size()
&& std::equal(match.begin(), match.end(), input.begin());
}
void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
const Alembic::AbcGeom::IXform &ixform, Object *ob,
float r_mat[4][4], float scale, bool has_alembic_parent = false);
template <typename Schema>
void get_min_max_time(const Schema &schema, chrono_t &min, chrono_t &max)
{
const Alembic::Abc::TimeSamplingPtr &time_samp = schema.getTimeSampling();
if (!schema.isConstant()) {
const size_t num_samps = schema.getNumSamples();
if (num_samps > 0) {
const chrono_t min_time = time_samp->getSampleTime(0);
min = std::min(min, min_time);
const chrono_t max_time = time_samp->getSampleTime(num_samps - 1);
max = std::max(max, max_time);
}
}
}
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name);
/* ************************** */
/* TODO(kevin): for now keeping these transformations hardcoded to make sure
* everything works properly, and also because Alembic is almost exclusively
* used in Y-up software, but eventually they'll be set by the user in the UI
* like other importers/exporters do, to support other axis. */
/* Copy from Y-up to Z-up. */
ABC_INLINE void copy_yup_zup(float zup[3], const float yup[3])
{
zup[0] = yup[0];
zup[1] = -yup[2];
zup[2] = yup[1];
}
ABC_INLINE void copy_yup_zup(short zup[3], const short yup[3])
{
zup[0] = yup[0];
zup[1] = -yup[2];
zup[2] = yup[1];
}
/* Copy from Z-up to Y-up. */
ABC_INLINE void copy_zup_yup(float yup[3], const float zup[3])
{
yup[0] = zup[0];
yup[1] = zup[2];
yup[2] = -zup[1];
}
ABC_INLINE void copy_zup_yup(short yup[3], const short zup[3])
{
yup[0] = zup[0];
yup[1] = zup[2];
yup[2] = -zup[1];
}
#endif /* __ABC_UTIL_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,67 @@
/*
* ***** 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.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Kevin Dietrich.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BKE_CACHEFILE_H__
#define __BKE_CACHEFILE_H__
/** \file BKE_cachefile.h
* \ingroup bke
*/
#ifdef __cplusplus
extern "C" {
#endif
struct CacheFile;
struct Main;
struct Scene;
void *BKE_cachefile_add(struct Main *bmain, const char *name);
void BKE_cachefile_init(struct CacheFile *cache_file);
void BKE_cachefile_free(struct CacheFile *cache_file);
struct CacheFile *BKE_cachefile_copy(struct Main *bmain, struct CacheFile *cache_file);
void BKE_cachefile_make_local(struct Main *bmain, struct CacheFile *cache_file, const bool lib_local);
void BKE_cachefile_reload(const struct Main *bmain, struct CacheFile *cache_file);
void BKE_cachefile_ensure_handle(const struct Main *bmain, struct CacheFile *cache_file);
void BKE_cachefile_update_frame(struct Main *bmain, struct Scene *scene, float ctime, const float fps);
bool BKE_cachefile_filepath_get(
const struct Main *bmain, const struct CacheFile *cache_file, float frame,
char r_filename[1024]);
float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps);
#ifdef __cplusplus
}
#endif
#endif /* __BKE_CACHEFILE_H__ */

View File

@@ -39,6 +39,7 @@ extern "C" {
struct ARegion;
struct bScreen;
struct CacheFile;
struct ListBase;
struct Main;
struct Object;
@@ -271,6 +272,8 @@ struct Text *CTX_data_edit_text(const bContext *C);
struct MovieClip *CTX_data_edit_movieclip(const bContext *C);
struct Mask *CTX_data_edit_mask(const bContext *C);
struct CacheFile *CTX_data_edit_cachefile(const bContext *C);
int CTX_data_selected_nodes(const bContext *C, ListBase *list);
struct EditBone *CTX_data_active_bone(const bContext *C);

View File

@@ -43,36 +43,36 @@ struct Main;
/* ------------ Grease-Pencil API ------------------ */
void free_gpencil_stroke(struct bGPDstroke *gps);
bool free_gpencil_strokes(struct bGPDframe *gpf);
void free_gpencil_frames(struct bGPDlayer *gpl);
void free_gpencil_layers(struct ListBase *list);
void free_gpencil_brushes(struct ListBase *list);
void free_gpencil_palettes(struct ListBase *list);
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
void BKE_gpencil_free_layers(struct ListBase *list);
void BKE_gpencil_free_brushes(struct ListBase *list);
void BKE_gpencil_free_palettes(struct ListBase *list);
void BKE_gpencil_free(struct bGPdata *gpd, bool free_palettes);
void gpencil_stroke_sync_selection(struct bGPDstroke *gps);
void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps);
struct bGPDframe *gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
struct bGPDframe *gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
struct bGPdata *gpencil_data_addnew(const char name[]);
struct bGPDframe *BKE_gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
struct bGPDframe *BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
struct bGPDlayer *BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
struct bGPdata *BKE_gpencil_data_addnew(const char name[]);
struct bGPDframe *gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
struct bGPDlayer *gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
struct bGPdata *gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
struct bGPDpalette *gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive);
struct bGPDpalette *gpencil_palette_duplicate(const struct bGPDpalette *palette_src);
struct bGPDpalettecolor *gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive);
struct bGPDpalette *BKE_gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive);
struct bGPDpalette *BKE_gpencil_palette_duplicate(const struct bGPDpalette *palette_src);
struct bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive);
struct bGPDbrush *gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive);
struct bGPDbrush *gpencil_brush_duplicate(const struct bGPDbrush *brush_src);
void gpencil_brush_init_presets(struct ToolSettings *ts);
struct bGPDbrush *BKE_gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive);
struct bGPDbrush *BKE_gpencil_brush_duplicate(const struct bGPDbrush *brush_src);
void BKE_gpencil_brush_init_presets(struct ToolSettings *ts);
/* Stroke and Fill - Alpha Visibility Threshold */
@@ -94,28 +94,28 @@ typedef enum eGP_GetFrame_Mode {
GP_GETFRAME_ADD_COPY = 2
} eGP_GetFrame_Mode;
struct bGPDframe *gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew);
struct bGPDframe *BKE_gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew);
struct bGPDframe *BKE_gpencil_layer_find_frame(struct bGPDlayer *gpl, int cframe);
bool gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
bool BKE_gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
struct bGPDlayer *gpencil_layer_getactive(struct bGPdata *gpd);
void gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
void gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
struct bGPDbrush *gpencil_brush_getactive(struct ToolSettings *ts);
void gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
void gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *palette);
struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts);
void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *palette);
struct bGPDpalette *gpencil_palette_getactive(struct bGPdata *gpd);
void gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
void gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette);
void gpencil_palette_change_strokes(struct bGPdata *gpd);
struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd);
void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
void BKE_gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette);
void BKE_gpencil_palette_change_strokes(struct bGPdata *gpd);
struct bGPDpalettecolor *gpencil_palettecolor_getactive(struct bGPDpalette *palette);
void gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active);
void gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor);
struct bGPDpalettecolor *gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name);
void gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname);
void gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name);
struct bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(struct bGPDpalette *palette);
void BKE_gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active);
void BKE_gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor);
struct bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name);
void BKE_gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname);
void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name);
#endif /* __BKE_GPENCIL_H__ */

View File

@@ -94,7 +94,7 @@ void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, const bool id_in_ma
struct ListBase *which_libbase(struct Main *mainlib, short type);
#define MAX_LIBARRAY 34
#define MAX_LIBARRAY 35
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
/* Main API */

View File

@@ -102,6 +102,7 @@ typedef struct Main {
ListBase movieclip;
ListBase mask;
ListBase linestyle;
ListBase cachefiles;
char id_tag_update[256];

View File

@@ -63,6 +63,8 @@ struct BVHTreeRay;
struct BVHTreeRayHit;
struct EdgeHash;
#define PARTICLE_COLLISION_MAX_COLLISIONS 10
#define PARTICLE_P ParticleData * pa; int p
#define LOOP_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++)
#define LOOP_EXISTING_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) if (!(pa->flag & PARS_UNEXIST))
@@ -205,8 +207,7 @@ typedef struct ParticleCollisionElement {
typedef struct ParticleCollision {
struct Object *current;
struct Object *hit;
struct Object *prev;
struct Object *skip;
struct Object *skip[PARTICLE_COLLISION_MAX_COLLISIONS+1];
struct Object *emitter;
struct CollisionModifierData *md; // collision modifier for current object;
@@ -218,7 +219,7 @@ typedef struct ParticleCollision {
float original_ray_length; //original length of co2-co1, needed for collision time evaluation
int prev_index;
int skip_count;
ParticleCollisionElement pce;

View File

@@ -81,6 +81,7 @@ set(SRC
intern/brush.c
intern/bullet.c
intern/bvhutils.c
intern/cachefile.c
intern/camera.c
intern/cdderivedmesh.c
intern/cloth.c
@@ -207,6 +208,7 @@ set(SRC
BKE_brush.h
BKE_bullet.h
BKE_bvhutils.h
BKE_cachefile.h
BKE_camera.h
BKE_ccg.h
BKE_cdderivedmesh.h
@@ -500,6 +502,13 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
if(WITH_ALEMBIC)
list(APPEND INC
../alembic
)
add_definitions(-DWITH_ALEMBIC)
endif()
if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
list(APPEND INC_SYS

View File

@@ -97,6 +97,7 @@ bool id_type_can_have_animdata(const short id_type)
case ID_MC:
case ID_MSK:
case ID_GD:
case ID_CF:
return true;
/* no AnimData */
@@ -1160,6 +1161,9 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u
/* grease pencil */
ANIMDATA_IDS_CB(mainptr->gpencil.first);
/* cache files */
ANIMDATA_IDS_CB(mainptr->cachefiles.first);
}
/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
@@ -1250,6 +1254,9 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const cha
/* grease pencil */
RENAMEFIX_ANIM_IDS(mainptr->gpencil.first);
/* cache files */
RENAMEFIX_ANIM_IDS(mainptr->cachefiles.first);
/* scenes */
RENAMEFIX_ANIM_NODETREE_IDS(mainptr->scene.first, Scene);
@@ -2873,6 +2880,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
/* grease pencil */
EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM);
/* cache files */
EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);
/* objects */
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets

View File

@@ -48,6 +48,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_brush_types.h"
#include "DNA_cachefile_types.h"
#include "DNA_image_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
@@ -653,6 +654,12 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data);
break;
}
case ID_CF:
{
CacheFile *cache_file = (CacheFile *)id;
rewrite_path_fixed(cache_file->filepath, visit_cb, absbase, bpath_user_data);
break;
}
default:
/* Nothing to do for other IDs that don't contain file paths. */
break;

View File

@@ -0,0 +1,173 @@
/*
* ***** 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.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Kevin Dietrich.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/cachefile.c
* \ingroup bke
*/
#include "DNA_anim_types.h"
#include "DNA_cachefile_types.h"
#include "DNA_scene_types.h"
#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_animsys.h"
#include "BKE_cachefile.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#ifdef WITH_ALEMBIC
# include "ABC_alembic.h"
#endif
void *BKE_cachefile_add(Main *bmain, const char *name)
{
CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name);
BKE_cachefile_init(cache_file);
return cache_file;
}
void BKE_cachefile_init(CacheFile *cache_file)
{
cache_file->handle = NULL;
cache_file->filepath[0] = '\0';
cache_file->override_frame = false;
cache_file->frame = 0.0f;
cache_file->is_sequence = false;
cache_file->scale = 1.0f;
}
/** Free (or release) any data used by this cachefile (does not free the cachefile itself). */
void BKE_cachefile_free(CacheFile *cache_file)
{
BKE_animdata_free((ID *)cache_file, false);
#ifdef WITH_ALEMBIC
ABC_free_handle(cache_file->handle);
#endif
BLI_freelistN(&cache_file->object_paths);
}
CacheFile *BKE_cachefile_copy(Main *bmain, CacheFile *cache_file)
{
CacheFile *new_cache_file = BKE_libblock_copy(bmain, &cache_file->id);
new_cache_file->handle = NULL;
BLI_listbase_clear(&cache_file->object_paths);
BKE_id_copy_ensure_local(bmain, &cache_file->id, &new_cache_file->id);
return new_cache_file;
}
void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib_local)
{
BKE_id_make_local_generic(bmain, &cache_file->id, true, lib_local);
}
void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file)
{
char filepath[FILE_MAX];
BLI_strncpy(filepath, cache_file->filepath, sizeof(filepath));
BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &cache_file->id));
#ifdef WITH_ALEMBIC
if (cache_file->handle) {
ABC_free_handle(cache_file->handle);
}
cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
#endif
}
void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
{
if (cache_file->handle == NULL) {
BKE_cachefile_reload(bmain, cache_file);
}
}
void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps)
{
CacheFile *cache_file;
char filename[FILE_MAX];
for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
/* Execute drivers only, as animation has already been done. */
BKE_animsys_evaluate_animdata(scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
if (!cache_file->is_sequence) {
continue;
}
const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
#ifdef WITH_ALEMBIC
ABC_free_handle(cache_file->handle);
cache_file->handle = ABC_create_handle(filename, NULL);
#endif
}
}
}
bool BKE_cachefile_filepath_get(
const Main *bmain, const CacheFile *cache_file, float frame,
char r_filepath[FILE_MAX])
{
BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
int fframe;
int frame_len;
if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
char ext[32];
BLI_path_frame_strip(r_filepath, true, ext);
BLI_path_frame(r_filepath, frame, frame_len);
BLI_ensure_extension(r_filepath, FILE_MAX, ext);
/* TODO(kevin): store sequence range? */
return BLI_exists(r_filepath);
}
return true;
}
float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const float fps)
{
const float frame = (cache_file->override_frame ? cache_file->frame : time);
return cache_file->is_sequence ? frame : frame / fps;
}

View File

@@ -3402,7 +3402,7 @@ void CDDM_calc_edges(DerivedMesh *dm)
BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
j = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
if (j == 0) {
if (j == 0 || !eindex) {
med->flag = ME_EDGEDRAW | ME_EDGERENDER;
*index = ORIGINDEX_NONE;
}

View File

@@ -46,6 +46,7 @@
#include "BLT_translation.h"
#include "DNA_armature_types.h"
#include "DNA_cachefile_types.h"
#include "DNA_constraint_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -63,6 +64,7 @@
#include "BKE_anim.h" /* for the curve calculation part */
#include "BKE_armature.h"
#include "BKE_bvhutils.h"
#include "BKE_cachefile.h"
#include "BKE_camera.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
@@ -86,6 +88,10 @@
# include "BPY_extern.h"
#endif
#ifdef WITH_ALEMBIC
# include "ABC_alembic.h"
#endif
/* ---------------------------------------------------------------------------- */
/* Useful macros for testing various common flag combinations */
@@ -4333,6 +4339,73 @@ static bConstraintTypeInfo CTI_OBJECTSOLVER = {
objectsolver_evaluate /* evaluate */
};
/* ----------- Transform Cache ------------- */
static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
bTransformCacheConstraint *data = con->data;
func(con, (ID **)&data->cache_file, false, userdata);
}
static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
#ifdef WITH_ALEMBIC
bTransformCacheConstraint *data = con->data;
Scene *scene = cob->scene;
const float frame = BKE_scene_frame_get(scene);
const float time = BKE_cachefile_time_offset(data->cache_file, frame, FPS);
CacheFile *cache_file = data->cache_file;
BKE_cachefile_ensure_handle(G.main, cache_file);
ABC_get_transform(cache_file->handle, cob->ob, data->object_path,
cob->matrix, time, cache_file->scale);
#else
UNUSED_VARS(con, cob);
#endif
UNUSED_VARS(targets);
}
static void transformcache_copy(bConstraint *con, bConstraint *srccon)
{
bTransformCacheConstraint *src = srccon->data;
bTransformCacheConstraint *dst = con->data;
BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path));
dst->cache_file = src->cache_file;
if (dst->cache_file) {
id_us_plus(&dst->cache_file->id);
}
}
static void transformcache_free(bConstraint *con)
{
bTransformCacheConstraint *data = con->data;
if (data->cache_file) {
id_us_min(&data->cache_file->id);
}
}
static bConstraintTypeInfo CTI_TRANSFORM_CACHE = {
CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */
sizeof(bTransformCacheConstraint), /* size */
"Transform Cache", /* name */
"bTransformCacheConstraint", /* struct name */
transformcache_free, /* free data */
transformcache_id_looper, /* id looper */
transformcache_copy, /* copy data */
NULL, /* new data */
NULL, /* get constraint targets */
NULL, /* flush constraint targets */
NULL, /* get target matrix */
transformcache_evaluate /* evaluate */
};
/* ************************* Constraints Type-Info *************************** */
/* All of the constraints api functions use bConstraintTypeInfo structs to carry out
* and operations that involve constraint specific code.
@@ -4374,6 +4447,7 @@ static void constraints_init_typeinfo(void)
constraintsTypeInfo[26] = &CTI_FOLLOWTRACK; /* Follow Track Constraint */
constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */
constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */
constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */
}
/* This function should be used for getting the appropriate type-info when only

View File

@@ -1067,6 +1067,11 @@ struct EditBone *CTX_data_active_bone(const bContext *C)
return ctx_data_pointer_get(C, "active_bone");
}
struct CacheFile *CTX_data_edit_cachefile(const bContext *C)
{
return ctx_data_pointer_get(C, "edit_cachefile");
}
int CTX_data_selected_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_bones", list);

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