General development of FilterManager and CommonFiltes

This commit is contained in:
Josh Yelon 2008-02-21 19:57:37 +00:00
parent b98c5f0bf5
commit 6ac5500f76
7 changed files with 496 additions and 46 deletions

View File

@ -18,30 +18,19 @@ clunky approach. - Josh
from FilterManager import FilterManager
from pandac.PandaModules import Point3, Vec3, Vec4
from pandac.PandaModules import NodePath, PandaNode
from pandac.PandaModules import Filename
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="""
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_p1 = l_texcoord - cartoondelta.xyzw;
float4 cartoon_p1 = l_texcoordN - cartoondelta.xyzw;
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_p3 = l_texcoord - cartoondelta.wzyx;
float4 cartoon_p3 = l_texcoordN - cartoondelta.wzyx;
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_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);
"""
CARTOON_PARAMS="""
uniform float4 k_cartoonseparation,
uniform float4 k_cartooncutoff,
"""
class FilterConfig:
pass
class CommonFilters:
""" Class CommonFilters implements certain common image postprocessing
@ -64,10 +52,16 @@ class CommonFilters:
self.configuration = {}
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):
self.manager.cleanup()
self.textures = {}
self.finalQuad = None
self.bloom = []
def reconfigure(self, fullrebuild, changed):
@ -82,31 +76,98 @@ class CommonFilters:
if (len(configuration) == 0):
return
needtexpix = False
needtex = {}
needtex["color"] = True
if (configuration.has_key("CartoonInk")):
needtex["normal"] = True
if (configuration.has_key("Bloom")):
needtex["bloom0"] = True
needtex["bloom1"] = True
needtex["bloom2"] = True
needtex["bloom3"] = True
for tex in needtex:
self.textures[tex] = Texture("scene-"+tex)
needtexpix = True
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 += "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:
text += "uniform sampler2D k_tx" + key + ",\n"
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 += "{\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")):
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"
print "Using shader: ", text
@ -120,6 +181,15 @@ class CommonFilters:
self.finalQuad.setShaderInput("cartoonseparation", Vec4(separation,0,separation,0))
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):
fullrebuild = (self.configuration.has_key("CartoonInk") == False)
self.configuration["CartoonInk"] = (separation, cutoff)
@ -128,6 +198,45 @@ class CommonFilters:
def delCartoonInk(self):
if (self.configuration.has_key("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")

View File

@ -61,10 +61,63 @@ class FilterManager:
self.win = win
self.engine = win.getGsg().getEngine()
self.region = region
self.wclears = self.getClears(self.win)
self.rclears = self.getClears(self.region)
self.camera = cam
self.caminit = cam.node().getInitialState()
self.scales = []
self.buffers = []
self.sizes = []
self.nextsort = self.win.getSort() - 1000
self.basex = 0
self.basey = 0
def getClears(self,region):
clears = []
for i in range(GraphicsOutput.RTPCOUNT):
clears.append((region.getClearActive(i), region.getClearValue(i)))
return clears
def setClears(self,region,clears):
for i in range(GraphicsOutput.RTPCOUNT):
(active, value) = clears[i]
region.setClearActive(i, active)
region.setClearValue(i, value)
def setStackedClears(self, region, clears0, clears1):
clears = []
for i in range(GraphicsOutput.RTPCOUNT):
(active, value) = clears0[i]
if (active == 0):
(active, value) = clears1[i]
region.setClearActive(i, active)
region.setClearValue(i, value)
return clears
def isFullscreen(self):
return ((self.region.getLeft() == 0.0) and
(self.region.getRight() == 1.0) and
(self.region.getBottom() == 0.0) and
(self.region.getTop() == 1.0))
def getScaledSize(self, mul, div, align):
""" Calculate the size of the desired window. Not public. """
winx = self.win.getXSize()
winy = self.win.getYSize()
if (div != 1):
winx = ((winx+align-1) / align) * align
winy = ((winy+align-1) / align) * align
winx = winx / div
winy = winy / div
if (mul != 1):
winx = winx * mul
winy = winy * mul
return winx,winy
def renderSceneInto(self, depthtex=False, colortex=False, normaltex=False, textures=None):
@ -77,9 +130,9 @@ class FilterManager:
To elaborate on how this all works:
* An offscreen buffer is created. It is set up to mimic
the original window - it is the same size, uses the
same clear colors, and contains a DisplayRegion that
uses the original camera.
the original display region - it is the same size,
uses the same clear colors, and contains a DisplayRegion
that uses the original camera.
* A fullscreen quad and an orthographic camera to render
that quad are both created. The original camera is
@ -90,6 +143,18 @@ class FilterManager:
offscreen buffer. A shader is applied that tints the
results pink.
* Automatic shader generation is enabled by default for
the main camera. You can override this by setting
shaders on individual nodes, or on the root of your
scene graph, but if you do, your own shaders need to
generate the outputs that the filter manager is expecting.
* All clears are disabled on the original display region.
If the display region fills the whole window, then clears
are disabled on the original window as well. It is
assumed that rendering the full-screen quad eliminates
the need to do clears.
Hence, the original window which used to contain the actual
scene, now contains a pink-tinted quad with a texture of the
scene. It is assumed that the user will replace the shader
@ -104,7 +169,11 @@ class FilterManager:
texgroup = (depthtex, colortex, normaltex, None)
buffer = self.createBuffer("filter-base", base.win.getXSize(), base.win.getYSize(), texgroup)
# Choose the size of the offscreen buffer.
winx = self.win.getXSize()
winy = self.win.getYSize()
buffer = self.createBuffer("filter-base", winx, winy, texgroup)
if (buffer == None):
return None
@ -137,26 +206,68 @@ class FilterManager:
self.region.setCamera(quadcam)
buffer.getDisplayRegion(0).setCamera(self.camera)
buffer.getDisplayRegion(0).setActive(1)
dr = buffer.getDisplayRegion(0)
self.setStackedClears(dr, self.rclears, self.wclears)
if (normaltex):
dr.setClearActive(GraphicsOutput.RTPAuxRgba0, 1)
dr.setClearValue(GraphicsOutput.RTPAuxRgba0, Vec4(0.0,0.0,0.0,0.0))
self.region.disableClears()
if (self.isFullscreen()):
self.win.disableClears()
dr.setCamera(self.camera)
dr.setActive(1)
self.scales.append(1)
self.buffers.append(buffer)
self.sizes.append((1, 1, 1))
return quad
def renderQuadInto(self, scale=1, depthtex=None, colortex=None, auxtex0=None, auxtex1=None):
def renderQuadInto(self, mul=1, div=1, align=1, depthtex=None, colortex=None, auxtex0=None, auxtex1=None):
""" Creates an offscreen buffer for an intermediate
computation. Installs a quad into the buffer. Returns
the fullscreen quad. """
the fullscreen quad. The size of the buffer is initially
equal to the size of the main window. The parameters 'mul',
'div', and 'align' can be used to adjust that size. """
self.notify.error('renderQuadInto not implemented yet.')
return None
texgroup = (depthtex, colortex, auxtex0, auxtex1)
def createBuffer(self, name, xsize, ysize, texgroup):
winx, winy = self.getScaledSize(mul, div, align)
buffer = self.createBuffer("filter-stage", winx, winy, texgroup, depthbits=0)
if (buffer == None):
return None
cm = CardMaker("filter-stage-quad")
cm.setFrameFullscreenQuad()
quad = NodePath(cm.generate())
quad.setDepthTest(0)
quad.setDepthWrite(0)
quad.setColor(Vec4(1,0.5,0.5,1))
quadcamnode = Camera("filter-quad-cam")
lens = OrthographicLens()
lens.setFilmSize(2, 2)
lens.setFilmOffset(0, 0)
lens.setNearFar(-1000, 1000)
quadcamnode.setLens(lens)
quadcam = quad.attachNewNode(quadcamnode)
buffer.getDisplayRegion(0).setCamera(quadcam)
buffer.getDisplayRegion(0).setActive(1)
self.buffers.append(buffer)
self.sizes.append((1, 1, 1))
return quad
def createBuffer(self, name, xsize, ysize, texgroup, depthbits=1):
""" Low-level buffer creation. Not intended for public use. """
print "Creating buffer: ",xsize,ysize,texgroup,depthbits
winprops = WindowProperties()
winprops.setSize(xsize, ysize)
props = FrameBufferProperties()
props.setRgbColor(1)
props.setDepthBits(1)
@ -177,6 +288,10 @@ class FilterManager:
buffer.addRenderTexture(auxtex0, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPAuxRgba0)
if (auxtex1):
buffer.addRenderTexture(auxtex1, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPAuxRgba1)
buffer.setSort(self.nextsort)
buffer.disableClears()
buffer.getDisplayRegion(0).disableClears()
self.nextsort += 1
return buffer
@ -187,9 +302,12 @@ class FilterManager:
for buffer in self.buffers:
buffer.clearRenderTextures()
self.engine.removeWindow(buffer)
self.scales = []
self.buffers = []
self.region.setCamera(self.camera)
self.sizes = []
self.setClears(self.win, self.wclears)
self.setClears(self.region, self.rclears)
self.camera.node().setInitialState(self.caminit)
self.nextsort = self.win.getSort() - 1000
self.basex = 0
self.basey = 0

