View Single Post
  #1  
Old 02-17-2011, 03:37 AM
chris_user chris_user is offline
Member
 
Join Date: Feb 2011
Posts: 20
shadows in mirror

one more problem...

in the attached sample I have the problem that the shadow just appears in the mirror, but no longer on the original object; if mirroring is deactivated it looks like it should, has anybody a clue for me whats going wrong?


object loading and running the scene:

Code:
import viz
import projector
import vizspace

viz.go()

viz.MainView.move([-6,2,0])
viz.MainView.setEuler([90,20,0])


###SPACENAVIGATOR###
def spacemove(e):
    viz.MainView.move(viz.Vector(e.pos)*e.elapsed)
viz.callback(vizspace.TRANSLATE_EVENT,spacemove)

def spacerot(e):
    viz.MainView.setAxisAngle(1,0,0,e.ori[0]*e.elapsed,viz.HEAD_ORI,viz.REL_LOCAL)
    viz.MainView.setAxisAngle(0,1,0,e.ori[1]*e.elapsed,viz.HEAD_ORI,viz.REL_LOCAL)
    viz.MainView.setAxisAngle(0,0,1,e.ori[2]*e.elapsed,viz.HEAD_ORI,viz.REL_LOCAL)
viz.callback(vizspace.ROTATE_EVENT,spacerot)

def spacebuttondown(button):
    print 'Button',button,'pressed'
viz.callback(vizspace.BUTTONDOWN_EVENT,spacebuttondown)

def spacebuttonup(button):
    print 'Button',button,'released'
viz.callback(vizspace.BUTTONUP_EVENT,spacebuttonup)


###OBJECTS###
plane = viz.addTexQuad()
plane.setScale(3,3,3)
plane.setEuler(0,90,90)

ball = viz.add('white_ball.wrl')
ball.setPosition(0,1,0)

ground = viz.add('tut_ground.wrl')
ground.setPosition(0,-.1,0)

###MIRROR###
def addMirror(mirror,mat=None):

	#If mirror matrix is not specifed, get matrix of mirror object
	if mat is None:
		mat = mirror.getMatrix()
		
	#Position of mirror
	pos = viz.Vector(mat.getPosition())
	
	#Direction mirror is pointing
	dir = viz.Vector(mat.getForward())
	dir.normalize()

	#Quaternion rotation of mirrorw
	quat = mat.getQuat()
	
	#Create render texture
	tex = viz.addRenderTexture()
	
	#Create render node for rendering reflection
	lens = viz.addRenderNode(size=[1024,1024])
	lens.attachTexture(tex)
	lens.setInheritView(True,viz.POST_MULT)
	lens.disable(viz.CULL_FACE,op=viz.OP_SET_OVERRIDE)

	#Setup reflection matrix
	rot = viz.Matrix.quat(quat)
	invRot = rot.inverse()
	lens.setMatrix(viz.Matrix.translate(pos*-1.0)*invRot*viz.Matrix.scale(1,1,-1)*rot*viz.Matrix.translate(pos))
	
	#Setup reflection clip plane
	plane = vizmat.Plane(pos=pos,normal=dir)
	dist = plane.distance([0,0,0])
	lens.clipPlane([-dir[0],-dir[1],-dir[2],dist+0.001])

	#Project reflection texture onto mirror
	mirror.texture(tex)
	mirror.texGen(viz.TEXGEN_PROJECT_EYE)


#Use existing painting as mirror and specify the matrix
mirrorsurface = viz.addTexQuad()
mirrorsurface.scale(6.5,3,.1)
mirrorsurface.setPosition([3.66, 1, 0]) #Y,Z,X
#mirrorsurface.alpha(0.1)
mirrorsurface.appearance(viz.TEXMODULATE)
mirrorsurfacerotation = [90,0,0] #rotation around the Z,Y,X axes
mirrorsurface.rotate(mirrorsurfacerotation)
m = viz.Matrix()
m.setPosition(mirrorsurface.getPosition(viz.ABS_GLOBAL))
m.setEuler(mirrorsurfacerotation[0]-180,-mirrorsurfacerotation[1], mirrorsurfacerotation[2]) #Z,X,Y

#Apply mirror settings to mirror object
addMirror(mirrorsurface,m)

#Increase ambient lighting
#viz.MainView.getHeadLight().ambient(.7,.7,.7)

###SHADOW###
#Shadow resolution (power of two)
#Higher values mean sharper shadows, but take more texture memory
SHADOW_RES = 512

#Postion of shadow projector
SHADOW_POS = [0,2,0]

#Controls size of orthographic shadow projector
#Large values mean larger area is covered, but resolution will be diluted
SHADOW_AREA = [10,10]

#Create shadow projector
import Shadow
shadow = Shadow.ShadowProjector(size=SHADOW_RES,pos=SHADOW_POS,area=SHADOW_AREA)

#Add avatar as a shadow caster
shadow.addCaster(ball)

#Add ground as shadow receiver
shadow.addReceiver(plane)
Shadow.py
Code:
import viz
import projector

