@@ -471,9 +471,27 @@ 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,
479+ shadertype.c_str ());
480+ // we already have a material under this name,
481+ Material& m = shaders ()[shaderID];
482+ // TODO: could we query the shadertype directly from the ShaderGroup?
483+ if (shadertype == " displacement" )
484+ m.disp = group;
485+ else if (shadertype == " surface" )
486+ m.surf = group;
487+ // skip the rest which would add a new material
488+ continue ;
489+ }
490+ } else {
491+ shadermap.emplace (name, int (shaders ().size ()));
492+ }
493+ }
494+ shaders ().emplace_back (Material { group, nullptr });
477495 m_shader_is_light.emplace_back (
478496 is_light_attr ? strtobool (is_light_attr.value ()) : false );
479497 } else {
@@ -925,7 +943,7 @@ SimpleRaytracer::eval_background(const Dual2<Vec3>& dir, ShadingContext* ctx,
925943 if (bounce >= 0 )
926944 sg.raytype = bounce > 0 ? Ray::DIFFUSE : Ray::CAMERA;
927945#ifndef __CUDACC__
928- shadingsys->execute (*ctx, *m_shaders[backgroundShaderID], sg);
946+ shadingsys->execute (*ctx, *m_shaders[backgroundShaderID]. surf , sg);
929947#else
930948 alignas (8 ) char closure_pool[256 ];
931949 execute_shader (sg, render_params.bg_id , closure_pool);
@@ -1000,11 +1018,11 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler,
10001018 int shaderID = scene.shaderid (hit.id );
10011019
10021020#ifndef __CUDACC__
1003- if (shaderID < 0 || !m_shaders[shaderID])
1021+ if (shaderID < 0 || !m_shaders[shaderID]. surf )
10041022 break ; // no shader attached? done
10051023
10061024 // execute shader and process the resulting list of closures
1007- shadingsys->execute (*ctx, *m_shaders[shaderID], sg);
1025+ shadingsys->execute (*ctx, *m_shaders[shaderID]. surf , sg);
10081026#else
10091027 if (shaderID < 0 )
10101028 break ; // no shader attached? done
@@ -1116,7 +1134,7 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler,
11161134 sample.u , sample.v );
11171135#ifndef __CUDACC__
11181136 // execute the light shader (for emissive closures only)
1119- shadingsys->execute (*ctx, *m_shaders[shaderID],
1137+ shadingsys->execute (*ctx, *m_shaders[shaderID]. surf ,
11201138 light_sg);
11211139#else
11221140 execute_shader (light_sg, shaderID, light_closure_pool);
@@ -1205,6 +1223,8 @@ SimpleRaytracer::prepare_render()
12051223 backgroundResolution = 0 ;
12061224 }
12071225
1226+ prepare_geometry ();
1227+
12081228 // build bvh and prepare triangles
12091229 scene.prepare (errhandler ());
12101230 prepare_lights ();
@@ -1241,7 +1261,7 @@ SimpleRaytracer::prepare_lights()
12411261 // collect all light emitting triangles
12421262 for (unsigned t = 0 , n = scene.num_prims (); t < n; t++) {
12431263 int shaderID = scene.shaderid (t);
1244- if (shaderID < 0 || !m_shaders[shaderID])
1264+ if (shaderID < 0 || !m_shaders[shaderID]. surf )
12451265 continue ; // no shader attached
12461266 if (m_shader_is_light[shaderID])
12471267 m_lightprims.emplace_back (t);
@@ -1252,6 +1272,129 @@ SimpleRaytracer::prepare_lights()
12521272}
12531273
12541274
1275+ void
1276+ SimpleRaytracer::prepare_geometry ()
1277+ {
1278+ bool have_displacement = false ;
1279+ for (const Material& m : shaders ()) {
1280+ if (m.disp ) {
1281+ have_displacement = true ;
1282+ break ;
1283+ }
1284+ }
1285+ if (have_displacement) {
1286+ errhandler ().infofmt (" Evaluating displacement shaders" );
1287+ // Loop through all triangles and run displacement shader if there is one
1288+ // or copy the input point if there is none
1289+ std::vector<Vec3> disp_verts (scene.verts .size (), Vec3 (0 , 0 , 0 ));
1290+ std::vector<int > valance (
1291+ scene.verts .size (),
1292+ 0 ); // number of times each vertex has been displaced
1293+
1294+ OSL::PerThreadInfo* thread_info = shadingsys->create_thread_info ();
1295+ ShadingContext* ctx = shadingsys->get_context (thread_info);
1296+
1297+ bool has_smooth_normals = false ;
1298+ for (int primID = 0 , nprims = scene.triangles .size (); primID < nprims;
1299+ primID++) {
1300+ Vec3 p[3 ], n[3 ];
1301+ Vec2 uv[3 ];
1302+
1303+ p[0 ] = scene.verts [scene.triangles [primID].a ];
1304+ p[1 ] = scene.verts [scene.triangles [primID].b ];
1305+ p[2 ] = scene.verts [scene.triangles [primID].c ];
1306+
1307+ valance[scene.triangles [primID].a ]++;
1308+ valance[scene.triangles [primID].b ]++;
1309+ valance[scene.triangles [primID].c ]++;
1310+
1311+ int shaderID = scene.shaderid (primID);
1312+ if (shaderID < 0 || !m_shaders[shaderID].disp ) {
1313+ disp_verts[scene.triangles [primID].a ] += p[0 ];
1314+ disp_verts[scene.triangles [primID].b ] += p[1 ];
1315+ disp_verts[scene.triangles [primID].c ] += p[2 ];
1316+ continue ;
1317+ }
1318+
1319+
1320+ Vec3 Ng = (p[0 ] - p[1 ]).cross (p[0 ] - p[2 ]);
1321+ float area = 0 .5f * Ng.length ();
1322+ Ng = Ng.normalize ();
1323+ if (scene.n_triangles [primID].a >= 0 ) {
1324+ n[0 ] = scene.normals [scene.n_triangles [primID].a ];
1325+ n[1 ] = scene.normals [scene.n_triangles [primID].b ];
1326+ n[2 ] = scene.normals [scene.n_triangles [primID].c ];
1327+ has_smooth_normals = true ;
1328+ } else {
1329+ n[0 ] = n[1 ] = n[2 ] = Ng;
1330+ }
1331+
1332+ if (scene.uv_triangles [primID].a >= 0 ) {
1333+ uv[0 ] = scene.uvs [scene.uv_triangles [primID].a ];
1334+ uv[1 ] = scene.uvs [scene.uv_triangles [primID].b ];
1335+ uv[2 ] = scene.uvs [scene.uv_triangles [primID].c ];
1336+ } else {
1337+ uv[0 ] = uv[1 ] = uv[2 ] = Vec2 (0 , 0 );
1338+ }
1339+
1340+ // displace each vertex
1341+ for (int i = 0 ; i < 3 ; i++) {
1342+ ShaderGlobals sg = {};
1343+ sg.P = p[i];
1344+ sg.Ng = Ng;
1345+ sg.N = n[i];
1346+ sg.u = uv[i].x ;
1347+ sg.v = uv[i].y ;
1348+ sg.I = (p[i] - camera.eye ).normalize ();
1349+ sg.surfacearea = area;
1350+ sg.renderstate = &sg;
1351+
1352+ shadingsys->execute (*ctx, *m_shaders[shaderID].disp , sg);
1353+
1354+ p[i] = sg.P ;
1355+ }
1356+ disp_verts[scene.triangles [primID].a ] += p[0 ];
1357+ disp_verts[scene.triangles [primID].b ] += p[1 ];
1358+ disp_verts[scene.triangles [primID].c ] += p[2 ];
1359+ }
1360+
1361+ // release context
1362+ shadingsys->release_context (ctx);
1363+ shadingsys->destroy_thread_info (thread_info);
1364+
1365+ // average each vertex by the number of times it was displaced
1366+ for (int i = 0 , n = scene.verts .size (); i < n; i++) {
1367+ if (valance[i] > 0 )
1368+ disp_verts[i] /= float (valance[i]);
1369+ else
1370+ disp_verts[i] = scene.verts [i];
1371+ }
1372+ // replace old data with the new
1373+ scene.verts = std::move (disp_verts);
1374+
1375+ if (has_smooth_normals) {
1376+ // Recompute the vertex normals (if we had some)
1377+ std::vector<Vec3> disp_normals (scene.normals .size (), Vec3 (0 , 0 , 0 ));
1378+ for (int primID = 0 , nprims = scene.triangles .size ();
1379+ primID < nprims; primID++) {
1380+ if (scene.n_triangles [primID].a >= 0 ) {
1381+ Vec3 p[3 ];
1382+ p[0 ] = scene.verts [scene.triangles [primID].a ];
1383+ p[1 ] = scene.verts [scene.triangles [primID].b ];
1384+ p[2 ] = scene.verts [scene.triangles [primID].c ];
1385+ // don't normalize to weight by area
1386+ Vec3 Ng = (p[0 ] - p[1 ]).cross (p[0 ] - p[2 ]);
1387+ disp_normals[scene.n_triangles [primID].a ] += Ng;
1388+ disp_normals[scene.n_triangles [primID].b ] += Ng;
1389+ disp_normals[scene.n_triangles [primID].c ] += Ng;
1390+ }
1391+ }
1392+ for (Vec3& n : disp_normals)
1393+ n = n.normalize ();
1394+ scene.normals = std::move (disp_normals);
1395+ }
1396+ }
1397+ }
12551398
12561399void
12571400SimpleRaytracer::render (int xres, int yres)
0 commit comments