Support multiple tangents for BI render & viewport

Normal Map node support for GLSL mode and the internal render (multiple tangents support).

The Normal Map node is a useful node which is present in the Cycles render.
It makes it possible to use normal mapping without additional material node in a node tree.
This patch implements Normal Map node for GLSL mode and the internal render.

Previously only the active UV layer was used to calculate tangents.
This commit is contained in:
Alexander Romanov 2016-04-26 18:43:02 +10:00 committed by Campbell Barton
parent 98babfa2b8
commit 5abae51a6e
Notes: blender-bot 2023-02-14 10:48:33 +01:00
Referenced by commit 7f682dd704, Fix T49226: Incorrect Material viewport shading of Cycles Normal Map node in Edit mode for an object with Array modifier
Referenced by issue #51746, Normal map handling regression in 2.78c BI
Referenced by issue #49499, Very slow subsurface with material mode in viewport and before rendering.
Referenced by issue #48757, blender internal tangent normal bake error
22 changed files with 751 additions and 341 deletions

View File

@ -160,6 +160,7 @@ shader_node_categories = [
NodeItem("ShaderNodeMapping"),
NodeItem("ShaderNodeVectorCurve"),
NodeItem("ShaderNodeVectorTransform"),
NodeItem("ShaderNodeNormalMap"),
]),
ShaderOldNodeCategory("SH_CONVERTOR", "Converter", items=[
NodeItem("ShaderNodeValToRGB"),

View File

@ -71,6 +71,7 @@
* as it is and stick with using BMesh and CDDM.
*/
#include "DNA_defs.h"
#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
@ -200,6 +201,8 @@ struct DerivedMesh {
/* use for converting to BMesh which doesn't store bevel weight and edge crease by default */
char cd_flag;
char tangent_mask; /* which tangent layers are calculated */
/** Calculate vert and face normals */
void (*calcNormals)(DerivedMesh *dm);
@ -210,7 +213,9 @@ struct DerivedMesh {
void (*calcLoopNormalsSpaceArray)(DerivedMesh *dm, const bool use_split_normals, const float split_angle,
struct MLoopNorSpaceArray *r_lnors_spacearr);
void (*calcLoopTangents)(DerivedMesh *dm);
void (*calcLoopTangents)(
DerivedMesh *dm, bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME], int tangent_names_count);
/** Recalculates mesh tessellation */
void (*recalcTessellation)(DerivedMesh *dm);
@ -763,7 +768,7 @@ typedef struct DMVertexAttribs {
struct {
float (*array)[4];
int em_offset, gl_index;
} tang;
} tang[MAX_MTFACE];
struct {
float (*array)[3];
@ -779,7 +784,20 @@ void DM_vertex_attributes_from_gpu(
void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop);
void DM_calc_loop_tangents(DerivedMesh *dm);
void DM_calc_tangents_names_from_gpu(
const struct GPUVertexAttribs *gattribs,
char (*tangent_names)[MAX_NAME], int *tangent_names_count);
void DM_add_named_tangent_layer_for_uv(
CustomData *uv_data, CustomData *tan_data, int numLoopData,
const char *layer_name);
void DM_calc_loop_tangents_step_0(
const CustomData *loopData, bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME], int tangent_names_count,
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
char *ract_uv_name, char *rren_uv_name, char *rtangent_mask);
void DM_calc_loop_tangents(
DerivedMesh *dm, bool calc_active_tangent, const char (*tangent_names)[MAX_NAME],
int tangent_names_count);
void DM_calc_auto_bump_scale(DerivedMesh *dm);
/** Set object's bounding box based on DerivedMesh min/max data */

View File

@ -293,8 +293,9 @@ void BKE_mesh_loops_to_mface_corners(
void BKE_mesh_loops_to_tessdata(
struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, struct MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces);
void BKE_mesh_tangent_loops_to_tessdata(struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces);
void BKE_mesh_tangent_loops_to_tessdata(
struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces, const char *layer_name);
int BKE_mesh_recalc_tessellation(
struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata,
struct MVert *mvert,

View File

@ -49,6 +49,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_linklist.h"
#include "BLI_task.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_editmesh.h"
@ -595,50 +596,49 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
int mf_idx;
int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
unsigned int (*loopindex)[4];
unsigned int (*loopindex)[4] = NULL;
/* Should never occure, but better abort than segfault! */
if (!polyindex)
return;
if (generate) {
for (int i = 0; i < ldata->totlayer; i++) {
if (ldata->layers[i].type == CD_TANGENT) {
CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[i].name);
for (int j = 0; j < ldata->totlayer; j++) {
if (ldata->layers[j].type == CD_TANGENT) {
CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[j].name);
CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
if (!loopindex) {
loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__);
for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
const int mf_len = mf->v4 ? 4 : 3;
unsigned int *ml_idx = loopindex[mf_idx];
/* Find out loop indices. */
/* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
for (int i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v);
if (tf_v != -1) {
ml_idx[tf_v] = i;
not_done--;
}
}
}
}
/* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
* Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
* 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
* So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
*/
BKE_mesh_tangent_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface, ldata->layers[j].name);
}
}
CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
if (loopindex)
MEM_freeN(loopindex);
BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true));
}
BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true));
loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__);
for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
const int mf_len = mf->v4 ? 4 : 3;
unsigned int *ml_idx = loopindex[mf_idx];
int i, not_done;
/* Find out loop indices. */
/* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
for (i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v);
if (tf_v != -1) {
ml_idx[tf_v] = i;
not_done--;
}
}
}
/* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
* Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
* 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
* So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
*/
BKE_mesh_tangent_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface);
MEM_freeN(loopindex);
if (G.debug & G_DEBUG)
printf("%s: Updated tessellated tangents of dm %p\n", __func__, dm);
}
@ -3207,96 +3207,28 @@ finally:
pRes[3] = fSign;
}
void DM_calc_loop_tangents(DerivedMesh *dm)
void DM_calc_tangents_names_from_gpu(
const GPUVertexAttribs *gattribs,
char (*tangent_names)[MAX_NAME], int *r_tangent_names_count)
{
/* mesh vars */
const MLoopTri *looptri;
MVert *mvert;
MLoopUV *mloopuv;
MPoly *mpoly;
MLoop *mloop;
float (*orco)[3] = NULL, (*tangent)[4];
int /* totvert, */ totface;
float (*fnors)[3];
float (*tlnors)[3];
if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) != -1)
return;
fnors = dm->getPolyDataArray(dm, CD_NORMAL);
/* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
* have to check this is valid...
*/
tlnors = dm->getLoopDataArray(dm, CD_NORMAL);
/* check we have all the needed layers */
/* totvert = dm->getNumVerts(dm); */ /* UNUSED */
looptri = dm->getLoopTriArray(dm);
totface = dm->getNumLoopTri(dm);
mvert = dm->getVertArray(dm);
mpoly = dm->getPolyArray(dm);
mloop = dm->getLoopArray(dm);
mloopuv = dm->getLoopDataArray(dm, CD_MLOOPUV);
if (!mloopuv) {
orco = dm->getVertDataArray(dm, CD_ORCO);
if (!orco)
return;
}
/* create tangent layer */
DM_add_loop_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
tangent = DM_get_loop_data_layer(dm, CD_TANGENT);
#ifdef USE_LOOPTRI_DETECT_QUADS
int num_face_as_quad_map;
int *face_as_quad_map = NULL;
/* map faces to quads */
if (totface != dm->getNumPolys(dm)) {
/* over alloc, since we dont know how many ngon or quads we have */
/* map fake face index to looptri */
face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
int i, j;
for (i = 0, j = 0; j < totface; i++, j++) {
face_as_quad_map[i] = j;
/* step over all quads */
if (mpoly[looptri[j].poly].totloop == 4) {
j++; /* skips the nest looptri */
}
int count = 0;
for (int b = 0; b < gattribs->totlayer; b++) {
if (gattribs->layer[b].type == CD_TANGENT) {
strcpy(tangent_names[count++], gattribs->layer[b].name);
}
num_face_as_quad_map = i;
}
else {
num_face_as_quad_map = totface;
}
#endif
*r_tangent_names_count = count;
}
static void DM_calc_loop_tangents_thread(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
struct SGLSLMeshToTangent *mesh2tangent = taskdata;
/* new computation method */
{
SGLSLMeshToTangent mesh2tangent = {NULL};
SMikkTSpaceContext sContext = {NULL};
SMikkTSpaceInterface sInterface = {NULL};
mesh2tangent.precomputedFaceNormals = fnors;
mesh2tangent.precomputedLoopNormals = tlnors;
mesh2tangent.looptri = looptri;
mesh2tangent.mloopuv = mloopuv;
mesh2tangent.mpoly = mpoly;
mesh2tangent.mloop = mloop;
mesh2tangent.mvert = mvert;
mesh2tangent.orco = orco;
mesh2tangent.tangent = tangent;
mesh2tangent.numTessFaces = totface;
#ifdef USE_LOOPTRI_DETECT_QUADS
mesh2tangent.face_as_quad_map = face_as_quad_map;
mesh2tangent.num_face_as_quad_map = num_face_as_quad_map;
#endif
sContext.m_pUserData = &mesh2tangent;
sContext.m_pUserData = mesh2tangent;
sContext.m_pInterface = &sInterface;
sInterface.m_getNumFaces = dm_ts_GetNumFaces;
sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
@ -3307,13 +3239,211 @@ void DM_calc_loop_tangents(DerivedMesh *dm)
/* 0 if failed */
genTangSpaceDefault(&sContext);
}
}
void DM_add_named_tangent_layer_for_uv(
CustomData *uv_data, CustomData *tan_data, int numLoopData,
const char *layer_name)
{
if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1)
{
CustomData_add_layer_named(
tan_data, CD_TANGENT, CD_CALLOC, NULL,
numLoopData, layer_name);
}
}
/**
* Here we get some useful information such as active uv layer name and search if it is already in tangent_names.
* Also, we calculate tangent_mask that works as a descriptor of tangents state.
* If tangent_mask has changed, then recalculate tangents.
*/
void DM_calc_loop_tangents_step_0(
const CustomData *loopData, bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME], int tangent_names_count,
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
/* Active uv in viewport */
*ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
ract_uv_name[0] = 0;
if (*ract_uv_n != -1) {
strcpy(ract_uv_name, loopData->layers[*ract_uv_n].name);
}
/* Active tangent in render */
*rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
rren_uv_name[0] = 0;
if (*rren_uv_n != -1) {
strcpy(rren_uv_name, loopData->layers[*rren_uv_n].name);
}
/* If active tangent not in tangent_names we take it into account */
*rcalc_act = false;
*rcalc_ren = false;
for (int i = 0; i < tangent_names_count; i++) {
if (tangent_names[i][0] == 0) {
calc_active_tangent = true;
}
}
if (calc_active_tangent) {
*rcalc_act = true;
*rcalc_ren = true;
for (int i = 0; i < tangent_names_count; i++) {
if (STREQ(ract_uv_name, tangent_names[i]))
*rcalc_act = false;
if (STREQ(rren_uv_name, tangent_names[i]))
*rcalc_ren = false;
}
}
*rtangent_mask = 0;
const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
for (int n = 0; n < uv_layer_num; n++) {
const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
bool add = false;
for (int i = 0; i < tangent_names_count; i++) {
if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
add = true;
break;
}
}
if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
(*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))
{
add = true;
}
if (add)
*rtangent_mask |= 1 << n;
}
}
void DM_calc_loop_tangents(
DerivedMesh *dm, bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME], int tangent_names_count)
{
if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV) == 0)
return;
int act_uv_n = -1;
int ren_uv_n = -1;
bool calc_act = false;
bool calc_ren = false;
char act_uv_name[MAX_NAME];
char ren_uv_name[MAX_NAME];
char tangent_mask = 0;
DM_calc_loop_tangents_step_0(
&dm->loopData, calc_active_tangent, tangent_names, tangent_names_count,
&calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
/* Check we have all the needed layers */
MPoly *mpoly = dm->getPolyArray(dm);
const MLoopTri *looptri = dm->getLoopTriArray(dm);
int totface = dm->getNumLoopTri(dm);
/* Allocate needed tangent layers */
for (int i = 0; i < tangent_names_count; i++)
if (tangent_names[i][0])
DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, tangent_names[i]);
if (calc_act && act_uv_name[0])
DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, act_uv_name);
if (calc_ren && ren_uv_name[0])
DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, ren_uv_name);
#ifdef USE_LOOPTRI_DETECT_QUADS
int num_face_as_quad_map;
int *face_as_quad_map = NULL;
/* map faces to quads */
if (totface != dm->getNumPolys(dm)) {
/* over alloc, since we dont know how many ngon or quads we have */
/* map fake face index to looptri */
face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
int k, j;
for (k = 0, j = 0; j < totface; k++, j++) {
face_as_quad_map[k] = j;
/* step over all quads */
if (mpoly[looptri[j].poly].totloop == 4) {
j++; /* skips the nest looptri */
}
}
num_face_as_quad_map = k;
}
else {
num_face_as_quad_map = totface;
}
#endif
/* Calculation */
{
TaskScheduler *scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
task_pool = BLI_task_pool_create(scheduler, NULL);
dm->tangent_mask = 0;
/* Calculate tangent layers */
SGLSLMeshToTangent data_array[MAX_MTFACE];
const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
for (int n = 0; n < tangent_layer_num; n++) {
int index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
BLI_assert(n < MAX_MTFACE);
SGLSLMeshToTangent *mesh2tangent = &data_array[n];
mesh2tangent->numTessFaces = totface;
#ifdef USE_LOOPTRI_DETECT_QUADS
mesh2tangent->face_as_quad_map = face_as_quad_map;
mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
#endif
mesh2tangent->mvert = dm->getVertArray(dm);
mesh2tangent->mpoly = dm->getPolyArray(dm);
mesh2tangent->mloop = dm->getLoopArray(dm);
mesh2tangent->looptri = dm->getLoopTriArray(dm);
/* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
* have to check this is valid...
*/
mesh2tangent->precomputedLoopNormals = dm->getLoopDataArray(dm, CD_NORMAL);
mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->faceData, CD_NORMAL);
mesh2tangent->orco = NULL;
mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
if (!mesh2tangent->mloopuv) {
mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
if (!mesh2tangent->orco)
continue;
}
mesh2tangent->tangent = dm->loopData.layers[index].data;
/* Fill the resulting tangent_mask */
int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
int uv_start = CustomData_get_layer_index(&dm->loopData, CD_MLOOPUV);
BLI_assert(uv_ind != -1 && uv_start != -1);
BLI_assert(uv_ind - uv_start < MAX_MTFACE);
dm->tangent_mask |= 1 << (uv_ind - uv_start);
BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
}
BLI_assert(dm->tangent_mask == tangent_mask);
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
}
#ifdef USE_LOOPTRI_DETECT_QUADS
if (face_as_quad_map) {
MEM_freeN(face_as_quad_map);
}
#undef USE_LOOPTRI_DETECT_QUADS
#endif
int uv_index, tan_index;
/* Update active layer index */
uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
/* Update render layer index */
uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n);
tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
}
}
@ -3487,15 +3617,13 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
if (dm->auto_bump_scale <= 0.0f)
DM_calc_auto_bump_scale(dm);
/* add a tangent layer if necessary */
for (b = 0; b < gattribs->totlayer; b++) {
if (gattribs->layer[b].type == CD_TANGENT) {
if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
dm->calcLoopTangents(dm);
}
break;
}
}
char tangent_names[MAX_MTFACE][MAX_NAME];
int tangent_names_count;
/* Add a tangent layer/layers. */
DM_calc_tangents_names_from_gpu(gattribs, tangent_names, &tangent_names_count);
if (tangent_names_count)
dm->calcLoopTangents(dm, false, (const char (*)[MAX_NAME])tangent_names, tangent_names_count);
for (b = 0; b < gattribs->totlayer; b++) {
if (gattribs->layer[b].type == CD_MTFACE) {
@ -3541,20 +3669,24 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
else if (gattribs->layer[b].type == CD_TANGENT) {
/* note, even with 'is_editmesh' this uses the derived-meshes loop data */
layer = CustomData_get_layer_index(&dm->loopData, CD_TANGENT);
attribs->tottang = 1;
if (gattribs->layer[b].name[0])
layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
else
layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
a = attribs->tottang++;
if (layer != -1) {
attribs->tang.array = dm->loopData.layers[layer].data;
attribs->tang.em_offset = dm->loopData.layers[layer].offset;
attribs->tang[a].array = dm->loopData.layers[layer].data;
attribs->tang[a].em_offset = dm->loopData.layers[layer].offset;
}
else {
attribs->tang.array = NULL;
attribs->tang.em_offset = -1;
attribs->tang[a].array = NULL;
attribs->tang[a].em_offset = -1;
}
attribs->tang.gl_index = gattribs->layer[b].glindex;
attribs->tang[a].gl_index = gattribs->layer[b].glindex;
}
else if (gattribs->layer[b].type == CD_ORCO) {
/* original coordinates */
@ -3636,10 +3768,12 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
}
/* tangent for normal mapping */
if (attribs->tottang) {
/*const*/ float (*array)[4] = attribs->tang.array;
const float *tang = (array) ? array[loop] : zero;
glVertexAttrib4fv(attribs->tang.gl_index, tang);
for (b = 0; b < attribs->tottang; b++) {
if (attribs->tang[b].array) {
/*const*/ float (*array)[4] = attribs->tang[b].array;
const float *tang = (array) ? array[a * 4 + vert] : zero;
glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
}
}
}

View File

@ -1049,11 +1049,13 @@ static void cdDM_drawMappedFacesGLSL(
numdata++;
}
}
if (matconv[a].attribs.tottang && matconv[a].attribs.tang.array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tang.gl_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
for (b = 0; b < matconv[a].attribs.tottang; b++) {
if (matconv[a].attribs.tang[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
}
}
if (numdata != 0) {
matconv[a].numdata = numdata;
@ -1105,11 +1107,13 @@ static void cdDM_drawMappedFacesGLSL(
offset += sizeof(unsigned char) * 4;
}
}
if (matconv[i].attribs.tottang && matconv[i].attribs.tang.array) {
const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array;
for (j = 0; j < mpoly->totloop; j++)
copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]);
offset += sizeof(float) * 4;
for (b = 0; b < matconv[i].attribs.tottang; b++) {
if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array;
for (j = 0; j < mpoly->totloop; j++)
copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]);
offset += sizeof(float) * 4;
}
}
}

