利用者:Timmeh/SummerOfCode2005/PyTexture

提供: wiki
移動先: 案内検索

Introduction to PyTexture

Latest Build- Win32 - pub/blender.zip

PyTexure( Pytex ) is a Python interface to the textures system in Blender, in it's current state of development it is meant as an alternative to C texture plugins, not a replacement. There are several situations where a C texture plugin would be a better choice than Pytex – for example very computation heavy texture algorithms. On the flip side, Pytex is an easier to use, more functional option, which with thoughtful use provides a very flexible, and painless interface.

Coding PyTextures

When coding PyTex scripts, it is helpful to consider them as a Scriptlink, anything you would avoid doing in a Scriptlink script avoid like the plague with PyTex. As Python is an interpreted language, it has an inherent slowness to it, so very slow operations are to be avoided.

All Pytex API functions can be found as members of BPyTexture objects. This method provides several distinct advantages, a) it makes it impossible to crosslink textures and Pytex scripts, b) scripts act only on the BPyTexture object that they are assigned to. This adds a level of foolproofing to PyTex, and allows easier tracking of errors.

PyTex API Functions

BPyTexture.getPytexCoords( ) - The getPytexCoords( ) function returns the current texture coordinates. As mentioned before PyTex is essentially a Scriptlink, calling the script for every step of the renderer over the given texture. Thus this function updates before every call to the PyTex script. Return type is a Tuple of length 3, (x, y, z) texture coordinates.

BPyTexture.setPytexIntensity( ) - This function sets the intensity value for the current texture coordinate. As with all Pytex set functions, the value is internally clamped to range [0..1], thus clamping in the Pytex script is unnecessary and will only serve to increase render times. Intensity value alone will make a PyTex script operate very much like an internal texture, where the white areas show on the material, as the mtex colour, and black regions are trasnparent.

BPyTexture.setPytexColour( ) - setPytexColour( ) allows the user to apply a 3 float or 4 float colour to the texture, (r, g, b) or (r, g, b, a). Note that for cases where an independent alpha function is desired, there is an API call to allow alpha to be set independent of colour. Currently the texture preview does not show colour PyTex scripts correctly. Therefore either look at the material preview, or test render.

BPyTexture.setPytexNormals( ) - The format of this function make it exceptionally flexible to use, however slightly more difficult. The function accepts 3 floats for input (x, y, z) which are the three components of a normal vector. Simply returning the texture coordinates for the current step will result in no nor effect. Each value must be slightly offset in the axis is corresponds to. For example :

x = intensity(x + offset, y, z);
y = intensity(x, y + offset, z);
z = intensity(x, y, z + offset);
BpyTexture.setPytexNormals(x, y, z);

Offset is typically a value of approximately 0.025 – 0.075, but actually may be any value, providing varied results. This method also makes it possible to change the offset dependant on texture coordinates, for example :

function offset( texvec ) {
   return Blender.Noise.turbulence( texvec, depth, hardness ) / 25;
}
x = intensity(x + offset(coords), y, z);
y = intensity(x, y + offset(coords), z);
z = intensity(x, y, z + offset(coords));
BpyTexture.setPytexNormals(x, y, z);

BPyTexture.setPytexAlpha( ) - setPytexAlpha( ) provides an interface for the addition of an alpha channel to a texture independent of colour. This allows an alpha-only texture which works similar to the alpha channel of an image texture. Note that PyTex alpha channels are still experimental and are prone to errors.

PyTexture Scripting

