Skip to content

Commit dd8b09d

Browse files
committed
testrender: Implement basic displacement shader support
Associate an (optional) displacement shader with each material. On startup, we execute the displacement for each face-vertex that has a valid displacement shader assigned. Signed-off-by: Chris Kulla <[email protected]>
1 parent cd04551 commit dd8b09d

File tree

1 file changed

+117
-2
lines changed

1 file changed

+117
-2
lines changed

src/testrender/simpleraytracer.cpp

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,7 @@ SimpleRaytracer::parse_scene_xml(const std::string& scenefile)
475475
if (auto it = shadermap.find(name); it != shadermap.end()) {
476476
int shaderID = it->second;
477477
if (shaderID >= 0 && shaderID < int(shaders().size())) {
478-
print(stderr, "Updating shader {} - {}\n", shaderID,
479-
shadertype);
478+
fprintf(stderr, "Updating shader %d - %s\n", shaderID, shadertype.c_str());
480479
// we already have a material under this name,
481480
Material& m = shaders()[shaderID];
482481
// TODO: could we query the shadertype directly from the ShaderGroup?
@@ -1223,6 +1222,122 @@ SimpleRaytracer::prepare_render()
12231222
backgroundResolution = 0;
12241223
}
12251224

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+
12261341
bool have_displacement = false;
12271342
for (const Material& m : shaders()) {
12281343
if (m.disp) {

0 commit comments

Comments
 (0)