Freestyle: Added preliminary support for textured strokes in Cycles.

Now the shader node tree of a line style ID datablock is used to define textures
as well as their mapping and influence.

TODO: Textures alpha channel mapping and influence.
TODO: Blend mode in the Output Line Style shader node.
This commit is contained in:
Tamito Kajiyama
2014-07-16 00:21:27 +09:00
parent 4677684cfd
commit fc85446c50
13 changed files with 225 additions and 110 deletions

View File

@@ -892,9 +892,10 @@ void Controller::InsertStyleModule(unsigned index, const char *iFileName)
_Canvas->InsertStyleModule(index, sm);
}
void Controller::InsertStyleModule(unsigned index, const char *iName, struct Text *iText)
void Controller::InsertStyleModule(unsigned index, const char *iName, struct FreestyleLineStyle *iLineStyle,
struct Text *iText)
{
StyleModule *sm = new BlenderStyleModule(iText, iName, _inter);
StyleModule *sm = new BlenderStyleModule(iText, iLineStyle, iName, _inter);
_Canvas->InsertStyleModule(index, sm);
}

View File

@@ -89,7 +89,8 @@ public:
Render *RenderStrokes(Render *re, bool render);
void SwapStyleModules(unsigned i1, unsigned i2);
void InsertStyleModule(unsigned index, const char *iFileName);
void InsertStyleModule(unsigned index, const char *iName, struct Text *iText);
void InsertStyleModule(unsigned index, const char *iName, struct FreestyleLineStyle *iLineStyle,
struct Text *iText);
void AddStyleModule(const char *iFileName);
void RemoveStyleModule(unsigned index);
void ReloadStyleModule(unsigned index, const char * iFileName);

View File