View File

@ -1259,7 +1259,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerDefault_mloopcol, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol,
layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol, NULL, NULL, NULL, layerMaxNum_mloopcol},
/* 18: CD_TANGENT */
{sizeof(float) * 4 * 4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(float) * 4 * 4, "", 0, N_("Tangent"), NULL, NULL, NULL, NULL, NULL},
/* 19: CD_MDISPS */
{sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps,
layerFree_mdisps, NULL, layerSwap_mdisps, NULL,

View File

@ -44,6 +44,7 @@
#include "BLI_math.h"
#include "BLI_jitter.h"
#include "BLI_bitmap.h"
#include "BLI_task.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_mesh.h"
@ -451,107 +452,14 @@ finally:
pRes[3] = fSign;
}
/**
* \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data.
*
* \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
* This is done because #CD_TANGENT is cache data used only for drawing.
*/
static void emDM_calcLoopTangents(DerivedMesh *dm)
static void emDM_calc_loop_tangents_thread(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
BMEditMesh *em = bmdm->em;
BMesh *bm = bmdm->em->bm;
/* mesh vars */
int cd_loop_uv_offset;
float (*orco)[3] = NULL, (*tangent)[4];
int /* totvert, */ totface;
const float (*fnors)[3];
const float (*tlnors)[3];
char htype_index = BM_LOOP;
if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) != -1)
return;
fnors = bmdm->polyNos; /* dm->getPolyDataArray(dm, CD_NORMAL) */
/* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
* have to check this is valid...
*/
tlnors = dm->getLoopDataArray(dm, CD_NORMAL);
/* check we have all the needed layers */
totface = em->tottri;
cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
/* needed for indexing loop-tangents */
htype_index = BM_LOOP;
if (cd_loop_uv_offset == -1) {
orco = dm->getVertDataArray(dm, CD_ORCO);
if (!orco)
return;
/* needed for orco lookups */
htype_index |= BM_VERT;
}
if (fnors) {
/* needed for face normal lookups */
htype_index |= BM_FACE;
}
BM_mesh_elem_index_ensure(bm, htype_index);
/* create tangent layer */
DM_add_loop_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
tangent = DM_get_loop_data_layer(dm, CD_TANGENT);
#ifdef USE_LOOPTRI_DETECT_QUADS
int num_face_as_quad_map;
int *face_as_quad_map = NULL;
/* map faces to quads */
if (bmdm->em->tottri != bm->totface) {
/* over alloc, since we dont know how many ngon or quads we have */
/* map fake face index to looptri */
face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
int i, j;
for (i = 0, j = 0; j < totface; i++, j++) {
face_as_quad_map[i] = j;
/* step over all quads */
if (em->looptris[j][0]->f->len == 4) {
j++; /* skips the nest looptri */
}
}
num_face_as_quad_map = i;
}
else {
num_face_as_quad_map = totface;
}
#endif
struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
/* new computation method */
{
SGLSLEditMeshToTangent mesh2tangent = {NULL};
SMikkTSpaceContext sContext = {NULL};
SMikkTSpaceInterface sInterface = {NULL};
mesh2tangent.precomputedFaceNormals = fnors;
mesh2tangent.precomputedLoopNormals = tlnors;
mesh2tangent.looptris = (const BMLoop *(*)[3])em->looptris;
mesh2tangent.cd_loop_uv_offset = cd_loop_uv_offset;
mesh2tangent.orco = (const float (*)[3])orco;
mesh2tangent.tangent = tangent;
mesh2tangent.numTessFaces = totface;
#ifdef USE_LOOPTRI_DETECT_QUADS
mesh2tangent.face_as_quad_map = face_as_quad_map;
mesh2tangent.num_face_as_quad_map = num_face_as_quad_map;
#endif
sContext.m_pUserData = &mesh2tangent;
sContext.m_pUserData = mesh2tangent;
sContext.m_pInterface = &sInterface;
sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
@ -559,10 +467,133 @@ static void emDM_calcLoopTangents(DerivedMesh *dm)
sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
sInterface.m_getNormal = emdm_ts_GetNormal;
sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
/* 0 if failed */
genTangSpaceDefault(&sContext);
}
}
/**
* \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data.
*
* \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
* This is done because #CD_TANGENT is cache data used only for drawing.
*/
static void emDM_calc_loop_tangents(
DerivedMesh *dm, bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME], int tangent_names_count)
{
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
BMEditMesh *em = bmdm->em;
BMesh *bm = bmdm->em->bm;
if (CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) == 0)
return;
int act_uv_n = -1;
int ren_uv_n = -1;
bool calc_act = false;
bool calc_ren = false;
char act_uv_name[MAX_NAME];
char ren_uv_name[MAX_NAME];
char tangent_mask = 0;
DM_calc_loop_tangents_step_0(
&bm->ldata, calc_active_tangent, tangent_names, tangent_names_count,
&calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
for (int i = 0; i < tangent_names_count; i++)
if (tangent_names[i][0])
DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, tangent_names[i]);
if (calc_act && act_uv_name[0])
DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, act_uv_name);
if (calc_ren && ren_uv_name[0])
DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, ren_uv_name);
int totface = em->tottri;
#ifdef USE_LOOPTRI_DETECT_QUADS
int num_face_as_quad_map;
int *face_as_quad_map = NULL;
/* map faces to quads */
if (bmdm->em->tottri != bm->totface) {
/* over alloc, since we dont know how many ngon or quads we have */
/* map fake face index to looptri */
face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
int i, j;
for (i = 0, j = 0; j < totface; i++, j++) {
face_as_quad_map[i] = j;
/* step over all quads */
if (em->looptris[j][0]->f->len == 4) {
j++; /* skips the nest looptri */
}
}
num_face_as_quad_map = i;
}
else {
num_face_as_quad_map = totface;
}
#endif
/* Calculation */
{
TaskScheduler *scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
task_pool = BLI_task_pool_create(scheduler, NULL);
dm->tangent_mask = 0;
/* Calculate tangent layers */
SGLSLEditMeshToTangent data_array[MAX_MTFACE];
int index = 0;
int n = 0;
CustomData_update_typemap(&dm->loopData);
const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
for (n = 0; n < tangent_layer_num; n++) {
index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
BLI_assert(n < MAX_MTFACE);
SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
mesh2tangent->numTessFaces = em->tottri;
#ifdef USE_LOOPTRI_DETECT_QUADS
mesh2tangent->face_as_quad_map = face_as_quad_map;
mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
#endif
mesh2tangent->precomputedFaceNormals = bmdm->polyNos; /* dm->getPolyDataArray(dm, CD_NORMAL) */
/* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
* have to check this is valid...
*/
mesh2tangent->precomputedLoopNormals = CustomData_get_layer(&dm->loopData, CD_NORMAL);
mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
/* needed for indexing loop-tangents */
int htype_index = BM_LOOP;
if (mesh2tangent->cd_loop_uv_offset == -1) {
mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
if (!mesh2tangent->orco)
continue;
/* needed for orco lookups */
htype_index |= BM_VERT;
}
if (mesh2tangent->precomputedFaceNormals) {
/* needed for face normal lookups */
htype_index |= BM_FACE;
}
BM_mesh_elem_index_ensure(bm, htype_index);
mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
mesh2tangent->tangent = dm->loopData.layers[index].data;
/* Fill the resulting tangent_mask */
int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name);
int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
BLI_assert(uv_ind != -1 && uv_start != -1);
BLI_assert(uv_ind - uv_start < MAX_MTFACE);
dm->tangent_mask |= 1 << (uv_ind - uv_start);
BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
}
BLI_assert(dm->tangent_mask == tangent_mask);
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
}
#ifdef USE_LOOPTRI_DETECT_QUADS
if (face_as_quad_map) {
MEM_freeN(face_as_quad_map);
@ -570,6 +601,15 @@ static void emDM_calcLoopTangents(DerivedMesh *dm)
#undef USE_LOOPTRI_DETECT_QUADS
#endif
}
/* Update active layer index */
int uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name);
CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
/* Update render layer index */
uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name);
CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
}
/** \} */
@ -1419,15 +1459,16 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
}
glVertexAttrib4ubv(attribs->mcol[i].gl_index, col);
}
if (attribs->tottang) {
for (i = 0; i < attribs->tottang; i++) {
const float *tang;
if (attribs->tang.em_offset != -1) {
tang = attribs->tang.array[BM_elem_index_get(loop)];
if (attribs->tang[i].em_offset != -1) {
tang = attribs->tang[i].array[BM_elem_index_get(loop)];
}
else {
tang = zero;
}
glVertexAttrib4fv(attribs->tang.gl_index, tang);
glVertexAttrib4fv(attribs->tang[i].gl_index, tang);
}
}
@ -2218,7 +2259,7 @@ DerivedMesh *getEditDerivedBMesh(
bmdm->dm.calcNormals = emDM_calcNormals;
bmdm->dm.calcLoopNormals = emDM_calcLoopNormals;
bmdm->dm.calcLoopNormalsSpaceArray = emDM_calcLoopNormalsSpaceArray;
bmdm->dm.calcLoopTangents = emDM_calcLoopTangents;
bmdm->dm.calcLoopTangents = emDM_calc_loop_tangents;
bmdm->dm.recalcTessellation = emDM_recalcTessellation;
bmdm->dm.recalcLoopTri = emDM_recalcLoopTri;

View File

@ -1148,7 +1148,7 @@ static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode
/* parses the geom+tex nodes */
ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l);
basemat->nmap_tangent_names_count = 0;
for (node = ntree->nodes.first; node; node = node->next) {
if (node->id) {
if (GS(node->id->name) == ID_MA) {
@ -1170,6 +1170,21 @@ static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode
else if (node->type == NODE_GROUP)
init_render_nodetree((bNodeTree *)node->id, basemat, r_mode, amb);
}
else if (node->typeinfo->type == SH_NODE_NORMAL_MAP) {
basemat->mode2_l |= MA_TANGENT_CONCRETE;
NodeShaderNormalMap *nm = node->storage;
bool taken_into_account = false;
for (int i = 0; i < basemat->nmap_tangent_names_count; i++) {
if (STREQ(basemat->nmap_tangent_names[i], nm->uv_map)) {
taken_into_account = true;
break;
}
}
if (!taken_into_account) {
BLI_assert(basemat->nmap_tangent_names_count < MAX_MTFACE + 1);
strcpy(basemat->nmap_tangent_names[basemat->nmap_tangent_names_count++], nm->uv_map);
}
}
}
}

View File

@ -2417,30 +2417,42 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData
}
}
void BKE_mesh_tangent_loops_to_tessdata(CustomData *fdata, CustomData *ldata, MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces)
void BKE_mesh_tangent_loops_to_tessdata(
CustomData *fdata, CustomData *ldata, MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces, const char *layer_name)
{
/* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
* Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
* this. Better imho to live with it for now. :/ --mont29
*/
const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT);
float (*ftangents)[4] = NULL;
float (*ltangents)[4] = NULL;
int findex, j;
const int *pidx;
unsigned int (*lidx)[4];
if (hasLoopTangent) {
/* need to do for all uv maps at some point */
float (*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT);
float (*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
if (layer_name)
ltangents = CustomData_get_layer_named(ldata, CD_TANGENT, layer_name);
else
ltangents = CustomData_get_layer(ldata, CD_TANGENT);
for (findex = 0, pidx = polyindices, lidx = loopindices;
findex < num_faces;
pidx++, lidx++, findex++)
{
int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
for (j = nverts; j--;) {
copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
if (ltangents) {
/* need to do for all uv maps at some point */
if (layer_name)
ftangents = CustomData_get_layer_named(fdata, CD_TANGENT, layer_name);
else
ftangents = CustomData_get_layer(fdata, CD_TANGENT);
if (ftangents) {
for (findex = 0, pidx = polyindices, lidx = loopindices;
findex < num_faces;
pidx++, lidx++, findex++)
{
int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
for (j = nverts; j--;) {
copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
}
}
}
}

View File

@ -3016,11 +3016,13 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
numdata++;
}
}
if (matconv[a].attribs.tottang && matconv[a].attribs.tang.array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tang.gl_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
for (b = 0; b < matconv[a].attribs.tottang; b++) {
if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
}
}
if (numdata != 0) {
matconv[a].numdata = numdata;
@ -3105,15 +3107,17 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
offset += sizeof(unsigned char) * 4;
}
}
if (matconv[i].attribs.tottang && matconv[i].attribs.tang.array) {
const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array + tot_loops;
for (b = 0; b < matconv[i].attribs.tottang; b++) {
if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array + tot_loops;
copy_v4_v4((float *)&varray[offset], looptang[0]);
copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]);
copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]);
copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]);
copy_v4_v4((float *)&varray[offset], looptang[0]);
copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]);
copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]);
copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]);
offset += sizeof(float) * 4;
offset += sizeof(float) * 4;
}
}
tot_loops += 4;

