Was Sie über das Photon Mapping für allgemeine Shader wissen sollten.
Photon Mapping ist seit der Version 11.0 Teil von PRMan. Die Lichtquellen mussten jedoch fest programmierte Abstände aufweisen und die Oberflächenmaterialien waren auf einen festen, begrenzten Satz von Materialien (matt, transzulent, chrom, transparent, Glas und Wasser) beschränkt. Die vielleicht größte Einschränkung war, dass Texturen in Photon Tracing Phasen nicht verwendet werden konnten.
PRMan 13.5 führte einen viel allgemeineren und flexibleren Ansatz für das Photon Mapping ein. Der Ansatz arbeitet mit sehr allgemeinen Shadern, einschließlich Flächenlichtquellen, Oberflächentexturen und Displacement Shadern. Der größte Nachteil ist, dass die direkte Beleuchtung und die Oberflächenfarben in Punktwolken-Dateien gebakt werden müssen. Zweck dieser Application Note ist es, Beispiele für den Einsatz von Photonen-Maps für Causting und Global Illumination mit sehr allgemeinen Lichtquellen und Surface Shadern zu liefern.
Sampling Illuminationen und Scattering-Koeffizienten.
Um die Emission und das Tracing von Photonen zu kontrollieren, müssen wir zunächst die Beleuchtung und die Oberflächenfarben baken.
Baken mit direkter Beleuchtung.
Die Photonen-Emission, die einfachen Lichtquellen entspricht, ist relativ unkompliziert. Allgemeine Light Source Shader können jedoch auch einen unnatürlichen Absturz der Entfernung, gefakte Shading-Positionen und Positions-Highlights etc. aufweisen. Es ist schwierig, die Photonenemission auf solche Shader abzustimmen. Hier werden wir jedoch einen anderen Ansatz verfolgen: Bewerten Sie die Light Source Shader an den Oberflächenpunkten, indem Sie die direkte Beleuchtung durch die Lichtquellen darstellen. Dabei wird jeder Lichtquellen-Shader grundsätzlich als „Black Box“ behandelt, die sich durch ihre Beleuchtung auf den Oberflächen der Szene auszeichnet.
Um die direkte Beleichtung festzulegen, müssen wir die Szene mit einem Lichtquellen-Shader rendern, der _Bestrahlungsstärke, L und _Bereich mit der Funktion bake3d() bakt. (L ist notwendig, wenn alle Oberflächen diffus sind).
Als Beispiel verwenden wir eine Box mit zwei Teekannen sowie Textur- und Displacement Maps. Die Szene wird von drei Lichtquellen beleuchtet. Sie speichern die Beleuchtung für den Einsatz in der Photonen-Emission – drei Lichtquellen werden in die gleiche Punktwolken Datei eingebrannt. Nachfolgend sind die beiden verwendeten Lichtquellen-Shader aufgeführt. Der Shader „Myspotlight“ ist ein Scheinwerfer ohne Abstandsverlust „Projectlightxz“ projiziert eine leichte Textur (in der x-z-Ebene) ähnlich einem Diaprojektor. Die Schatten werden mit Raytracing berechnet.
Die Zeile „L = L;“ ist ein notwendiger Trick, um eine unerwünschte Optimierung zu vermeiden und damit sicherzustellen, dass der Lichtquellen-Shader auf allen Shading-Grids betrieben wird.
light
myspotlight(
float intensity = 1;
color lightcolor = 1;
float falloff = 0; // default: no fall-off
point from = point "shader" (0,0,0); // light position
vector dir = (0, -1, 0); // light direction (center of cone)
float coneangle = radians(30);
float conedeltaangle = radians(5);
string filename = "";) // point cloud file
{
uniform float cosoutside = cos(coneangle);
uniform float cosinside = cos(coneangle-conedeltaangle);
vector dirn, Ln;
float dist, cosangle, atten;
float a = area(Ps, "dicing"); // micropolygon area
dirn = normalize(dir);
illuminate(from, dirn, coneangle) {
L = L; // trick to avoid skipping light source shader call !!
dist = length(L);
Ln = L / dist;
cosangle = dirn.Ln;
atten = pow(dist, -falloff); // distance fall-off
atten *= smoothstep(cosoutside, cosinside, cosangle); // cone edge
Cl = atten * intensity * lightcolor;
Cl *= transmission(Ps, from); // ray traced shadow
// Compute irradiance to bake
float dot = -(Ln.N) / length(N);
color irrad = Cl * abs(dot);
// Bake the direct illum, illum direction, and micropolygon area
if (filename != "" && (irrad[0] > 0 || irrad[1] > 0 || irrad[2] > 0))
bake3d(filename, "_irradiance,L,_area", Ps, N, "interpolate", 1,
"_irradiance", irrad, "L", Ln, "_area", a);
}
}
light
projectorlightxz(
float intensity = 1;
color lightcolor = 1;
float minx = -1, maxx = 1, minz = -1, maxz = 1;
string texturename = "";
point from = point "shader" (0,0,0); // light position
vector dir = (0, -1, 0); // light direction (don't illum behind)
string filename = "";) // point cloud file name
{
uniform float dx = maxx - minx, dz = maxz - minz;
vector Ln;
float x = Ps[0], z = Ps[2], s, t;
float a = area(Ps, "dicing"); // micropolygon area
illuminate(from, dir, PI/2) {
if (minx <= x && x <= maxx && minz <= z && z <= maxz) {
// Compute illumination (ignoring shadow)
Cl = intensity * lightcolor;
if (texturename != "") {
s = (x - minx) / dx;
t = (z - minz) / dz;
Cl *= texture(texturename, s, t);
}
// Compute ray-traced shadow
Cl *= transmission(Ps, from);
// Compute irradiance to bake
Ln = normalize(L);
float dot = -(Ln.N) / length(N);
color irrad = Cl * abs(dot);
// Bake the direct illum, illum direction, and micropolygon area
if (filename != "" && (irrad[0] > 0 || irrad[1] > 0 || irrad[2] > 0))
bake3d(filename, "_irradiance,L,_area", Ps, N, "interpolate", 1,
"_irradiance", irrad, "L", Ln, "_area", a);
}
}
}
Der Vollständigkeit halber sind die drei Displacement Shader im Folgenden aufgeführt. Der Einsatz von Displacement-Shadern zeigt hier, dass Displacement- mit Photonen-Mapping gut funktioniert.
Hier ist die RIB-Datei für die Szene:
FrameBegin 1
Format 400 400 1
ShadingInterpolation "smooth"
PixelSamples 4 4
Display "box_bake_direct" "it" "rgba"
Projection "perspective" "fov" 30
Translate 0 0 5
DisplayChannel "color _irradiance"
DisplayChannel "vector L"
DisplayChannel "float _area"
WorldBegin
Attribute "cull" "hidden" 0 # ensure illum is baked behind objects
Attribute "cull" "backfacing" 0 # ensure illum is baked on backsides
Attribute "dice" "rasterorient" 0 # view-independent dicing
# Turn on ray-traced shadows
Attribute "visibility" "transmission" 1
Attribute "trace" "bias" 0.0001
# Turn on displacements
Attribute "trace" "displacements" 1
Attribute "displacementbound" "sphere" 0.1 "coordinatesystem" "world"
# Light sources (each bakes its own illumination)
LightSource "myspotlight" 1 # wide white spot
"point from" [0.5 0.999 0] "vector dir" [0 -1 0] "float coneangle" 1.2
"string filename" "box_direct.ptc"
LightSource "myspotlight" 2 # narrow red spot
"point from" [0.5 0.999 -0.5] "vector dir" [-0.3 -1 0.3]
"float intensity" 0.5 "color lightcolor" [1 0 0] "float coneangle" 0.3
"string filename" "box_direct.ptc"
LightSource "projectorlightxz" 3 # project bright prman logo texture
"point from" [-0.7 0 0.75] "vector dir" [0 1 0]
"float minx" -0.9 "float maxx" -0.4
"float minz" 5.5 "float maxz" 5.99
"float intensity" 2
"texturename" "prman_logo.tex"
"filename" "box_direct.ptc"
Surface "matte"
# Left wall
AttributeBegin
Displacement "dispsinz" "float freq" 22 "float scale" 0.1
Polygon "P" [ -1 1 -1 -1 1 1 -1 -1 1 -1 -1 -1 ]
"s" [0 1 1 0] "t" [0 0 1 1]
AttributeEnd
AttributeBegin
Polygon "P" [ 1 -1 -1 1 -1 1 1 1 1 1 1 -1 ] # right wall
Polygon "P" [ -1 -1 1 1 -1 1 1 -1 -1 -1 -1 -1 ] # floor
Polygon "P" [ -1 1 -1 1 1 -1 1 1 1 -1 1 1 ] # ceiling
AttributeEnd
# Back wall
AttributeBegin
Attribute "displacementbound" "sphere" 0.01 "coordinatesystem" "world"
Displacement "dispmap" "string texturename" "prman_logo.tex"
"float scale" -0.01
Polygon "P" [ -1 1 1 1 1 1 1 -1 1 -1 -1 1 ]
"s" [-1 2 2 -1] "t" [-1 -1 2 2]
AttributeEnd
# Left teapot (chrome, but matte in this pass)
AttributeBegin
Translate -0.35 -0.999 0.35
Scale 0.18 0.18 0.18
Rotate -30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
# Right teapot (displaced matte)
AttributeBegin
ShadingRate 0.25 # dense tessellation for fine displacement details
Displacement "disppumpkin" "float freq" 9 "float scale" 0.05
Translate 0.35 -0.999 -0.35
Scale 0.18 0.18 0.18
Rotate 30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
WorldEnd
FrameEnd
Sonderfall: Wenn alle Oberflächen rein diffus sind, muss die L-Richtung nicht eingebrannt werden. In diesem Fall genügt es, die gesamte CI (die Summe der Beleuchtung aller Lichtquellen) zusammen mit der Mikropolygonfläche zu baken. Dies kann entweder im Oberflächen-Shader oder in einem Atmosphere-Shader erfolgen.
Potentieller Pit-Fall: Wenn mehrere Lichtquellen in die gleiche Punktwolken-Datei schreiben, dann ist es wichtig, dass die Display-Kanäle nicht „EliminateDuplicateGrids“ einschalten. Wenn ja, dann werden nur Punkte der ersten Lichtquelle in der Punktwolke gespeichert. Wenn EliminateDuplicateGrids eingeschaltet sein muss (für Netrendering), dann sollte das Baken in einem Surface Shader (oder Atmosphere-Shader) erfolgen.
Baking Scattering Koeffizienten.
Um die Scattering Koeffizienten festzulegen, muss die Szene mit Oberflächenschattierungen gerendert werden, die die Streukoeffizienten für die Oberflächenmaterialien der Objekte baken.
Der Oberflächen-Shader „bake_scattercoeffs“ speichert Scattering Koeffizienten für das Photonen Tracing: diffuse Reflexion, Spiegelreflexion, diffuse Refraction und Specular Refraction. (Das Baken und spätere Nachschlagen basiert auf den nach außen gerichteten Oberflächen-Normals).
surface
bake_scattercoeffs(string filename = "", displaychannels = "";
color specrefl = 0, diffrefr = 0, specrefr = 0;
float ior = 1;
string texturename = "")
{
color diffrefl = Cs;
normal Nn = normalize(N);
// Multiply diffuse color by texture, if present
if (texturename != "")
diffrefl *= texture(texturename);
// Store scattering coefficients in point cloud file
bake3d(filename, displaychannels, P, Nn, "interpolate", 1,
"diffrefl", diffrefl, "specrefl", specrefl,
"diffrefr", diffrefr, "specrefr", specrefr, "ior", ior);
Ci = diffrefl * Os;
Oi = Os;
}
Hier ist die RIB-Datei:
FrameBegin 1
Format 400 400 1
ShadingInterpolation "smooth"
PixelSamples 4 4
Display "box_bake_scattercoeffs" "it" "rgba"
Projection "perspective" "fov" 30
Translate 0 0 5
DisplayChannel "color diffrefl"
DisplayChannel "color specrefl"
DisplayChannel "color diffrefr" # unused in this example
DisplayChannel "color specrefr" # unused in this example
DisplayChannel "float ior" # unused in this example
WorldBegin
Attribute "cull" "hidden" 0 # ensure illum is baked behind objects
Attribute "cull" "backfacing" 0 # ensure illum is baked on backsides
Attribute "dice" "rasterorient" 0 # view-independent dicing
# Turn on displacements
Attribute "trace" "displacements" 1
Attribute "displacementbound" "sphere" 0.1 "coordinatesystem" "world"
# Left wall
AttributeBegin
Displacement "dispsinz" "float freq" 22 "float scale" 0.1
Surface "bake_scattercoeffs"
"string filename" "box_scattercoeffs.ptc"
"string displaychannels" "diffrefl,specrefl"
"string texturename" "irma.tex"
Polygon "P" [ -1 1 -1 -1 1 1 -1 -1 1 -1 -1 -1 ]
"s" [0 1 1 0] "t" [0 0 1 1]
AttributeEnd
# Right wall
AttributeBegin
Surface "bake_scattercoeffs"
"string filename" "box_scattercoeffs.ptc"
"string displaychannels" "diffrefl,specrefl"
"string texturename" "tinny.tex"
Polygon "P" [ 1 -1 -1 1 -1 1 1 1 1 1 1 -1 ]
"s" [0 1 1 0] "t" [1 1 0 0]
AttributeEnd
# Floor
AttributeBegin
Surface "bake_scattercoeffs"
"string filename" "box_scattercoeffs.ptc"
"string displaychannels" "diffrefl,specrefl"
"string texturename" "checkerboard10.tex"
Polygon "P" [ -1 -1 1 1 -1 1 1 -1 -1 -1 -1 -1 ]
"s" [0 0.995 0.995 0] "t" [0.005 0.005 0.995 0.995]
AttributeEnd
# Ceiling
AttributeBegin
Color [0.8 0.8 0.8]
Surface "bake_scattercoeffs"
"string filename" "box_scattercoeffs.ptc"
"string displaychannels" "diffrefl,specrefl"
Polygon "P" [ -1 1 -1 1 1 -1 1 1 1 -1 1 1 ]
AttributeEnd
# Back wall
AttributeBegin
Color [0.8 0.8 0.8]
Attribute "displacementbound" "sphere" 0.01 "coordinatesystem" "world"
Displacement "dispmap" "string texturename" "prman_logo.tex"
"float scale" -0.01
Surface "bake_scattercoeffs"
"string filename" "box_scattercoeffs.ptc"
"string displaychannels" "diffrefl,specrefl"
Polygon "P" [ -1 1 1 1 1 1 1 -1 1 -1 -1 1 ]
"s" [-1 2 2 -1] "t" [-1 -1 2 2]
AttributeEnd
# Left teapot (chrome)
AttributeBegin
Color [0 0 0]
Surface "bake_scattercoeffs" "color specrefl" [1 1 1]
"string filename" "box_scattercoeffs.ptc"
"string displaychannels" "diffrefl,specrefl"
Translate -0.35 -0.999 0.35
Scale 0.18 0.18 0.18
Rotate -30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
# Right teapot (matte)
AttributeBegin
Color [0.8 0.8 0.8]
ShadingRate 0.25
Displacement "disppumpkin" "float freq" 9 "float scale" 0.05
Surface "bake_scattercoeffs"
"string filename" "box_scattercoeffs.ptc"
"string displaychannels" "diffrefl,specrefl"
Translate 0.35 -0.999 -0.35
Scale 0.18 0.18 0.18
Rotate 30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
WorldEnd
FrameEnd
In diesem Beispiel haben wir nur diffuse und spiegelnde Reflexionsfaktoren gebakt. Es ist auch möglich, diffuse und spiegelnde Refraction-Koeffizienten sowie den Index of Refraction (ior) zu baken.
In diesem Beispiel wurden alle Scattering-Koeffizienten zu einer einzigen Punktwolkendatei gebakt. Es ist auch möglich, mehrere Punktwolken zu baken z.B. eine pro Objekt in der Szene.
Photonen-Emission und -Tracing.
Der nächste Schritt ist die Photonen-Emission und -Tracing. Die Photonen-Emission und -Tracing wird von den oben gebakten Punktwolken geleitet.
Festlegen der Photonen-Emission.
Photonen werden wie bisher emittiert: mit einem Photonenversteck. Neu ist, dass die Photonen-Emission durch eine Punktwolke spezifiziert werden kann, die mit dem Parameter „Emissionspunktwolke“ übergeben wird. Zum Beispiel:
Hider "photon" "emit" 100000 "emissionpointcloud" "box_direct.ptc"
Wenn keine Emissionspunktwolke angegeben ist, kehrt PRMan zum alten Verhalten zurück: Es emittiert Photonen, die den Lichtquellen in der Szene entsprechen (so weit wie möglich).
Spezifikation von Oberflächenmaterialien.
Die für die Oberflächenstreuung zu verwendende Punktwolke (diffrefl, diffrefr, specrefl, specrefr, ior) wird mit dem Attribut „Photon“ „Shading-Modell“ und einem Dateinamen vorangestellt mit „PointCloud“ oder „Brickmap:“ angegeben. Zum Beispiel:
Attribute "photon" "shadingmodel" "pointcloud:foo.ptc"
Attribute "photon" "shadingmodel" "brickmap:bar.bkm"
Auch die alten, vordefinierten Oberflächenmaterialien können weiterhin verwendet werden:
Attribute "photon" "shadingmodel" ["matte" | "translucent" | "chrome"
| "transparent" | "glass" | "water" | "refractive:ior=..." | "dielectric"
| "absorbing"].
Beispiel: Photonen-Emission und -Tracing in der Boxenszene.
In der folgenden RIB-Datei wird die Illumination Point-Cloud „box_direct.ptc“ zur Steuerung der Photonenemission und die Scattering-Koeffizienten in „box_scattercoeffs.ptc“ zum Photonen-Tracing verwendet.
FrameBegin 1
Hider "photon" "emit" 1000000 "emissionpointcloud" "box_direct.ptc"
Format 400 400 1 # not necessary, but makes ptviewer display nicer
Projection "perspective" "fov" 30 # ditto
Translate 0 0 5
WorldBegin
# The name of the global photon map and caustic photon map files
Attribute "photon" "globalmap" "box_gpm.ptc"
Attribute "photon" "causticmap" "box_cpm.ptc"
# Ray tracing attributes
Attribute "trace" "maxspeculardepth" 5
Attribute "trace" "maxdiffusedepth" 5
Attribute "trace" "bias" 0.0001
Attribute "trace" "displacements" 1
Attribute "displacementbound" "sphere" 0.1 "coordinatesystem" "world"
Attribute "dice" "rasterorient" 0 # view-indep dicing to match ptcloud
# Use surface scattering values in point cloud box_scattercoeffs.ptc
Attribute "photon" "shadingmodel" "pointcloud:box_scattercoeffs.ptc"
# Matte box
AttributeBegin
Displacement "dispsinz" "float freq" 22 "float scale" 0.1
Polygon "P" [ -1 1 -1 -1 1 1 -1 -1 1 -1 -1 -1 ] # left wall
"s" [0 1 1 0] "t" [0 0 1 1]
AttributeEnd
AttributeBegin
Polygon "P" [ 1 -1 -1 1 -1 1 1 1 1 1 1 -1 ] # right wall
Polygon "P" [ -1 -1 1 1 -1 1 1 -1 -1 -1 -1 -1 ] # floor
Polygon "P" [ -1 1 -1 1 1 -1 1 1 1 -1 1 1 ] # ceiling
AttributeEnd
AttributeBegin
Attribute "displacementbound" "sphere" 0.01 "coordinatesystem" "world"
Displacement "dispmap" "string texturename" "prman_logo.tex"
"float scale" -0.01
Polygon "P" [ -1 1 1 1 1 1 1 -1 1 -1 -1 1 ] # back wall
"s" [-1 2 2 -1] "t" [-1 -1 2 2]
AttributeEnd
# Left teapot (chrome)
AttributeBegin
Translate -0.35 -0.999 0.35
Scale 0.18 0.18 0.18
Rotate -30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
# Right teapot (matte)
AttributeBegin
ShadingRate 0.25 # to match pointcloud
Displacement "disppumpkin" "float freq" 9 "float scale" 0.05
Translate 0.35 -0.999 -0.35
Scale 0.18 0.18 0.18
Rotate 30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
WorldEnd
FrameEnd
Durch das Ausführen dieser RIB-Datei wird eine globale Photonen-Map „box_gpm.ptc“ mit ca. 2,6 Millionen Photonen erzeugt.
Berechnung der Radiosity Map.
Unter Verwendung der Leistungen der Photonen-Map und der diffusen Oberflächenfarben können wir eine Radiositätsschätzung an jeder Photonenposition berechnen. Die resultierende Punktwolke wird oft als Radiosity Map bezeichnet. Die Radiosity Map kann mit dem eigenständigen Programm ptfilter berechnet werden. Zum Beispiel:
ptfilter -photonmap -nphotons 200 -threads 4 box_gpm.ptc box_rad.ptc
Neuer Schritt: Neuabtastung der Radiosity Map.
Dieser Schritt stellt sicher, dass keine Lücken in der Radiosity Map entstehen. Dieser Schritt ist nur notwendig, wenn im folgenden Rendering-Schritt punktbasierte Color-Bleedings für die endgültige Sammlung verwendet werden und wenn die Photonen-Map Lücken zwischen den Photonen in Gebieten mit geringer Beleuchtung aufweist. In unserem Map-Beispiel ist die Vorderseite der verschobenen, diffusen Teekanne ein solcher Bereich, ebenso wie die Bodenbereiche unter den Teekannen.
Dies ist ein Shader, der Radiositätswerte aus einer Radiosity Map liest und in eine andere schreibt:
surface
resample_radiositymap(string infile = "", outfile = "")
{
color rad = 0;
float a = area(P, "dicing"); // micropolygon area
// Read radiosity values from photon map with precomputed radiosities
texture3d(infile, P, N, "_radiosity", rad);
// Store area and radiosity in a new point cloud file
bake3d(outfile, "_area,_radiosity", P, N, "interpolate", 1,
"_area", a, "_radiosity", rad);
// Compute Ci and Oi
Ci = rad * Os;
Oi = Os;
}
Und hier ist die RIB-Datei für das Resampling der Radiosity Map:
FrameBegin 1
Format 400 400 1
ShadingInterpolation "smooth"
PixelSamples 4 4
Display "box_resample_radiositymap" "it" "rgba"
Projection "perspective" "fov" 30
Translate 0 0 5
DisplayChannel "float _area"
DisplayChannel "color _radiosity"
WorldBegin
Attribute "cull" "hidden" 0 # ensure illum is baked behind objects
Attribute "cull" "backfacing" 0 # ensure illum is baked on backsides
Attribute "dice" "rasterorient" 0 # view-independent dicing
# Turn on displacements
Attribute "trace" "displacements" 1
Attribute "displacementbound" "sphere" 0.1 "coordinatesystem" "world"
# Same shader for all surfaces
Surface "resample_radiositymap"
"string infile" "box_rad.ptc" "string outfile" "box_rad2.ptc"
# Left wall
AttributeBegin
Displacement "dispsinz" "float freq" 22 "float scale" 0.1
Polygon "P" [ -1 1 -1 -1 1 1 -1 -1 1 -1 -1 -1 ]
"s" [0 1 1 0] "t" [0 0 1 1]
AttributeEnd
# Right wall
AttributeBegin
Polygon "P" [ 1 -1 -1 1 -1 1 1 1 1 1 1 -1 ]
"s" [0 1 1 0] "t" [1 1 0 0]
AttributeEnd
# Floor
AttributeBegin
Polygon "P" [ -1 -1 1 1 -1 1 1 -1 -1 -1 -1 -1 ]
"s" [0 0.995 0.995 0] "t" [0.005 0.005 0.995 0.995]
AttributeEnd
# Ceiling
AttributeBegin
Color [0.8 0.8 0.8]
Polygon "P" [ -1 1 -1 1 1 -1 1 1 1 -1 1 1 ]
AttributeEnd
# Back wall
AttributeBegin
Color [0.8 0.8 0.8]
Attribute "displacementbound" "sphere" 0.01 "coordinatesystem" "world"
Displacement "dispmap" "string texturename" "prman_logo.tex"
"float scale" -0.01
Polygon "P" [ -1 1 1 1 1 1 1 -1 1 -1 -1 1 ]
"s" [-1 2 2 -1] "t" [-1 -1 2 2]
AttributeEnd
# Left teapot (chrome)
AttributeBegin
Color [0 0 0]
Translate -0.35 -0.999 0.35
Scale 0.18 0.18 0.18
Rotate -30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
# Right teapot (matte)
AttributeBegin
Color [0.8 0.8 0.8]
ShadingRate 0.25
Displacement "disppumpkin" "float freq" 9 "float scale" 0.05
Translate 0.35 -0.999 -0.35
Scale 0.18 0.18 0.18
Rotate 30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
WorldEnd
FrameEnd
Rendering mit Final Gathering.
Alles, was bleibt, ist das endgültige Bild zu rendern. Die oben gezeigte Radiosity Map ist offensichtlich zu verrauscht, um direkt zu rendern, also müssen wir eine abschließende Sammlung durchführen, um die Qualität zu verbessern. Die endgültige Sammlung kann auf zwei Arten erfolgen:
- Erstellen Sie eine Brick-Map aus der Radiosity Map Punktwolke und verwenden Sie Ray-Traced Final Gathering. Dieser Ansatz wird in der Anwendungsnotiz Global Illumination beschrieben.
- Punktbasiertes Color-Bleeding: Dies ähnelt dem obigen Anwendungshinweisen zur punktbasierten Approximate Ambient Occlusion und Color Bleeding beschriebenen Color Bleeding Application Note. Der einzige Unterschied besteht darin, dass die Punktwolke in diesem Fall eine globale Beleuchtung und keine direkte Beleuchtung darstellt.
In diesem Beispiel verwenden wir den punktbasierten Ansatzm da er in der Regel schneller ist. Dies ist ein Shader, der punktbasierte Color-Bleedings berechnet.
surface
matte_ptbased_globillum(uniform string texturename = "";
uniform string globillumfile = "", causticfile = "";
float Kd = 1;
float maxvariation = 0.0;
float causticphotons = 100)
{
color irrad = 0, tex = 1;
normal Nn = normalize(N);
// Compute direct illumination
irrad = diffuse(Nn);
// Add point-based color bleeding
if (globillumfile != "")
irrad += indirectdiffuse(P, Nn, 0, "pointbased", 1, "clamp", 1,
"sortbleeding", 1, "samplebase", 1.0,
"maxvariation", maxvariation,
"colorhitsides", "front", // new for PRMan 15.2
"filename", globillumfile);
// Add caustic
if (causticfile != "")
irrad += photonmap(causticfile, P, Nn, "estimator", causticphotons);
// Lookup texture
if (texturename != "")
tex = texture(texturename);
// Set Ci and Oi
Ci = Kd * Cs * tex * irrad;
Ci *= Os; // premultiply opacity
Oi = Os;
}
Beachten Sie, dass, um die beste Qualität der punktbasierten Color-Bleeding zu erhalten, die indirekten Diffuse-()-Parameter „Clamp“ und „Sortbleeding“ eingeschaltet sind und „Colorhitsides“ „Front“ ist.
Nachfolgend finden Sie die RIB-Datei für die Darstellung des endgültigen hochwertigen Bildes der „Global Illumination“ in der Box.
FrameBegin 1
Format 400 400 1
ShadingInterpolation "smooth"
PixelSamples 4 4
Display "box_render_gi" "it" "rgba"
Projection "perspective" "fov" 30
Translate 0 0 5
WorldBegin
# Turn on ray-traced shadows and reflections
Attribute "visibility" "transmission" 1
Attribute "visibility" "specular" 1 # make objects visible to refl. rays
Attribute "trace" "bias" 0.001 # incr. if fewer photons in photon map
# Turn on displacements
Attribute "trace" "displacements" 1
Attribute "displacementbound" "sphere" 0.1 "coordinatesystem" "world"
# Light sources (no baking)
LightSource "myspotlight" 1
"point from" [0.5 0.999 0] "vector dir" [0 -1 0] "float coneangle" 1.2
LightSource "myspotlight" 2
"point from" [0.5 0.999 -0.5] "vector dir" [-0.3 -1 0.3]
"float intensity" 0.5 "color lightcolor" [1 0 0] "float coneangle" 0.3
LightSource "projectorlightxz" 3
"point from" [-0.7 0 0.75] "vector dir" [0 1 0]
"float minx" -0.9 "float maxx" -0.4 "float minz" 5.5 "float maxz" 5.99
"float intensity" 2
"string texturename" "prman_logo.tex"
# Left wall (displaced and texture mapped)
AttributeBegin
Attribute "dice" "rasterorient" 0 # view-indep dicing avoids skinny mps
Displacement "dispsinz" "float freq" 22 "float scale" 0.1
Surface "matte_ptbased_globillum"
"string texturename" "irma.tex"
"string globillumfile" "box_rad2.ptc"
#"string causticfile" "box_cpm.ptc" "float causticphotons" 100
Polygon "P" [ -1 1 -1 -1 1 1 -1 -1 1 -1 -1 -1 ]
"s" [0 1 1 0] "t" [0 0 1 1]
AttributeEnd
# Right wall (texture mapped)
AttributeBegin
Surface "matte_ptbased_globillum"
"string texturename" "tinny.tex"
"string globillumfile" "box_rad2.ptc"
#"string causticfile" "box_cpm.ptc" "float causticphotons" 100
Polygon "P" [ 1 -1 -1 1 -1 1 1 1 1 1 1 -1 ]
"s" [0 1 1 0] "t" [1 1 0 0]
AttributeEnd
# Floor (texture mapped)
AttributeBegin
Surface "matte_ptbased_globillum"
"string texturename" "checkerboard10.tex"
"string globillumfile" "box_rad2.ptc"
#"string causticfile" "box_cpm.ptc" "float causticphotons" 100
Polygon "P" [ -1 -1 1 1 -1 1 1 -1 -1 -1 -1 -1 ]
"s" [0 0.995 0.995 0] "t" [0.005 0.005 0.995 0.995]
AttributeEnd
# Ceiling
AttributeBegin
Color [0.8 0.8 0.8]
Surface "matte_ptbased_globillum"
"string globillumfile" "box_rad2.ptc"
#"string causticfile" "box_cpm.ptc" "float causticphotons" 100
Polygon "P" [ -1 1 -1 1 1 -1 1 1 1 -1 1 1 ]
AttributeEnd
# Back wall (displaced)
AttributeBegin
Color [0.8 0.8 0.8]
Attribute "displacementbound" "sphere" 0.01 "coordinatesystem" "world"
Displacement "dispmap" "string texturename" "prman_logo.tex"
"float scale" -0.01
Surface "matte_ptbased_globillum"
"string globillumfile" "box_rad2.ptc"
#"string causticfile" "box_cpm.ptc" "float causticphotons" 100
Polygon "P" [ -1 1 1 1 1 1 1 -1 1 -1 -1 1 ]
"s" [-1 2 2 -1] "t" [-1 -1 2 2]
AttributeEnd
# Left teapot (chrome)
AttributeBegin
Surface "aachrome" "float samples" 4
Translate -0.35 -0.999 0.35
Scale 0.18 0.18 0.18
Rotate -30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
# Right teapot (displaced matte)
AttributeBegin
Color [0.8 0.8 0.8]
ShadingRate 0.25
Displacement "disppumpkin" "float freq" 9 "float scale" 0.05
Surface "matte_ptbased_globillum"
"string globillumfile" "box_rad2.ptc"
#"string causticfile" "box_cpm.ptc" "float causticphotons" 100
Translate 0.35 -0.999 -0.35
Scale 0.18 0.18 0.18
Rotate 30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
WorldEnd
FrameEnd
(Wenn Sie diese RIB-Datei ausführen, ignorieren Sie die Warnung, dass die Punktwolkendatei keine float_area-Daten enthält. Stattdessen werden die Disc Radii verwendet, was für diesen Zweck völlig in Ordnung ist.)
Ein Caustics-Beispiel.
Das in den vorherigen Abschnitten gezeigte Box-Beispiel hat Caustics aus der spiegelnden Teekanne. Die Caustics sind jedoch nicht sehr ausgeprägt. Hier ist ein einfacheres Beispiel mit klareren Caustics. Die Szene besteht aus einer texturierten, spiegelnden Teekanne auf einer diffusen Ebene.
Hier ist die RIB-Datei zum Baken der direkten Beleuchtung:
FrameBegin 1
Format 400 300 1
ShadingInterpolation "smooth"
PixelSamples 4 4
Display "teapotcaustic_bake_direct" "it" "rgba"
Projection "perspective" "fov" 18
Translate 0 0.75 5
Rotate -45 1 0 0
DisplayChannel "color _irradiance"
DisplayChannel "vector L"
DisplayChannel "float _area"
WorldBegin
Attribute "cull" "hidden" 0 # ensure illum is baked behind objects
Attribute "cull" "backfacing" 0 # ensure illum is baked on backsides
Attribute "dice" "rasterorient" 0 # view-independent dicing
# Turn on ray-traced shadows
Attribute "visibility" "transmission" 1
Attribute "trace" "bias" 0.0001
# Light source (white spot that bakes its own illumination)
LightSource "myspotlight" 1
"point from" [1 1 -1] "vector dir" [-1 -1.5 1] "float coneangle" 0.25
"string filename" "teapotcaustic_direct.ptc"
Surface "matte"
# Teapot (chrome, but matte in this pass)
AttributeBegin
Translate -0.35 -1 0.35
Scale 0.18 0.18 0.18
Rotate -30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
# Ground plane
AttributeBegin
Polygon "P" [ -1 -1 1 1 -1 1 1 -1 -1 -1 -1 -1 ]
AttributeEnd
WorldEnd
FrameEnd
Hier ist die RIB-Datei zum Baken der Scattering-Koeffizienten aus der texturierten Spiegelteekanne:
FrameBegin 1
Format 400 300 1
ShadingInterpolation "smooth"
PixelSamples 4 4
Display "teapotcaustic_bake_scattercoeffs" "it" "rgba"
Projection "perspective" "fov" 18
Translate 0 0.75 5
Rotate -45 1 0 0
DisplayChannel "color diffrefl" # unused in this example
DisplayChannel "color specrefl"
DisplayChannel "color diffrefr" # unused in this example
DisplayChannel "color specrefr" # unused in this example
DisplayChannel "float ior" # unused in this example
WorldBegin
Attribute "cull" "hidden" 0 # ensure illum is baked behind objects
Attribute "cull" "backfacing" 0 # ensure illum is baked on backsides
Attribute "dice" "rasterorient" 0 # view-independent dicing
# Teapot (textured chrome)
AttributeBegin
Surface "bake_scattercoeffs" "color specrefl" [1 1 1]
"string filename" "teapotcaustic_scattercoeffs.ptc"
"string displaychannels" "specrefl"
"string spectexturename" "irma.tex"
"string texturename" "irma.tex" # not necessary for caustic
Translate -0.35 -1 0.35
Scale 0.18 0.18 0.18
Rotate -30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
# Floor
AttributeBegin
Surface "constant"
Polygon "P" [ -1 -1 1 1 -1 1 1 -1 -1 -1 -1 -1 ]
AttributeEnd
WorldEnd
FrameEnd
In diesem Beispiel verwenden wir eine Brick-Map für die Scattering-Koeffizienten. Aus der Punktwolke wird mit dem Brickmake-Programm die Brick-Map generiert:
brickmake teapotcaustic_scattercoeffs.ptc teapotcaustic_scattercoeffs.bkm
Als nächstes ist es an der Zeit, Photonen zu tracen. Wir werden 1 Million Photonen mit einer Verteilung emittieren, die der in die teapotcaustic_direct.ptc Punktwolke eingebrannten Beleuchtung entspricht. Die Photonenstreuung wird durch die Scattering-Koeffizienten gesteuert, die in der Brick Map Datei teapotcaustic_scattercoeffs.bkm gespeichert sind. Hier ist die RIB-Datei für die Photonenemission und -streuung:
FrameBegin 1
Hider "photon" "emissionpointcloud" "teapotcaustic_direct.ptc"
"emit" 1000000
Format 400 300 1 # not necessary, but makes ptviewer display nicer
Projection "perspective" "fov" 18 # ditto
Translate 0 0.75 5
Rotate -45 1 0 0
WorldBegin
# The name of the caustic photon map file to be written
Attribute "photon" "causticmap" "teapotcaustic_cpm.ptc"
# Ray tracing attributes
Attribute "trace" "maxspeculardepth" 5
Attribute "trace" "maxdiffusedepth" 5
Attribute "trace" "bias" 0.0001
Attribute "dice" "rasterorient" 0 # view-indep dicing to match ptcloud
# Use surface scattering values in pointcloud or brickmap
Attribute "photon" "shadingmodel"
#"pointcloud:teapotcaustic_scattercoeffs.ptc"
"brickmap:teapotcaustic_scattercoeffs.bkm"
# Teapot (textured chrome)
AttributeBegin
Translate -0.35 -1 0.35
Scale 0.18 0.18 0.18
Rotate -30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
# Matte ground plane
AttributeBegin
Attribute "photon" "shadingmodel" "matte"
Polygon "P" [ -1 -1 1 1 -1 1 1 -1 -1 -1 -1 -1 ]
AttributeEnd
WorldEnd
FrameEnd
Das Ergebnis ist eine geätzte Photonen-Map-Datei (teapotcausting_cpm.ptc genannt) mit rund 196.000 Photonen. Die Darstellung der geätzten Photonen-Map mit ptviewer – mehrfach 200.000.000 teapotcuastic_cpm.ptc sorgt dafür, dass die durch die Textur auf der Teekanne verursachten farbigen Ätzungen deutlich sichtbar sind.
Die Shader, die für die Darstellung des endgültigen Bildes verwendet werden, sind „paintedchrome“ (verwendet für die texturierte Chromteekanne) und „matte_und-caustic“ (verwendet für die Grundplatte):
surface
paintedchrome (float Kr = 1, Ks = 0, shinyness = 50, samples = 4, blue = 0;
string texturename = "")
{
color Crefl, Cspec = 0, tex;
float depth, s;
float diffuseraydepth = 0;
rayinfo("diffusedepth", diffuseraydepth);
rayinfo("depth", depth);
s = (depth == 0) ? samples : 1; // only 1 ray for secondary reflections
if (Kr > 0 && N.I < 0 && diffuseraydepth == 0) {
normal Nn = normalize(N);
vector In = normalize(I);
vector reflDir = reflect(In,Nn);
Crefl = environment("raytrace", reflDir, "samples", s);
} else { // don't reflect inside object
Crefl = 0;
}
// Specular highlights
if (Ks > 0 && diffuseraydepth == 0) {
vector V = -normalize(I); // view direction
normal Nn = normalize(N);
Cspec = specular(Nn, V, 1/shinyness);
}
if (texturename != "") {
tex = texture(texturename);
Crefl *= tex;
Cspec *= tex;
}
Ci = Kr * Crefl + Ks * Cspec + color(0, 0, blue);
Oi = 1;
}
surface
matte_and_caustic(uniform string filename = "";
float Ka = 1, Kd = 1, Kc = 1, nphotons = 50)
{
color irrad = 0;
normal Nn = normalize(N);
irrad = Ka * ambient() + Kd * diffuse(Nn);
irrad += Kc * photonmap(filename, P, Nn, "estimator", nphotons);
Ci = Kd * Cs * irrad;
Ci *= Os; // premultiply opacity
Oi = Os;
}
Hier ist die RIB-Datei für die Darstellung der berechneten Caustics:
FrameBegin 1
Format 400 300 1
ShadingInterpolation "smooth"
PixelSamples 4 4
Display "teapotcaustic_render" "it" "rgba"
Projection "perspective" "fov" 18
Translate 0 0.75 5
Rotate -45 1 0 0
WorldBegin
# Turn on ray-traced reflections and shadows
Attribute "visibility" "specular" 1
Attribute "visibility" "transmission" 1
Attribute "trace" "bias" 0.0001
# Light source
LightSource "myspotlight" 1 # white spot
"point from" [1 1 -1] "vector dir" [-1 -1.5 1] "float coneangle" 0.25
LightSource "ambientlight" 2 "float intensity" 0.1
# Teapot (textured chrome)
AttributeBegin
Surface "paintedchrome" "float Kr" 1 "float Ks" 1 "float shinyness" 25
"string texturename" "irma.tex"
Translate -0.35 -1 0.35
Scale 0.18 0.18 0.18
Rotate -30 0 1 0
Rotate -90 1 0 0
Geometry "teapot"
AttributeEnd
# Ground plane
AttributeBegin
Surface "matte_and_caustic" "filename" "teapotcaustic_cpm.ptc"
"float nphotons" 200 "float Kc" 6
Polygon "P" [ -1 -1 1 1 -1 1 1 -1 -1 -1 -1 -1 ]
AttributeEnd
WorldEnd
FrameEnd
Da die Caustic ausbreitet ist, ist sie eher schwach (im Gegensatz zu einem fokussierten Caustic). Aus diesem Grund haben wir einen „Kc“-Wert von 6 verwendet, um ihn künstlich aufzuhellen.
In diesem Beispiel werden weder das Causting-Gussobjekt noch die Causting-Empfänger als Displacement Map dargestellt, aber sie hätten es leicht sein können.
Bekannte Einschränkungen.
Die Implementierung hat die folgenden bekannten Einschränkungen:
- PRMan kann derzeit nur eine Punktwolke (oder eine Brick-Map) für Scattering-Koeffizienten verarbeiten. Es wäre schön, die Möglichkeit zu haben, mehr Punktwolken und Brick-Maps zu haben, zum Beispiel eine pro Objekt.
- Keine glänzende Reflexion oder Refraction (weder isotrop noch anisotrop) in der Photon Scattering Phase.
- Wenn gebakte Scattering Koeffizienten verwendet werden, können wir keine richtungsabhängigen Scattering Koeffizienten wie die Fresnel-Formeln verwenden. (Verwenden Sie das Einbaumaterial „Glas“ für Glas mit Fresnel-Reflexion und Refraction).
Displacement Shader.
Der Shader „Dispmap“ verwendet eine Textur-Map für das Displacement, „dispsinz“ berechnet eine Wellen-Displacement in Abhängigkeit von der Z-Position (tiefe) und „disppumpkin“ berechnet ein Displacment, die eine Teekanne wie einen Kürbis aussehen lässt.
displacement
dispmap (string texturename = ""; float scale = 1.0, invert = 0)
{
color tex;
vector Nn = normalize(N);
float avetex, disp;
// Compute displacement
tex = texture(texturename);
avetex = (tex[0] + tex[1] + tex[2]) / 3;
if (invert != 0) // convert bright to dark and vice versa
avetex = 1 - avetex;
disp = scale * avetex;
// Displace P and calculate the new normal
P = P + disp * Nn;
N = calculatenormal(P);
}
displacement
dispsinz (float freq = 1.0, scale = 1.0)
{
// Calculate displacement
point Pobject = transform("object", P);
float z = zcomp(Pobject);
float disp = scale * sin(freq*z);
// Displace position and calculate the new normal
P = P + disp * normalize(N);
N = calculatenormal(P);
}
displacement
disppumpkin (float freq = 1, scale = 0.1)
{
// Convert N from current (camera) space to object space
vector Nobj = normalize(vtransform("object", N));
// Compute displacement
float angle = atan(ycomp(Nobj), xcomp(Nobj));
float disp = scale * cos(freq*angle);
// Displace position and calculate the new normal
P = P + disp * normalize(N);
N = calculatenormal(P);
}
Damit sind wir soweit mit unserem Beitrag zum Photonen-Mapping durch. Falls Sie noch Fragen oder Anmerkungen zu diesem Beitrag haben sollten, hinterlassen Sie uns unten einen Kommentar.
Vielen Dank für ihren Besuch.