Blender (jusqu'à 2.49)
|
Python
: animation
LOD-o-matic,
level
of details for animation
(version
française)
|
|
Attention :
sorry but this script does not work with
Blender 2.40 . |
In 3d animation,
the computing times can be very long unless reducing the definition of
the objects according to their distance from the camera. In Blender, the
python scripting makes it possible to automate this operation.
Surface
Subdivision
Blender offers an option of surface subdivision
of the Catmull-Clarck type with 7 levels of smoothness (0->6) applicable
to the objects of the meshes type. Certain artists are using this
tool to reduce the weight of the objects according to the distance. A value
of 4 or 5 for the objects closest to the camera (beyond the
number of faces would be prohibitory) and 0 for most distant.
[ Figure 1 ].
Automation
for motion
Only one trouble: this operation
must be carried out by hand and is not very practical during an animation
because it is necessary to recalibrate division between each image.
It is the kind of work which a script can do while being connected to current
animation to carry out computation in background task at each change of
frame
To bind a script to the scene.
The whole of the objects used in current
animation is gathered in a "scene" :
In python, everything that is related to
a scene (rendering information, lists of objects related to this scene,
for example) is managed through a module of the same name. The first
thing to do is to obtain a variable representing the scene object thanks
to the method:
To facilitate comprehension, one writes
all the variables in uppercase letter.
The lamps objects, the cameras as well
as the scenes have a method which makes it possible to automatically associate
a script to them, which will be executed at each change of frame:
SCENE.addScriptLink(NAME,EVENT) |
The bond should be established only once,
which obliges us to recover and to test the list of already dependent scripts
:
SCRIPTLINK=SCENE.getScriptLinks(EVENT) |
[Figure 3]
SCENE.addScriptLink(NAME,EVENT) |
The state
of the camera.
The scene gives access to the camera data
:
CAMERA=Scene.getCurrent().getCurrentCamera() |
which has two limits, ClipStart
and ClipEnd [ Figure 4 ], before and back :
[Figure 4]
CAMclipEN=CAMERA.getData().getClipEnd() |
All that is outwards will not be displayed.
Thus, one sorts systematically all the objects, to treat only those which
are inside and whose SubSurf option is activated.
To accelerate
a little by using Bounding Box.
Each object of Blender contains the data
of the bounding box in which it is locked up(Figure 4, pink lines).
Whatever the number of vertices the mesh contains, while passing by this
bounding box one knows the position of the more extreme of them. Thus it
remains only eight tests to carry out, to know if a part of this
object is within the limits of vision
of the camera.
It only remains to do a simple division
on the distance that separates the object from the camera , and to arrange
the result in a list to nourish the function :
M.setSubDivLevels([LOD,LOD]) |
which will fix the value of the surface
subdivision
[Figures 5 et 6].
Improvements are possible while not taking
into account the objects that would be completely below the ClipStart limit
of the camera, or apart from the visual pyramid.
The Script
Download
the script
Download
the blend file
#!BPY
"""
Name: 'A Cool Faked LOD'
Blender: 234
Group: 'Animation''
Tooltip: ' his script loads itself automatically
to manage the effects Level of Detail in the current
scene but only in Framechanged mode..'
"""
__author__ = "Jean-Michel Soler (jms)"
__url__ = (""" "Script's homepage, ",
"Communicate problems and errors,
http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender""")
__version__ = "11/2004"
__bpydoc__ = """
This script loads itself automatically
to manage the effects Level of Detail in the current scene
but
only in Framechanged mode.
Usage:
One can launch the script from the
animation scripts menu or load it in the text window and make
alt-p.
"""
# ====================================
# (c) jmsoler 01/11/2004,
# ====================================
#========================================
# Load Main module
#========================================
import Blender
#========================================
# Load sub-module
#========================================
from Blender import NMesh,Scene,Object,Text
from math import floor
#=========================================
# DATA DEFINITION
#=========================================
#=========================================
# Display LOD effects in EDIT mode
# if value = zero the effect is limited to render only
#=========================================
EDITMODE=0
#=========================================
# Maximum zone limited to 4 numbers to
avoid
# a too great number of surface
#=========================================
MAXZONE=4
#=========================================
# Link to current Scene
#=========================================
SCENE=Scene.getCurrent()
VERSION=Blender.Get('version')
#=========================================
# Collect information of camera
#=========================================
CAMERA=Scene.getCurrent().getCurrentCamera()
if CAMERA!=None:
CAMPOS=CAMERA.mat[3][:]
CAMclipST=CAMERA.getData().getClipStart()
CAMclipEN=CAMERA.getData().getClipEnd()
LIMITE= [abs(CAMPOS[n]+CAMclipEN)
for n in [0,1,2]]
else:
TEXT="Sorry but he
scrit does not find an active camera %%t|"
TEXT+=" Add a camera
or make at least a render to activate the one are currently using in your
file ."
Blender.Draw.PupMenu(TEXT)
FRAGMENT=4.0
#=========================================
# Automatic link of script to the scene.
...
#=========================================
DEVELOPPEMENT=0
EVENT='FrameChanged'
NAME='LOD.py'
def Charge(NAME):
try:
WINDOWTEXTES=Text.Get(NAME)
print WINDOWTEXTES
except:
DIR
= Blender.Get('homedir')
SCRIPTDIR=DIR+Blender.sys.sep+'scripts'+Blender.sys.sep
Text.Load(SCRIPTDIR+NAME)
#=========================================
# ... only if development is completed
#=========================================
if not DEVELOPPEMENT:
scriptlink=SCENE.getScriptLinks(EVENT)
if scriptlink!=None
and NAME not in scriptlink:
if
VERSION>=234:
Charge(NAME)
SCENE.addScriptLink(NAME,EVENT)
elif scriptlink==None
:
if
VERSION>=234:
Charge(NAME)
SCENE.addScriptLink(NAME,EVENT)
#=========================================
# FUNCTIONS DEFINITIONS
#=========================================
#=========================================
#
#=========================================
def longueur_vect(p1,p2):
p3=[]
p3.append(p2[0]-p1[0])
p3.append(p2[1]-p1[1])
p3.append(p2[2]-p1[2])
return [abs(p3[0]**2+p3[1]**2+p3[2]**2)**0.5,1.0,1.0]
def in_LIMIT(O,CAMPOS):
OMTRX=O.getMatrix()[3][:]
OBB= [l for l in O.getBoundBox()
if (LIMITE[0]-longueur_vect(l,CAMPOS)[0])>0]
for l in OBB:
LOD=int(FRAGMENT-
floor(longueur_vect(l,CAMPOS)[0]/(LIMITE[0]/FRAGMENT)))
if
EDITMODE:
LOD0=LOD
else
:
LOD0=0#
M=O.getData()
M.setSubDivLevels([LOD,LOD])
M.update()
#O.makeDisplayList()
#=========================================
# One recovers all the objects of the
current scene
# but only if it has the activated option
subsurf
#=========================================
OBJ=[O for O in Object.Get()
if O.getType()=='Mesh' and
(O.getData().mode &
NMesh.Modes['SUBSURF'])]
for O in OBJ:
in_LIMIT(O,CAMPOS)
if VERSION==234: Blender.Window.RedrawAll() |
Variable
EDITMODE : limiter les effets au rendu de l'animation
This modification makes it possible to reduce display time
in edit mode :
...
#=========================================
# Display LOD effects in EDIT mode
# if value = zero the effect is limited to render only
#=========================================
EDITMODE=0
... |
...
if EDITMODE:
LOD0=LOD
else :
LOD0=0#O.getData().getSubDivLevels()[0]
... |
Les questions concernant cette page
peuvent être posées sur :
news://news.zoo-logique.org/3D.Blender
|