View File

@ -135,6 +135,13 @@ void linearrgb_to_srgb(vec4 col_from, out vec4 col_to)
col_to.a = col_from.a;
}
void color_to_normal(vec3 color, out vec3 normal)
{
normal.x = 2.0 * ((color.r) - 0.5);
normal.y = -2.0 * ((color.g) - 0.5);
normal.z = 2.0 * ((color.b) - 0.5);
}
#define M_PI 3.14159265358979323846
#define M_1_PI 0.31830988618379069
@ -369,6 +376,10 @@ void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
outval = length(outvec);
outvec = normalize(outvec);
}
void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec)
{
outvec = strength*v1 + (1 - strength) * v2;
}
void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
@ -2701,9 +2712,12 @@ void node_object_info(out vec3 location, out float object_index, out float mater
random = 0.0;
}
void node_normal_map(float strength, vec4 color, vec3 N, out vec3 result)
void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
{
result = N;
vec3 B = tangent.w * cross(normal, tangent.xyz);
outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
outnormal = normalize(outnormal);
}
void node_bump(float strength, float dist, float height, vec3 N, out vec3 result)

View File

@ -197,6 +197,10 @@ typedef struct Material {
short tot_slots;
short pad4[3];
/* multiple tangent (Normal Map node) */
char nmap_tangent_names[9][64]; /* [MAX_MTFACE+1][MAX_NAME]; +1 for empty name */
int nmap_tangent_names_count, pad5;
struct TexPaintSlot *texpaintslot; /* cached slot for painting. Make sure to recalculate before use
* with refresh_texpaint_image_cache */
ListBase gpumaterial; /* runtime */
@ -305,6 +309,7 @@ typedef struct Material {
/* mode2 (is int) */
#define MA_CASTSHADOW (1 << 0)
#define MA_MODE2_PIPELINE (MA_CASTSHADOW)
#define MA_TANGENT_CONCRETE (1 << 1)
/* mapflag */
#define MA_MAPFLAG_UVPROJECT (1 << 0)

View File

@ -46,12 +46,127 @@ static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = attr;
}
static int gpu_shader_normal_map(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
GPUNodeLink *normal;
GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &normal);
static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
{
float vecIn[3];
float strength;
float B[4];
float *T;
float *N;
int j;
return GPU_stack_link(mat, "node_normal_map", in, out, normal);
if (data) {
ShadeInput *shi = ((ShaderCallData *)data)->shi;
NodeShaderNormalMap *nm = node->storage;
nodestack_get_vec(&strength, SOCK_FLOAT, in[0]);
nodestack_get_vec(vecIn, SOCK_VECTOR, in[1]);
vecIn[0] = -2 * (vecIn[0] - 0.5f);
vecIn[1] = 2 * (vecIn[1] - 0.5f);
vecIn[2] = 2 * (vecIn[2] - 0.5f);
CLAMP_MIN(strength, 0.0f);
N = shi->vno;
int uv_index = 0;
switch (nm->space) {
case SHD_NORMAL_MAP_TANGENT:
if (nm->uv_map[0]) {
/* find uv map by name */
for (int i = 0; i < shi->totuv; i++) {
if (STREQ(shi->uv[i].name, nm->uv_map)) {
uv_index = i;
break;
}
}
}
else {
uv_index = shi->actuv;
}
T = shi->tangents[uv_index];
cross_v3_v3v3(B, N, T);
mul_v3_fl(B, T[3]);
for (j = 0; j < 3; j++)
out[0]->vec[j] = vecIn[0] * T[j] + vecIn[1] * B[j] + vecIn[2] * N[j];
interp_v3_v3v3(out[0]->vec, N, out[0]->vec, strength);
break;
case SHD_NORMAL_MAP_OBJECT:
case SHD_NORMAL_MAP_BLENDER_OBJECT:
mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn);
interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
break;
case SHD_NORMAL_MAP_WORLD:
case SHD_NORMAL_MAP_BLENDER_WORLD:
mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn);
interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
break;
}
normalize_v3(out[0]->vec);
}
}
static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
int r;
NodeShaderNormalMap *nm = node->storage;
GPUNodeLink *negnorm;
GPUNodeLink *realnorm;
GPUNodeLink *strength;
float d[4] = {0, 0, 0, 0};
if (in[0].link)
strength = in[0].link;
else
strength = GPU_uniform(in[0].vec);
if (in[1].link) {
r = GPU_link(mat, "color_to_normal", in[1].link, &realnorm);
if (!r) return r;
r = GPU_link(mat, "mtex_negate_texnormal", realnorm, &realnorm);
}
else
r = 1;
GPU_link(mat, "math_max", strength, GPU_uniform(d), &strength);
GPU_link(mat, "vec_math_negate", GPU_builtin(GPU_VIEW_NORMAL), &negnorm);
switch (nm->space) {
case SHD_NORMAL_MAP_TANGENT:
if (in[1].link) {
r = GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &out[0].link);
if (!r) return r;
}
break;
case SHD_NORMAL_MAP_OBJECT:
case SHD_NORMAL_MAP_BLENDER_OBJECT:
if (in[1].link) {
r = GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_LOC_TO_VIEW_MATRIX), &out[0].link);
if (!r) return r;
}
break;
case SHD_NORMAL_MAP_WORLD:
case SHD_NORMAL_MAP_BLENDER_WORLD:
if (in[1].link) {
r = GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_VIEW_MATRIX), &out[0].link);
if (!r) return r;
}
break;
}
if (out[0].link) {
r = GPU_link(mat, "vec_math_mix", strength, out[0].link, negnorm, &out[0].link);
if (!r) return r;
r = GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
if (!r) return r;
}
return r;
}
/* node type definition */
@ -60,12 +175,13 @@ void register_node_type_sh_normal_map(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR, 0);
node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_compatibility(&ntype, NODE_NEW_SHADING | NODE_OLD_SHADING);
node_type_socket_templates(&ntype, sh_node_normal_map_in, sh_node_normal_map_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_normal_map);
node_type_storage(&ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, gpu_shader_normal_map);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal_map);
nodeRegisterType(&ntype);
}

