|
@@ -18,30 +18,19 @@ clunky approach. - Josh
|
|
|
from FilterManager import FilterManager
|
|
from FilterManager import FilterManager
|
|
|
from pandac.PandaModules import Point3, Vec3, Vec4
|
|
from pandac.PandaModules import Point3, Vec3, Vec4
|
|
|
from pandac.PandaModules import NodePath, PandaNode
|
|
from pandac.PandaModules import NodePath, PandaNode
|
|
|
|
|
+from pandac.PandaModules import Filename
|
|
|
from pandac.PandaModules import RenderState, Texture, Shader
|
|
from pandac.PandaModules import RenderState, Texture, Shader
|
|
|
-
|
|
|
|
|
-HEADER = """//Cg
|
|
|
|
|
-
|
|
|
|
|
-void vshader(float4 vtx_position : POSITION,
|
|
|
|
|
- out float4 l_position : POSITION,
|
|
|
|
|
- out float4 l_texcoord : TEXCOORD0,
|
|
|
|
|
- uniform float4 texpad_txcolor,
|
|
|
|
|
- uniform float4x4 mat_modelproj)
|
|
|
|
|
-{
|
|
|
|
|
- l_position=mul(mat_modelproj, vtx_position);
|
|
|
|
|
- l_texcoord=(vtx_position.xzxz * texpad_txcolor) + texpad_txcolor;
|
|
|
|
|
-}
|
|
|
|
|
-"""
|
|
|
|
|
|
|
+import sys,os
|
|
|
|
|
|
|
|
CARTOON_BODY="""
|
|
CARTOON_BODY="""
|
|
|
-float4 cartoondelta = k_cartoonseparation * texpix_txcolor.xwyw;
|
|
|
|
|
-float4 cartoon_p0 = l_texcoord + cartoondelta.xyzw;
|
|
|
|
|
|
|
+float4 cartoondelta = k_cartoonseparation * texpix_txnormal.xwyw;
|
|
|
|
|
+float4 cartoon_p0 = l_texcoordN + cartoondelta.xyzw;
|
|
|
float4 cartoon_c0 = tex2D(k_txnormal, cartoon_p0.xy);
|
|
float4 cartoon_c0 = tex2D(k_txnormal, cartoon_p0.xy);
|
|
|
-float4 cartoon_p1 = l_texcoord - cartoondelta.xyzw;
|
|
|
|
|
|
|
+float4 cartoon_p1 = l_texcoordN - cartoondelta.xyzw;
|
|
|
float4 cartoon_c1 = tex2D(k_txnormal, cartoon_p1.xy);
|
|
float4 cartoon_c1 = tex2D(k_txnormal, cartoon_p1.xy);
|
|
|
-float4 cartoon_p2 = l_texcoord + cartoondelta.wzyx;
|
|
|
|
|
|
|
+float4 cartoon_p2 = l_texcoordN + cartoondelta.wzyx;
|
|
|
float4 cartoon_c2 = tex2D(k_txnormal, cartoon_p2.xy);
|
|
float4 cartoon_c2 = tex2D(k_txnormal, cartoon_p2.xy);
|
|
|
-float4 cartoon_p3 = l_texcoord - cartoondelta.wzyx;
|
|
|
|
|
|
|
+float4 cartoon_p3 = l_texcoordN - cartoondelta.wzyx;
|
|
|
float4 cartoon_c3 = tex2D(k_txnormal, cartoon_p3.xy);
|
|
float4 cartoon_c3 = tex2D(k_txnormal, cartoon_p3.xy);
|
|
|
float4 cartoon_mx = max(cartoon_c0,max(cartoon_c1,max(cartoon_c2,cartoon_c3)));
|
|
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)));
|
|
float4 cartoon_mn = min(cartoon_c0,min(cartoon_c1,min(cartoon_c2,cartoon_c3)));
|
|
@@ -50,10 +39,9 @@ float cartoon_thresh = dot(cartoon_trigger.xyz,float3(1,1,1));
|
|
|
o_color = lerp(o_color, float4(0,0,0,1), cartoon_thresh);
|
|
o_color = lerp(o_color, float4(0,0,0,1), cartoon_thresh);
|
|
|
"""
|
|
"""
|
|
|
|
|
|
|
|
-CARTOON_PARAMS="""
|
|
|
|
|
-uniform float4 k_cartoonseparation,
|
|
|
|
|
-uniform float4 k_cartooncutoff,
|
|
|
|
|
-"""
|
|
|
|
|
|
|
+class FilterConfig:
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
class CommonFilters:
|
|
class CommonFilters:
|
|
|
|
|
|
|
|
""" Class CommonFilters implements certain common image postprocessing
|
|
""" Class CommonFilters implements certain common image postprocessing
|
|
@@ -64,10 +52,16 @@ class CommonFilters:
|
|
|
self.configuration = {}
|
|
self.configuration = {}
|
|
|
self.cleanup()
|
|
self.cleanup()
|
|
|
|
|
|
|
|
|
|
+ def loadShader(self, name):
|
|
|
|
|
+ fn = os.path.join(os.path.abspath(os.path.dirname(__file__)), name)
|
|
|
|
|
+ print "loading shader: ", dir
|
|
|
|
|
+ return Shader.load(Filename.fromOsSpecific(fn))
|
|
|
|
|
+
|
|
|
def cleanup(self):
|
|
def cleanup(self):
|
|
|
self.manager.cleanup()
|
|
self.manager.cleanup()
|
|
|
self.textures = {}
|
|
self.textures = {}
|
|
|
self.finalQuad = None
|
|
self.finalQuad = None
|
|
|
|
|
+ self.bloom = []
|
|
|
|
|
|
|
|
def reconfigure(self, fullrebuild, changed):
|
|
def reconfigure(self, fullrebuild, changed):
|
|
|
|
|
|
|
@@ -82,31 +76,98 @@ class CommonFilters:
|
|
|
if (len(configuration) == 0):
|
|
if (len(configuration) == 0):
|
|
|
return
|
|
return
|
|
|
|
|
|
|
|
- needtexpix = False
|
|
|
|
|
needtex = {}
|
|
needtex = {}
|
|
|
needtex["color"] = True
|
|
needtex["color"] = True
|
|
|
if (configuration.has_key("CartoonInk")):
|
|
if (configuration.has_key("CartoonInk")):
|
|
|
needtex["normal"] = True
|
|
needtex["normal"] = True
|
|
|
|
|
+ if (configuration.has_key("Bloom")):
|
|
|
|
|
+ needtex["bloom0"] = True
|
|
|
|
|
+ needtex["bloom1"] = True
|
|
|
|
|
+ needtex["bloom2"] = True
|
|
|
|
|
+ needtex["bloom3"] = True
|
|
|
for tex in needtex:
|
|
for tex in needtex:
|
|
|
self.textures[tex] = Texture("scene-"+tex)
|
|
self.textures[tex] = Texture("scene-"+tex)
|
|
|
needtexpix = True
|
|
needtexpix = True
|
|
|
|
|
|
|
|
self.finalQuad = self.manager.renderSceneInto(textures = self.textures)
|
|
self.finalQuad = self.manager.renderSceneInto(textures = self.textures)
|
|
|
|
|
|
|
|
- text = HEADER
|
|
|
|
|
|
|
+ if (configuration.has_key("Bloom")):
|
|
|
|
|
+ bloomconf = configuration["Bloom"]
|
|
|
|
|
+ bloom0=self.textures["bloom0"]
|
|
|
|
|
+ bloom1=self.textures["bloom1"]
|
|
|
|
|
+ bloom2=self.textures["bloom2"]
|
|
|
|
|
+ bloom3=self.textures["bloom3"]
|
|
|
|
|
+ if (bloomconf.size == "large"):
|
|
|
|
|
+ scale=8
|
|
|
|
|
+ downsampler="filter-down4.sha"
|
|
|
|
|
+ elif (bloomconf.size == "medium"):
|
|
|
|
|
+ scale=4
|
|
|
|
|
+ downsampler="filter-copy.sha"
|
|
|
|
|
+ else:
|
|
|
|
|
+ scale=2
|
|
|
|
|
+ downsampler="filter-copy.sha"
|
|
|
|
|
+ self.bloom.append(self.manager.renderQuadInto(colortex=bloom0, div=2, align=scale))
|
|
|
|
|
+ self.bloom.append(self.manager.renderQuadInto(colortex=bloom1, div=scale, align=scale))
|
|
|
|
|
+ self.bloom.append(self.manager.renderQuadInto(colortex=bloom2, div=scale, align=scale))
|
|
|
|
|
+ self.bloom.append(self.manager.renderQuadInto(colortex=bloom3, div=scale, align=scale))
|
|
|
|
|
+ self.bloom[0].setShaderInput("src", self.textures["color"])
|
|
|
|
|
+ self.bloom[0].setShader(self.loadShader("filter-bloomi.sha"))
|
|
|
|
|
+ self.bloom[1].setShaderInput("src", bloom0)
|
|
|
|
|
+ self.bloom[1].setShader(self.loadShader(downsampler))
|
|
|
|
|
+ self.bloom[2].setShaderInput("src", bloom1)
|
|
|
|
|
+ self.bloom[2].setShader(self.loadShader("filter-bloomx.sha"))
|
|
|
|
|
+ self.bloom[3].setShaderInput("src", bloom2)
|
|
|
|
|
+ self.bloom[3].setShader(self.loadShader("filter-bloomy.sha"))
|
|
|
|
|
+
|
|
|
|
|
+ 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"
|
|
|
|
|
+ if (configuration.has_key("CartoonInk")):
|
|
|
|
|
+ text += " uniform float4 texpad_txnormal,\n"
|
|
|
|
|
+ text += " uniform float4 texpix_txnormal,\n"
|
|
|
|
|
+ text += " out float4 l_texcoordN : TEXCOORD1,\n"
|
|
|
|
|
+ if (configuration.has_key("Bloom")):
|
|
|
|
|
+ text += " uniform float4 texpad_txbloom3,\n"
|
|
|
|
|
+ text += " out float4 l_texcoordB : TEXCOORD2,\n"
|
|
|
|
|
+ text += " uniform float4x4 mat_modelproj)\n"
|
|
|
|
|
+ text += "{\n"
|
|
|
|
|
+ text += " l_position=mul(mat_modelproj, vtx_position);\n"
|
|
|
|
|
+ text += " l_texcoordC=(vtx_position.xzxz * texpad_txcolor) + texpad_txcolor;\n"
|
|
|
|
|
+ if (configuration.has_key("CartoonInk")):
|
|
|
|
|
+ text += " l_texcoordN=(vtx_position.xzxz * texpad_txnormal) + texpad_txnormal;\n"
|
|
|
|
|
+ if (configuration.has_key("Bloom")):
|
|
|
|
|
+ text += " l_texcoordB=(vtx_position.xzxz * texpad_txbloom3) + texpad_txbloom3;\n"
|
|
|
|
|
+ if (configuration.has_key("HalfPixelShift")):
|
|
|
|
|
+ text += " l_texcoordC+=texpix_txcolor*0.5;\n"
|
|
|
|
|
+ if (configuration.has_key("CartoonInk")):
|
|
|
|
|
+ text += " l_texcoordN+=texpix_txnormal*0.5;\n"
|
|
|
|
|
+ text += "}\n"
|
|
|
|
|
+
|
|
|
text += "void fshader(\n"
|
|
text += "void fshader(\n"
|
|
|
- text += "float4 l_texcoord : TEXCOORD0,\n"
|
|
|
|
|
- if (needtexpix):
|
|
|
|
|
- text += "uniform float4 texpix_txcolor,\n"
|
|
|
|
|
|
|
+ text += "float4 l_texcoordC : TEXCOORD0,\n"
|
|
|
|
|
+ text += "uniform float4 texpix_txcolor,\n"
|
|
|
|
|
+ if (configuration.has_key("CartoonInk")):
|
|
|
|
|
+ text += "float4 l_texcoordN : TEXCOORD1,\n"
|
|
|
|
|
+ text += "uniform float4 texpix_txnormal,\n"
|
|
|
|
|
+ if (configuration.has_key("Bloom")):
|
|
|
|
|
+ text += "float4 l_texcoordB : TEXCOORD2,\n"
|
|
|
for key in self.textures:
|
|
for key in self.textures:
|
|
|
text += "uniform sampler2D k_tx" + key + ",\n"
|
|
text += "uniform sampler2D k_tx" + key + ",\n"
|
|
|
if (configuration.has_key("CartoonInk")):
|
|
if (configuration.has_key("CartoonInk")):
|
|
|
- text += CARTOON_PARAMS
|
|
|
|
|
|
|
+ text += "uniform float4 k_cartoonseparation,\n"
|
|
|
|
|
+ text += "uniform float4 k_cartooncutoff,\n"
|
|
|
text += "out float4 o_color : COLOR)\n"
|
|
text += "out float4 o_color : COLOR)\n"
|
|
|
text += "{\n"
|
|
text += "{\n"
|
|
|
- text += " o_color = tex2D(k_txcolor, l_texcoord.xy);\n"
|
|
|
|
|
|
|
+ text += " o_color = tex2D(k_txcolor, l_texcoordC.xy);\n"
|
|
|
if (configuration.has_key("CartoonInk")):
|
|
if (configuration.has_key("CartoonInk")):
|
|
|
text += CARTOON_BODY
|
|
text += CARTOON_BODY
|
|
|
|
|
+ if (configuration.has_key("Bloom")):
|
|
|
|
|
+ text += "o_color = saturate(o_color);\n";
|
|
|
|
|
+ text += "float4 bloom = 0.5*tex2D(k_txbloom3, l_texcoordB.xy);\n"
|
|
|
|
|
+ text += "o_color = 1-((1-bloom)*(1-o_color));\n"
|
|
|
text += "}\n"
|
|
text += "}\n"
|
|
|
|
|
|
|
|
print "Using shader: ", text
|
|
print "Using shader: ", text
|
|
@@ -120,6 +181,15 @@ class CommonFilters:
|
|
|
self.finalQuad.setShaderInput("cartoonseparation", Vec4(separation,0,separation,0))
|
|
self.finalQuad.setShaderInput("cartoonseparation", Vec4(separation,0,separation,0))
|
|
|
self.finalQuad.setShaderInput("cartooncutoff", Vec4(cutoff,cutoff,cutoff,cutoff))
|
|
self.finalQuad.setShaderInput("cartooncutoff", Vec4(cutoff,cutoff,cutoff,cutoff))
|
|
|
|
|
|
|
|
|
|
+ if (changed == "Bloom") or fullrebuild:
|
|
|
|
|
+ if (configuration.has_key("Bloom")):
|
|
|
|
|
+ bloomconf = configuration["Bloom"]
|
|
|
|
|
+ intensity = bloomconf.intensity * 3.0
|
|
|
|
|
+ self.bloom[0].setShaderInput("blend", bloomconf.blendx, bloomconf.blendy, bloomconf.blendz, bloomconf.blendw)
|
|
|
|
|
+ self.bloom[0].setShaderInput("trigger", bloomconf.mintrigger, 1.0/(bloomconf.maxtrigger-bloomconf.mintrigger), 0.0, 0.0)
|
|
|
|
|
+ self.bloom[0].setShaderInput("desat", bloomconf.desat)
|
|
|
|
|
+ self.bloom[3].setShaderInput("intensity", intensity, intensity, intensity, intensity)
|
|
|
|
|
+
|
|
|
def setCartoonInk(self, separation=1, cutoff=0.3):
|
|
def setCartoonInk(self, separation=1, cutoff=0.3):
|
|
|
fullrebuild = (self.configuration.has_key("CartoonInk") == False)
|
|
fullrebuild = (self.configuration.has_key("CartoonInk") == False)
|
|
|
self.configuration["CartoonInk"] = (separation, cutoff)
|
|
self.configuration["CartoonInk"] = (separation, cutoff)
|
|
@@ -128,6 +198,45 @@ class CommonFilters:
|
|
|
def delCartoonInk(self):
|
|
def delCartoonInk(self):
|
|
|
if (self.configuration.has_key("CartoonInk")):
|
|
if (self.configuration.has_key("CartoonInk")):
|
|
|
del self.configuration["CartoonInk"]
|
|
del self.configuration["CartoonInk"]
|
|
|
- self.reconfigure(True)
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
|
|
+ self.reconfigure(True, "CartoonInk")
|
|
|
|
|
+
|
|
|
|
|
+ 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"):
|
|
|
|
|
+ if (maxtrigger==None): maxtrigger=mintrigger+0.8
|
|
|
|
|
+ oldconfig = self.configuration.get("Bloom", None)
|
|
|
|
|
+ fullrebuild = True
|
|
|
|
|
+ if (oldconfig) and (oldconfig.size == size):
|
|
|
|
|
+ fullrebuild = False
|
|
|
|
|
+ newconfig = FilterConfig()
|
|
|
|
|
+ (newconfig.blendx, newconfig.blendy, newconfig.blendz, newconfig.blendw) = blend
|
|
|
|
|
+ newconfig.maxtrigger = maxtrigger
|
|
|
|
|
+ newconfig.mintrigger = mintrigger
|
|
|
|
|
+ newconfig.desat = desat
|
|
|
|
|
+ newconfig.intensity = intensity
|
|
|
|
|
+ newconfig.size = size
|
|
|
|
|
+ self.configuration["Bloom"] = newconfig
|
|
|
|
|
+ self.reconfigure(fullrebuild, "Bloom")
|
|
|
|
|
+
|
|
|
|
|
+ def delBloom(self):
|
|
|
|
|
+ if (self.configuration.has_key("Bloom")):
|
|
|
|
|
+ del self.configuration["Bloom"]
|
|
|
|
|
+ self.reconfigure(True, "Bloom")
|
|
|
|
|
+
|
|
|
|
|
+ def setHalfPixelShift(self):
|
|
|
|
|
+ fullrebuild = (self.configuration.has_key("HalfPixelShift") == False)
|
|
|
|
|
+ self.configuration["HalfPixelShift"] = 1
|
|
|
|
|
+ self.reconfigure(fullrebuild, "HalfPixelShift")
|
|
|
|
|
+
|
|
|
|
|
+ def delHalfPixelShift(self):
|
|
|
|
|
+ if (self.configuration.has_key("HalfPixelShift")):
|
|
|
|
|
+ del self.configuration["HalfPixelShift"]
|
|
|
|
|
+ self.reconfigure(True, "HalfPixelShift")
|
|
|
|
|
+
|
|
|
|
|
+ def setFSBloom(self):
|
|
|
|
|
+ fullrebuild = (self.configuration.has_key("FSBloom") == False)
|
|
|
|
|
+ self.configuration["FSBloom"] = 1
|
|
|
|
|
+ self.reconfigure(fullrebuild, "FSBloom")
|
|
|
|
|
+
|
|
|
|
|
+ def delFSBloom(self):
|
|
|
|
|
+ if (self.configuration.has_key("FSBloom")):
|
|
|
|
|
+ del self.configuration["FSBloom"]
|
|
|
|
|
+ self.reconfigure(True, "FSBloom")
|