class ShadowProjector(object):
	def __init__(self,kernel=9,alpha=1,size=256,pos=(0,10,0),euler=(0,90,0),area=[5,5],scene=viz.MainScene):
		
		#Create render texture
		self.shadowTex = viz.addRenderTexture(wrap=viz.CLAMP_TO_BORDER,borderColor=viz.WHITE)
		
		#Create render node to render shadow caster to texture
		self.shadowPass = viz.addRenderNode(scene=scene,size=[size,size],inheritView=False,autoClip=False)
		self.shadowPass.setClearColor(viz.WHITE)
		self.shadowPass.attachTexture(self.shadowTex)
		self.shadowPass.setScene(None)
		
		#Apply shader to render node so everything is black
		code = """
		#define I	%alpha%
		void main()
		{
			gl_FragColor = vec4(I,I,I,1.0);
		}
		"""
		shader = viz.addShader(frag=code.replace('%alpha%',str(1.0-alpha)))
		self.shadowPass.apply(shader,op=viz.OP_SET_OVERRIDE)
		
		#Create projector for projecting shadow texture onto receivers
		self.texProj = projector.add(self.shadowTex,scene=scene,cubemap=False)
		
		#Save all render node passes
		self.passes = [self.shadowPass]
		
		#Setup render nodes to blur shadow texture
		if kernel:
			blur_source = """
			uniform sampler2D srcImage;
			void main(void)
			{
				vec4 color = vec4(0,0,0,0);
				%code%
				color.a = 1.0;
				gl_FragColor = color;
			}"""
			horz_source = 'color += texture2D( srcImage, gl_TexCoord[0].xy + vec2( %f, 0.0 ) ) * %f;'
			vert_source = 'color += texture2D( srcImage, gl_TexCoord[0].xy + vec2( 0.0, %f ) ) * %f;'
			
			#Calculate weight and offsets for blur code
			weights = []
			offsets = []
			mid = float(kernel - 1)
			kernel *= 2
			for i in xrange(0,kernel,2):
				offsets.append( ((i-mid) / 2.0) * (1.0 / size) )
				x = (i - mid) / mid
				weights.append( 0.05 + ((-(x*x) + 1.0) / 4.0) )
			
			#Normalize weights
			frac = 1.0 / sum(weights)
			weights = [ frac * x for x in weights ]

			#Create blur code for shaders
			horz_blur_code = []
			vert_blur_code = []
			for w,o in zip(weights,offsets):
				horz_blur_code.append(horz_source%(o,w))
				vert_blur_code.append(vert_source%(o,w))
			
			#Create shaders
			horzBlurShader = viz.addShader(frag=blur_source.replace('%code%','\n'.join(horz_blur_code)))
			vertBlurShader = viz.addShader(frag=blur_source.replace('%code%','\n'.join(vert_blur_code)))
			srcImageUniform = viz.addUniformInt('srcImage',0)
			
			#Render texture for ping-ponging
			tex2 = viz.addRenderTexture()
			
			"""
			Pass 2 renders the shadow texture onto a quad.
			The quad has a shader attached which blurs the texture horizontally.
			"""
			self.blurPass1 = viz.addRenderNode(scene=scene)
			self.blurPass1.setHUD(0,200,0,200,renderQuad=True)
			self.blurPass1.setSize(size,size)
			self.blurPass1.setBuffer(viz.RENDER_FBO)
			self.blurPass1.setOrder(viz.PRE_RENDER,1)
			self.blurPass1.attachTexture(tex2)
			self.blurPass1.texture(self.shadowTex)
			self.blurPass1.apply(horzBlurShader)
			self.blurPass1.apply(srcImageUniform)
			self.passes.append(self.blurPass1)
			
			"""
			Pass 3 renders the texture from pass 2 onto a quad.
			The quad has a shader attached which blurs the texture vertically.
			"""
			self.blurPass2 = viz.addRenderNode(scene=scene)
			self.blurPass2.setHUD(0,200,0,200,renderQuad=True)
			self.blurPass2.setSize(size,size)
			self.blurPass2.setBuffer(viz.RENDER_FBO)
			self.blurPass2.setOrder(viz.PRE_RENDER,2)
			self.blurPass2.attachTexture(self.shadowTex)
			self.blurPass2.texture(tex2)
			self.blurPass2.apply(vertBlurShader)
			self.blurPass2.apply(srcImageUniform)
			self.passes.append(self.blurPass2)
			
			#Remove texture/shader/uniforms (already applied)
			horzBlurShader.remove()
			vertBlurShader.remove()
			srcImageUniform.remove()
			tex2.remove()

		#Initialize shadow area/pos/euler
		self.setArea(area)
		self.setPosition(pos)
		self.setEuler(euler)
		
	def addCaster(self,node):
		"""Add a shadow caster node"""
		node.duplicate(viz.MainScene,self.shadowPass)
		
	def addReceiver(self,node,unit=1):
		"""Add a shadow receiver node"""
		self.texProj.affect(node,unit)
		
	def setPosition(self,pos):
		"""Set position of shadow projector"""
		self.shadowPass.setPosition(pos)
		self.texProj.setPosition(pos)
		
	def setEuler(self,euler):
		"""Set euler of shadow projector"""
		self.shadowPass.setEuler(euler)
		self.texProj.setEuler(euler)

	def setArea(self,area):
		"""Set [width,height] area of orthographic projection of shadow"""
		proj = viz.Matrix.ortho(-area[0]/2.0,area[0]/2.0,-area[1]/2.0,area[1]/2.0,0.1,1000)
		self.shadowPass.setProjectionMatrix(proj)
		self.texProj.ortho(area[0],area[1])
		
	def visible(self,mode):
		"""Enable shadow projector"""
		for p in self.passes:
			p.visible(mode)
		self.texProj.visible(mode)
	
	def remove(self):
		"""Permanently remove all resources"""
		for p in self.passes:
			p.remove(False)
		self.shadowTex.remove()
		self.texProj.remove()
thanks in advance
Reply With Quote