The basic format of every PyTexture will be similar :

 
import Blender; initialise variables; [[BlenderDev/BPyTexture|BPyTexture]] bpytex; 
 function int_func( texvec ) { calculate intensity_value; return intensity_value; }
 function col_func( texvec ) { calculate colour_values; return colour_values; }
 function nor_func( texvec ) { calculate normal_vector; return normal_vector;

 coords = bpytex.getPytexCoords( );

 bpytex.setPytexIntensity( int_func( coords ) );
 bpytex.setPytexColour( col_func( coords ) );
 bpytex.setPytexNormals( nor_func( coords ) );

This layout is ,of course, arbitrary, and may be changed to suit individual needs and coding styles.

All PyTex functions may be called independently of one another, and only the required functions need be called, for example, if only intensity is desired, then only intensity code need be written.

Example Scripts

Coloured Clouds

import Blender

tex = Blender.Texture.Get("Tex")
texvec = tex.getPytexCoords()

def int_func(tex, coords):
   intensity = Blender.Noise.turbulence(coords, 3, 0)
   tex.setPytexIntensity(intensity) 

def nor_func(tex, coords):
   nabla = 0.025
   x = Blender.Noise.turbulence((coords[0] + nabla, coords[1], coords[2]), 3, 0)
   y = Blender.Noise.turbulence((coords[0], coords[1] + nabla, coords[2]), 3, 0)
   z = Blender.Noise.turbulence((coords[0], coords[1], coords[2] + nabla), 3, 0)
   tex.setPytexNormals(x, y, z)

def col_func(tex, coords):
   r = Blender.Noise.turbulence((coords[0], coords[1], coords[2]), 3, 0)
   g = Blender.Noise.turbulence((coords[1], coords[0], coords[2]), 3, 0)
   b = Blender.Noise.turbulence((coords[1], coords[2], coords[0]), 3, 0)
   tex.setPytexColour(r, g, b)

def alpha_func(tex, coords):
   a = Blender.Noise.turbulence((coords[2], coords[0], coords[1]), 3, 0)
   tex.setPytexAlpha(a) 

int_func(tex, texvec)
col_func(tex, texvec)
#alpha_func(tex, texvec)
#nor_func(tex, texvec)

This script illustrates a PyTex script coded in a style similar to that laid out above, the next Pytex, a marble texture, is coded in an entirely different but still valid style. If it runs without errors when pressing Alt+P, then it will run fine as a Pytex.

Marble

import Blender
import math

def sin_bias (a):
   return 0.5 + 0.5 * math.sin(a)

def saw_bias (a):
   b = 2 * math.pi
   n = int(a/b)
   a -= n * b

   if a < 0:
      a += b

   return a / b

def tri_bias (a):
   b = 2 * math.pi
   a = 1 - 2 ''' abs(math.floor((a ''' (1/b))+0.5) - (a*(1/b))) return a;

def soft (a):
   return a

def sharp (a):
   return a''''''0.5

def sharper (a):
   return sharp(sharp(a))

pytex_name = "Marble"
tex_obj = Blender.Texture.GetCurrentPytex()
coords = tex_obj.getPytexCoords()
opt_nbasis = 1
opt_wf = sin_bias
opt_turb = 10
opt_ns = 0.25
opt_nd = 5
opt_def = soft

n = (coords[0] + coords[1] + coords[2]) * 5
m = n + opt_turb * Blender.Noise.turbulence(coords, opt_nd, opt_nbasis)

m = opt_wf(m)
m = opt_def(m)

tex_obj.setPytexIntensity(m)

This PyTex script is modelled off the Blender internal marble function but allows for much more tailoring through changing the opt_ var values.

Adding PyTextures to Materials

Adding PyTex textures is as simple as adding any other texture. Simply a matter of selecting the PyTex texture type and linking a valid pytex script.

<img src="http://www.sutabi.tk/timmeh/data/gsoc/doc/pytex1.jpg"></img>

Select the Pytex Texture Type

<img src="http://www.sutabi.tk/timmeh/data/gsoc/doc/pytex2.jpg"></img>

Select Link Text

<img src="http://www.sutabi.tk/timmeh/data/gsoc/doc/pytex3.jpg"></img>

Link to the PyTex script

PyTex Renders

<img src="http://www.sutabi.tk/timmeh/data/gsoc/doc/pytex_render.jpg"></img> <img src="http://www.sutabi.tk/timmeh/data/gsoc/doc/pytex_render2.jpg"></img> <img src="http://www.sutabi.tk/timmeh/data/gsoc/doc/pytex_render3.jpg"></img> <img src="http://www.sutabi.tk/timmeh/data/gsoc/doc/pytex_render4.jpg"></img>



PyTexture – Python Texture Plugins

Introduction:

PyTexture is a simplified, Python-based implementation for extending Blender's texture capabilities. Currently Blender uses dynamic library based texture plugins which must be coded in C, which limits their flexibility, ease of use and the number of people who can implement them.