View File

@ -139,6 +139,7 @@ typedef struct ShadeInput {
float refcol[4], displace[3];
float strandco, tang[3], nmapnorm[3], nmaptang[4], stress, winspeed[4];
float duplilo[3], dupliuv[3];
float tangents[8][4]; /* 8 = MAX_MTFACE */
ShadeInputUV uv[8]; /* 8 = MAX_MTFACE */
ShadeInputCol col[8]; /* 8 = MAX_MCOL */

View File

@ -334,6 +334,8 @@ typedef struct ObjectRen {
char (*mcol)[MAX_CUSTOMDATA_LAYER_NAME];
int actmtface, actmcol, bakemtface;
char tangent_mask; /* which tangent layer should be calculated */
float obmat[4][4]; /* only used in convertblender.c, for instancing */
/* used on makeraytree */

View File

@ -76,7 +76,7 @@ typedef struct VlakTableNode {
int *origindex;
int totmtface, totmcol;
float *surfnor;
float *tangent;
float *tangent_arrays[MAX_MTFACE];
struct RadFace **radface;
} VlakTableNode;
@ -137,7 +137,7 @@ struct MTFace *RE_vlakren_get_tface(struct ObjectRen *obr, VlakRen *ren, int n,
struct MCol *RE_vlakren_get_mcol(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify);
int *RE_vlakren_get_origindex(struct ObjectRen *obr, VlakRen *vlak, int verify);
float *RE_vlakren_get_surfnor(struct ObjectRen *obr, VlakRen *ren, int verify);
float *RE_vlakren_get_nmap_tangent(struct ObjectRen *obr, VlakRen *ren, int verify);
float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify);
RadFace **RE_vlakren_get_radface(struct ObjectRen *obr, VlakRen *ren, int verify);
void RE_vlakren_get_normal(struct Render *re, struct ObjectInstanceRen *obi, struct VlakRen *vlr, float *nor);

View File

@ -425,7 +425,7 @@ static TriTessFace *mesh_calc_tri_tessface(
if (tangent) {
DM_ensure_normals(dm);
DM_calc_loop_tangents(dm);
DM_calc_loop_tangents(dm, true, NULL, 0);
tspace = dm->getLoopDataArray(dm, CD_TANGENT);
BLI_assert(tspace);

View File

@ -304,7 +304,7 @@ static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr, int do_tangent)
typedef struct {
ObjectRen *obr;
int mtface_index;
} SRenderMeshToTangent;
/* interface */
@ -337,7 +337,7 @@ static void GetTextureCoordinate(const SMikkTSpaceContext *pContext, float r_uv[
//assert(vert_index>=0 && vert_index<4);
SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
MTFace *tface= RE_vlakren_get_tface(pMesh->obr, vlr, pMesh->obr->actmtface, NULL, 0);
MTFace *tface= RE_vlakren_get_tface(pMesh->obr, vlr, pMesh->mtface_index, NULL, 0);
const float *coord;
if (tface != NULL) {
@ -371,7 +371,7 @@ static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[
//assert(vert_index>=0 && vert_index<4);
SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
VlakRen *vlr = RE_findOrAddVlak(pMesh->obr, face_num);
float *ftang = RE_vlakren_get_nmap_tangent(pMesh->obr, vlr, 1);
float *ftang = RE_vlakren_get_nmap_tangent(pMesh->obr, vlr, pMesh->mtface_index, true);
if (ftang!=NULL) {
copy_v3_v3(&ftang[iVert*4+0], fvTangent);
ftang[iVert*4+3]=fSign;
@ -457,7 +457,12 @@ static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_verte
sInterface.m_getNormal = GetNormal;
sInterface.m_setTSpaceBasic = SetTSpace;
genTangSpaceDefault(&sContext);
for (a = 0; a < MAX_MTFACE; a++) {
if (obr->tangent_mask & 1 << a) {
mesh2tangent.mtface_index = a;
genTangSpaceDefault(&sContext);
}
}
}
}
@ -3113,7 +3118,8 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3],
float *orco = NULL;
short (*loop_nors)[4][3] = NULL;
bool need_orco = false, need_stress = false, need_nmap_tangent = false, need_tangent = false, need_origindex = false;
bool need_orco = false, need_stress = false, need_tangent = false, need_origindex = false;
bool need_nmap_tangent_concrete = false;
int a, a1, ok, vertofs;
int end, totvert = 0;
bool do_autosmooth = false, do_displace = false;
@ -3148,9 +3154,11 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
if (ma->mode_l & MA_NORMAP_TANG) {
if (me->mtpoly==NULL) {
need_orco= 1;
need_tangent= 1;
}
need_nmap_tangent= 1;
need_tangent= 1;
}
if (ma->mode2_l & MA_TANGENT_CONCRETE) {
need_nmap_tangent_concrete = true;
}
}
}
@ -3161,7 +3169,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
need_orco= 1;
need_tangent= 1;
}
need_nmap_tangent= 1;
need_nmap_tangent_concrete = true;
}
/* check autosmooth and displacement, we then have to skip only-verts optimize
@ -3274,14 +3282,13 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
/* store customdata names, because DerivedMesh is freed */
RE_set_customdata_names(obr, &dm->faceData);
/* add tangent layer if we need one */
if (need_nmap_tangent!=0 && CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) {
bool generate_data = false;
if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
dm->calcLoopTangents(dm);
generate_data = true;
}
DM_generate_tangent_tessface_data(dm, generate_data);
/* add tangent layers if we need */
if ((ma->nmap_tangent_names_count && need_nmap_tangent_concrete) || need_tangent) {
dm->calcLoopTangents(
dm, need_tangent,
(const char (*)[MAX_NAME])ma->nmap_tangent_names, ma->nmap_tangent_names_count);
obr->tangent_mask = dm->tangent_mask;
DM_generate_tangent_tessface_data(dm, need_nmap_tangent_concrete || need_tangent);
}
/* still to do for keys: the correct local texture coordinate */
@ -3401,7 +3408,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
CustomDataLayer *layer;
MTFace *mtface, *mtf;
MCol *mcol, *mc;
int index, mtfn= 0, mcn= 0, mtng=0, mln = 0, vindex;
int index, mtfn= 0, mcn= 0, mln = 0, vindex;
char *name;
int nr_verts = v4!=0 ? 4 : 3;
@ -3424,17 +3431,24 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
for (vindex=0; vindex<nr_verts; vindex++)
mc[vindex]=mcol[a*4+rev_tab[vindex]];
}
else if (layer->type == CD_TANGENT && mtng < 1) {
if (need_nmap_tangent != 0) {
const float * tangent = (const float *) layer->data;
float * ftang = RE_vlakren_get_nmap_tangent(obr, vlr, 1);
else if (layer->type == CD_TANGENT) {
if (need_nmap_tangent_concrete || need_tangent) {
int uv_start = CustomData_get_layer_index(&dm->faceData, CD_MTFACE);
int uv_index = CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, layer->name);
BLI_assert(uv_start >= 0 && uv_index >= 0);
if ((uv_start < 0 || uv_index < 0))
continue;
int n = uv_index - uv_start;
const float *tangent = (const float *) layer->data;
float *ftang = RE_vlakren_get_nmap_tangent(obr, vlr, n, true);
for (vindex=0; vindex<nr_verts; vindex++) {
copy_v4_v4(ftang+vindex*4, tangent+a*16+rev_tab[vindex]*4);
mul_mat3_m4_v3(mat, ftang+vindex*4);
normalize_v3(ftang+vindex*4);
}
}
mtng++;
}
else if (layer->type == CD_TESSLOOPNORMAL && mln < 1) {
if (loop_nors) {
@ -3542,7 +3556,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
}
if (recalc_normals!=0 || need_tangent!=0)
calc_vertexnormals(re, obr, recalc_normals, need_tangent, need_nmap_tangent);
calc_vertexnormals(re, obr, recalc_normals, need_tangent, need_nmap_tangent_concrete);
}
MEM_SAFE_FREE(loop_nors);

View File

@ -456,7 +456,7 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, bool require_t
if (require_tangent) {
if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1)
DM_calc_loop_tangents(dm);
DM_calc_loop_tangents(dm, true, NULL, 0);
pvtangent = DM_get_loop_data_layer(dm, CD_TANGENT);
}