View File

@ -0,0 +1,85 @@
//Cg
//
// blend.rgb
//
// This shader converts to black-and-white before calculating
// scene brightness. To do this, it uses a weighted average of
// R,G,B. The blend parameter controls the weighting.
//
// desat.x
//
// Desaturation level. If zero, the bloom's color is equal to
// the color of the input pixel. If one, the bloom's color is
// white.
//
// trigger.x
//
// Must be equal to mintrigger.
//
// mintrigger is the minimum brightness to trigger a bloom,
// and maxtrigger is the brightness at which the bloom
// reaches maximum intensity.
//
// trigger.y
//
// Must be equal to (1.0/(maxtrigger-mintrigger)) where
//
// mintrigger is the minimum brightness to trigger a bloom,
// and maxtrigger is the brightness at which the bloom
// reaches maximum intensity.
//
void vshader(float4 vtx_position : POSITION,
out float4 l_position : POSITION,
out float2 l_texcoordNW : TEXCOORD0,
out float2 l_texcoordNE : TEXCOORD1,
out float2 l_texcoordSW : TEXCOORD2,
out float2 l_texcoordSE : TEXCOORD3,
uniform float4 texpad_src,
uniform float4 texpix_src,
uniform float4x4 mat_modelproj)
{
l_position=mul(mat_modelproj, vtx_position);
float2 c=(vtx_position.xz * texpad_src.xy) + texpad_src.xy;
float4 offs = texpix_src * 0.5;
l_texcoordNW = c + float2( offs.x, -offs.y);
l_texcoordNE = c + float2( offs.x, offs.y);
l_texcoordSW = c + float2(-offs.x, -offs.y);
l_texcoordSE = c + float2(-offs.x, offs.y);
}
void fshader(float2 l_texcoordNW : TEXCOORD0,
float2 l_texcoordNE : TEXCOORD1,
float2 l_texcoordSW : TEXCOORD2,
float2 l_texcoordSE : TEXCOORD3,
uniform sampler2D k_src : TEXUNIT0,
out float4 o_color : COLOR,
uniform float4 k_blend,
uniform float4 k_trigger,
uniform float4 k_desat
)
{
float4 inputNW = tex2D(k_src, l_texcoordNW);
float briteNW = dot(inputNW, k_blend);
float scaleNW = saturate((briteNW - k_trigger.x) * k_trigger.y);
float4 colorNW = scaleNW * lerp(inputNW, float4(1,1,1,1), k_desat.x);
float4 inputNE = tex2D(k_src, l_texcoordNE);
float briteNE = dot(inputNE, k_blend);
float scaleNE = saturate((briteNE - k_trigger.x) * k_trigger.y);
float4 colorNE = scaleNE * lerp(inputNE, float4(1,1,1,1), k_desat.x);
float4 inputSW = tex2D(k_src, l_texcoordSW);
float briteSW = dot(inputSW, k_blend);
float scaleSW = saturate((briteSW - k_trigger.x) * k_trigger.y);
float4 colorSW = scaleSW * lerp(inputSW, float4(1,1,1,1), k_desat.x);
float4 inputSE = tex2D(k_src, l_texcoordSE);
float briteSE = dot(inputSE, k_blend);
float scaleSE = saturate((briteSE - k_trigger.x) * k_trigger.y);
float4 colorSE = scaleSE * lerp(inputSE, float4(1,1,1,1), k_desat.x);
o_color = (colorNW + colorNE + colorSW + colorSE) * 0.25;
}