PyTexture is designed to counteract the downfalls of the current system and extend it's possibilities. Anything that is possible with Blender internal textures or C library plugins is possible with PyTextures, as well as being able to take it a step further, and utilise any data obtainable through the Python API to define the texture. For example, a texture could be made to change colour depending on its location from a specific point.

In the future, by allowing access to render data such as surface normals, a true shader system could be built, blurring the lines between texture and material and allowing inifinite flexibility and thus creativity and realism.

When using PyTexture, the workflow changes very little from standard texturing, apart from the actual coding of the PyTex script of course.

Implementation

When applied to a texture, PyTex will require similar data to that required by existing dynamic plugins. Therefore a subset of the PluginTex struct will be suitable for PyTex.

typedef struct PyTex {
   char name[160];
   Text *text;
   int vars;
   void *varstr;
   float *result;
   Pytex_Script *pytex
} PyTex;

see: PyTex

A pointer to this struct will also be added to the Tex struct, such that it is easily accessible by texture functions.

Simplistically, each PyTexture will consist of three (3) parts:

Initialistion

In the initialisation phase of the script, all PyTex functions are registered with Blender. This could be achieved with a basic extension of the Blender.Texture module to allow a register function to be called much like the existing Blender.Draw.Register function.

To handle the storage of the registered functions a struct similar to the Script struct will need to be created.

typedef struct Pytex_Script {
   ID id;
   void *py_ui;
   void *py_int;
   void *py_nor;
   void *py_dict;
} PyTex_Script;

see: PyTex_Script

Interface

The interface section of the script deals with creating the UI for the script on Blender's texture panels. A couple of methods present themselves for doing this.

Utilising the existing dynamic plugin method, that is, have a variable documenting how many elements there are, and a string to define each element, will simplify the process of generating the interface for each PyTexture.

Implementing this system would be very similar to the existing dynamic plugin code.

varstr = pytex->varstr;

if(varstr) {
   for( a = 0; a < pytex->vars; a++, varstr++ ) {
      xco = 140 * (a / 6) + 1;
      yco = 125 - 20 * (a % 6) + 1;
      uiDefBut(block, varstr->type, B_PLUGBUT + a, varstr->name, xco, yco, 137, 19, 
         &(pit->data[a]), varstr->min, varstr->max, 100, 0, varstr->tip);
   }
}

As this data would be stored in the PyTex struct, it would be unnecessary to repeatedly call the interface function to redraw the screen, saving slow calls to the Python interpreter.

Texture Functions

The texture functions form the core of a PyTexture script. Ideally, a seperate intensity and nor function will be created for every Pytex. This serves two purposes, allows the flexibility of having a seperate algorithm for both intensity and nor, and thus possiblities for optimisation. It also allows for easier integration of a caching scheme down the track.

An intensity function will have a very basic code outline, requiring only a function that recieves an x, y, and z coordinate and returns a single float value. eg.

def pytex_intensity(x, y, z):
   return avg([x, y, z])

Likewise a nor function will require accepting a vector and nor scale vaariable and return the modified nor vector. As is common practise with inbuilt textures, the nor function could call the intensity function to get its offset, or use a different function to set the offset. eg.

def pytex_nor(texvec, scale):
   texvec[0] = pytex_intensity(texvec[0] + scale, texvec[1], texvec[2])
   texvec[1] = pytex_intensity(texvec[0], texvec[1] + scale, texvec[2])
   texvec[2] = pytex_intensity(texvec[0], texvec[1], texvec[2] + scale)

   return texvec

Once the function has been called and returned a value, the Blender coder will asses the returned value and clamp it if necessary.

A data diagram showing the interactions of the relevant parts is shown below.

<img src='http://www.sutabi.tk/timmeh/data/gsoc/flow.jpg'></img>

New Code:

*../source/blender/render/intern/source/texture.c will house the code to call [[BlenderDev/PyTex|PyTex]] functions are rendertime.
*../source/blender/blenkernel/intern/texture.c will house all code required to attach [[BlenderDev/PyTextures|PyTextures]] to textures, such as open_pytex, add_pytex etc, etc.
*../source/blender/python/api2_2x/texture.c will have the register code added to it to extend the Blender.Texture 
module.
*../source/blender/blenkernel/BKE_plugin_types.h will have the [[BlenderDev/PyTex|PyTex]] struct definition added to it.
*../source/blender/include/BPI_script.h will have the [[BlenderDev/PyTex_Script|PyTex_Script]] struct definition added to it.
*../source/blender/src/buttons_shading.c will have the interface drawing code added to it.
*../blender/include/butspace.h will have UI declarations added.