View File

@ -70,6 +70,7 @@
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_texture_types.h"
#include "DNA_listBase.h"
#include "DNA_particle_types.h"
#include "BKE_customdata.h"
@ -380,19 +381,28 @@ float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify)
return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS;
}
float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int verify)
float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify)
{
float *tangent;
float **tangents;
int nr= vlak->index>>8;
tangent= obr->vlaknodes[nr].tangent;
if (tangent==NULL) {
if (verify)
tangent= obr->vlaknodes[nr].tangent= MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table");
tangents = obr->vlaknodes[nr].tangent_arrays;
if (index + 1 > 8) {
return NULL;
}
index = index < 0 ? 0: index;
if (tangents[index] == NULL) {
if (verify) {
tangents[index] = MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table");
}
else
return NULL;
}
return tangent + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS;
return tangents[index] + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS;
}
RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify)
@ -415,7 +425,8 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
VlakRen *vlr1 = RE_findOrAddVlak(obr, obr->totvlak++);
MTFace *mtface, *mtface1;
MCol *mcol, *mcol1;
float *surfnor, *surfnor1, *tangent, *tangent1;
float *surfnor, *surfnor1;
float *tangent, *tangent1;
int *origindex, *origindex1;
RadFace **radface, **radface1;
int i, index = vlr1->index;
@ -447,9 +458,11 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
copy_v3_v3(surfnor1, surfnor);
}
tangent= RE_vlakren_get_nmap_tangent(obr, vlr, 0);
if (tangent) {
tangent1= RE_vlakren_get_nmap_tangent(obr, vlr1, 1);
for (i=0; i < MAX_MTFACE; i++) {
tangent = RE_vlakren_get_nmap_tangent(obr, vlr, i, false);
if (!tangent)
continue;
tangent1 = RE_vlakren_get_nmap_tangent(obr, vlr1, i, true);
memcpy(tangent1, tangent, sizeof(float)*RE_NMAP_TANGENT_ELEMS);
}
@ -790,8 +803,10 @@ void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
MEM_freeN(vlaknodes[a].origindex);
if (vlaknodes[a].surfnor)
MEM_freeN(vlaknodes[a].surfnor);
if (vlaknodes[a].tangent)
MEM_freeN(vlaknodes[a].tangent);
for (int b = 0; b < MAX_MTFACE; b++) {
if (vlaknodes[a].tangent_arrays[b])
MEM_freeN(vlaknodes[a].tangent_arrays[b]);
}
if (vlaknodes[a].radface)
MEM_freeN(vlaknodes[a].radface);
}