@@ -34,6 +34,7 @@ extern "C" {
#include "DNA_camera_types.h"
#include "DNA_listBase.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_mesh_types.h"
@@ -60,8 +61,6 @@ extern "C" {
#include <limits.h>
#define USE_CYCLES_FOR_STROKE_RENDERING 1
namespace Freestyle {
BlenderStrokeRenderer::BlenderStrokeRenderer(bContext *C, Render *re, int render_count) : StrokeRenderer()
@@ -107,11 +106,7 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(bContext *C, Render *re, int render
freestyle_scene->r.filtertype = old_scene->r.filtertype;
freestyle_scene->r.gauss = old_scene->r.gauss;
freestyle_scene->r.dither_intensity = old_scene->r.dither_intensity;
#ifdef USE_CYCLES_FOR_STROKE_RENDERING
BLI_strncpy(freestyle_scene->r.engine, old_scene->r.engine, sizeof(freestyle_scene->r.engine));
#else
BLI_strncpy(freestyle_scene->r.engine, "BLENDER_RENDER", sizeof(freestyle_scene->r.engine));
#endif
freestyle_scene->r.im_format.planes = R_IMF_PLANES_RGBA;
freestyle_scene->r.im_format.imtype = R_IMF_IMTYPE_PNG;
BKE_scene_disable_color_management(freestyle_scene);
@@ -219,111 +214,123 @@ unsigned int BlenderStrokeRenderer::get_stroke_mesh_id(void) const
return mesh_id;
}
Material* BlenderStrokeRenderer::GetStrokeMaterial(bContext *C, Main *bmain, Scene *scene)
Material* BlenderStrokeRenderer::GetStrokeShader(bContext *C, Main *bmain, FreestyleLineStyle *linestyle)
{
Material *ma = BKE_material_add(bmain, "stroke_material");
Material *ma = BKE_material_add(bmain, "stroke_shader");
bNodeTree *ntree;
bNode *output_linestyle = NULL;
bNodeSocket *fromsock, *tosock;
PointerRNA fromptr, toptr;
ma->mode |= MA_VERTEXCOLP;
ma->mode |= MA_TRANSP;
ma->mode |= MA_SHLESS;
ma->vcol_alpha = 1;
cout << "linestyle " << linestyle << " nodetree " << linestyle->nodetree << " use_nodes " << linestyle->use_nodes << endl;
if (linestyle && linestyle->use_nodes && linestyle->nodetree) {
// make a copy of linestyle->nodetree
ntree = ntreeCopyTree_ex(linestyle->nodetree, bmain, true);
if (BKE_scene_use_new_shading_nodes(scene)) {
bNodeTree *ntree;
bNodeSocket *fromsock, *tosock;
ntree = ntreeAddTree(NULL, "stroke_material", "ShaderNodeTree");
ma->nodetree = ntree;
ma->use_nodes = 1;
bNode *input_attribute = nodeAddStaticNode(C, ntree, SH_NODE_ATTRIBUTE);
input_attribute->locx = 0.0f;
input_attribute->locy = 0.0f;
NodeShaderAttribute *storage = (NodeShaderAttribute *)input_attribute->storage;
BLI_strncpy(storage->name, "Col", sizeof(storage->name));
bNode *shader_emission = nodeAddStaticNode(C, ntree, SH_NODE_EMISSION);
shader_emission->locx = 200.0f;
shader_emission->locy = 0.0f;
bNode *input_light_path = nodeAddStaticNode(C, ntree, SH_NODE_LIGHT_PATH);
input_light_path->locx = 200.0f;
input_light_path->locy = 300.0f;
bNode *shader_mix = nodeAddStaticNode(C, ntree, SH_NODE_MIX_SHADER);
shader_mix->locx = 400.0f;
shader_mix->locy = 100.0f;
bNode *output_material = nodeAddStaticNode(C, ntree, SH_NODE_OUTPUT_MATERIAL);
output_material->locx = 600.0f;
output_material->locy = 100.0f;
fromsock = (bNodeSocket *)BLI_findlink(&input_attribute->outputs, 0);
tosock = (bNodeSocket *)BLI_findlink(&shader_emission->inputs, 0);
nodeAddLink(ntree, input_attribute, fromsock, shader_emission, tosock);
fromsock = (bNodeSocket *)BLI_findlink(&shader_emission->outputs, 0);
tosock = (bNodeSocket *)BLI_findlink(&shader_mix->inputs, 2);
nodeAddLink(ntree, shader_emission, fromsock, shader_mix, tosock);
fromsock = (bNodeSocket *)BLI_findlink(&input_light_path->outputs, 0);
tosock = (bNodeSocket *)BLI_findlink(&shader_mix->inputs, 0);
nodeAddLink(ntree, input_light_path, fromsock, shader_mix, tosock);
fromsock = (bNodeSocket *)BLI_findlink(&shader_mix->outputs, 0);
tosock = (bNodeSocket *)BLI_findlink(&output_material->inputs, 0);
nodeAddLink(ntree, shader_mix, fromsock, output_material, tosock);
nodeSetActive(ntree, shader_mix);
ntreeUpdateTree(bmain, ntree);
// find the active Output Line Style node
for (bNode *node = (bNode *)ntree->nodes.first; node; node = node->next) {
if (node->type == SH_NODE_OUTPUT_LINESTYLE && (node->flag & NODE_DO_OUTPUT)) {
output_linestyle = node;
cout << "output found" << endl;
break;
}
}
}
else {
ntree = ntreeAddTree(NULL, "stroke_shader", "ShaderNodeTree");
}
ma->nodetree = ntree;
ma->use_nodes = 1;
bNode *input_attribute = nodeAddStaticNode(C, ntree, SH_NODE_ATTRIBUTE);
input_attribute->locx = 0.0f;
input_attribute->locy = -200.0f;
NodeShaderAttribute *storage = (NodeShaderAttribute *)input_attribute->storage;
BLI_strncpy(storage->name, "Col", sizeof(storage->name));
bNode *color_mix_rgb = nodeAddStaticNode(C, ntree, SH_NODE_MIX_RGB);
color_mix_rgb->custom1 = MA_RAMP_BLEND; // Mix
color_mix_rgb->locx = 200.0f;
color_mix_rgb->locy = -200.0f;
tosock = (bNodeSocket *)BLI_findlink(&color_mix_rgb->inputs, 0); // Fac
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr);
RNA_float_set(&toptr, "default_value", 1.0f);
bNode *shader_emission = nodeAddStaticNode(C, ntree, SH_NODE_EMISSION);
shader_emission->locx = 400.0f;
shader_emission->locy = -200.0f;
bNode *input_light_path = nodeAddStaticNode(C, ntree, SH_NODE_LIGHT_PATH);
input_light_path->locx = 400.0f;
input_light_path->locy = 100.0f;
bNode *shader_mix = nodeAddStaticNode(C, ntree, SH_NODE_MIX_SHADER);
shader_mix->locx = 600.0f;
shader_mix->locy = 100.0f;
bNode *output_material = nodeAddStaticNode(C, ntree, SH_NODE_OUTPUT_MATERIAL);
output_material->locx = 800.0f;
output_material->locy = 100.0f;
fromsock = (bNodeSocket *)BLI_findlink(&input_attribute->outputs, 0); // Color
tosock = (bNodeSocket *)BLI_findlink(&color_mix_rgb->inputs, 2); // Color2
nodeAddLink(ntree, input_attribute, fromsock, color_mix_rgb, tosock);
fromsock = (bNodeSocket *)BLI_findlink(&color_mix_rgb->outputs, 0); // Color
tosock = (bNodeSocket *)BLI_findlink(&shader_emission->inputs, 0); // Color
nodeAddLink(ntree, color_mix_rgb, fromsock, shader_emission, tosock);
fromsock = (bNodeSocket *)BLI_findlink(&shader_emission->outputs, 0); // Emission
tosock = (bNodeSocket *)BLI_findlink(&shader_mix->inputs, 2); // Shader (second)
nodeAddLink(ntree, shader_emission, fromsock, shader_mix, tosock);
fromsock = (bNodeSocket *)BLI_findlink(&input_light_path->outputs, 0); // In Camera Ray
tosock = (bNodeSocket *)BLI_findlink(&shader_mix->inputs, 0); // Fac
nodeAddLink(ntree, input_light_path, fromsock, shader_mix, tosock);
fromsock = (bNodeSocket *)BLI_findlink(&shader_mix->outputs, 0); // Shader
tosock = (bNodeSocket *)BLI_findlink(&output_material->inputs, 0); // Surface
nodeAddLink(ntree, shader_mix, fromsock, output_material, tosock);
if (output_linestyle) {
bNodeSocket *outsock;
bNodeLink *link;
outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 0); // Color
link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
if (link) {
tosock = (bNodeSocket *)BLI_findlink(&color_mix_rgb->inputs, 1); // Color1
nodeAddLink(ntree, link->fromnode, link->fromsock, color_mix_rgb, tosock);
}
outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 1); // Color Fac
tosock = (bNodeSocket *)BLI_findlink(&color_mix_rgb->inputs, 0); // Fac
link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
if (link) {
nodeAddLink(ntree, link->fromnode, link->fromsock, color_mix_rgb, tosock);
}
else {
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock, &fromptr);
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr);
RNA_float_set(&toptr, "default_value", RNA_float_get(&fromptr, "default_value"));
}
#if 0 // TODO
outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 2); // Alpha
outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 3); // Alpha Fac
#endif
}
nodeSetActive(ntree, shader_mix);
ntreeUpdateTree(bmain, ntree);
return ma;
}
void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
{
bool has_mat = false;
int a = 0;
// Look for a good existing material
for (Link *lnk = (Link *)freestyle_bmain->mat.first; lnk; lnk = lnk->next) {
Material *ma = (Material*) lnk;
bool texs_are_good = true;
// as soon as textures differ it's not the right one
for (int a = 0; a < MAX_MTEX; a++) {
if (ma->mtex[a] != iStrokeRep->getMTex(a)) {
texs_are_good = false;
break;
}
}
if (texs_are_good) {
iStrokeRep->setMaterial(ma);
has_mat = true;
break; // if textures are good, no need to search anymore
}
}
// If still no material, create one
if (!has_mat) {
Material *ma = BlenderStrokeRenderer::GetStrokeMaterial(_context, freestyle_bmain, freestyle_scene);
// Textures
//for (int a = 0; a < MAX_MTEX; a++) {
while (iStrokeRep->getMTex(a)) {
ma->mtex[a] = (MTex *)iStrokeRep->getMTex(a);
// We'll generate both with tips and without tips
// coordinates, on two different UV layers.
if (ma->mtex[a]->texflag & MTEX_TIPS) {
BLI_strncpy(ma->mtex[a]->uvname, "along_stroke_tips", sizeof(ma->mtex[a]->uvname));
}
else {
BLI_strncpy(ma->mtex[a]->uvname, "along_stroke", sizeof(ma->mtex[a]->uvname));
}
a++;
}
if (BKE_scene_use_new_shading_nodes(freestyle_scene)) {
Material *ma = BlenderStrokeRenderer::GetStrokeShader(_context, freestyle_bmain, iStrokeRep->getLineStyle());
if (strcmp(freestyle_scene->r.engine, "CYCLES") == 0) {
PointerRNA scene_ptr;
@@ -334,6 +341,56 @@ void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
iStrokeRep->setMaterial(ma);
}
else {
bool has_mat = false;
int a = 0;
// Look for a good existing material
for (Link *lnk = (Link *)freestyle_bmain->mat.first; lnk; lnk = lnk->next) {
Material *ma = (Material*)lnk;
bool texs_are_good = true;
// as soon as textures differ it's not the right one
for (int a = 0; a < MAX_MTEX; a++) {
if (ma->mtex[a] != iStrokeRep->getMTex(a)) {
texs_are_good = false;
break;
}
}
if (texs_are_good) {
iStrokeRep->setMaterial(ma);
has_mat = true;
break; // if textures are good, no need to search anymore
}
}
// If still no material, create one
if (!has_mat) {
Material *ma = BKE_material_add(freestyle_bmain, "stroke_material");
ma->mode |= MA_VERTEXCOLP;
ma->mode |= MA_TRANSP;
ma->mode |= MA_SHLESS;
ma->vcol_alpha = 1;
// Textures
//for (int a = 0; a < MAX_MTEX; a++) {
while (iStrokeRep->getMTex(a)) {
ma->mtex[a] = (MTex *)iStrokeRep->getMTex(a);
// We'll generate both with tips and without tips
// coordinates, on two different UV layers.
if (ma->mtex[a]->texflag & MTEX_TIPS) {
BLI_strncpy(ma->mtex[a]->uvname, "along_stroke_tips", sizeof(ma->mtex[a]->uvname));
}
else {
BLI_strncpy(ma->mtex[a]->uvname, "along_stroke", sizeof(ma->mtex[a]->uvname));
}
a++;
}
iStrokeRep->setMaterial(ma);
}
}
RenderStrokeRepBasic(iStrokeRep);
}

View File

@@ -34,6 +34,7 @@ struct Object;
struct Render;
struct Scene;
struct bContext;
struct FreestyleLineStyle;
}
namespace Freestyle {
@@ -52,7 +53,7 @@ public:
Render *RenderScene(Render *re, bool render);
static Material* GetStrokeMaterial(bContext *C, Main *bmain, Scene *scene);
static Material* GetStrokeShader(bContext *C, Main *bmain, FreestyleLineStyle *linestyle);
protected:
Main *freestyle_bmain;

View File

@@ -33,6 +33,8 @@ extern "C" {
#include "BKE_library.h"
#include "BKE_text.h"
#include "BLI_utildefines.h"
struct FreestyleLineStyle;
}
namespace Freestyle {
@@ -40,15 +42,25 @@ namespace Freestyle {
class BlenderStyleModule : public StyleModule
{
public:
BlenderStyleModule(struct Text *text, const string &name, Interpreter *inter) : StyleModule(name, inter)
BlenderStyleModule(struct Text *text, struct FreestyleLineStyle *linestyle, const string &name,
Interpreter *inter) : StyleModule(name, inter)
{
_text = text;
_linestyle = linestyle;
}
virtual ~BlenderStyleModule()
{
}
virtual StrokeLayer *execute()
{
StrokeLayer *sl = StyleModule::execute();
sl->SetLineStyle(_linestyle);
return sl;
}
protected:
virtual int interpret()
{
@@ -59,6 +71,7 @@ protected:
private:
struct Text *_text;
struct FreestyleLineStyle *_linestyle;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BlenderStyleModule")

View File

@@ -328,7 +328,7 @@ static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl)
cout << " (" << module_conf->script->name << ")";
cout << endl;
}
controller->InsertStyleModule(layer_count, id_name, module_conf->script);
controller->InsertStyleModule(layer_count, id_name, NULL, module_conf->script);
controller->toggleLayer(layer_count, true);
layer_count++;
}
@@ -369,7 +369,7 @@ static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl)
(lineset->linestyle ? (lineset->linestyle->id.name + 2) : "<NULL>") << endl;
}
Text *text = create_lineset_handler(bmain, srl->name, lineset->name);
controller->InsertStyleModule(layer_count, lineset->name, text);
controller->InsertStyleModule(layer_count, lineset->name, lineset->linestyle, text);
controller->toggleLayer(layer_count, true);
if (!(lineset->selection & FREESTYLE_SEL_EDGE_TYPES) || !lineset->edge_types) {
++use_ridges_and_valleys;
@@ -736,7 +736,12 @@ void FRS_move_active_lineset_down(FreestyleConfig *config)
Material *FRS_create_stroke_material(bContext *C, Main *bmain, Scene *scene)
{
return BlenderStrokeRenderer::GetStrokeMaterial(C, bmain, scene);
FreestyleLineStyle *linestyle = CTX_data_linestyle_from_scene(scene);
if (!linestyle) {
cout << "FRS_create_stroke_material: No active line style in the current scene" << endl;
}
return BlenderStrokeRenderer::GetStrokeShader(C, bmain, linestyle);
}
} // extern "C"

View File

@@ -774,6 +774,13 @@ void Stroke::ScaleThickness(float iFactor)
}
}
void Stroke::SetLineStyle(struct FreestyleLineStyle *iLineStyle)
{
if (!_rep)
_rep = new StrokeRep(this);
_rep->setLineStyle(iLineStyle);
}
void Stroke::Render(const StrokeRenderer *iRenderer)
{
if (!_rep)

View File

@@ -45,6 +45,8 @@
extern "C" {
#include "DNA_material_types.h"
struct FreestyleLineStyle;
}
#ifndef MAX_MTEX
@@ -623,6 +625,7 @@ public:
/* Render method */
void ScaleThickness(float iFactor);
void SetLineStyle(struct FreestyleLineStyle *iLineStyle);
void Render(const StrokeRenderer *iRenderer);
void RenderBasic(const StrokeRenderer *iRenderer);

View File

@@ -43,6 +43,13 @@ void StrokeLayer::ScaleThickness(float iFactor)
}
}
void StrokeLayer::SetLineStyle(struct FreestyleLineStyle *iLineStyle)
{
for (StrokeLayer::stroke_container::iterator s = _strokes.begin(), send = _strokes.end(); s != send; ++s) {
(*s)->SetLineStyle(iLineStyle);
}
}
void StrokeLayer::Render(const StrokeRenderer *iRenderer)
{
for (StrokeLayer::stroke_container::iterator s = _strokes.begin(), send = _strokes.end(); s != send; ++s) {

View File

@@ -34,6 +34,10 @@
#include "MEM_guardedalloc.h"
#endif
extern "C" {
struct FreestyleLineStyle;
}
namespace Freestyle {
class Stroke;
@@ -63,6 +67,7 @@ public:
/*! Render method */
void ScaleThickness(float iFactor);
void SetLineStyle(struct FreestyleLineStyle *iLineStyle);
void Render(const StrokeRenderer *iRenderer);
void RenderBasic(const StrokeRenderer *iRenderer);

View File

@@ -704,6 +704,7 @@ StrokeRep::StrokeRep()
{
_stroke = 0;
_strokeType = Stroke::OPAQUE_MEDIUM;
_lineStyle = NULL;
_textureStep = 1.0;
for (int a = 0; a < MAX_MTEX; a++) {
_mtex[a] = NULL;
@@ -724,6 +725,7 @@ StrokeRep::StrokeRep(Stroke *iStroke)
{
_stroke = iStroke;
_strokeType = iStroke->getMediumType();
_lineStyle = NULL;
_textureId = iStroke->getTextureId();
_textureStep = iStroke->getTextureStep();
for (int a = 0; a < MAX_MTEX; a++) {
@@ -757,6 +759,7 @@ StrokeRep::StrokeRep(const StrokeRep& iBrother)
_strokeType = iBrother._strokeType;
_textureId = iBrother._textureId;
_textureStep = iBrother._textureStep;
_lineStyle = iBrother._lineStyle;
for (int a = 0; a < MAX_MTEX; a++) {
if (iBrother._mtex[a]) {
_mtex[a] = iBrother._mtex[a];

View File

@@ -38,6 +38,7 @@
extern "C" {
#include "DNA_material_types.h" // for MAX_MTEX
struct FreestyleLineStyle;
}
namespace Freestyle {
@@ -186,6 +187,7 @@ protected:
float _textureStep;
MTex *_mtex[MAX_MTEX];
Material *_material;
FreestyleLineStyle *_lineStyle;
// float _averageTextureAlpha;
@@ -222,6 +224,11 @@ public:
return _material;
}
inline FreestyleLineStyle *getLineStyle() const
{
return _lineStyle;
}
inline vector<Strip*>& getStrips()
{
return _strips;
@@ -258,6 +265,11 @@ public:
_mtex[idx] = mtex_ptr;
}*/
inline void setLineStyle(FreestyleLineStyle *iLineStyle)
{
_lineStyle = iLineStyle;
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:StrokeRep")
#endif

View File

@@ -62,7 +62,7 @@ public:
virtual ~StyleModule() {}
StrokeLayer *execute()
virtual StrokeLayer *execute()
{
if (!_inter) {
cerr << "Error: no interpreter was found to execute the script" << endl;