View File

@ -0,0 +1,47 @@
//Cg
void vshader(float4 vtx_position : POSITION,
out float4 l_position : POSITION,
out float4 l_texcoord0 : TEXCOORD0,
out float4 l_texcoord1 : TEXCOORD1,
out float4 l_texcoord2 : TEXCOORD2,
uniform float4 texpad_src,
uniform float4 texpix_src,
uniform float4x4 mat_modelproj)
{
l_position=mul(mat_modelproj, vtx_position);
float2 c=(vtx_position.xz * texpad_src.xy) + texpad_src.xy;
float offset = texpix_src.x;
l_texcoord0 = float4(c.x-offset* -4, c.x-offset* -3, c.x-offset* -2, c.y);
l_texcoord1 = float4(c.x-offset* -1, c.x-offset* 0, c.x-offset* 1, c.y);
l_texcoord2 = float4(c.x-offset* 2, c.x-offset* 3, c.x-offset* 4, c.y);
}
void fshader(float4 l_texcoord0 : TEXCOORD0,
float4 l_texcoord1 : TEXCOORD1,
float4 l_texcoord2 : TEXCOORD2,
uniform sampler2D k_src : TEXUNIT0,
out float4 o_color : COLOR) {
float4 color = float4(0,0,0,0);
// color = 10 * tex2D(k_src, l_texcoord0.xw);
// color += 45 * tex2D(k_src, l_texcoord0.yw);
// color += 120 * tex2D(k_src, l_texcoord0.zw);
// color += 210 * tex2D(k_src, l_texcoord1.xw);
// color += 252 * tex2D(k_src, l_texcoord1.yw);
// color += 210 * tex2D(k_src, l_texcoord1.zw);
// color += 120 * tex2D(k_src, l_texcoord2.xw);
// color += 45 * tex2D(k_src, l_texcoord2.yw);
// color += 10 * tex2D(k_src, l_texcoord2.zw);
// o_color = color / 1022.0;
color = 50 * tex2D(k_src, l_texcoord0.xw);
color += 100 * tex2D(k_src, l_texcoord0.yw);
color += 150 * tex2D(k_src, l_texcoord0.zw);
color += 200 * tex2D(k_src, l_texcoord1.xw);
color += 200 * tex2D(k_src, l_texcoord1.yw);
color += 200 * tex2D(k_src, l_texcoord1.zw);
color += 150 * tex2D(k_src, l_texcoord2.xw);
color += 100 * tex2D(k_src, l_texcoord2.yw);
color += 50 * tex2D(k_src, l_texcoord2.zw);
o_color = color / 1200.0;
}