View File

@ -884,7 +884,10 @@ void shade_input_set_shade_texco(ShadeInput *shi)
float u = shi->u, v = shi->v;
float l = 1.0f + u + v, dl;
int mode = shi->mode; /* or-ed result for all nodes */
int mode2 = shi->mode2;
short texco = shi->mat->texco;
const bool need_mikk_tangent = (mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT);
const bool need_mikk_tangent_concrete = (mode2 & MA_TANGENT_CONCRETE) != 0;
/* calculate dxno */
if (shi->vlr->flag & R_SMOOTH) {
@ -905,8 +908,8 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
/* calc tangents */
if (mode & (MA_TANGENT_V | MA_NORMAP_TANG) || R.flag & R_NEED_TANGENT) {
const float *tangent, *s1, *s2, *s3;
if (mode & (MA_TANGENT_V | MA_NORMAP_TANG) || mode2 & MA_TANGENT_CONCRETE || R.flag & R_NEED_TANGENT) {
const float *s1, *s2, *s3;
float tl, tu, tv;
if (shi->vlr->flag & R_SMOOTH) {
@ -943,14 +946,18 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
}
if (mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT) {
tangent = RE_vlakren_get_nmap_tangent(obr, shi->vlr, 0);
if (need_mikk_tangent || need_mikk_tangent_concrete) {
int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
float c0[3], c1[3], c2[3];
int acttang = obr->actmtface;
if (tangent) {
int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
float c0[3], c1[3], c2[3];
vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
/* cycle through all tangent in vlakren */
for (int i = 0; i < MAX_MTFACE; i++) {
const float *tangent = RE_vlakren_get_nmap_tangent(obr, shi->vlr, i, false);
if (!tangent)
continue;
copy_v3_v3(c0, &tangent[j1 * 4]);
copy_v3_v3(c1, &tangent[j2 * 4]);
@ -966,13 +973,19 @@ void shade_input_set_shade_texco(ShadeInput *shi)
/* we don't normalize the interpolated TBN tangent
* corresponds better to how it's done in game engines */
shi->nmaptang[0] = (tl * c2[0] - tu * c0[0] - tv * c1[0]);
shi->nmaptang[1] = (tl * c2[1] - tu * c0[1] - tv * c1[1]);
shi->nmaptang[2] = (tl * c2[2] - tu * c0[2] - tv * c1[2]);
shi->tangents[i][0] = (tl * c2[0] - tu * c0[0] - tv * c1[0]);
shi->tangents[i][1] = (tl * c2[1] - tu * c0[1] - tv * c1[1]);
shi->tangents[i][2] = (tl * c2[2] - tu * c0[2] - tv * c1[2]);
/* the sign is the same for all 3 vertices of any
* non degenerate triangle. */
shi->nmaptang[3] = tangent[j1 * 4 + 3];
shi->tangents[i][3] = tangent[j1 * 4 + 3];
if (acttang == i && need_mikk_tangent) {
for (int m = 0; m < 4; m++) {
shi->nmaptang[m] = shi->tangents[i][m];
}
}
}
}
}

View File

@ -962,7 +962,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene,
if (CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) {
bool generate_data = false;
if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
DM_calc_loop_tangents(dm);
DM_calc_loop_tangents(dm, true, NULL, 0);
generate_data = true;
}
DM_generate_tangent_tessface_data(dm, generate_data);