利用者:Maike/SummerOfCode2007

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

GLSL Shader Editing and Preview System

Overview


This project's goals are: to implement support for improving Blender's current material display in the 3D View window, using GLSL programmable hardware shaders; extend Blender's 3D View real-time material preview to support node-based materials by implementing a system to combine shader fragments that represent each node of the graph at real-time and, from those fragments, generate GLSL shaders; create a GLSL shaders representation for Blender's material nodes.

Further objectives, if the remaining time allows are: to create a generic GLSL shader node, allowing users to create their own shader in Blender's Text Editor window; to allow the import/export of GLSL code for a material node network and to integrate it with Blender's scripting system and the forthcoming PyNodes API.

Project Goals


This project's main goals are:

  • Display real-time materials in the 3D Viewport
  • Extend the latter to support node-based materials

This project's extra goals are:

  • Create a generic GLSL shader node
  • Allow to import/export GLSL code for a material node network
  • Integrate it with Blender's scripting system


During the duration of this project all the efforts shall be directed to the accomplishment of its main goals. If these goals are accomplished before scheduled the efforts will be redirected to the project's extra goals.


Planning


Blender Material Related Structures

In Blender it is possible to have different scenes and in each scene we have different layers always being one or more active, containing or not objects.

If a scene contains objects it will have a linked list of Base elements, and each one of these elements points to an Object. Not going into detail about the intermediate structures, basically an Object can be a light source, a mesh, a metaball and so on. As this project's main goal is to create a GLSL material preview system on the Viewport 3D, it will only focus on objects to which is possible to assign Materials, or by other words, it will only focus on object which are rendered.

An Object might be linked to many Materials, but only the assigned one is used on the rendering process, being possible for a Material to be assigned or linked to different Object, thus allowing Objects to share Materials.

A Material can be a material or a node material and the latter can have as nodes other materials. Actually, a node material internally is represented as an extension to a Material as for each node material created a bNodeTree, a structure that represents the node network, is created and linked to a Material. A node material is composed of different nodes and each of these nodes is represented as a bNode structure. A node, or more, in the node material network can be material node and if so, it is linked to a Material.


Blender tree example.


Proposed Structures for GLSL Shader Creation

I propose the creation of the following types of structures:

  • GLSL_List - basically it is a linked list that is used to create a list of lights or a list of materials.
  • GLSL_Light - this structure represents a light in the present scene, it stores the light type and the specular and diffuse toggle values. This is necessary because, at the moment, when an event occurs it is not possible to know exactly what was changed and, therefore, these light parameters are stored in order to be compared to the present ones when an event that involves a light is triggered. Finally for that comparison each GLSL_Light has a pointer to the light it represents.
  • GLSL_MaterialTree - for each material, node based or not, a structure of this type will be created. It has a list of GLSL_Materials and it stores the light types, the specular and diffuse shaders used by the material and the type of values that textures used by the material may affect. This is done in order to append to the GLSL shader code, GLSL functions for visibility and diffuse and/or specular calculations. Finally it has GLSL_Program structures for the drawing of the material on shaded and textured mode.
  • GLSL_Material - it represents a simple material, keeping track of its specular and diffuse shader, keeping a pointer to the represented Material and an array of pointers to the different materials that might use this Material.
  • GLSL_Program - this structure defines a GLSL program, it keeps that descriptor for the respective GLSL program, returned by a glCreateProgram() call, and pointer arrays to vertex and fragment shaders used by this program.
Structures for GLSL shader creation.


I found necessary to keep an hash table that has as key a Material pointer and as value its GLSL representation and another that links a material, node-based or not, to a GLSL_MaterialTree, being this possible having as key a pointer to a Material or a bNodeTree and as value the corresponding GLSL_MaterialTree. As the first is needed to record material changes or its removal, the latter is needed not only to write the shaders but also to update parameters when a node network suffers any changes.

Hash tables linking GLSL structures to Blender material structures.


Only visible materials will be kept in such structures and, for this purpose, whenever a scene or the selected visible layers change, only the visible materials on the new set will be kept, being the others deleted and new ones created.


GLSL Code Generation

Everytime a new material, node based or not, is created or reconstructed, a GLSL program will be created and, to do so, its code will be generated.

A light structure will be created containing all the different light properties, an array of elements of this type will be created with its size equal to the number of lights that illuminate the object being drawn.

Lighting calculations will be done only for material nodes and envolve at most three different calculations:

  • Fragment visibility - and for this calculation there will be a generic function for each light type.
  • Diffuse light - for each diffuse shader there will be two different functions, one for hemi lights and the other for the rest.
  • Specular light - will use the same scheme as diffuse light.

Generic functions representing node calculations will be stored in files for every node type except for material nodes. For a material, if it uses textures, each texture will be considered as if it was a node texture.

The node tree will be evaluated bottom-up and for each branch, until a material, a texture or a color ramp node is found, all the calculations will be done in the CPU. After that all calculations will be dealt within the GLSL program.

For each node type, its assigned function will have as parameters all the possible - assigned or not - input varibles, and they will all be defined as inout variables, meaning that if any of these variables changes within the function, their new value will be accessible to the main function. In order to do so and to assign as input for one node, output from another, for each node, new variables will be created in the main function and its value set, either by setting a constant value or by assigning it the value of an output variable previously calculated.

