That’s the plan B.
I’m using displacement shaders for procedural environment modeling quite extensively, so having realtime feedback while in edit mode would be quite awesome.
I’ve been triying with the baking API, but the results seems to be running at the wrong UV positions for some reason I can’t figure.
I’ve been debugging the code and even if I make a UV bake pass, the UVs that comes out are different from the ones I pass.
If I manually move every UV vertex to the same coordinate the results are accurate so it’s probably some interpolation problem ?
Honestly, at this point I’m quite lost.
Here’s the modifier code in case someone wants to take a look at it:
static DerivedMesh* applyModifier(ModifierData *md, Object *ob,
DerivedMesh *derivedMesh,
ModifierApplyFlag flag)
{
TestModifierData* tmd = (TestModifierData*)md;
ModifierData* nmd = &tmd->modifier;
DerivedMesh *dm = CDDM_copy(derivedMesh);
MVert* verts = dm->getVertArray(dm);
MLoop* loops = dm->getLoopArray(dm);
MLoopTri* loop_tris = dm->getLoopTriArray(dm);
MLoopUV* loop_uvs = CustomData_get_layer(&dm->loopData, CD_MLOOPUV);
const int loop_count = dm->getNumLoops(dm);
const int loop_tri_count = dm->getNumLoopTri(dm);
const int vert_count = dm->getNumVerts(dm);
float(*UVs)[2] = MEM_mallocN(sizeof(float) * vert_count * 2, __func__);
int* primitive_ids = MEM_mallocN(sizeof(int) * vert_count, __func__);
for (int v = 0; v < vert_count; v++)
{
for (int t = 0; t < loop_tri_count; t++)
{
MLoopTri* loop_tri = loop_tris + t;
if (loop_tri->tri[0] == v ||
loop_tri->tri[1] == v ||
loop_tri->tri[2] == v)
{
primitive_ids[v] = t;
break;
}
}
for (int l = 0; l < loop_count; l++)
{
if (loops[l].v == v)
{
const float *uv = loop_uvs[l].uv;
copy_v2_v2(UVs[v], uv);
break;
}
}
}
BakePixel* bake_pixels = MEM_mallocN(sizeof(BakePixel) * vert_count, __func__);
for (int v = 0; v < vert_count; v++)
{
BakePixel* pixel = bake_pixels + v;
pixel->object_id = 0;
pixel->primitive_id = primitive_ids[v];
copy_v2_v2(pixel->uv, UVs[v]);
pixel->du_dx = pixel->du_dy = pixel->dv_dx = pixel->dv_dy = 0;
bake_differentials(pixel,
UVs[loop_tris[primitive_ids[v]].tri[0]],
UVs[loop_tris[primitive_ids[v]].tri[1]],
UVs[loop_tris[primitive_ids[v]].tri[2]]);
}
// Build a new scene for baking, with just a copy of the current mesh
Scene* scene = BKE_scene_add(G.main, "BAKE");
BLI_strncpy(scene->r.engine, RE_engine_id_CYCLES, sizeof(scene->r.engine));
Object* object = BKE_object_add(G.main, scene, OB_MESH, "Bake_dummy");
Mesh* bake_mesh = BKE_mesh_from_object(object);
DM_to_mesh(dm, bake_mesh, object, CD_MASK_MESH, false);
for (int i = 0; i < ob->totcol; i++)
{
BKE_object_material_slot_add(object);
Mesh* ob_mesh = (Mesh*)ob->data;
assign_material(object, ob_mesh->mat[i], i, BKE_MAT_ASSIGN_OBDATA);
}
Render *re = RE_NewRender(scene->id.name);
RE_bake_engine_set_engine_parameters(re, G.main, scene);
float* result = MEM_mallocN(sizeof(float) * vert_count * 4, __func__);
RE_bake_engine(re, object, 0, bake_pixels, vert_count, 4, SCE_PASS_EMIT, R_BAKE_PASS_FILTER_EMIT, result);
for (int i = 0; i < vert_count; i++)
{
MVert* vert = verts + i;
float displace[3];
normal_short_to_float_v3(displace, vert->no);
mul_v3_fl(displace, result[i * 4]);
add_v3_v3(vert->co, displace);
}
BKE_libblock_delete(G.main, &object->id);
BKE_libblock_delete(G.main, &scene->id);
MEM_freeN(result);
MEM_freeN(bake_pixels);
MEM_freeN(UVs);
MEM_freeN(primitive_ids);
return dm;
}
It assumes the mesh is pre-triangulated and it has already a UV layer.