Future:

Ideally given the relatively slow nature of Python as it's an interpreted language, some kind of caching system should be implemented. In any scene where the camera is not moving, the same texture coordinates are used for the view, this allows extensive reuse of already calculated texture coordinates and could provide a speed up of between 25-50% in some cases. In cases where the camera is moving, this figure is likely to be significantly less, or even slower in some cases, as the overhead for looking-up cached values may prove to negate any positive effect of caching. A caching system also removes the possibility of random textures, and as such, must be switchable, thus an interface option to enable caching must surely be included.

with the inclusion of this to bf-blender probably in 2.41 release (possibly in the orange branch really soon now), will get review and more experimentation probably really soon now. --antont

Thanks

Thanks to Campbell Barton (ideasman), my mentor for all his help with design and coding. As well to Martin Poirier(theeth) for his discussions regarding design. Also thanks to all the great guys on the #blendercoders channel for their continued help and support throughout the project. Last but definitely not least, thanks to Chris Want(Hos), without who's work, this opportunity would not be possible for anyone.

-- DeveloperWikiTimothyWakeham - 24 Jul 2005


PyTexture Implementation in Blender – An Extensible Python Based Texture Plugin System

The proposal is to implement a Python based texture descriptor for increased flexibility for artists and animators using Blender. A texture is an image that can be applied to 3 dimensional objects, to affect how light interacts with the objects surface. Textures can also be used to displace a surface or modify the surface normals to imitate additional geometry.

Textures can be made from a photo or image editor, for example a photograph or painting, or may be produced procedurally with a mathematical equation, for example wood, http://home.iprimus.com.au/snapper63/wood.jpg and clouds http://home.iprimus.com.au/snapper63/clouds.jpg

Blender's current texture plugin implementation uses a C, dynamic plugin system which is not only inflexible and time consuming to code, but difficult for non-programmers to implement. These plugins are called directly from Blender's render pipeline, and return a value for each point on the surface of the object.

PyTexture's implementation will render the current plugin system obsolete, along with its negative effects. It will allow fast and easy use of Python to define new textures, and will be easily accessible to beginner and professional coders alike. Furthermore as Blender uses Python natively as its scripting language, no other software such as compilers is required. This also negates the time consuming compile/test/debug cycles, as Python is an interpreted language and does not require compiling.

PyTextures will allow a level of control unlike any current texture implementation in Blender, both internal and plugin based. This stems from the ability to use any Blender object data in the definition of the texture, which could include vertex location, surface normals, or any other geometric data. This will bring Blender's texture functionality up to par with the likes of Renderman and EVA (http://www.algorithmic.com/gallery_e.html) and will for allow for an unprecedented level of artistic expression through the creation of textures such as crosshatch(http://www.algorithmic.com/Geggs.html), watercolour and faked volumetrics.

The basic requirements to allow this functionality include: 1. A mechanism to link PyTextures to objects. 2. Relevant modifications to the UI to allow PyTexture linking. 3. Blender access to the Python interpreter throughout the render pipeline to allow calling of the PyTexture as render-time 4. Python access to render data. I expect that the project will take between 6 and 8 weeks of research and development followed by two weeks of documentation, testing, and texture development for release. Development will begin as soon as approval is received. A basic timeline is as follows : 1. Research – collaborate with mentor and investigate the detailed inner workings of the Blender render pipeline. 2. Design – develop a detailed design based on the research undertaken. 3. Implement – implement the Blender internal systems to handle PyTextures. 4. Test and Debug – test all aspects of the new modules incorporated into the Blender Python API. Fix any bugs. 5. Develop and Implement a series of PyTextures to demonstrate their power and flexibility. 6. Documentation – Complete the required user documentation. 7. Release. This project will see a vast improvement in the quality and range of textures achievable with Blender. As a user friendly system, I expect that a greater number of people will utilise PyTextures, and thus create a repository of advanced texture scripts which could be distributed within Blend files.

-- DeveloperWikiTimothyWakeham - 02 Jul 2005