Finally, for variable naming I was thinking of creating a GHash table within the GLSL_MaterialTree, that would link a bNode, a Material or a MTex to a new structure that would keep an unique number that identifies the node within the tree, the node type and a flag to be set when the value would already have been calculated and used as input for another node.

Implementation Details


This section will be updated as the project evolves.



Graphics Card GLSL Support


First of all we must check if the graphics card has the extensions GL_ARB_vertex_program and GL_ARB_fragment_program, as if it doesn't there will be no GLSL support, making it impossible to utilize this feature. This will be done when Blender initializes OpenGL.

Materials


Each material will have assigned to it its own GLSL program which will be responsible for drawing any primitive that uses that material. Each time the scene is drawn vertices properties like their positions and colors have to be sent to the shader. Other vertex independent material properties are sent to the program at the time of its creation and only revaluated when changed.

Material Creation

Whenever a material is created a new GLSL program will be created and associated to that material. This way a program will have to be linked and its shaders recompiled only when a material property that changes the program's structure is changed. When such thing happens, the vertex and fragment shaders will be rewritten, recompiled, attached to the respective program and this program linked.

Material Changes

Every time a material property is changed one of two things can happen:

  • The change affects the program's structure and the shaders have to be rewritten, recompiled, attached and the program linked
  • The change affects only a uniform and it has to bee updated within the program.


Lights


Lights will probably be the biggest bottleneck of this project. In order to calculate lighting it is necessary to calculate separately the effect of each light on the material and then add it all together. Well, the problem is that GLSL doesn't support program cycles without knowing its upper limit on compile time. So it is mandatory to define it at compile time and to do so we need to know how many lights there are in a scene.

When a light parameter such as energy, color, distance, etc is changed is it only necessary to update it within the program. The problem arises when a new light is added onto the scene. When such thing happens, and it will happen frequently, the number of lights changes and it is necessary to rewrite the shaders, recompile them, attach them and link the program. Well, when a program is linked, the value of all variables in it is set to 0. So it will be necessary to pass again all the values relative to material parameters to the program.

* DISCARDED * Another approach I though of recently consists in calculating the lights' effects using multipass. If done this way the removal of a light wouldn't affect the program's performance, and when creating a new light it would only be necessary to create a program - and the respective vertex and fragment shaders - responsible for calculating the effect of this light on the different materials.

* NEW * The latter approach was discarded. If done, for every material all the values would have to be passed to shader via uniform for each frame.

Node-based Materials


The approach will be similar to the one chosen for materials. The shader will be written on the fly, and each time a parameter is changed the program will be updated. Every time that the graph changed the shader will be rewritten.


Textures


The approach isn't, at the moment, defined. It will probably be one of the following:

  • Send all the textures to the shader and do all the calculations
  • Calculate the color using multipass

* NEW * I'm thinking about detecting the maximum number of texture units the graphics card supports and if the number of textures is less or equal to that value the calculations will be done in one pass. If not, multipass will be used. If texture is used for vertex displacement, such calculations must be done in the vertex shader.

Work Done



Material Diffuse Shaders


All the following examples used only a lamp as lighting.

Lambert
Lambert diffuse shading.
Lambert diffuse shading.


Oren-Nayar
Oren-Nayar diffuse shading.
Oren-Nayar diffuse shading.


Toon
Toon diffuse shading.
Toon diffuse shading.


Minnaert
Minnaert diffuse shading.
Minnaert diffuse shading.


Fresnel
Fresnel diffuse shading.
Fresnel diffuse shading.


Material Specular Shaders


All the following examples used only a lamp as lighting.

Cook-Torrance
Cook-Torrance specular shading.
Cook-Torrance specular shading.


Phong
Phong specular shading.
Phong specular shading.


Blinn
Blinn specular shading.
Blinn specular shading.


Toon
Toon specular shading.
Toon specular shading.


WardIso
Wardiso specular shading.
Wardiso specular shading.


Material Parameters


Vertex Color as Color (VCol Paint)
Vertices colors used as color.


Vertex Color as Extra Light (VCol Light)
Vertices colors used as extra light.


Use UV Texture as Face (TexFace)
UV Texture.
UV Texture with modified uv coordinates.
UV Texture.


Light Types


Lamp
Lamp light.
Lamp light without specular shading.
Lamp light without diffuse shading.


Sun
Sun light.
Sun light without specular shading.
Sun light without diffuse shading.


Hemi
Hemi light.
Hemi light without specular shading.
Hemi light without diffuse shading.


Viewport Shading


Solid

This viewport shading mode uses the lights defined in user preferences.

Solid mode with two active lights.
Solid mode with two active lights.


Shaded

This viewport shading mode uses the lights set by the user.

Shaded mode using a lamp and a sun light.
Shaded mode using a sun light.


Textured

Currently only supports UV Texture.


To Be Corrected


  • The eye position is not well defined, so specularity appears dislocated
  • VCol Light needs to be reviewed as its result is not satisfactory
  • Currently the glsl programs are being created for each material, at every step of the drawing process which leads to total inefficiency.



Video Preview


I made this video just to show what has been done. It is not even near completion, it is just a start. As you can see there are some problems. Most of them are because I don't quite know how to get the eye coordinates. Finding that vector will solve almost all the problems you can see in the video.

GLSL Preview Video.