View File

@ -0,0 +1,38 @@
//Cg
void vshader(float4 vtx_position : POSITION,
out float4 l_position : POSITION,
out float4 l_texcoord0 : TEXCOORD0,
out float4 l_texcoord1 : TEXCOORD1,
out float4 l_texcoord2 : TEXCOORD2,
uniform float4 texpad_src,
uniform float4 texpix_src,
uniform float4x4 mat_modelproj)
{
l_position=mul(mat_modelproj, vtx_position);
float2 c=(vtx_position.xz * texpad_src.xy) + texpad_src.xy;
float offset = texpix_src.y;
l_texcoord0 = float4(c.y-offset* -4, c.y-offset* -3, c.y-offset* -2, c.x);
l_texcoord1 = float4(c.y-offset* -1, c.y-offset* 0, c.y-offset* 1, c.x);
l_texcoord2 = float4(c.y-offset* 2, c.y-offset* 3, c.y-offset* 4, c.x);
}
void fshader(float4 l_texcoord0 : TEXCOORD0,
float4 l_texcoord1 : TEXCOORD1,
float4 l_texcoord2 : TEXCOORD2,
uniform sampler2D k_src : TEXUNIT0,
uniform float4 k_intensity,
out float4 o_color : COLOR) {
float4 color = float4(0,0,0,0);
color = 50 * tex2D(k_src, l_texcoord0.wx);
color += 100 * tex2D(k_src, l_texcoord0.wy);
color += 150 * tex2D(k_src, l_texcoord0.wz);
color += 200 * tex2D(k_src, l_texcoord1.wx);
color += 200 * tex2D(k_src, l_texcoord1.wy);
color += 200 * tex2D(k_src, l_texcoord1.wz);
color += 150 * tex2D(k_src, l_texcoord2.wx);
color += 100 * tex2D(k_src, l_texcoord2.wy);
color += 50 * tex2D(k_src, l_texcoord2.wz);
o_color = color / 1200.0;
o_color = o_color * k_intensity;
}

