@@ -471,9 +471,26 @@ SimpleRaytracer::parse_scene_xml(const std::string& scenefile)
471471 }
472472 }
473473 shadingsys->ShaderGroupEnd (*group);
474- if (name_attr)
475- shadermap.emplace (name_attr.value (), int (shaders ().size ()));
476- shaders ().emplace_back (group);
474+ if (name_attr) {
475+ if (auto it = shadermap.find (name); it != shadermap.end ()) {
476+ int shaderID = it->second ;
477+ if (shaderID >= 0 && shaderID < int (shaders ().size ())) {
478+ fprintf (stderr, " Updating shader %d - %s\n " , shaderID, shadertype.c_str ());
479+ // we already have a material under this name,
480+ Material& m = shaders ()[shaderID];
481+ // TODO: could we query the shadertype directly from the ShaderGroup?
482+ if (shadertype == " displacement" )
483+ m.disp = group;
484+ else if (shadertype == " surface" )
485+ m.surf = group;
486+ // skip the rest which would add a new material
487+ continue ;
488+ }
489+ } else {
490+ shadermap.emplace (name, int (shaders ().size ()));
491+ }
492+ }
493+ shaders ().emplace_back (Material { group, nullptr });
477494 m_shader_is_light.emplace_back (
478495 is_light_attr ? strtobool (is_light_attr.value ()) : false );
479496 } else {
@@ -925,7 +942,7 @@ SimpleRaytracer::eval_background(const Dual2<Vec3>& dir, ShadingContext* ctx,
925942 if (bounce >= 0 )
926943 sg.raytype = bounce > 0 ? Ray::DIFFUSE : Ray::CAMERA;
927944#ifndef __CUDACC__
928- shadingsys->execute (*ctx, *m_shaders[backgroundShaderID], sg);
945+ shadingsys->execute (*ctx, *m_shaders[backgroundShaderID]. surf , sg);
929946#else
930947 alignas (8 ) char closure_pool[256 ];
931948 execute_shader (sg, render_params.bg_id , closure_pool);
@@ -1000,11 +1017,11 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler,
10001017 int shaderID = scene.shaderid (hit.id );
10011018
10021019#ifndef __CUDACC__
1003- if (shaderID < 0 || !m_shaders[shaderID])
1020+ if (shaderID < 0 || !m_shaders[shaderID]. surf )
10041021 break ; // no shader attached? done
10051022
10061023 // execute shader and process the resulting list of closures
1007- shadingsys->execute (*ctx, *m_shaders[shaderID], sg);
1024+ shadingsys->execute (*ctx, *m_shaders[shaderID]. surf , sg);
10081025#else
10091026 if (shaderID < 0 )
10101027 break ; // no shader attached? done
@@ -1116,7 +1133,7 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler,
11161133 sample.u , sample.v );
11171134#ifndef __CUDACC__
11181135 // execute the light shader (for emissive closures only)
1119- shadingsys->execute (*ctx, *m_shaders[shaderID],
1136+ shadingsys->execute (*ctx, *m_shaders[shaderID]. surf ,
11201137 light_sg);
11211138#else
11221139 execute_shader (light_sg, shaderID, light_closure_pool);
@@ -1205,6 +1222,122 @@ SimpleRaytracer::prepare_render()
12051222 backgroundResolution = 0 ;
12061223 }
12071224
1225+ bool have_displacement = false ;
1226+ for (const Material& m : shaders ()) {
1227+ if (m.disp ) {
1228+ have_displacement = true ;
1229+ break ;
1230+ }
1231+ }
1232+ if (have_displacement) {
1233+ errhandler ().infofmt (" Evaluating displacement shaders" );
1234+ // Loop through all triangles and run displacement shader if there is one
1235+ // or copy the input point if there is none
1236+ std::vector<Vec3> disp_verts (scene.verts .size (), Vec3 (0 , 0 , 0 ));
1237+ std::vector<int > valance (scene.verts .size (), 0 ); // number of times each vertex has been displaced
1238+
1239+ OSL::PerThreadInfo* thread_info = shadingsys->create_thread_info ();
1240+ ShadingContext* ctx = shadingsys->get_context (thread_info);
1241+
1242+ bool has_smooth_normals = false ;
1243+ for (int primID = 0 , nprims = scene.triangles .size (); primID < nprims; primID++) {
1244+ Vec3 p[3 ], n[3 ];
1245+ Vec2 uv[3 ];
1246+
1247+ p[0 ] = scene.verts [scene.triangles [primID].a ];
1248+ p[1 ] = scene.verts [scene.triangles [primID].b ];
1249+ p[2 ] = scene.verts [scene.triangles [primID].c ];
1250+
1251+ valance[scene.triangles [primID].a ]++;
1252+ valance[scene.triangles [primID].b ]++;
1253+ valance[scene.triangles [primID].c ]++;
1254+
1255+ int shaderID = scene.shaderid (primID);
1256+ if (shaderID < 0 || !m_shaders[shaderID].disp ) {
1257+ disp_verts[scene.triangles [primID].a ] += p[0 ];
1258+ disp_verts[scene.triangles [primID].b ] += p[1 ];
1259+ disp_verts[scene.triangles [primID].c ] += p[2 ];
1260+ continue ;
1261+ }
1262+
1263+
1264+ Vec3 Ng = (p[0 ] - p[1 ]).cross (p[0 ] - p[2 ]);
1265+ float area = 0 .5f * Ng.length ();
1266+ Ng = Ng.normalize ();
1267+ if (scene.n_triangles [primID].a >= 0 ) {
1268+ n[0 ] = scene.normals [scene.n_triangles [primID].a ];
1269+ n[1 ] = scene.normals [scene.n_triangles [primID].b ];
1270+ n[2 ] = scene.normals [scene.n_triangles [primID].c ];
1271+ has_smooth_normals = true ;
1272+ } else {
1273+ n[0 ] = n[1 ] = n[2 ] = Ng;
1274+ }
1275+
1276+ if (scene.uv_triangles [primID].a >= 0 ) {
1277+ uv[0 ] = scene.uvs [scene.uv_triangles [primID].a ];
1278+ uv[1 ] = scene.uvs [scene.uv_triangles [primID].b ];
1279+ uv[2 ] = scene.uvs [scene.uv_triangles [primID].c ];
1280+ } else {
1281+ uv[0 ] = uv[1 ] = uv[2 ] = Vec2 (0 , 0 );
1282+ }
1283+
1284+ // displace each vertex
1285+ for (int i = 0 ; i < 3 ; i++) {
1286+ ShaderGlobals sg = {};
1287+ sg.P = p[i];
1288+ sg.Ng = Ng;
1289+ sg.N = n[i];
1290+ sg.u = uv[i].x ;
1291+ sg.v = uv[i].y ;
1292+ sg.I = (p[i] - camera.eye ).normalize ();
1293+ sg.surfacearea = area;
1294+ sg.renderstate = &sg;
1295+
1296+ shadingsys->execute (*ctx, *m_shaders[shaderID].disp , sg);
1297+
1298+ p[i] = sg.P ;
1299+ }
1300+ disp_verts[scene.triangles [primID].a ] += p[0 ];
1301+ disp_verts[scene.triangles [primID].b ] += p[1 ];
1302+ disp_verts[scene.triangles [primID].c ] += p[2 ];
1303+ }
1304+
1305+ // release context
1306+ shadingsys->release_context (ctx);
1307+ shadingsys->destroy_thread_info (thread_info);
1308+
1309+ // average each vertex by the number of times it was displaced
1310+ for (int i = 0 , n = scene.verts .size (); i < n; i++) {
1311+ if (valance[i] > 0 )
1312+ disp_verts[i] /= float (valance[i]);
1313+ else
1314+ disp_verts[i] = scene.verts [i];
1315+ }
1316+ // replace old data with the new
1317+ scene.verts = std::move (disp_verts);
1318+
1319+ if (has_smooth_normals) {
1320+ // Recompute the vertex normals (if we had some)
1321+ std::vector<Vec3> disp_normals (scene.normals .size (), Vec3 (0 , 0 , 0 ));
1322+ for (int primID = 0 , nprims = scene.triangles .size (); primID < nprims; primID++) {
1323+ if (scene.n_triangles [primID].a >= 0 ) {
1324+ Vec3 p[3 ];
1325+ p[0 ] = scene.verts [scene.triangles [primID].a ];
1326+ p[1 ] = scene.verts [scene.triangles [primID].b ];
1327+ p[2 ] = scene.verts [scene.triangles [primID].c ];
1328+ // don't normalize to weight by area
1329+ Vec3 Ng = (p[0 ] - p[1 ]).cross (p[0 ] - p[2 ]);
1330+ disp_normals[scene.n_triangles [primID].a ] += Ng;
1331+ disp_normals[scene.n_triangles [primID].b ] += Ng;
1332+ disp_normals[scene.n_triangles [primID].c ] += Ng;
1333+ }
1334+ }
1335+ for (Vec3& n : disp_normals)
1336+ n = n.normalize ();
1337+ scene.normals = std::move (disp_normals);
1338+ }
1339+ }
1340+
12081341 // build bvh and prepare triangles
12091342 scene.prepare (errhandler ());
12101343 prepare_lights ();
@@ -1241,7 +1374,7 @@ SimpleRaytracer::prepare_lights()
12411374 // collect all light emitting triangles
12421375 for (unsigned t = 0 , n = scene.num_prims (); t < n; t++) {
12431376 int shaderID = scene.shaderid (t);
1244- if (shaderID < 0 || !m_shaders[shaderID])
1377+ if (shaderID < 0 || !m_shaders[shaderID]. surf )
12451378 continue ; // no shader attached
12461379 if (m_shader_is_light[shaderID])
12471380 m_lightprims.emplace_back (t);
0 commit comments