diff -Naur '--exclude-from=binaries_and_temp_stuff.txt' panda3d-1.8.1/direct/src/filter/CommonFilters.py panda3d-1.8.1-jj/direct/src/filter/CommonFilters.py --- panda3d-1.8.1/direct/src/filter/CommonFilters.py 2011-12-27 11:48:27.000000000 +0200 +++ panda3d-1.8.1-jj/direct/src/filter/CommonFilters.py 2013-09-07 03:03:17.478513197 +0300 @@ -35,7 +35,7 @@ float4 cartoon_c3 = tex2D(k_txaux, cartoon_p3.xy); float4 cartoon_mx = max(cartoon_c0,max(cartoon_c1,max(cartoon_c2,cartoon_c3))); float4 cartoon_mn = min(cartoon_c0,min(cartoon_c1,min(cartoon_c2,cartoon_c3))); -float cartoon_thresh = saturate(dot(cartoon_mx - cartoon_mn, float4(3,3,0,0)) - 0.5); +float cartoon_thresh = saturate(dot(cartoon_mx - cartoon_mn, float4(3,3,0,0)) - k_cutoff.x); o_color = lerp(o_color, k_cartooncolor, cartoon_thresh); """ @@ -66,6 +66,7 @@ self.bloom = [] self.blur = [] self.ssao = [] + self.advanced_ink = [] if self.task != None: taskMgr.remove(self.task) self.task = None @@ -75,6 +76,8 @@ """ Reconfigure is called whenever any configuration change is made. """ configuration = self.configuration + advanced_ink = (configuration.has_key("CartoonInk") and configuration["CartoonInk"].use_advanced_ink) + advanced_ink_depth = (advanced_ink and configuration["CartoonInk"].depth_enabled) if (fullrebuild): @@ -87,6 +90,12 @@ needtex = {} needtex["color"] = True if (configuration.has_key("CartoonInk")): + if (advanced_ink): + needtex["ink0"] = True + needtex["inkblur0"] = True + needtex["inkblur1"] = True + if (advanced_ink_depth): + needtex["depth"] = True needtex["aux"] = True auxbits |= AuxBitplaneAttrib.ABOAuxNormal if (configuration.has_key("AmbientOcclusion")): @@ -128,6 +137,31 @@ self.blur[1].setShaderInput("src", blur0) self.blur[1].setShader(self.loadShader("filter-blury.sha")) + if (advanced_ink): + inkblur0=self.textures["inkblur0"] + inkblur1=self.textures["inkblur1"] + + # in advanced_ink mode, the inking is first done into an intermediate texture, + # using the alpha value to indicate where ink is present. + ink0=self.textures["ink0"] + self.advanced_ink.append(self.manager.renderQuadInto(colortex=ink0)) + # the blur texture is half the size of the ink texture. + self.advanced_ink.append(self.manager.renderQuadInto(colortex=inkblur0,div=2)) + self.advanced_ink.append(self.manager.renderQuadInto(colortex=inkblur1)) + + self.advanced_ink[0].setShaderInput("txaux", self.textures["aux"]) # normal map + if (advanced_ink_depth): + self.advanced_ink[0].setShaderInput("txdepth", self.textures["depth"]) + self.advanced_ink[0].setShader(self.loadShader("filter-advanced-ink-withdepth.sha")) + else: + self.advanced_ink[0].setShader(self.loadShader("filter-advanced-ink-nodepth.sha")) + # we then set up 3-tap Gaussian blur, affecting also the alpha channel. + self.advanced_ink[1].setShaderInput("src", ink0) + self.advanced_ink[1].setShader(self.loadShader("filter-advanced-ink-blurx.sha")) + self.advanced_ink[2].setShaderInput("src", inkblur0) + self.advanced_ink[2].setShader(self.loadShader("filter-advanced-ink-blury.sha")) + # the final filter then blends in the blurred ink onto the scene. + if (configuration.has_key("AmbientOcclusion")): ssao0=self.textures["ssao0"] ssao1=self.textures["ssao1"] @@ -172,25 +206,53 @@ self.bloom[3].setShaderInput("src", bloom2) self.bloom[3].setShader(self.loadShader("filter-bloomy.sha")) + # This helper function is used to match TEXCOORD register numbers between the + # generated vshader and fshader. This enables us to always use consecutive registers + # regardless of which combination of filters is in use. + # + # Usage: for example, + # getTexCoordSemantic("C") + # will return the first free TEXCOORD semantic (e.g. "TEXCOORD0") upon first call, + # and will return the same semantic when called for the same name + # (in the example, "C") upon all subsequent calls. + # + # The name is an arbitrary label. + # + # When the vshader is generated, it effectively allocates the register numbers + # to use for each TEXCOORD output; the fshader generator then retrieves + # those allocated numbers to use in its corresponding inputs. + # + tcs = {} + counter = [ 0 ] + def getTexCoordSemantic(name): + if name not in tcs: + # HACK: the counter is packed into a list so that we can modify its value here + tcs[name] = "TEXCOORD%d" % counter[0] + counter[0] += 1 + return tcs[name] + text = "//Cg\n" text += "void vshader(float4 vtx_position : POSITION,\n" text += " out float4 l_position : POSITION,\n" text += " uniform float4 texpad_txcolor,\n" text += " uniform float4 texpix_txcolor,\n" - text += " out float4 l_texcoordC : TEXCOORD0,\n" + text += " out float4 l_texcoordC : %s,\n" % getTexCoordSemantic("C") if (configuration.has_key("CartoonInk")): text += " uniform float4 texpad_txaux,\n" text += " uniform float4 texpix_txaux,\n" - text += " out float4 l_texcoordN : TEXCOORD1,\n" + text += " out float4 l_texcoordN : %s,\n" % getTexCoordSemantic("N") if (configuration.has_key("Bloom")): text += " uniform float4 texpad_txbloom3,\n" - text += " out float4 l_texcoordB : TEXCOORD2,\n" - if (configuration.has_key("BlurSharpen")): + text += " out float4 l_texcoordB : %s,\n" % getTexCoordSemantic("B") + if (configuration.has_key("BlurSharpen") ): text += " uniform float4 texpad_txblur1,\n" - text += " out float4 l_texcoordBS : TEXCOORD3,\n" + text += " out float4 l_texcoordBS : %s,\n" % getTexCoordSemantic("BS") + if (advanced_ink): + text += " uniform float4 texpad_txinkblur1,\n" + text += " out float4 l_texcoordIBS : %s,\n" % getTexCoordSemantic("IBS") if (configuration.has_key("AmbientOcclusion")): text += " uniform float4 texpad_txssao2,\n" - text += " out float4 l_texcoordAO : TEXCOORD4,\n" + text += " out float4 l_texcoordAO : %s,\n"% getTexCoordSemantic("AO") text += " uniform float4x4 mat_modelproj)\n" text += "{\n" text += " l_position=mul(mat_modelproj, vtx_position);\n" @@ -201,6 +263,8 @@ text += " l_texcoordB=(vtx_position.xzxz * texpad_txbloom3) + texpad_txbloom3;\n" if (configuration.has_key("BlurSharpen")): text += " l_texcoordBS=(vtx_position.xzxz * texpad_txblur1) + texpad_txblur1;\n" + if (advanced_ink): + text += " l_texcoordIBS=(vtx_position.xzxz * texpad_txinkblur1) + texpad_txinkblur1;\n" if (configuration.has_key("AmbientOcclusion")): text += " l_texcoordAO=(vtx_position.xzxz * texpad_txssao2) + texpad_txssao2;\n" if (configuration.has_key("HalfPixelShift")): @@ -210,23 +274,27 @@ text += "}\n" text += "void fshader(\n" - text += "float4 l_texcoordC : TEXCOORD0,\n" + text += "float4 l_texcoordC : %s,\n" % getTexCoordSemantic("C") text += "uniform float4 texpix_txcolor,\n" if (configuration.has_key("CartoonInk")): - text += "float4 l_texcoordN : TEXCOORD1,\n" + text += "float4 l_texcoordN : %s,\n" % getTexCoordSemantic("N") text += "uniform float4 texpix_txaux,\n" if (configuration.has_key("Bloom")): - text += "float4 l_texcoordB : TEXCOORD2,\n" + text += "float4 l_texcoordB : %s,\n" % getTexCoordSemantic("B") if (configuration.has_key("BlurSharpen")): - text += "float4 l_texcoordBS : TEXCOORD3,\n" + text += "float4 l_texcoordBS : %s,\n" % getTexCoordSemantic("BS") text += "uniform float4 k_blurval,\n" + if (advanced_ink): + text += "float4 l_texcoordIBS : %s,\n" % getTexCoordSemantic("IBS") + text += "uniform float4 k_inkblurval,\n" if (configuration.has_key("AmbientOcclusion")): - text += "float4 l_texcoordAO : TEXCOORD4,\n" + text += "float4 l_texcoordAO : %s,\n" % getTexCoordSemantic("AO") for key in self.textures: text += "uniform sampler2D k_tx" + key + ",\n" - if (configuration.has_key("CartoonInk")): + if (configuration.has_key("CartoonInk") and not advanced_ink): text += "uniform float4 k_cartoonseparation,\n" text += "uniform float4 k_cartooncolor,\n" + text += "uniform float4 k_cutoff,\n" if (configuration.has_key("VolumetricLighting")): text += "uniform float4 k_casterpos,\n" text += "uniform float4 k_vlparams,\n" @@ -234,9 +302,35 @@ text += "{\n" text += " o_color = tex2D(k_txcolor, l_texcoordC.xy);\n" if (configuration.has_key("CartoonInk")): - text += CARTOON_BODY + if (not advanced_ink): + text += CARTOON_BODY + else: + # Alpha blend final result from advanced-ink -> blurx -> blury chain. + # However, we must do the blur/sharpen first. + # + # - k_txinkblur1 is the Gaussian-blurred ink buffer (half size) + # - k_txink0 is the unblurred original ink buffer (full size, hence texcoordN is ok for it) + # - we lerp these to apply blur/sharpen, affecting ink lines only + # (both buffers contain only ink, with various alpha values) + # - then we alpha-blend the result onto finalQuad, mixing with o_color. + text += "float4 advanced_ink_color = lerp(tex2D(k_txinkblur1, l_texcoordIBS.xy), tex2D(k_txink0, l_texcoordN.xy), k_inkblurval.x);" + text += "float advanced_ink_a = advanced_ink_color.a;" + text += "advanced_ink_color.a = 1;" + text += "o_color = lerp(o_color, advanced_ink_color, advanced_ink_a);" if (configuration.has_key("AmbientOcclusion")): text += "o_color *= tex2D(k_txssao2, l_texcoordAO.xy).r;\n" + # Note: the reason BlurSharpen and CartoonInk are incompatible is that the final inking + # takes place here in the "main" filter, but the blur filter obviously cannot use finalQuad + # as its input. It uses the scene color texture, which has no ink lines. + # + # Hence, the blur input will only see the original scene before any ink lines have been rendered. + # A three-stage approach would be needed to overcome this. + # + # This holds regardless of whether using the "traditional" or the "advanced" inker. + # It wouldn't help to blur first before inking, because then the ink would not see the blur + # (being perfectly sharp, on top of the image, regardless of the blur value). + # The ordering of ink first, then blur, is better for moderate blur amounts. + # if (configuration.has_key("BlurSharpen")): text += " o_color = lerp(tex2D(k_txblur1, l_texcoordBS.xy), o_color, k_blurval.x);\n" if (configuration.has_key("Bloom")): @@ -273,8 +367,16 @@ if (changed == "CartoonInk") or fullrebuild: if (configuration.has_key("CartoonInk")): c = configuration["CartoonInk"] - self.finalQuad.setShaderInput("cartoonseparation", Vec4(c.separation, 0, c.separation, 0)) - self.finalQuad.setShaderInput("cartooncolor", c.color) + if advanced_ink: + self.advanced_ink[0].setShaderInput("cartoonseparation", Vec4(c.separation, 0, c.separation, 0)) + self.advanced_ink[0].setShaderInput("cartooncolor", c.color) + self.advanced_ink[0].setShaderInput("cutoff", Vec4(c.cutoff,c.cutoff,c.cutoff,c.cutoff)) + self.advanced_ink[0].setShaderInput("mult", Vec4(3.0,3.0,0.0,0.0)) + self.finalQuad.setShaderInput("inkblurval", Vec4(c.blurval, c.blurval, c.blurval, c.blurval)) + else: + self.finalQuad.setShaderInput("cartoonseparation", Vec4(c.separation, 0, c.separation, 0)) + self.finalQuad.setShaderInput("cartooncolor", c.color) + self.finalQuad.setShaderInput("cutoff", Vec4(c.cutoff,c.cutoff,c.cutoff,c.cutoff)) if (changed == "BlurSharpen") or fullrebuild: if (configuration.has_key("BlurSharpen")): @@ -316,11 +418,82 @@ if task != None: return task.cont - def setCartoonInk(self, separation=1, color=(0, 0, 0, 1)): + def setCartoonInk(self, separation=1, color=(0, 0, 0, 1), cutoff=0.5, use_advanced_ink=False, blur_amount=0.5, depth_enabled=False): + """Enables the cartoon inking filter. + + The inking is based on examining discontinuities in the normal map, as viewed from the camera. + + Parameters: + separation = stencil size for examining discontinuities, in pixels. + Pixels in the +x, -x, +y and -y directions from the current pixel + will be examined, with the distance for each check set to 'separation'. + Values in the range 0.6 ... 1.0 are usually good. + + color = color to use for ink, as (R,G,B,A) tuple. + The alpha component gives the _maximum_ alpha value that the filter is allowed + to produce. + + cutoff = sensitivity for normal map discontinuities. Make this smaller if not all edges + are getting inked. Make this larger if internal edges in areas that are supposed + to look smooth are getting picked up by the inker. The default is usually fine. + + use_advanced_ink = use alternate inking algorithm. + + + When advanced_ink is enabled, the following extra parameters are available: + + blur_amount = amount of blurring to apply to the ink lines. This parameter works the same way as the + 'amount' parameter of the BlurSharpen filter. A value of 0.0 means fully blurred, + while 1.0 means no effect. Values over 1.0 cause sharpening. + + The blur stencil is a 3x3 Gaussian; only neighboring pixels will be affected. + + The blur is selective. It will only cause ink to spread further; it will never + take ink away from existing lines. Each pixel is blurred only if it would add + more ink to the pixel than existed there before the blurring. This preserves + the sharpness of the ink lines. + + The intended use of this option is to make the ink lines look somewhat antialiased. + + depth_enabled = make the ink line thicker or thinner depending on the distance, of each inked pixel, + from the camera. + + The minimum and maximum thickness have fixed values proportional to 'separation', + and correspond to distances of the far and near planes of the camera (respectively). + Distances in between will have a line thickness between these. + + + CAUTION: CartoonInk and BlurSharpen are incompatible. While they will both load + without problems, the blur filter does not "see" the lines drawn by CartoonInk, + and will ignore them when computing the blurred image. + + The heavier the effect of BlurSharpen ('amount' parameter farther from "no effect" 1.0), + the more severe the overwriting of the ink lines. At amount=0.0, the ink lines will be completely + erased by the blur filter. Slight blur such as amount=0.8 looks somewhat ok; the lines then become + slightly translucent, but not too much so. + + """ fullrebuild = (self.configuration.has_key("CartoonInk") == False) + + # when certain options change, we must rebuild. + if self.configuration.has_key("CartoonInk"): + if use_advanced_ink != self.configuration["CartoonInk"].use_advanced_ink: + fullrebuild = True + if use_advanced_ink: + if depth_enabled != self.configuration["CartoonInk"].depth_enabled: + fullrebuild = True + newconfig = FilterConfig() newconfig.separation = separation newconfig.color = color + newconfig.cutoff = cutoff + + # advanced_ink parameters + # + newconfig.use_advanced_ink = use_advanced_ink + newconfig.blurval = blur_amount + newconfig.depth_enabled = depth_enabled + self.configuration["CartoonInk"] = newconfig return self.reconfigure(fullrebuild, "CartoonInk") @@ -331,6 +504,31 @@ return True def setBloom(self, blend=(0.3,0.4,0.3,0.0), mintrigger=0.6, maxtrigger=1.0, desat=0.6, intensity=1.0, size="medium"): + """Enables a bloom filter. + + Parameters: + blend = (R,G,B,A) tuple containing weights for each channel. Using these weights, + a weighted sum of the channels is computed at each pixel, forming the + brightness value for that pixel. + + The default (0.3,0.4,0.3,0.0) simply converts the pixel's RGB into grayscale + (automatically blooming bright pixels), while setting blend=(0.0,0.0,0.0,1.0) + would use the alpha channel as a glow map, ignoring the RGB. + + mintrigger = the minimum brightness to trigger a bloom. + + maxtrigger = the brightness at which the bloom reaches maximum intensity. + + desat = desaturation level. At 0.0, the bloom's color is equal to the + color of the input pixel. At 1.0, the bloom's color is white. + + intensity = strength of the bloom layer, when it is rendered onto the final image. + + size = one of "off" (disable filter), "small", "medium" or "large". + Controls the size of the bloom halo, i.e. the distance how far the effect + reaches out from each blooming pixel. + + """ if (size==0): size="off" elif (size==1): size="small" elif (size==2): size="medium" @@ -360,6 +558,12 @@ return True def setHalfPixelShift(self): + """Enables a half-pixel shift filter. + + This filter displaces the image toward the upper left by half a pixel. + This is done by modifying the texture coordinates of the color and normal maps. + + """ fullrebuild = (self.configuration.has_key("HalfPixelShift") == False) self.configuration["HalfPixelShift"] = 1 return self.reconfigure(fullrebuild, "HalfPixelShift") @@ -371,6 +575,16 @@ return True def setViewGlow(self): + """Enables a glow map debugging filter. + + Glow maps are often stored in the alpha channel. This filter, after the render + is otherwise complete, copies the alpha channel into the red channel, making + the alpha values visible. + + The original red channel is overwritten, making this filter not so useful for + rendering final output, but very useful for spotting errors in glow maps. + + """ fullrebuild = (self.configuration.has_key("ViewGlow") == False) self.configuration["ViewGlow"] = 1 return self.reconfigure(fullrebuild, "ViewGlow") @@ -382,6 +596,11 @@ return True def setInverted(self): + """Enables the invert filter. + + This filter inverts the colors, like a film negative. + + """ fullrebuild = (self.configuration.has_key("Inverted") == False) self.configuration["Inverted"] = 1 return self.reconfigure(fullrebuild, "Inverted") @@ -394,6 +613,7 @@ def setVolumetricLighting(self, caster, numsamples = 32, density = 5.0, decay = 0.1, exposure = 0.1): oldconfig = self.configuration.get("VolumetricLighting", None) + """Enables a volumetric lighting filter.""" # TODO: read examples and document this fullrebuild = True if (oldconfig) and (oldconfig.caster == caster): fullrebuild = False @@ -426,6 +646,11 @@ return True def setAmbientOcclusion(self, numsamples = 16, radius = 0.05, amount = 2.0, strength = 0.01, falloff = 0.000002): + """Enables a screen space ambient occlusion (SSAO) filter. + + Maximum supported numsamples is 16. + + """ fullrebuild = (self.configuration.has_key("AmbientOcclusion") == False) newconfig = FilterConfig() newconfig.numsamples = numsamples diff -Naur '--exclude-from=binaries_and_temp_stuff.txt' panda3d-1.8.1/direct/src/filter/filter-advanced-ink-blurx.sha panda3d-1.8.1-jj/direct/src/filter/filter-advanced-ink-blurx.sha --- panda3d-1.8.1/direct/src/filter/filter-advanced-ink-blurx.sha 1970-01-01 02:00:00.000000000 +0200 +++ panda3d-1.8.1-jj/direct/src/filter/filter-advanced-ink-blurx.sha 2013-09-01 17:49:40.145500351 +0300 @@ -0,0 +1,41 @@ +//Cg +// +//Cg profile arbvp1 arbfp1 + +void vshader(float4 vtx_position : POSITION, + float2 vtx_texcoord0 : TEXCOORD0, + out float4 l_position : POSITION, + out float2 l_texcoord0 : TEXCOORD0, + uniform float4 texpad_src, + uniform float4x4 mat_modelproj) +{ + l_position=mul(mat_modelproj, vtx_position); + l_texcoord0 = (vtx_position.xz * texpad_src.xy) + texpad_src.xy; +} + +// blur affecting also alpha channel (used by advanced_ink) +// +// The blur radius is only one pixel in each direction; this looks better on the edges. +// +void fshader(float2 l_texcoord0 : TEXCOORD0, + out float4 o_color : COLOR, + uniform float2 texpix_src, + uniform sampler2D k_src : TEXUNIT0) +{ + // 3-tap gaussian + float4 origcolor = tex2D(k_src, l_texcoord0); + o_color = 2.0*origcolor; + o_color += tex2D(k_src, float2(l_texcoord0.x - texpix_src.x, l_texcoord0.y)); + o_color += tex2D(k_src, float2(l_texcoord0.x + texpix_src.x, l_texcoord0.y)); + o_color /= 4; + + // Only blur if it increases opacity. + // + // This is a sort of poor man's antialiasing for lines (without the filter knowing there are lines); + // filter-advanced-ink-*.sha uses the alpha channel to encode where ink is present. + // This will smooth the edges of lines, without damaging the solid part of the lines. + // + if(o_color.a - origcolor.a < 0) + o_color = origcolor; +} + diff -Naur '--exclude-from=binaries_and_temp_stuff.txt' panda3d-1.8.1/direct/src/filter/filter-advanced-ink-blury.sha panda3d-1.8.1-jj/direct/src/filter/filter-advanced-ink-blury.sha --- panda3d-1.8.1/direct/src/filter/filter-advanced-ink-blury.sha 1970-01-01 02:00:00.000000000 +0200 +++ panda3d-1.8.1-jj/direct/src/filter/filter-advanced-ink-blury.sha 2013-09-01 17:49:25.553500770 +0300 @@ -0,0 +1,41 @@ +//Cg +// +//Cg profile arbvp1 arbfp1 + +void vshader(float4 vtx_position : POSITION, + float2 vtx_texcoord0 : TEXCOORD0, + out float4 l_position : POSITION, + out float2 l_texcoord0 : TEXCOORD0, + uniform float4 texpad_src, + uniform float4x4 mat_modelproj) +{ + l_position=mul(mat_modelproj, vtx_position); + l_texcoord0 = (vtx_position.xz * texpad_src.xy) + texpad_src.xy; +} + +// blur affecting also alpha channel (used by advanced_ink) +// +// The blur radius is only one pixel in each direction; this looks better on the edges. +// +void fshader(float2 l_texcoord0 : TEXCOORD0, + out float4 o_color : COLOR, + uniform float2 texpix_src, + uniform sampler2D k_src : TEXUNIT0) +{ + // 3-tap gaussian + float4 origcolor = tex2D(k_src, l_texcoord0); + o_color = 2.0*origcolor; + o_color += tex2D(k_src, float2(l_texcoord0.x, l_texcoord0.y - texpix_src.y)); + o_color += tex2D(k_src, float2(l_texcoord0.x, l_texcoord0.y + texpix_src.y)); + o_color /= 4; + + // Only blur if it increases opacity. + // + // This is a sort of poor man's antialiasing for lines (without the filter knowing there are lines); + // filter-advanced-ink-*.sha uses the alpha channel to encode where ink is present. + // This will smooth the edges of lines, without damaging the solid part of the lines. + // + if(o_color.a - origcolor.a < 0) + o_color = origcolor; +} + diff -Naur '--exclude-from=binaries_and_temp_stuff.txt' panda3d-1.8.1/direct/src/filter/filter-advanced-ink-nodepth.sha panda3d-1.8.1-jj/direct/src/filter/filter-advanced-ink-nodepth.sha --- panda3d-1.8.1/direct/src/filter/filter-advanced-ink-nodepth.sha 1970-01-01 02:00:00.000000000 +0200 +++ panda3d-1.8.1-jj/direct/src/filter/filter-advanced-ink-nodepth.sha 2013-09-07 01:45:57.338495945 +0300 @@ -0,0 +1,67 @@ +//Cg +// +//Cg profile arbvp1 arbfp1 + +void vshader(float4 vtx_position : POSITION, + out float4 l_position : POSITION, + uniform float4 texpad_txaux, + uniform float4 texpix_txaux, + out float4 l_texcoordN : TEXCOORD1, + uniform float4x4 mat_modelproj) +{ + l_position=mul(mat_modelproj, vtx_position); + l_texcoordN=(vtx_position.xzxz * texpad_txaux) + texpad_txaux; +} + +// Cartoon inker originally from CommonFilters.py. Modified to output always k_cartooncolor, +// but with alpha depending on whether a pixel has ink or not. +// +// See also filter-advanced-ink-withdepth.sha. +// +void fshader(out float4 o_color : COLOR, + float4 l_texcoordN : TEXCOORD1, + uniform float4 texpix_txaux, + uniform sampler2D k_txaux, + uniform float4 k_cartoonseparation, + uniform float4 k_cartooncolor, + uniform float4 k_cutoff, + uniform float4 k_mult) +{ + // This logic is the same as in the original inking code. + float4 cartoondelta = k_cartoonseparation * texpix_txaux.xwyw; + float4 cartoon_p0 = l_texcoordN + cartoondelta.xyzw; + float4 cartoon_c0 = tex2D(k_txaux, cartoon_p0.xy); + float4 cartoon_p1 = l_texcoordN - cartoondelta.xyzw; + float4 cartoon_c1 = tex2D(k_txaux, cartoon_p1.xy); + float4 cartoon_p2 = l_texcoordN + cartoondelta.wzyx; + float4 cartoon_c2 = tex2D(k_txaux, cartoon_p2.xy); + float4 cartoon_p3 = l_texcoordN - cartoondelta.wzyx; + float4 cartoon_c3 = tex2D(k_txaux, cartoon_p3.xy); + float4 cartoon_mx = max(cartoon_c0,max(cartoon_c1,max(cartoon_c2,cartoon_c3))); + float4 cartoon_mn = min(cartoon_c0,min(cartoon_c1,min(cartoon_c2,cartoon_c3))); + + // Here two new parameters are available: + // k_mult - float4, with last two components zero. First two components are used + // to tune the steepness of the alpha gradient along the ink lines. + // The original code used float4(3,3,0,0). + // k_cutoff - float4, where only the first component matters. This works like + // the cutoff parameter in Cartoon-Shader/Tut-Cartoon-Advanced.py + // in the standard sample programs in the Panda3D distribution. + // + float cartoon_thresh = saturate(dot(cartoon_mx - cartoon_mn, k_mult) - k_cutoff.x); +/* float cartoon_thresh = step(0.5, dot(cartoon_mx - cartoon_mn, k_mult) - k_cutoff.x);*/ + + // Output always k_cartooncolor, but with alpha depending on result. + // + // The minimum alpha is 0; the maximum is k_cartooncolor.a (i.e. the alpha component + // of the color specified for inking; see setCartoonInk() in CommonFilters.py). + // + // This is rendered into an intermediate texture, which will be blurred + // (affecting also the alpha channel) in a later pass, before CommonFilters.py + // blits the result onto its finalQuad. See filter-advanced-ink-blur[xy].sha. + // + float4 tempcolor = k_cartooncolor; + tempcolor.a = 0; + o_color = lerp(tempcolor, k_cartooncolor, cartoon_thresh); +} + diff -Naur '--exclude-from=binaries_and_temp_stuff.txt' panda3d-1.8.1/direct/src/filter/filter-advanced-ink-withdepth.sha panda3d-1.8.1-jj/direct/src/filter/filter-advanced-ink-withdepth.sha --- panda3d-1.8.1/direct/src/filter/filter-advanced-ink-withdepth.sha 1970-01-01 02:00:00.000000000 +0200 +++ panda3d-1.8.1-jj/direct/src/filter/filter-advanced-ink-withdepth.sha 2013-09-07 01:45:52.494495927 +0300 @@ -0,0 +1,89 @@ +//Cg +// +//Cg profile arbvp1 arbfp1 + +void vshader(float4 vtx_position : POSITION, + out float4 l_position : POSITION, + uniform float4 texpad_txaux, + uniform float4 texpix_txaux, + uniform float4 texpad_txdepth, + uniform float4 texpix_txdepth, + out float4 l_texcoordN : TEXCOORD1, + out float4 l_texcoordD : TEXCOORD2, + uniform float4x4 mat_modelproj) +{ + l_position=mul(mat_modelproj, vtx_position); + l_texcoordN=(vtx_position.xzxz * texpad_txaux) + texpad_txaux; + l_texcoordD=(vtx_position.xzxz * texpad_txdepth) + texpad_txdepth; +} + +// Cartoon inker originally from CommonFilters.py. Modified to output always k_cartooncolor, +// but with alpha depending on whether a pixel has ink or not. +// +// This version also utilizes the depth map to make the line thicker or thinner +// depending on the pixel's distance from the camera. +// +// See also filter-advanced-ink-nodepth.sha. +// +void fshader(out float4 o_color : COLOR, + float4 l_texcoordN : TEXCOORD1, + float4 l_texcoordD : TEXCOORD2, + uniform float4 texpix_txaux, + uniform sampler2D k_txaux, + uniform float4 texpix_txdepth, + uniform sampler2D k_txdepth, + uniform float4 k_cartoonseparation, + uniform float4 k_cartooncolor, + uniform float4 k_cutoff, + uniform float4 k_mult) +{ + // depth is always in the range 0.0 ... 1.0. + float depth = tex2D(k_txdepth, l_texcoordD.xy); + + // The lerp effectively modulates k_cartoonseparation, using the depth data. + // + // The 0.5 and 2.0 are arbitrarily chosen limits for the modifier, + // which look good for commonly used values of k_cartoonseparation (0.6 ... 1.0). + // + // Also, the square falloff (1.0 - depth**2) looks good without introducing + // division by zero issues for pixels very close to the camera. + // + float4 cartoondelta = lerp(0.5, 2.0, 1.0 - depth*depth) * k_cartoonseparation * texpix_txaux.xwyw; + + // This logic is the same as in the original inking code. + float4 cartoon_p0 = l_texcoordN + cartoondelta.xyzw; + float4 cartoon_c0 = tex2D(k_txaux, cartoon_p0.xy); + float4 cartoon_p1 = l_texcoordN - cartoondelta.xyzw; + float4 cartoon_c1 = tex2D(k_txaux, cartoon_p1.xy); + float4 cartoon_p2 = l_texcoordN + cartoondelta.wzyx; + float4 cartoon_c2 = tex2D(k_txaux, cartoon_p2.xy); + float4 cartoon_p3 = l_texcoordN - cartoondelta.wzyx; + float4 cartoon_c3 = tex2D(k_txaux, cartoon_p3.xy); + float4 cartoon_mx = max(cartoon_c0,max(cartoon_c1,max(cartoon_c2,cartoon_c3))); + float4 cartoon_mn = min(cartoon_c0,min(cartoon_c1,min(cartoon_c2,cartoon_c3))); + + // Here two new parameters are available: + // k_mult - float4, with last two components zero. First two components are used + // to tune the steepness of the alpha gradient along the ink lines. + // The original code used float4(3,3,0,0). + // k_cutoff - float4, where only the first component matters. This works like + // the cutoff parameter in Cartoon-Shader/Tut-Cartoon-Advanced.py + // in the standard sample programs in the Panda3D distribution. + // + float cartoon_thresh = saturate(dot(cartoon_mx - cartoon_mn, k_mult) - k_cutoff.x); +/* float cartoon_thresh = step(0.5, dot(cartoon_mx - cartoon_mn, k_mult) - k_cutoff.x);*/ + + // Output always k_cartooncolor, but with alpha depending on result. + // + // The minimum alpha is 0; the maximum is k_cartooncolor.a (i.e. the alpha component + // of the color specified for inking; see setCartoonInk() in CommonFilters.py). + // + // This is rendered into an intermediate texture, which will be blurred + // (affecting also the alpha channel) in a later pass, before CommonFilters.py + // blits the result onto its finalQuad. See filter-advanced-ink-blur[xy].sha. + // + float4 tempcolor = k_cartooncolor; + tempcolor.a = 0; + o_color = lerp(tempcolor, k_cartooncolor, cartoon_thresh); +} + diff -Naur '--exclude-from=binaries_and_temp_stuff.txt' panda3d-1.8.1/panda/src/pgraph/lightRampAttrib.cxx panda3d-1.8.1-jj/panda/src/pgraph/lightRampAttrib.cxx --- panda3d-1.8.1/panda/src/pgraph/lightRampAttrib.cxx 2011-11-07 02:08:05.000000000 +0200 +++ panda3d-1.8.1-jj/panda/src/pgraph/lightRampAttrib.cxx 2013-09-01 16:47:18.853608356 +0300 @@ -78,6 +78,84 @@ } //////////////////////////////////////////////////////////////////// +// Function: LightRampAttrib::make_single_threshold +// Access: Published, Static +// Description: Constructs a new LightRampAttrib object. This +// causes the luminance of the diffuse (and optionally also specular) +// lighting contribution to be quantized using a single threshold, +// but with linear smoothing of the transition: +// @code +// a = threshold0 - smoothing; +// b = threshold0 + smoothing; +// if (original_luminance > b) { +// luminance = level0; +// } else if (original_luminance < a) { +// luminance = 0.0; +// } +// else +// { +// luminance = lerp(0.0, level0, (original_luminance - a)/(b - a)); +// } +// @endcode +// This version uses the same quantization parameters +// for the diffuse and specular contributions. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightRampAttrib:: +make_single_threshold(PN_stdfloat thresh0, PN_stdfloat val0, PN_stdfloat smooth0, bool affect_specular) { + LightRampAttrib *attrib = new LightRampAttrib(); + attrib->_mode = LRT_single_threshold; + attrib->_threshold[0] = thresh0; + attrib->_level[0] = val0; + attrib->_smoothing[0] = smooth0; + attrib->_affect_specular = affect_specular; + if(affect_specular) { + // By default, we use the same quantization parameters + // for the specular contribution as for the diffuse contribution. + attrib->_threshold_specular[0] = thresh0; + attrib->_level_specular[0] = val0; + attrib->_smoothing_specular[0] = smooth0; + } + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightRampAttrib::make_single_threshold +// Access: Published, Static +// Description: Constructs a new LightRampAttrib object. This +// causes the luminance of the diffuse (and optionally also specular) +// lighting contribution to be quantized using a single threshold, +// but with linear smoothing of the transition: +// @code +// a = threshold0 - smoothing; +// b = threshold0 + smoothing; +// if (original_luminance > b) { +// luminance = level0; +// } else if (original_luminance < a) { +// luminance = 0.0; +// } +// else +// { +// luminance = lerp(0.0, level0, (original_luminance - a)/(b - a)); +// } +// @endcode +// This version allows specifying different quantization parameters +// for the diffuse and specular contributions. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightRampAttrib:: +make_single_threshold(PN_stdfloat thresh0, PN_stdfloat val0, PN_stdfloat smooth0, bool affect_specular, PN_stdfloat thresh0_specular, PN_stdfloat val0_specular, PN_stdfloat smooth0_specular) { + LightRampAttrib *attrib = new LightRampAttrib(); + attrib->_mode = LRT_single_threshold; + attrib->_threshold[0] = thresh0; + attrib->_level[0] = val0; + attrib->_smoothing[0] = smooth0; + attrib->_affect_specular = affect_specular; + attrib->_threshold_specular[0] = thresh0_specular; + attrib->_level_specular[0] = val0_specular; + attrib->_smoothing_specular[0] = smooth0_specular; + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// // Function: LightRampAttrib::make_double_threshold // Access: Published, Static // Description: Constructs a new LightRampAttrib object. This @@ -96,11 +174,117 @@ CPT(RenderAttrib) LightRampAttrib:: make_double_threshold(PN_stdfloat thresh0, PN_stdfloat val0, PN_stdfloat thresh1, PN_stdfloat val1) { LightRampAttrib *attrib = new LightRampAttrib(); - attrib->_mode = LRT_single_threshold; + attrib->_mode = LRT_double_threshold; + attrib->_threshold[0] = thresh0; + attrib->_level[0] = val0; + attrib->_threshold[1] = thresh1; + attrib->_level[1] = val1; + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightRampAttrib::make_double_threshold +// Access: Published, Static +// Description: Constructs a new LightRampAttrib object. This +// causes the luminance of the diffuse (and optionally also specular) +// lighting contribution to be quantized using two thresholds, +// but with linear smoothing of the transitions. +// It is assumed that threshold1 > threshold0, +// and that the smoothing ranges do not overlap. +// @code +// a = threshold0 - smooth0; +// b = threshold0 + smooth0; +// c = threshold1 - smooth1; +// d = threshold1 + smooth1; +// if (original_luminance > d) { +// luminance = level1; +// } else if (original_luminance < c) { +// if (original_luminance > b) { +// luminance = level0; // between b and c +// } else if (original_luminance < a) { +// luminance = 0.0; +// } else { // between a and b +// luminance = lerp(0.0, level0, (original_luminance - a)/(b - a)); +// } +// } else { // between c and d +// luminance = lerp(level0, level1, (original_luminance - c)/(d - c)); +// } +// @endcode +// This version uses the same quantization parameters +// for the diffuse and specular contributions. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightRampAttrib:: +make_double_threshold(PN_stdfloat thresh0, PN_stdfloat val0, PN_stdfloat smooth0, PN_stdfloat thresh1, PN_stdfloat val1, PN_stdfloat smooth1, bool affect_specular) { + LightRampAttrib *attrib = new LightRampAttrib(); + attrib->_mode = LRT_double_threshold; + attrib->_threshold[0] = thresh0; + attrib->_level[0] = val0; + attrib->_smoothing[0] = smooth0; + attrib->_threshold[1] = thresh1; + attrib->_level[1] = val1; + attrib->_smoothing[1] = smooth1; + attrib->_affect_specular = affect_specular; + if(affect_specular) { + // By default, we use the same quantization parameters + // for the specular contribution as for the diffuse contribution. + attrib->_threshold_specular[0] = thresh0; + attrib->_level_specular[0] = val0; + attrib->_smoothing_specular[0] = smooth0; + attrib->_threshold_specular[1] = thresh1; + attrib->_level_specular[1] = val1; + attrib->_smoothing_specular[1] = smooth1; + } + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightRampAttrib::make_double_threshold +// Access: Published, Static +// Description: Constructs a new LightRampAttrib object. This +// causes the luminance of the diffuse (and optionally also specular) +// lighting contribution to be quantized using two thresholds, +// but with linear smoothing of the transitions. +// It is assumed that threshold1 > threshold0, +// and that the smoothing ranges do not overlap. +// @code +// a = threshold0 - smooth0; +// b = threshold0 + smooth0; +// c = threshold1 - smooth1; +// d = threshold1 + smooth1; +// if (original_luminance > d) { +// luminance = level1; +// } else if (original_luminance < c) { +// if (original_luminance > b) { +// luminance = level0; // between b and c +// } else if (original_luminance < a) { +// luminance = 0.0; +// } else { // between a and b +// luminance = lerp(0.0, level0, (original_luminance - a)/(b - a)); +// } +// } else { // between c and d +// luminance = lerp(level0, level1, (original_luminance - c)/(d - c)); +// } +// @endcode +// This version allows specifying different quantization parameters +// for the diffuse and specular contributions. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightRampAttrib:: +make_double_threshold(PN_stdfloat thresh0, PN_stdfloat val0, PN_stdfloat smooth0, PN_stdfloat thresh1, PN_stdfloat val1, PN_stdfloat smooth1, bool affect_specular, PN_stdfloat thresh0_specular, PN_stdfloat val0_specular, PN_stdfloat smooth0_specular, PN_stdfloat thresh1_specular, PN_stdfloat val1_specular, PN_stdfloat smooth1_specular) { + LightRampAttrib *attrib = new LightRampAttrib(); + attrib->_mode = LRT_double_threshold; attrib->_threshold[0] = thresh0; attrib->_level[0] = val0; + attrib->_smoothing[0] = smooth0; attrib->_threshold[1] = thresh1; attrib->_level[1] = val1; + attrib->_smoothing[1] = smooth1; + attrib->_affect_specular = affect_specular; + attrib->_threshold_specular[0] = thresh0_specular; + attrib->_level_specular[0] = val0_specular; + attrib->_smoothing_specular[0] = smooth0_specular; + attrib->_threshold_specular[1] = thresh1_specular; + attrib->_level_specular[1] = val1_specular; + attrib->_smoothing_specular[1] = smooth1_specular; return return_new(attrib); } diff -Naur '--exclude-from=binaries_and_temp_stuff.txt' panda3d-1.8.1/panda/src/pgraph/lightRampAttrib.h panda3d-1.8.1-jj/panda/src/pgraph/lightRampAttrib.h --- panda3d-1.8.1/panda/src/pgraph/lightRampAttrib.h 2011-11-07 02:08:05.000000000 +0200 +++ panda3d-1.8.1-jj/panda/src/pgraph/lightRampAttrib.h 2013-09-01 15:54:37.201699627 +0300 @@ -46,7 +46,11 @@ static CPT(RenderAttrib) make_default(); static CPT(RenderAttrib) make_identity(); static CPT(RenderAttrib) make_single_threshold(PN_stdfloat thresh0, PN_stdfloat lev0); + static CPT(RenderAttrib) make_single_threshold(PN_stdfloat thresh0, PN_stdfloat lev0, PN_stdfloat smooth0, bool affect_specular); + static CPT(RenderAttrib) make_single_threshold(PN_stdfloat thresh0, PN_stdfloat lev0, PN_stdfloat smooth0, bool affect_specular, PN_stdfloat thresh0_specular, PN_stdfloat lev0_specular, PN_stdfloat smooth0_specular); static CPT(RenderAttrib) make_double_threshold(PN_stdfloat thresh0, PN_stdfloat lev0, PN_stdfloat thresh1, PN_stdfloat lev1); + static CPT(RenderAttrib) make_double_threshold(PN_stdfloat thresh0, PN_stdfloat lev0, PN_stdfloat smooth0, PN_stdfloat thresh1, PN_stdfloat lev1, PN_stdfloat smooth1, bool affect_specular); + static CPT(RenderAttrib) make_double_threshold(PN_stdfloat thresh0, PN_stdfloat lev0, PN_stdfloat smooth0, PN_stdfloat thresh1, PN_stdfloat lev1, PN_stdfloat smooth1, bool affect_specular, PN_stdfloat thresh0_specular, PN_stdfloat lev0_specular, PN_stdfloat smooth0_specular, PN_stdfloat thresh1_specular, PN_stdfloat lev1_specular, PN_stdfloat smooth1_specular); static CPT(RenderAttrib) make_hdr0(); static CPT(RenderAttrib) make_hdr1(); static CPT(RenderAttrib) make_hdr2(); @@ -55,7 +59,12 @@ INLINE LightRampMode get_mode() const; INLINE PN_stdfloat get_level(int n) const; INLINE PN_stdfloat get_threshold(int n) const; - + INLINE PN_stdfloat get_smoothing(int n) const; + INLINE bool get_affect_specular() const; + INLINE PN_stdfloat get_level_specular(int n) const; + INLINE PN_stdfloat get_threshold_specular(int n) const; + INLINE PN_stdfloat get_smoothing_specular(int n) const; + public: virtual void output(ostream &out) const; @@ -68,6 +77,11 @@ LightRampMode _mode; PN_stdfloat _level[2]; PN_stdfloat _threshold[2]; + PN_stdfloat _smoothing[2]; + bool _affect_specular; + PN_stdfloat _level_specular[2]; + PN_stdfloat _threshold_specular[2]; + PN_stdfloat _smoothing_specular[2]; static CPT(RenderAttrib) _default; diff -Naur '--exclude-from=binaries_and_temp_stuff.txt' panda3d-1.8.1/panda/src/pgraph/lightRampAttrib.I panda3d-1.8.1-jj/panda/src/pgraph/lightRampAttrib.I --- panda3d-1.8.1/panda/src/pgraph/lightRampAttrib.I 2011-10-10 08:25:16.000000000 +0300 +++ panda3d-1.8.1-jj/panda/src/pgraph/lightRampAttrib.I 2013-09-01 15:45:04.733716151 +0300 @@ -26,6 +26,15 @@ _level[1] = 0.0; _threshold[0] = 0.0; _threshold[1] = 0.0; + _smoothing[0] = 0.0; + _smoothing[1] = 0.0; + _affect_specular = false; + _level_specular[0] = 0.0; + _level_specular[1] = 0.0; + _threshold_specular[0] = 0.0; + _threshold_specular[1] = 0.0; + _smoothing_specular[0] = 0.0; + _smoothing_specular[1] = 0.0; } //////////////////////////////////////////////////////////////////// @@ -59,3 +68,58 @@ if ((n<0)||(n>1)) return 0.0; return _threshold[n]; } + +//////////////////////////////////////////////////////////////////// +// Function: LightRampAttrib::get_smoothing +// Access: Published +// Description: Returns the smoothing value for the nth range (range = threshold +- smoothing). +//////////////////////////////////////////////////////////////////// +INLINE PN_stdfloat LightRampAttrib:: +get_smoothing(int n) const { + if ((n<0)||(n>1)) return 0.0; + return _smoothing[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightRampAttrib::get_affect_specular +// Access: Published +// Description: Returns whether this light ramp affects specular lighting. If false, then diffuse only. This parameter only affects quantizing (cartoon shading) light ramps. +//////////////////////////////////////////////////////////////////// +INLINE bool LightRampAttrib:: +get_affect_specular() const { + return _affect_specular; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightRampAttrib::get_level_specular +// Access: Published +// Description: Returns the nth lighting level for the specular contribution. Only relevant if affect_specular is enabled. +//////////////////////////////////////////////////////////////////// +INLINE PN_stdfloat LightRampAttrib:: +get_level_specular(int n) const { + if ((n<0)||(n>1)) return 0.0; + return _level_specular[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightRampAttrib::get_threshold_specular +// Access: Published +// Description: Returns the nth threshold level for the specular contribution. Only relevant if affect_specular is enabled. +//////////////////////////////////////////////////////////////////// +INLINE PN_stdfloat LightRampAttrib:: +get_threshold_specular(int n) const { + if ((n<0)||(n>1)) return 0.0; + return _threshold_specular[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightRampAttrib::get_smoothing_specular +// Access: Published +// Description: Returns the smoothing value for the nth range (range = threshold +- smoothing) for the specular contribution. Only relevant if affect_specular is enabled. +//////////////////////////////////////////////////////////////////// +INLINE PN_stdfloat LightRampAttrib:: +get_smoothing_specular(int n) const { + if ((n<0)||(n>1)) return 0.0; + return _smoothing_specular[n]; +} + diff -Naur '--exclude-from=binaries_and_temp_stuff.txt' panda3d-1.8.1/panda/src/pgraphnodes/shaderGenerator.cxx panda3d-1.8.1-jj/panda/src/pgraphnodes/shaderGenerator.cxx --- panda3d-1.8.1/panda/src/pgraphnodes/shaderGenerator.cxx 2013-02-12 17:28:17.000000000 +0200 +++ panda3d-1.8.1-jj/panda/src/pgraphnodes/shaderGenerator.cxx 2013-09-01 16:44:23.741613411 +0300 @@ -1159,36 +1159,113 @@ } const LightRampAttrib *light_ramp = DCAST(LightRampAttrib, rs->get_attrib_def(LightRampAttrib::get_class_slot())); if(_auto_ramp_on) { - switch (light_ramp->get_mode()) { - case LightRampAttrib::LRT_single_threshold: - { - PN_stdfloat t = light_ramp->get_threshold(0); - PN_stdfloat l0 = light_ramp->get_level(0); - text << "\t // Single-threshold light ramp\n"; - text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n"; - text << "\t float lr_scale = (lr_in < " << t << ") ? 0.0 : (" << l0 << "/lr_in);\n"; - text << "\t tot_diffuse = tot_diffuse * lr_scale;\n"; - break; + // Cartoon shading. + // + // We might have to generate almost identical code twice (once for diffuse and once for specular, + // if affect_specular is enabled for the light ramp). Hence we loop. + // + // search tag: tot_diffuse, tot_specular + // + bool do_ramp[2]; // diffuse, specular + do_ramp[0] = ( _separate_ambient_diffuse && _have_diffuse) || + (!_separate_ambient_diffuse && (_have_ambient || _have_diffuse)); + do_ramp[1] = _have_specular && light_ramp->get_affect_specular() == true; + const char* rn[] = { "diffuse", "specular" }; // ramp name (for generating unique variable names, + // and for referring to tot_*) + + for(int j=0; j<2; ++j) { + if( !do_ramp[j] ) + continue; + + PN_stdfloat t0, l0, s0, t1, l1, s1; + if( j == 0 ) { // diffuse + t0 = light_ramp->get_threshold(0); + l0 = light_ramp->get_level(0); + s0 = light_ramp->get_smoothing(0); + t1 = light_ramp->get_threshold(1); + l1 = light_ramp->get_level(1); + s1 = light_ramp->get_smoothing(1); + } + else { // specular + // By default, these are initialized to the same values + // as the corresponding diffuse parameters. See panda/pgraph/lightRampAttrib.[I|cxx]. + t0 = light_ramp->get_threshold_specular(0); + l0 = light_ramp->get_level_specular(0); + s0 = light_ramp->get_smoothing_specular(0); + t1 = light_ramp->get_threshold_specular(1); + l1 = light_ramp->get_level_specular(1); + s1 = light_ramp->get_smoothing_specular(1); } - case LightRampAttrib::LRT_double_threshold: - { - PN_stdfloat t0 = light_ramp->get_threshold(0); - PN_stdfloat t1 = light_ramp->get_threshold(1); - PN_stdfloat l0 = light_ramp->get_level(0); - PN_stdfloat l1 = light_ramp->get_level(1); - PN_stdfloat l2 = light_ramp->get_level(2); - text << "\t // Double-threshold light ramp\n"; - text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n"; - text << "\t float lr_out = " << l0 << "\n"; - text << "\t if (lr_in > " << t0 << ") lr_out=" << l1 << ";\n"; - text << "\t if (lr_in > " << t1 << ") lr_out=" << l2 << ";\n"; - text << "\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n"; + + switch (light_ramp->get_mode()) { + case LightRampAttrib::LRT_single_threshold: + { + text << "\t // Single-threshold light ramp (for " << rn[j] << " lighting)\n"; + text << "\t float lr_" << rn[j] << "_in = dot(tot_" << rn[j] << ".rgb, float3(0.33,0.34,0.33));\n"; + + if( s0 == 0.0 ) + { + text << "\t // sharp transition with thresholding only\n"; + text << "\t float lr_" << rn[j] << "_scale = (lr_" << rn[j] << "_in < " << t0 << ") ? 0.0 : (" << l0 << "/lr_" << rn[j] << "_in);\n"; + } + else + { + text << "\t // smoothed transition with linear interpolation\n"; + text << "\t float lr_" << rn[j] << "_a = max(" << t0 << " - " << s0 << ", 0.0);\n"; + text << "\t float lr_" << rn[j] << "_b = min(" << t0 << " + " << s0 << ", 1.0);\n"; + text << "\t float lr_" << rn[j] << "_scale = (lr_" << rn[j] << "_in < lr_" << rn[j] << "_a) ? 0.0 : ( (lr_" << rn[j] << "_in > lr_" << rn[j] << "_b) ? " << l0 << "/lr_" << rn[j] << "_in : lerp(0.0, " << l0 << ", (lr_" << rn[j] << "_in-lr_" << rn[j] << "_a)/(lr_" << rn[j] << "_b-lr_" << rn[j] << "_a) )/lr_" << rn[j] << "_in );\n"; + } + + text << "\t tot_" << rn[j] << " = tot_" << rn[j] << " * lr_" << rn[j] << "_scale;\n"; + break; + } + case LightRampAttrib::LRT_double_threshold: + { + text << "\t // Double-threshold light ramp (for " << rn[j] << " lighting)\n"; + text << "\t float lr_" << rn[j] << "_in = dot(tot_" << rn[j] << ".rgb, float3(0.33,0.34,0.33));\n"; + text << "\t float lr_" << rn[j] << "_out = 0.0;\n"; + + // transition from 0 to l0 + // + if( s0 == 0.0 ) + { + text << "\t // 0 -> l0: sharp transition with thresholding only\n"; + text << "\t if (lr_" << rn[j] << "_in > " << t0 << ") lr_" << rn[j] << "_out=" << l0 << ";\n"; + } + else + { + text << "\t // 0 -> l0: smoothed transition with linear interpolation\n"; + text << "\t float lr_" << rn[j] << "_a = max(" << t0 << " - " << s0 << ", 0.0);\n"; + text << "\t float lr_" << rn[j] << "_b = min(" << t0 << " + " << s0 << ", 1.0);\n"; + text << "\t if (lr_" << rn[j] << "_in > lr_" << rn[j] << "_b) lr_" << rn[j] << "_out =" << l0 << ";\n"; + text << "\t else if (lr_" << rn[j] << "_in > lr_" << rn[j] << "_a) lr_" << rn[j] << "_out = lerp(0.0, " << l0 << ", (lr_" << rn[j] << "_in - lr_" << rn[j] << "_a)/(lr_" << rn[j] << "_b - lr_" << rn[j] << "_a));\n"; + } + + // transition from l0 to l1 + // + if( s1 == 0.0 ) + { + text << "\t // l0 -> l1: sharp transition with thresholding only\n"; + text << "\t if (lr_" << rn[j] << "_in > " << t1 << ") lr_" << rn[j] << "_out=" << l1 << ";\n"; + } + else + { + text << "\t // l0 -> l1: smoothed transition with linear interpolation\n"; + text << "\t float lr_" << rn[j] << "_c = max(" << t1 << " - " << s1 << ", 0.0);\n"; + text << "\t float lr_" << rn[j] << "_d = min(" << t1 << " + " << s1 << ", 1.0);\n"; + text << "\t if (lr_" << rn[j] << "_in > lr_" << rn[j] << "_d) lr_" << rn[j] << "_out=" << l1 << ";\n"; + text << "\t else if (lr_" << rn[j] << "_in > lr_" << rn[j] << "_c) lr_" << rn[j] << "_out= lerp(" << l0 << ", " << l1 << ", (lr_" << rn[j] << "_in - lr_" << rn[j] << "_c)/(lr_" << rn[j] << "_d - lr_" << rn[j] << "_c));\n"; + } + + text << "\t tot_" << rn[j] << " = tot_" << rn[j] << " * (lr_" << rn[j] << "_out / lr_" << rn[j] << "_in);\n"; + break; + } + default: break; } - default: - break; } } + text << "\t // Begin view-space light summation\n"; if (_have_emission) { if (_map_index_glow >= 0 && _auto_glow_on) {