# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Python Computer Graphics Kit.
#
# The Initial Developer of the Original Code is Matthias Baas.
# Portions created by the Initial Developer are Copyright (C) 2004
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
# $Id$
import os.path
import protocols
from Interfaces import *
from slots import *
import lookat
from lightsource import LightSource
import ribexport
from math import *
# MayaSpotLight
class MayaSpotLight(LightSource):
"""This class represents a spotlight that approximates a Maya spot light.
The direction of the light is the local negative Z axis.
"""
protocols.advise(instancesProvide=[ISceneItem, ribexport.ILightSource])
def __init__(self,
name="MayaSpotLight",
enabled = True,
color = (1,1,1),
intensity = 1.0,
decayRate = 0,
coneAngle = 40,
penumbraAngle = 0,
dropoff = 0,
useDepthMapShadows = False,
dmapResolution = 512,
useMidDistDmap = True,
useDmapAutoFocus = True,
dmapFocus = 90.0,
dmapFilterSize = 1,
dmapBias = 0.001,
target=vec3(0,0,0), # spot
**params
):
LightSource.__init__(self, name=name, **params)
# target = vec3(target)
# Target
# self.target_slot = Vec3Slot(target)
# self.addSlot("target", self.target_slot)
self.enabled = enabled
self.color = vec3(color)
self.intensity = float(intensity)
self.decayRate = int(decayRate)
self.coneAngle = float(coneAngle)
self.penumbraAngle = float(penumbraAngle)
self.dropoff = float(dropoff)
self.useDepthMapShadows = bool(useDepthMapShadows)
self.dmapResolution = int(dmapResolution)
self.useMidDistDmap = bool(useMidDistDmap)
self.useDmapAutoFocus = bool(useDmapAutoFocus)
self.dmapFocus = float(dmapFocus)
self.dmapFilterSize = float(dmapFilterSize)
self.dmapBias = float(dmapBias)
def protocols(self):
return [ISceneItem]
def createPasses(self):
"""Returns a list of RenderPass objects."""
if self.useDepthMapShadows:
if self.useDmapAutoFocus:
fov = max(self.coneAngle, self.coneAngle+2*self.penumbraAngle)
else:
fov = self.dmapFocus
shadpass = ribexport.ShadowPass(
output = [("shadow.z", "zfile", "z", {})],
light = self,
fov = fov,
resolution = self.dmapResolution,
orientoffset = mat4(1).rotation(pi, vec3(0,1,0))
)
return [shadpass]
return []
def shaderName(self):
"""Returns the name of the corresponding light shader or None.
"""
return "mayaspotlight"
def shaderSource(self):
"""Returns surface shader source code as a string or None.
"""
return """// MayaSpotLight shader
light $SHADERNAME(
uniform color lightcolor = color "rgb" (1, 1, 1);
uniform float intensity = 1.0;
uniform float decayRate = 0;
uniform float coneAngle = 40.0;
uniform float penumbraAngle = 0.0;
uniform float dropoff = 0.0;
uniform string dmapName = "";
uniform float dmapFilterSize = 1;
uniform float dmapBias = 0.001;
)
{
uniform vector axis = normalize(vector "shader" (0,0,-1));
uniform float coneAngle2 = radians(0.5*coneAngle);
uniform float penumbra_start = coneAngle2;
uniform float penumbra_end = coneAngle2;
if (penumbraAngle<0)
penumbra_start += radians(penumbraAngle);
else
penumbra_end += radians(penumbraAngle);
uniform float penumbra_range = penumbra_end-penumbra_start;
illuminate(point "shader" (0,0,0), axis, penumbra_end)
{
vector L0 = normalize(L);
float dist = length(vtransform("world", L));
float att = 1.0;
// Penumbra
float angle = acos(L0.axis);
// Linear decay inside the penumbra
// att *= clamp(1.0-(angle-penumbra_start)/penumbra_range, 0.0, 1.0);
// Smooth decay inside the penumbra
att *= 1.0-smoothstep(penumbra_start, penumbra_end, angle);
// Dropoff
// att *= clamp(2.0-pow(exp(angle),dropoff/255), 0.0, 1.0);
// Decay
if (dist>1.0)
att /= pow(dist, decayRate);
Cl = att * intensity * lightcolor;
if (dmapName!="")
Cl *= 1.0 - shadow(dmapName, Ps, "width", dmapFilterSize, "bias", dmapBias, "samples", 32);
}
}
"""
def shaderParams(self, passes):
"""Return a dictionary with shader parameters and their values."""
params = {"intensity":self.intensity,
"uniform color lightcolor":self.color,
"uniform float decayRate":self.decayRate,
"uniform float coneAngle":self.coneAngle,
"uniform float penumbraAngle":self.penumbraAngle,
"uniform float dropoff":self.dropoff,
}
if self.useDepthMapShadows and passes[0].done():
zfile = passes[0].realFilename(passes[0].output[0][0])
mapname = os.path.splitext(zfile)[0]+".map"
params["uniform string dmapName"] = mapname
params["uniform float dmapFilterSize"] = self.dmapFilterSize
params["uniform float dmapBias"] = self.dmapBias
return params
|