Page MenuHome

collada-export-tangents-bitangents.diff

File Metadata

Author
Jeremy Karlson (germ)
Created
Nov 13 2013, 4:18 PM

collada-export-tangents-bitangents.diff

diff -r 60c124edbdb7 -r 7dbe2cb1c076 Blender/GeometryExporter.cpp
--- a/Blender/GeometryExporter.cpp Sat Dec 29 22:19:29 2012 -0800
+++ b/Blender/GeometryExporter.cpp Sat Dec 29 22:24:10 2012 -0800
@@ -1,4 +1,4 @@
-/*
+/**
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -36,9 +36,11 @@
#include "GeometryExporter.h"
#include "DNA_meshdata_types.h"
+#include "DNA_material_types.h"
extern "C" {
#include "BLI_utildefines.h"
+ #include "BLI_math_vector.h"
#include "BKE_DerivedMesh.h"
#include "BKE_main.h"
@@ -89,6 +91,10 @@
std::string geom_id = get_geometry_id(ob, use_instantiation);
std::vector<Normal> nor;
std::vector<Face> norind;
+ std::vector<Tangent> tan;
+ std::vector<Face> tanind;
+ std::vector<Binormal> bin;
+ std::vector<Face> binind;
// Skip if linked geometry was already exported from another reference
if (use_instantiation &&
@@ -105,6 +111,11 @@
create_normals(nor, norind, me);
+ bool has_tangents = create_tangents(tan, tanind, ob);
+
+ if (has_tangents)
+ create_binormals(bin, binind, nor, tan, tanind);
+
// openMesh(geoId, geoName, meshId)
openMesh(geom_id, geom_name);
@@ -114,6 +125,12 @@
// writes <source> for normal coords
createNormalsSource(geom_id, me, nor);
+ // writes <source> for tangents and binormals
+ if (has_tangents) {
+ createTangentsSource(geom_id, me, tan);
+ createBinormalsSource(geom_id, me, bin);
+ }
+
bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
// writes <source> for uv coords if mesh has uv coords
@@ -139,11 +156,11 @@
// XXX slow
if (ob->totcol) {
for (int a = 0; a < ob->totcol; a++) {
- createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
+ createPolylist(a, has_uvs, has_color, has_tangents, ob, me, geom_id, norind, tanind, binind);
}
}
else {
- createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
+ createPolylist(0, has_uvs, has_color, has_tangents, ob, me, geom_id, norind, tanind, binind);
}
}
@@ -223,10 +240,13 @@
void GeometryExporter::createPolylist(short material_index,
bool has_uvs,
bool has_color,
+ bool has_tangents,
Object *ob,
Mesh *me,
std::string& geom_id,
- std::vector<Face>& norind)
+ std::vector<Face>& norind,
+ std::vector<Face>& tanind,
+ std::vector<Face>& binind)
{
MFace *mfaces = me->mface;
int totfaces = me->totface;
@@ -256,13 +276,17 @@
fprintf(stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index);
return;
}
-
+
Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
COLLADASW::Polylist polylist(mSW);
-
+
+ // do not export normals if "shadeless"
+ //bool has_normals = ma==0 || !(ma->mode & MA_SHLESS);
+ bool has_normals = true;
+
// sets count attribute in <polylist>
polylist.setCount(faces_in_polylist);
-
+
// sets material name
if (ma) {
std::string material_id = get_material_id(ma);
@@ -274,14 +298,20 @@
COLLADASW::InputList &til = polylist.getInputList();
// creates <input> in <polylist> for vertices
- COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
-
- // creates <input> in <polylist> for normals
- COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
-
+ int offset = 0;
+
+ COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), offset);
+ offset++;
+
til.push_back(input1);
- til.push_back(input2);
-
+ // sets material name
+ if (has_normals) {
+ // creates <input> in <polylist> for normals
+ COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), offset);
+ offset++;
+ til.push_back(input2);
+ }
+
// if mesh has uv coords writes <input> for TEXCOORD
int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1;
@@ -291,17 +321,30 @@
// char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
makeUrl(makeTexcoordSourceId(geom_id, i)),
- 2, // offset always 2, this is only until we have optimized UV sets
+ offset, // offset always 2, this is only until we have optimized UV sets
i // set number equals UV map index
);
+ offset++;
til.push_back(input3);
}
}
if (has_color) {
- COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::COLOR), has_uvs ? 3 : 2);
+ COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::COLOR), offset);
+ offset++;
til.push_back(input4);
}
+
+ if (has_tangents) {
+ // creates <input> in <polylist> for tangents
+ COLLADASW::Input intan(COLLADASW::InputSemantic::TEXTANGENT, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::TEXTANGENT), offset);
+ offset++;
+ til.push_back(intan);
+ // creates <input> in <polylist> for binormals
+ COLLADASW::Input inbin(COLLADASW::InputSemantic::TEXBINORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::TEXBINORMAL), offset);
+ offset++;
+ til.push_back(inbin);
+ }
// sets <vcount>
polylist.setVCountList(vcount_list);
@@ -320,15 +363,23 @@
unsigned int *v = &f->v1;
unsigned int *n = &norind[i].v1;
+ unsigned int *tg = &tanind[i].v1;
+ unsigned int *tb = &binind[i].v1;
for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
polylist.appendValues(v[j]);
- polylist.appendValues(n[j]);
-
- if (has_uvs)
- polylist.appendValues(texindex + j);
-
+ if (has_normals)
+ polylist.appendValues(n[j]);
+ if (has_uvs) {
+ for (int k=0; k<num_layers; ++k) {
+ polylist.appendValues(texindex + j);
+ }
+ }
if (has_color)
polylist.appendValues(texindex + j);
+ if (has_tangents) {
+ polylist.appendValues(tg[j]);
+ polylist.appendValues(tb[j]);
+ }
}
}
@@ -560,6 +611,148 @@
}
}
+//creates <source> for tangents
+void GeometryExporter::createTangentsSource(std::string geom_id, Mesh *me, std::vector<Tangent>& tan)
+{
+ COLLADASW::FloatSourceF source(mSW);
+ source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXTANGENT));
+ source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXTANGENT) +
+ ARRAY_ID_SUFFIX);
+ source.setAccessorCount((unsigned long)tan.size());
+ source.setAccessorStride(3);
+ COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+ param.push_back("X");
+ param.push_back("Y");
+ param.push_back("Z");
+
+ source.prepareToAppendValues();
+
+ std::vector<Tangent>::iterator it;
+ for (it = tan.begin(); it != tan.end(); it++) {
+ Tangent& t = *it;
+ source.appendValues(t.x, t.y, t.z);
+ }
+
+ source.finish();
+}
+
+//creates <source> for binormals
+void GeometryExporter::createBinormalsSource(std::string geom_id, Mesh *me, std::vector<Binormal>& bin)
+{
+ COLLADASW::FloatSourceF source(mSW);
+ source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXBINORMAL));
+ source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXBINORMAL) +
+ ARRAY_ID_SUFFIX);
+ source.setAccessorCount((unsigned long)bin.size());
+ source.setAccessorStride(3);
+ COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+ param.push_back("X");
+ param.push_back("Y");
+ param.push_back("Z");
+
+ source.prepareToAppendValues();
+
+ std::vector<Binormal>::iterator it;
+ for (it = bin.begin(); it != bin.end(); it++) {
+ Binormal& b = *it;
+ source.appendValues(b.x, b.y, b.z);
+ }
+
+ source.finish();
+}
+
+bool GeometryExporter::create_tangents(std::vector<Tangent> &tan, std::vector<Face> &tanind, Object *ob)
+{
+ // check if a tangent space normal map has been attached to this object
+ //bool need_tangents = false;
+ //for (int a=0; a<ob->totcol; a++) {
+ // Material *ma = give_current_material(ob, a+1);
+ // if (ma) {
+ // for (int b=0; b<MAX_MTEX; b++) {
+ // MTex *mtex = ma->mtex[b];
+ // if (mtex && mtex->tex) {
+ // if (mtex->mapto & MAP_NORM &&mtex->normapspace==MTEX_NSPACE_TANGENT) {
+ // need_tangents=true;
+ // break;
+ // }
+ // }
+ // }
+ // }
+ //}
+ //if (!need_tangents) return false;
+
+ // create intermediate mesh with tangents
+ bool has_tangents = false;
+ DerivedMesh *dm;
+ dm = mesh_create_derived_render(mScene,ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
+ if (dm) {
+ DM_add_tangent_layer(dm);
+ float* tangent = (float*)DM_get_tessface_data_layer(dm, CD_TANGENT);
+ if (tangent) {
+ int totface = dm->getNumTessFaces(dm);
+ MFace *mf = dm->getTessFaceArray(dm);
+ int nt=0;
+ // custom data format #18: 4 x vec4
+ for (int i=0; i<totface; ++i, ++mf) {
+ float* d = tangent;
+ tangent+=16;
+ Face f;
+ Tangent t;
+ f.v1 = nt++;
+ t.x = *d++; t.y = *d++; t.z = *d++; t.w = *d++;
+ tan.push_back(t);
+ f.v2 = nt++;
+ t.x = *d++; t.y = *d++; t.z = *d++; t.w = *d++;
+ tan.push_back(t);
+ f.v3 = nt++;
+ t.x = *d++; t.y = *d++; t.z = *d++; t.w = *d++;
+ tan.push_back(t);
+ if (mf->v4) {
+ f.v4 = nt++;
+ t.x = *d++; t.y = *d++; t.z = *d++; t.w = *d++;
+ tan.push_back(t);
+ }
+ tanind.push_back(f);
+ }
+ has_tangents = true;
+ }
+ // else: tangents not available
+ dm->release(dm);
+ }
+ // else: unable to create derived mesh
+ return has_tangents;
+}
+
+void GeometryExporter::create_binormals(std::vector<Binormal> &bin, std::vector<Face> &binind, std::vector<Normal> &nor, std::vector<Tangent> &tan, std::vector<Face> &tanind)
+{
+ for (unsigned int i = 0; i < tan.size(); i++)
+ {
+ float f[3];
+
+ float n[3];
+ n[0] = nor[i].x; n[1] = nor[i].y; n[2] = nor[i].z;
+
+ float t[3];
+ t[0] = tan[i].x; t[1] = tan[i].y; t[2] = tan[i].z;
+
+ cross_v3_v3v3(f, n, t);
+ normalize_v3(f);
+
+ if (tan[i].w < 0)
+ negate_v3(f);
+
+ Binormal b;
+ b.x = f[0]; b.y = f[1]; b.z = f[2];
+
+ bin.push_back(b);
+ }
+
+ for (unsigned int i = 0; i < tanind.size(); i++)
+ {
+ binind.push_back(tanind[i]);
+ }
+}
+
std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
{
return geom_id + getSuffixBySemantic(type) + other_suffix;
diff -r 60c124edbdb7 -r 7dbe2cb1c076 Blender/GeometryExporter.h
--- a/Blender/GeometryExporter.h Sat Dec 29 22:19:29 2012 -0800
+++ b/Blender/GeometryExporter.h Sat Dec 29 22:24:10 2012 -0800
@@ -57,6 +57,16 @@
float x, y, z;
};
+ struct Tangent
+ {
+ float x, y, z, w;
+ };
+
+ struct Binormal
+ {
+ float x, y, z;
+ };
+
Scene *mScene;
public:
@@ -75,10 +85,13 @@
void createPolylist(short material_index,
bool has_uvs,
bool has_color,
+ bool retain,
Object *ob,
Mesh *me,
std::string& geom_id,
- std::vector<Face>& norind);
+ std::vector<Face>& norind,
+ std::vector<Face>& tanind,
+ std::vector<Face>& binind);
// creates <source> for positions
void createVertsSource(std::string geom_id, Mesh *me);
@@ -90,11 +103,23 @@
//creates <source> for texcoords
void createTexcoordsSource(std::string geom_id, Mesh *me);
+ //creates <source> for tangents
+ void createTangentsSource(std::string geom_id, Mesh *me, std::vector<Tangent>& tan);
+
+ //creates <source> for binormals
+ void createBinormalsSource(std::string geom_id, Mesh *me, std::vector<Binormal>& bin);
+
//creates <source> for normals
void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor);
void create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me);
+ //returns true if tangents are needed/available
+ bool create_tangents(std::vector<Tangent> &tan, std::vector<Face> &ind, Object *ob);
+
+ //returns true if binormals are needed/available
+ void create_binormals(std::vector<Binormal> &bin, std::vector<Face> &binind, std::vector<Normal> &nor, std::vector<Tangent> &tan, std::vector<Face> &tanind);
+
std::string getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix = "");
COLLADASW::URI getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix = "");

Event Timeline