jonp Posted April 22, 2009 Share Posted April 22, 2009 I found some pretty good info on projecting textures here: http://forums.odforce.net/index.php?showtopic=2749&st=12 However, I was wondering if there is a way to achieve the same effect without using a light shader or NDC space. I'm trying to project density into a volume, and if I understand the order of shading in Mantra, using a light shader prevents me from using that density projection for normal calculation or shadowing... correct? -JP Quote Link to comment Share on other sites More sharing options...
Mario Marengo Posted April 22, 2009 Share Posted April 22, 2009 I found some pretty good info on projecting textures here:http://forums.odforce.net/index.php?showtopic=2749&st=12 However, I was wondering if there is a way to achieve the same effect without using a light shader or NDC space. I'm trying to project density into a volume, and if I understand the order of shading in Mantra, using a light shader prevents me from using that density projection for normal calculation or shadowing... correct? -JP If your light shader can (by projection or otherwise) solve for density at Ps and export it, then the surface/volume shader should be able to import it and use it. For the volume shader to then go ahead and compute N from derivatives of the imported densities is something that needs to be tested though (I've never tried it myself and, even though Du(), Dv(), and Dw() are now available for volume shaders, I'm not certain if they would work on imported values... they should, but it needs testing). With regard to shadows, I believe the volume shader is simply called for each sample along the march toward the light and its Of output accumulated, none of which should be broken by having the density that Of depends on come in as an import as opposed to a bound parameter... but I could be missing something. It's worth a try, and it should be pretty straight forward to test it out. Cheers. Quote Link to comment Share on other sites More sharing options...
jonp Posted April 23, 2009 Author Share Posted April 23, 2009 So far my workflow has been: Create a separate illuminance loop in the surface shader for the projection light using light mask parameters to isolate its contribution, then multiply my bound density by its output, then pipe that into the standard calcOpacity subnet vop for volumes. I'll try importing a density var from a light shader later today but I don't know exactly how that would be different from what I'm doing. Why I am most confused about this is that for one light(light with shadow contribution) to be affected by another(light with density contribution) you would have to make sure they are called in the right order in the shader, right? -jp Quote Link to comment Share on other sites More sharing options...
mrice Posted April 23, 2009 Share Posted April 23, 2009 Cool idea! I got the basics to work doing exactly what you're saying, but importing a variable from the light shader. I'm not sure how to get correct shadows though, seems youre right the density would have to be modified before the surface shader is called. Quote Link to comment Share on other sites More sharing options...
Mario Marengo Posted April 24, 2009 Share Posted April 24, 2009 So far my workflow has been:Create a separate illuminance loop in the surface shader for the projection light using light mask parameters to isolate its contribution, then multiply my bound density by its output, then pipe that into the standard calcOpacity subnet vop for volumes. I'll try importing a density var from a light shader later today but I don't know exactly how that would be different from what I'm doing. Why I am most confused about this is that for one light(light with shadow contribution) to be affected by another(light with density contribution) you would have to make sure they are called in the right order in the shader, right? -jp Hmm.. yes, I "get" your workflow, but I guess I misunderstood your intent from your initial post. I thought the light was defining the density everywhere, and since you said "using a light shader prevents me from using that density projection for normal calculation or shadowing", I thought you needed to calc normals from the density gradient of said projections... which is why I mentioned derivs.. But from this last post it seems you just want to scale an existing bound density field by a projected image-based scaling factor... like a cookie cutter? Anyway, here's a quick sketch of what I was talking about, assuming a simple "cookie-cutter density light": 2 lights, both have shadows, 1 of them is standard illumination only, and the other one projects illumination as usual, but also exports a density scaling factor (which is the alpha of the image in this example), which the volume shader imports and uses to scale the bound density. projden.hip But I take it then that this is not what you're after? P.S: Here's the code for the "density light" and the volume shader used above: vol_projden.vfl: #pragma label denscale "Normal Density" #pragma label pdenscale "Projected Density" #pragma hint density hidden surface vol_projden ( float denscale = 1; // density scaling for bound density float pdenscale = 10; // density scaling for projected density float density = 1; // bound density field (hidden) ) { vector illum = 0; float dens = density; if(!isshadowray()) { illuminance(P,{0,1,0},M_PI) { float kd = 1; if(limport("density",kd)) dens *= kd*pdenscale; shadow(Cl); illum += Cl; } } Of = 1 - exp(-denscale*dens); Cf = illum * Of; F = isotropic(); } light_projden.vfl: #pragma label denimage "Density Image" #pragma label dmin "Minimum Density" #pragma hint density hidden light light_projden ( string denimage = "default.rat"; float dmin = 0; export float density = 1; ) { Cl = 0; if(denimage!="") { vector Pndc = toNDC(wo_space(Ps)); vector4 rgba = texture(denimage,Pndc.x,Pndc.y, "filter","gauss", "width" ,2, "mode","black"); float dout = rgba.a; density = lerp(dmin,dout,filterstep(dmin,dout,"filter","gauss")); Cl = (vector)rgba; } } Quote Link to comment Share on other sites More sharing options...
Mario Marengo Posted April 24, 2009 Share Posted April 24, 2009 ...but the projected butterfly doesn't itself cast shadows... that's the problem, isn't it? Huh. Interesting challenge, this. You can't remove the if(!isshadow()) because you'll end up with infinite recursion. There might be a way using the new getlights() and eval_light() functions to roll your own illuminance (and sampling your own shadows)... Quote Link to comment Share on other sites More sharing options...
jonp Posted April 24, 2009 Author Share Posted April 24, 2009 ...but the projected butterfly doesn't itself cast shadows... that's the problem, isn't it?Huh. Interesting challenge, this. You can't remove the if(!isshadow()) because you'll end up with infinite recursion. There might be a way using the new getlights() and eval_light() functions to roll your own illuminance (and sampling your own shadows)... Yep, that's the crux right there. I want the density projection from a light shader to cast shadows in the volume from other lights. Quote Link to comment Share on other sites More sharing options...
Mario Marengo Posted April 24, 2009 Share Posted April 24, 2009 Yep, that's the crux right there. I want the density projection from a light shader to cast shadows in the volume from other lights. I think the only way is to move everything to the surface shader. I'll explain when I get home... gotta run. Quote Link to comment Share on other sites More sharing options...
jonp Posted April 24, 2009 Author Share Posted April 24, 2009 Nice work Mario, thanks! I expected a surface shader-only solution... I think the only way is to move everything to the surface shader. I'll explain when I get home... gotta run. Quote Link to comment Share on other sites More sharing options...
Jason Posted April 25, 2009 Share Posted April 25, 2009 Nothing to add, except "interesting thread!" Quote Link to comment Share on other sites More sharing options...
Mario Marengo Posted April 25, 2009 Share Posted April 25, 2009 Oh, man! I suck! I left the files at work thinking I'd ftp them home later... and forgot they were scheduled to start moving everything to a new ISP starting tonight. And they said it'd take up to 40+ hours. I left in a rush and forgot. So sorry! Anyway. Doesn't matter. All it was is moving the projection to the surface shader. You'll need to know the name of light object to project from (this will let you do the P transform), then some of the projection parameters depending on how "true-to-the-light you want the projection to be (focal, aperture, etc), then some parms for the density scaling. Finally, but optionally, if you want maintain the pixel aspect regardless of zoom, you can use the teximport() function to grab "texture:resolution" (a vector). Of course, you could also simplify the whole NDC-project to a simple scaled {x,y} (after transform) since you don't have to duplicate a given light's frustum (just some scaled/zoomed version of its POV). Yup, a bit of a PITA, but really, I'm quite convinced now that there's no way to query light sources in any way when the surface/volume shader is being called during an opacity march. Hope that makes sense. I'll post the files as soon as I can get at them. Quote Link to comment Share on other sites More sharing options...
itriix Posted April 25, 2009 Share Posted April 25, 2009 I think the only way is to move everything to the surface shader. I'll explain when I get home... gotta run. Hi Mario, I was just wondering if you could post a hip... looks very interesting. i'd like to study it!! Quote Link to comment Share on other sites More sharing options...
Mario Marengo Posted April 26, 2009 Share Posted April 26, 2009 Bah! I still can't get at the files, so I rewrote it (with a little more attention to the projection and overall filtering). The only problem with this method is that if you just use the projector light as the IFD-bound object to transform to, then it won't work with mapped shadows. This is because the only light object included in the IFD snippet which generates the shadow map will be the light for which the shadow is being generated (and only that one). So, the way around this, is to create a null, parented to each projector light, which is set to output as a transform to the IFD (a "space"), then use that as a reference instead of the actual light object. Also, there seems to be a possible bug (needs further testing to make sure), with the ptransform() function. In transforming P to calculate the projection, we want the inverse of the current-to-light transform, but trying to write this as ptransform(light_obj,"space:current",P) fails during shadow map generation, so instead, I write it as P*invert(otransform(light_obj)); which seems to work properly in all modes. Other than that, it's just a duplication of the light projection, done inside the surface shader. Hope it makes sense. Cheers! projden5.hip projden.vfl : #include <math.h> vector maxfv(float a; vector b ) { return set( max(a,b.x), max(a,b.y), max(a,b.z) ); } vector gamma(vector col; float g) { return pow(col,1./g); } float depthavg(float val; vector voxdim; int doabs) { float x = val; float dx = Du(x); float dy = Dv(x); float dz = Dw(x); if(doabs) { dx = abs(dx); dy = abs(dy); dz = abs(dz); } float a = voxdim.x * (2.*x + dx) / 2.; float b = voxdim.y * (2.*x + dy) / 2.; float c = voxdim.z * (2.*x + dz) / 2.; return (a+b+c) / (voxdim.x+voxdim.y+voxdim.z); } vector depthavgV(vector val; vector voxdim; int doabs) { float x = val.x; float y = val.y; float z = val.z; return set(depthavg(x,voxdim,doabs), depthavg(y,voxdim,doabs), depthavg(z,voxdim,doabs) ); } #pragma label denscale "Density" #pragma label plight1 "Proj Light 1" #pragma label pmap1 "Proj Image 1" #pragma label pgamma1 "Proj Gamma 1" #pragma label pfw1 "Proj Filter Width 1" #pragma label paov1 "Proj Angle 1" #pragma label pzoom1 "Proj Zoom 1" #pragma label pdens1 "Proj Density 1" #pragma hint density hidden surface projden ( float denscale = 1; // projector block string plight1 = ""; string pmap1 = ""; float pgamma1 = 0.454545; // = 1/2.2, because assumes display gamma=2.2 float pfw1 = 1.5; float paov1 = 45; float pzoom1 = 1; float pdens1 = 1; // bound fields float density = 1; ) { float dens = density*denscale; vector illum = 0; vector voxdim = set(length(dPds),length(dPdt),dPdz); // go through all the projectors and update dens/illum float kdens = 1; vector p,res; vector4 rgba; float u,v,d; if(plight1!="" && pmap1!="") { // the following doesn't work... though it should //p = ptransform(plight1,"space:current",P); // so I use otransform() instead. Make sure the 'plight' object is // a null object (child of the light) set to output transform to the IFD p = P*invert(otransform(plight1)); res = teximport(pmap1,"texture:resolution",res); d = 2*tan(pzoom1*radians(paov1)/2); u = 0.5 - (res.x*p.x/p.z) / d; v = 0.5 - (res.y*p.y/p.z) / d; rgba = texture(pmap1,u,v,"mode","black","filter","gauss","width",pfw1); illum += gamma((vector)rgba,pgamma1); kdens *= rgba.a*pdens1; } float pdens = density * kdens; // set density (watch for discontinuity at projection's edge) d = lerp(dens,pdens,filterstep(dens,pdens,"filter","gauss")); d = max(0,depthavg(d,voxdim,0)); Of = 1 - exp(-d); // normal illuminance illuminance(P,{0,1,0},M_PI) { shadow(Cl); illum += maxfv(0,Cl); } illum = maxfv(0,depthavgV(illum,voxdim,0)); Cf = illum * Of; F = isotropic(); } Quote Link to comment Share on other sites More sharing options...
itriix Posted April 27, 2009 Share Posted April 27, 2009 thanks much! can't wait to give this a look! so busy at the moment. Jonathan Quote Link to comment Share on other sites More sharing options...
jonp Posted April 28, 2009 Author Share Posted April 28, 2009 Thanks Mario! Impressive! The shader makes more sense every time I look at the code, but alas I haven't yet had time to test it out. What's great (I'm guessing) is that the code that mimics the light NDC space could be applied to other special cases as well (transparency mapping for surfaces, etc). -JP Quote Link to comment Share on other sites More sharing options...
Mario Marengo Posted April 28, 2009 Share Posted April 28, 2009 What's great (I'm guessing) is that the code that mimics the light NDC space could be applied to other special cases as well (transparency mapping for surfaces, etc). Yes... in theory Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.