View File

@ -0,0 +1,20 @@
//Cg
void vshader(float4 vtx_position : POSITION,
out float4 l_position : POSITION,
out float2 l_texcoord : TEXCOORD0,
uniform float4 texpad_src,
uniform float4x4 mat_modelproj)
{
l_position=mul(mat_modelproj, vtx_position);
l_texcoord = (vtx_position.xz * texpad_src.xy) + texpad_src.xy;
}
void fshader(float2 l_texcoord : TEXCOORD0,
uniform sampler2D k_src : TEXUNIT0,
out float4 o_color : COLOR)
{
o_color = tex2D(k_src, l_texcoord);
}

View File

@ -0,0 +1,33 @@
//Cg
void vshader(float4 vtx_position : POSITION,
out float4 l_position : POSITION,
out float2 l_texcoordNW : TEXCOORD0,
out float2 l_texcoordNE : TEXCOORD1,
out float2 l_texcoordSW : TEXCOORD2,
out float2 l_texcoordSE : TEXCOORD3,
uniform float4 texpad_src,
uniform float4 texpix_src,
uniform float4x4 mat_modelproj)
{
l_position=mul(mat_modelproj, vtx_position);
float2 c=(vtx_position.xz * texpad_src.xy) + texpad_src.xy;
l_texcoordNW = c + float2( texpix_src.x, -texpix_src.y);
l_texcoordNE = c + float2( texpix_src.x, texpix_src.y);
l_texcoordSW = c + float2(-texpix_src.x, -texpix_src.y);
l_texcoordSE = c + float2(-texpix_src.x, texpix_src.y);
}
void fshader(float2 l_texcoordNW : TEXCOORD0,
float2 l_texcoordNE : TEXCOORD1,
float2 l_texcoordSW : TEXCOORD2,
float2 l_texcoordSE : TEXCOORD3,
uniform sampler2D k_src : TEXUNIT0,
out float4 o_color : COLOR) {
float4 colorNW = tex2D(k_src, l_texcoordNW);
float4 colorNE = tex2D(k_src, l_texcoordNE);
float4 colorSW = tex2D(k_src, l_texcoordSW);
float4 colorSE = tex2D(k_src, l_texcoordSE);
o_color = (colorNW + colorNE + colorSW + colorSE);
}