This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/gpu/intern/gpu_material.c

2528 lines
81 KiB
C
Raw Normal View History

/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
2010-02-12 13:34:04 +00:00
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2006 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Brecht Van Lommel.
*
* ***** END GPL LICENSE BLOCK *****
*/
2011-02-27 20:25:53 +00:00
/** \file blender/gpu/intern/gpu_material.c
* \ingroup gpu
*
* Manages materials, lights and textures.
2011-02-27 20:25:53 +00:00
*/
#include <math.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_world_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BKE_anim.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
#include "BKE_group.h"
#include "IMB_imbuf_types.h"
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_lamp.h"
#include "GPU_material.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "gpu_codegen.h"
#include "gpu_lamp_private.h"
2016-06-09 05:37:46 +10:00
#ifdef WITH_OPENSUBDIV
# include "BKE_DerivedMesh.h"
#endif
/* Structs */
typedef enum DynMatProperty {
DYN_LAMP_CO = 1,
DYN_LAMP_VEC = 2,
DYN_LAMP_IMAT = 4,
DYN_LAMP_PERSMAT = 8,
} DynMatProperty;
static struct GPUWorld {
float mistenabled;
float mistype;
float miststart;
float mistdistance;
float mistintensity;
float mistcol[4];
float horicol[3];
float ambcol[4];
float zencol[3];
} GPUWorld;
struct GPUMaterial {
Scene *scene; /* DEPRECATED was only usefull for lamps */
Material *ma;
/* material for mesh surface, worlds or something else.
* some code generation is done differently depending on the use case */
int type; /* DEPRECATED */
const void *engine_type; /* attached engine type */
int options; /* to identify shader variations (shadow, probe, world background...) */
/* for creating the material */
ListBase nodes;
GPUNodeLink *outlink;
/* for binding the material */
GPUPass *pass;
GPUVertexAttribs attribs;
int builtins;
int alpha, obcolalpha;
int dynproperty;
/* for passing uniforms */
int viewmatloc, invviewmatloc;
int obmatloc, invobmatloc;
int localtoviewmatloc, invlocaltoviewmatloc;
2011-12-09 23:26:06 +00:00
int obcolloc, obautobumpscaleloc;
int cameratexcofacloc;
int partscalarpropsloc;
int partcoloc;
int partvel;
int partangvel;
int objectinfoloc;
ListBase lamps;
bool bound;
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
bool is_opensubdiv;
};
/* Forward declaration so shade_light_textures() can use this, while still keeping the code somewhat organized */
2016-01-10 07:12:10 +11:00
static void texture_rgb_blend(
GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg,
int blendtype, GPUNodeLink **in);
/* Functions */
static GPUMaterial *GPU_material_construct_begin(Material *ma)
{
GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
material->ma = ma;
return material;
}
static void gpu_material_set_attrib_id(GPUMaterial *material)
{
GPUVertexAttribs *attribs = &material->attribs;
GPUPass *pass = material->pass;
if (!pass) {
attribs->totlayer = 0;
return;
}
GPUShader *shader = GPU_pass_shader(pass);
if (!shader) {
attribs->totlayer = 0;
return;
}
/* convert from attribute number to the actual id assigned by opengl,
* in case the attrib does not get a valid index back, it was probably
* removed by the glsl compiler by dead code elimination */
int b = 0;
for (int a = 0; a < attribs->totlayer; a++) {
char name[32];
BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid);
attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name);
BLI_snprintf(name, sizeof(name), "att%d_info", attribs->layer[a].attribid);
attribs->layer[a].glinfoindoex = GPU_shader_get_uniform(shader, name);
if (attribs->layer[a].glindex >= 0) {
attribs->layer[b] = attribs->layer[a];
b++;
}
}
attribs->totlayer = b;
}
static int gpu_material_construct_end(GPUMaterial *material, const char *passname)
{
if (material->outlink) {
GPUNodeLink *outlink = material->outlink;
material->pass = GPU_generate_pass(&material->nodes, outlink,
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
&material->attribs, &material->builtins, material->type,
passname,
material->is_opensubdiv,
GPU_material_use_new_shading_nodes(material));
if (!material->pass)
return 0;
gpu_material_set_attrib_id(material);
GPUShader *shader = GPU_pass_shader(material->pass);
if (material->builtins & GPU_VIEW_MATRIX)
material->viewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_VIEW_MATRIX));
if (material->builtins & GPU_INVERSE_VIEW_MATRIX)
material->invviewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_INVERSE_VIEW_MATRIX));
if (material->builtins & GPU_OBJECT_MATRIX)
material->obmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_MATRIX));
if (material->builtins & GPU_INVERSE_OBJECT_MATRIX)
material->invobmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_INVERSE_OBJECT_MATRIX));
if (material->builtins & GPU_LOC_TO_VIEW_MATRIX)
material->localtoviewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_LOC_TO_VIEW_MATRIX));
if (material->builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX)
material->invlocaltoviewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_INVERSE_LOC_TO_VIEW_MATRIX));
if (material->builtins & GPU_OBCOLOR)
material->obcolloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBCOLOR));
if (material->builtins & GPU_AUTO_BUMPSCALE)
2011-12-09 23:26:06 +00:00
material->obautobumpscaleloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_AUTO_BUMPSCALE));
if (material->builtins & GPU_CAMERA_TEXCO_FACTORS)
material->cameratexcofacloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_CAMERA_TEXCO_FACTORS));
if (material->builtins & GPU_PARTICLE_SCALAR_PROPS)
material->partscalarpropsloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_SCALAR_PROPS));
if (material->builtins & GPU_PARTICLE_LOCATION)
material->partcoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_LOCATION));
if (material->builtins & GPU_PARTICLE_VELOCITY)
material->partvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_VELOCITY));
if (material->builtins & GPU_PARTICLE_ANG_VELOCITY)
material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY));
if (material->builtins & GPU_OBJECT_INFO)
material->objectinfoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_INFO));
return 1;
}
else {
GPU_pass_free_nodes(&material->nodes);
}
return 0;
}
void GPU_material_free(ListBase *gpumaterial)
{
for (LinkData *link = gpumaterial->first; link; link = link->next) {
GPUMaterial *material = link->data;
if (material->pass)
GPU_pass_free(material->pass);
BLI_freelistN(&material->lamps);
MEM_freeN(material);
}
BLI_freelistN(gpumaterial);
}
2016-01-10 07:12:10 +11:00
void GPU_material_bind(
GPUMaterial *material, int oblay, int viewlay, double time, int mipmap,
float viewmat[4][4], float viewinv[4][4], float camerafactors[4], bool scenelock)
{
if (material->pass) {
GPUShader *shader = GPU_pass_shader(material->pass);
SceneRenderLayer *srl = scenelock ? BLI_findlink(&material->scene->r.layers, material->scene->r.actlay) : NULL;
if (srl)
viewlay &= srl->lay;
/* handle layer lamps */
if (material->type == GPU_MATERIAL_TYPE_MESH) {
for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) {
GPULamp *lamp = nlink->data;
2016-01-10 07:12:10 +11:00
if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) &&
GPU_lamp_override_visible(lamp, srl, material->ma))
{
lamp->dynenergy = lamp->energy;
copy_v3_v3(lamp->dyncol, lamp->col);
}
else {
lamp->dynenergy = 0.0f;
lamp->dyncol[0] = lamp->dyncol[1] = lamp->dyncol[2] = 0.0f;
}
if (material->dynproperty & DYN_LAMP_VEC) {
copy_v3_v3(lamp->dynvec, lamp->vec);
normalize_v3(lamp->dynvec);
negate_v3(lamp->dynvec);
mul_mat3_m4_v3(viewmat, lamp->dynvec);
}
if (material->dynproperty & DYN_LAMP_CO) {
copy_v3_v3(lamp->dynco, lamp->co);
mul_m4_v3(viewmat, lamp->dynco);
}
if (material->dynproperty & DYN_LAMP_IMAT) {
mul_m4_m4m4(lamp->dynimat, lamp->imat, viewinv);
}
if (material->dynproperty & DYN_LAMP_PERSMAT) {
2016-01-10 07:12:10 +11:00
/* The lamp matrices are already updated if we're using shadow buffers */
if (!GPU_lamp_has_shadow_buffer(lamp)) {
GPU_lamp_update_buffer_mats(lamp);
2016-01-10 07:12:10 +11:00
}
mul_m4_m4m4(lamp->dynpersmat, lamp->persmat, viewinv);
}
}
}
/* note material must be bound before setting uniforms */
GPU_pass_bind(material->pass, time, mipmap);
/* handle per material built-ins */
if (material->builtins & GPU_VIEW_MATRIX) {
2016-01-10 07:12:10 +11:00
GPU_shader_uniform_vector(shader, material->viewmatloc, 16, 1, (float *)viewmat);
}
if (material->builtins & GPU_INVERSE_VIEW_MATRIX) {
2016-01-10 07:12:10 +11:00
GPU_shader_uniform_vector(shader, material->invviewmatloc, 16, 1, (float *)viewinv);
}
if (material->builtins & GPU_CAMERA_TEXCO_FACTORS) {
if (camerafactors) {
2016-01-10 07:12:10 +11:00
GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float *)camerafactors);
}
else {
/* use default, no scaling no offset */
float borders[4] = {1.0f, 1.0f, 0.0f, 0.0f};
2016-01-10 07:12:10 +11:00
GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float *)borders);
}
}
GPU_pass_update_uniforms(material->pass);
material->bound = 1;
}
}
GPUBuiltin GPU_get_material_builtins(GPUMaterial *material)
{
return material->builtins;
}
2016-01-10 07:12:10 +11:00
void GPU_material_bind_uniforms(
GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
float autobumpscale, GPUParticleInfo *pi, float object_info[3])
{
if (material->pass) {
GPUShader *shader = GPU_pass_shader(material->pass);
float invmat[4][4], col[4];
float localtoviewmat[4][4];
float invlocaltoviewmat[4][4];
/* handle per object builtins */
if (material->builtins & GPU_OBJECT_MATRIX) {
2016-01-10 07:12:10 +11:00
GPU_shader_uniform_vector(shader, material->obmatloc, 16, 1, (float *)obmat);
}
if (material->builtins & GPU_INVERSE_OBJECT_MATRIX) {
invert_m4_m4(invmat, obmat);
2016-01-10 07:12:10 +11:00
GPU_shader_uniform_vector(shader, material->invobmatloc, 16, 1, (float *)invmat);
}
if (material->builtins & GPU_LOC_TO_VIEW_MATRIX) {
if (viewmat) {
mul_m4_m4m4(localtoviewmat, viewmat, obmat);
GPU_shader_uniform_vector(shader, material->localtoviewmatloc, 16, 1, (float *)localtoviewmat);
}
}
if (material->builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) {
if (viewmat) {
mul_m4_m4m4(localtoviewmat, viewmat, obmat);
invert_m4_m4(invlocaltoviewmat, localtoviewmat);
GPU_shader_uniform_vector(shader, material->invlocaltoviewmatloc, 16, 1, (float *)invlocaltoviewmat);
}
}
if (material->builtins & GPU_OBCOLOR) {
copy_v4_v4(col, obcol);
CLAMP(col[3], 0.0f, 1.0f);
GPU_shader_uniform_vector(shader, material->obcolloc, 4, 1, col);
}
if (material->builtins & GPU_AUTO_BUMPSCALE) {
2011-12-09 23:26:06 +00:00
GPU_shader_uniform_vector(shader, material->obautobumpscaleloc, 1, 1, &autobumpscale);
}
if (material->builtins & GPU_PARTICLE_SCALAR_PROPS) {
GPU_shader_uniform_vector(shader, material->partscalarpropsloc, 4, 1, pi->scalprops);
}
if (material->builtins & GPU_PARTICLE_LOCATION) {
GPU_shader_uniform_vector(shader, material->partcoloc, 3, 1, pi->location);
}
if (material->builtins & GPU_PARTICLE_VELOCITY) {
GPU_shader_uniform_vector(shader, material->partvel, 3, 1, pi->velocity);
}
if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) {
GPU_shader_uniform_vector(shader, material->partangvel, 3, 1, pi->angular_velocity);
}
if (material->builtins & GPU_OBJECT_INFO) {
GPU_shader_uniform_vector(shader, material->objectinfoloc, 3, 1, object_info);
}
}
}
void GPU_material_unbind(GPUMaterial *material)
{
if (material->pass) {
material->bound = 0;
GPU_pass_unbind(material->pass);
}
}
bool GPU_material_bound(GPUMaterial *material)
{
return material->bound;
}
Scene *GPU_material_scene(GPUMaterial *material)
{
return material->scene;
}
GPUMatType GPU_Material_get_type(GPUMaterial *material)
{
return material->type;
}
GPUPass *GPU_material_get_pass(GPUMaterial *material)
{
return material->pass;
}
void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs)
{
*attribs = material->attribs;
}
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
{
if (!material->outlink)
material->outlink = link;
}
void GPU_material_enable_alpha(GPUMaterial *material)
{
material->alpha = 1;
}
TexFace to Material Settings big patch Summary: ======== The idea here is to move the texface options into the material panel. For images with the change please visit: http://code.blender.org/index.php/2011/09/bge-material-texface-changes 1 - Some of the legacy problems 2.49 and 2.5x has with the texface system: ========================================================================== 1.1) Shadow, Bilboard and Halo are mutual exclusive (in the code), yet you can select a face to be more than one mode. 1.2) Sort only works for blend Alpha yet it's an option regardless of the Transparency Blend you pick. 1.3) Shared doesn't affect anything in BGE. 1.4) ObColor only works for Text objects (old bitmap texts) when using Texture Face Materials. (not address yet, I so far ignored obcolor) 2 - Notes: ============ 2.1) Now "Use Face Textures" in material Option panel will work in Multitexture even if there is no texture channel. 2.2) In FaceTexture mode it will use TexFace all the time, even if you don't check the "Use Texture Face" option in the UI. It's a matter of decision, since the code for either way is there. I decided by the solution that makes the creation of a material fast - in this mode the user doesn't need to mess with textures or this "Use Texture Face" option at all. I'm not strong in my opinion here. But I think if we don't have this then what is the point of the Texture Face mode? 2.3) I kept references for tface only when we need the image, UV or the tiling setting. It should help later when/if we split the Image and UV layers from the tface struct (Campbell and Brecht proposal). 3 - Changes in a Nutshell: ========================== 3.1) "Texture Face" panel (in the Mesh/Object Data panel) no longer exists. Those settings are all part of the material properties, visible when Game Render is set. 3.2) "Texture Face" Shading mode (in the Render panel) is now called “Single Texture”, it needs a material for special settings (e.g. Billboard, Alpha Sort, …). 3.3) New options in the Material Panel * Shadeless option in the Material panel is now supported for all three Shading modes. * Physics is now toggleable, this is the old Collision option. * Two Side (on) is now called Back Culling (off). * Alpha Sort is one of the Alpha options, together (and mutually exclusive) to Alpha Blend, Alpha Clip, Add and Opaque (i.e. solid). * Shadow, Billboard and Halo are grouped in the “Face Orientation” property. * "Face Textures" and "Face Textures Alpha" (under Options) can be used for all but GLSL shading mode (to be supported in GLSL eventually). * The backend in the game engine is still the same as before. The only changes are in the interface and in the way you need to think your materials. The bottomline is: It’s no longer possible to share materials between faces that do not share the same game properties. 4 - Acknowledgment: ================== Mike Pan for the design discussions, and testing along the whole development process. Vitor Balbio for the first hands-on code with the interface changes. That helped me a lot to push me into work on that. Benoit Bolsee and Brecht van Lommel for patch review (* no one reviewed the whole patch, or the latest iteractions, so I still hold liability for any problems). Blender artists that gave feedback and helped testing the patch. Patch review and original documentation can be found here: http://wiki.blender.org/index.php/User:Dfelinto/TexFace http://codereview.appspot.com/4289041/
2011-09-19 19:55:59 +00:00
GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4])
{
if (material->alpha || (material->obcolalpha && obcol[3] < 1.0f))
return GPU_BLEND_ALPHA;
else
return GPU_BLEND_SOLID;
}
void gpu_material_add_node(GPUMaterial *material, GPUNode *node)
{
BLI_addtail(&material->nodes, node);
}
/* Code generation */
bool GPU_material_do_color_management(GPUMaterial *mat)
{
if (!BKE_scene_check_color_management_enabled(mat->scene))
return false;
Color Management, Stage 2: Switch color pipeline to use OpenColorIO Replace old color pipeline which was supporting linear/sRGB color spaces only with OpenColorIO-based pipeline. This introduces two configurable color spaces: - Input color space for images and movie clips. This space is used to convert images/movies from color space in which file is saved to Blender's linear space (for float images, byte images are not internally converted, only input space is stored for such images and used later). This setting could be found in image/clip data block settings. - Display color space which defines space in which particular display is working. This settings could be found in scene's Color Management panel. When render result is being displayed on the screen, apart from converting image to display space, some additional conversions could happen. This conversions are: - View, which defines tone curve applying before display transformation. These are different ways to view the image on the same display device. For example it could be used to emulate film view on sRGB display. - Exposure affects on image exposure before tone map is applied. - Gamma is post-display gamma correction, could be used to match particular display gamma. - RGB curves are user-defined curves which are applying before display transformation, could be used for different purposes. All this settings by default are only applying on render result and does not affect on other images. If some particular image needs to be affected by this transformation, "View as Render" setting of image data block should be set to truth. Movie clips are always affected by all display transformations. This commit also introduces configurable color space in which sequencer is working. This setting could be found in scene's Color Management panel and it should be used if such stuff as grading needs to be done in color space different from sRGB (i.e. when Film view on sRGB display is use, using VD16 space as sequencer's internal space would make grading working in space which is close to the space using for display). Some technical notes: - Image buffer's float buffer is now always in linear space, even if it was created from 16bit byte images. - Space of byte buffer is stored in image buffer's rect_colorspace property. - Profile of image buffer was removed since it's not longer meaningful. - OpenGL and GLSL is supposed to always work in sRGB space. It is possible to support other spaces, but it's quite large project which isn't so much important. - Legacy Color Management option disabled is emulated by using None display. It could have some regressions, but there's no clear way to avoid them. - If OpenColorIO is disabled on build time, it should make blender behaving in the same way as previous release with color management enabled. More details could be found at this page (more details would be added soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.64/Color_Management -- Thanks to Xavier Thomas, Lukas Toene for initial work on OpenColorIO integration and to Brecht van Lommel for some further development and code/ usecase review!
2012-09-15 10:05:07 +00:00
return true;
}
bool GPU_material_use_new_shading_nodes(GPUMaterial *mat)
{
return BKE_scene_use_new_shading_nodes(mat->scene);
}
bool GPU_material_use_world_space_shading(GPUMaterial *mat)
{
return BKE_scene_use_world_space_shading(mat->scene);
}
static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist)
{
GPUNodeLink *visifac;
/* from get_lamp_visibility */
if (lamp->type == LA_SUN || lamp->type == LA_HEMI) {
mat->dynproperty |= DYN_LAMP_VEC;
2016-01-10 07:12:10 +11:00
GPU_link(mat, "lamp_visibility_sun_hemi",
GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), lv, dist, &visifac);
return visifac;
}
else {
mat->dynproperty |= DYN_LAMP_CO;
2016-01-10 07:12:10 +11:00
GPU_link(mat, "lamp_visibility_other",
GPU_builtin(GPU_VIEW_POSITION),
GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), lv, dist, &visifac);
if (lamp->type == LA_AREA)
return visifac;
switch (lamp->falloff_type) {
case LA_FALLOFF_CONSTANT:
break;
case LA_FALLOFF_INVLINEAR:
2016-01-10 07:12:10 +11:00
GPU_link(mat, "lamp_falloff_invlinear",
GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac);
break;
case LA_FALLOFF_INVSQUARE:
2016-01-10 07:12:10 +11:00
GPU_link(mat, "lamp_falloff_invsquare",
GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac);
break;
case LA_FALLOFF_SLIDERS:
2016-01-10 07:12:10 +11:00
GPU_link(mat, "lamp_falloff_sliders",
GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob),
GPU_dynamic_uniform(&lamp->att1, GPU_DYNAMIC_LAMP_ATT1, lamp->ob),
GPU_dynamic_uniform(&lamp->att2, GPU_DYNAMIC_LAMP_ATT2, lamp->ob), *dist, &visifac);
break;
case LA_FALLOFF_INVCOEFFICIENTS:
GPU_link(mat, "lamp_falloff_invcoefficients",
GPU_dynamic_uniform(&lamp->coeff_const, GPU_DYNAMIC_LAMP_COEFFCONST, lamp->ob),
GPU_dynamic_uniform(&lamp->coeff_lin, GPU_DYNAMIC_LAMP_COEFFLIN, lamp->ob),
GPU_dynamic_uniform(&lamp->coeff_quad, GPU_DYNAMIC_LAMP_COEFFQUAD, lamp->ob), *dist, &visifac);
break;
case LA_FALLOFF_CURVE:
{
float *array;
int size;
curvemapping_initialize(lamp->curfalloff);
curvemapping_table_RGBA(lamp->curfalloff, &array, &size);
2016-01-10 07:12:10 +11:00
GPU_link(mat, "lamp_falloff_curve",
GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob),
GPU_texture(size, array), *dist, &visifac);
break;
}
}
if (lamp->mode & LA_SPHERE)
2016-01-10 07:12:10 +11:00
GPU_link(mat, "lamp_visibility_sphere",
GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob),
*dist, visifac, &visifac);
if (lamp->type == LA_SPOT) {
GPUNodeLink *inpr;
if (lamp->mode & LA_SQUARE) {
mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT;
2016-01-10 07:12:10 +11:00
GPU_link(mat, "lamp_visibility_spot_square",
GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob),
GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob),
GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr);
}
else {
mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT;
2016-01-10 07:12:10 +11:00
GPU_link(mat, "lamp_visibility_spot_circle",
GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob),
GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob),
GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr);
}
2016-01-10 07:12:10 +11:00
GPU_link(mat, "lamp_visibility_spot",
GPU_dynamic_uniform(&lamp->spotsi, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob),
GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTBLEND, lamp->ob),
2016-01-10 07:12:10 +11:00
inpr, visifac, &visifac);
}
GPU_link(mat, "lamp_visibility_clamp", visifac, &visifac);
return visifac;
}
}
#if 0
static void area_lamp_vectors(LampRen *lar)
{
float xsize = 0.5f * lar->area_size, ysize = 0.5f * lar->area_sizey;
/* make it smaller, so area light can be multisampled */
float multifac = 1.0f / sqrtf((float)lar->ray_totsamp);
xsize *= multifac;
ysize *= multifac;
/* corner vectors */
lar->area[0][0] = lar->co[0] - xsize * lar->mat[0][0] - ysize * lar->mat[1][0];
lar->area[0][1] = lar->co[1] - xsize * lar->mat[0][1] - ysize * lar->mat[1][1];
lar->area[0][2] = lar->co[2] - xsize * lar->mat[0][2] - ysize * lar->mat[1][2];
/* corner vectors */
lar->area[1][0] = lar->co[0] - xsize * lar->mat[0][0] + ysize * lar->mat[1][0];
lar->area[1][1] = lar->co[1] - xsize * lar->mat[0][1] + ysize * lar->mat[1][1];
lar->area[1][2] = lar->co[2] - xsize * lar->mat[0][2] + ysize * lar->mat[1][2];
/* corner vectors */
lar->area[2][0] = lar->co[0] + xsize * lar->mat[0][0] + ysize * lar->mat[1][0];
lar->area[2][1] = lar->co[1] + xsize * lar->mat[0][1] + ysize * lar->mat[1][1];
lar->area[2][2] = lar->co[2] + xsize * lar->mat[0][2] + ysize * lar->mat[1][2];
/* corner vectors */
lar->area[3][0] = lar->co[0] + xsize * lar->mat[0][0] - ysize * lar->mat[1][0];
lar->area[3][1] = lar->co[1] + xsize * lar->mat[0][1] - ysize * lar->mat[1][1];
lar->area[3][2] = lar->co[2] + xsize * lar->mat[0][2] - ysize * lar->mat[1][2];
/* only for correction button size, matrix size works on energy */
lar->areasize = lar->dist * lar->dist / (4.0f * xsize * ysize);
}
#endif
2016-01-10 07:12:10 +11:00
static void ramp_blend(
GPUMaterial *mat, GPUNodeLink *fac, GPUNodeLink *col1, GPUNodeLink *col2, int type,
GPUNodeLink **r_col)
{
static const char *names[] = {"mix_blend", "mix_add", "mix_mult", "mix_sub",
"mix_screen", "mix_div", "mix_diff", "mix_dark", "mix_light",
"mix_overlay", "mix_dodge", "mix_burn", "mix_hue", "mix_sat",
"mix_val", "mix_color", "mix_soft", "mix_linear"};
2016-01-10 07:12:10 +11:00
GPU_link(mat, names[type], fac, col1, col2, r_col);
}
2016-01-10 07:12:10 +11:00
static void do_colorband_blend(
GPUMaterial *mat, ColorBand *coba, GPUNodeLink *fac, float rampfac, int type,
GPUNodeLink *incol, GPUNodeLink **r_col)
{
GPUNodeLink *tmp, *alpha, *col;
float *array;
int size;
/* do colorband */
colorband_table_RGBA(coba, &array, &size);
GPU_link(mat, "valtorgb", fac, GPU_texture(size, array), &col, &tmp);
/* use alpha in fac */
GPU_link(mat, "mtex_alpha_from_col", col, &alpha);
GPU_link(mat, "math_multiply", alpha, GPU_uniform(&rampfac), &fac);
/* blending method */
2016-01-10 07:12:10 +11:00
ramp_blend(mat, fac, incol, col, type, r_col);
}
static void ramp_diffuse_result(GPUShadeInput *shi, GPUNodeLink **diff)
{
Material *ma = shi->mat;
GPUMaterial *mat = shi->gpumat;
if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS)) {
if (ma->ramp_col) {
2016-01-10 07:12:10 +11:00
if (ma->rampin_col == MA_RAMP_IN_RESULT) {
GPUNodeLink *fac;
GPU_link(mat, "ramp_rgbtobw", *diff, &fac);
/* colorband + blend */
do_colorband_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, *diff, diff);
}
}
}
}
2016-01-10 07:12:10 +11:00
static void add_to_diffuse(
GPUMaterial *mat, Material *ma, GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *rgb,
GPUNodeLink **r_diff)
{
GPUNodeLink *fac, *tmp, *addcol;
if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS) &&
ma->ramp_col && (ma->mode & MA_RAMP_COL))
{
/* MA_RAMP_IN_RESULT is exceptional */
2016-01-10 07:12:10 +11:00
if (ma->rampin_col == MA_RAMP_IN_RESULT) {
addcol = shi->rgb;
}
else {
/* input */
switch (ma->rampin_col) {
case MA_RAMP_IN_ENERGY:
GPU_link(mat, "ramp_rgbtobw", rgb, &fac);
break;
case MA_RAMP_IN_SHADER:
2016-01-10 07:12:10 +11:00
fac = is;
break;
case MA_RAMP_IN_NOR:
GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
break;
default:
GPU_link(mat, "set_value_zero", &fac);
break;
}
/* colorband + blend */
do_colorband_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, shi->rgb, &addcol);
}
}
else
addcol = shi->rgb;
/* output to */
2016-01-10 07:12:10 +11:00
GPU_link(mat, "shade_madd", *r_diff, rgb, addcol, r_diff);
}
static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec)
{
Material *ma = shi->mat;
GPUMaterial *mat = shi->gpumat;
if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS) &&
ma->ramp_spec && ma->rampin_spec == MA_RAMP_IN_RESULT)
{
GPUNodeLink *fac;
GPU_link(mat, "ramp_rgbtobw", *spec, &fac);
/* colorband + blend */
do_colorband_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec);
}
}
static void do_specular_ramp(GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *t, GPUNodeLink **spec)
{
Material *ma = shi->mat;
GPUMaterial *mat = shi->gpumat;
GPUNodeLink *fac, *tmp;
*spec = shi->specrgb;
/* MA_RAMP_IN_RESULT is exception */
if (ma->ramp_spec && (ma->rampin_spec != MA_RAMP_IN_RESULT)) {
/* input */
switch (ma->rampin_spec) {
case MA_RAMP_IN_ENERGY:
fac = t;
break;
case MA_RAMP_IN_SHADER:
fac = is;
break;
case MA_RAMP_IN_NOR:
GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
break;
default:
GPU_link(mat, "set_value_zero", &fac);
break;
}
/* colorband + blend */
do_colorband_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec);
}
}
static void add_user_list(ListBase *list, void *data)
{
LinkData *link = MEM_callocN(sizeof(LinkData), "GPULinkData");
link->data = data;
BLI_addtail(list, link);
}
static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **rgb)
{
for (int i = 0; i < MAX_MTEX; ++i) {
MTex *mtex = lamp->la->mtex[i];
if (mtex && mtex->tex && (mtex->tex->type & TEX_IMAGE) && mtex->tex->ima) {
mat->dynproperty |= DYN_LAMP_PERSMAT;
2016-01-08 16:42:47 +11:00
float one = 1.0f;
GPUNodeLink *tex_rgb;
GPU_link(mat, "shade_light_texture",
2016-01-10 07:12:10 +11:00
GPU_builtin(GPU_VIEW_POSITION),
GPU_image(mtex->tex->ima, &mtex->tex->iuser, false),
GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
&tex_rgb);
texture_rgb_blend(mat, tex_rgb, *rgb, GPU_uniform(&one), GPU_uniform(&mtex->colfac), mtex->blendtype, rgb);
}
}
}
static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *lamp)
{
Material *ma = shi->mat;
GPUMaterial *mat = shi->gpumat;
GPUNodeLink *lv, *dist, *is, *inp, *i;
GPUNodeLink *outcol, *specfac, *t, *shadfac = NULL, *lcol;
2016-01-08 16:42:47 +11:00
float one = 1.0f;
if ((lamp->mode & LA_ONLYSHADOW) && !(ma->mode & MA_SHADOW))
return;
GPUNodeLink *vn = shi->vn;
GPUNodeLink *view = shi->view;
GPUNodeLink *visifac = lamp_get_visibility(mat, lamp, &lv, &dist);
#if 0
if (ma->mode & MA_TANGENT_V)
GPU_link(mat, "shade_tangent_v", lv, GPU_attribute(CD_TANGENT, ""), &vn);
#endif
GPU_link(mat, "shade_inp", vn, lv, &inp);
if (lamp->mode & LA_NO_DIFF) {
GPU_link(mat, "shade_is_no_diffuse", &is);
}
else if (lamp->type == LA_HEMI) {
GPU_link(mat, "shade_is_hemi", inp, &is);
}
else {
if (lamp->type == LA_AREA) {
float area[4][4] = {{0.0f}}, areasize = 0.0f;
2016-01-10 07:12:10 +11:00
mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_CO;
GPU_link(mat, "shade_inp_area",
GPU_builtin(GPU_VIEW_POSITION),
GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob),
GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), vn,
GPU_uniform((float *)area),
GPU_uniform(&areasize),
GPU_uniform(&lamp->k), &inp);
}
is = inp; /* Lambert */
if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADERS)) {
if (ma->diff_shader == MA_DIFF_ORENNAYAR)
2016-01-10 07:12:10 +11:00
GPU_link(mat, "shade_diffuse_oren_nayer", inp, vn, lv, view,
GPU_uniform(&ma->roughness), &is);
else if (ma->diff_shader == MA_DIFF_TOON)
2016-01-10 07:12:10 +11:00
GPU_link(mat, "shade_diffuse_toon", vn, lv, view,
GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
else if (ma->diff_shader == MA_DIFF_MINNAERT)
2016-01-10 07:12:10 +11:00
GPU_link(mat, "shade_diffuse_minnaert", inp, vn, view,
GPU_uniform(&ma->darkness), &is);
else if (ma->diff_shader == MA_DIFF_FRESNEL)
2016-01-10 07:12:10 +11:00
GPU_link(mat, "shade_diffuse_fresnel", vn, lv, view,
GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
}
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADERS))
if (ma->shade_flag & MA_CUBIC)
GPU_link(mat, "shade_cubic", is, &is);
i = is;
GPU_link(mat, "shade_visifac", i, visifac, shi->refl, &i);
GPU_link(mat, "set_rgb", GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob), &lcol);
shade_light_textures(mat, lamp, &lcol);
2016-01-10 07:12:10 +11:00
GPU_link(mat, "shade_mul_value_v3",
GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), lcol, &lcol);
2012-03-09 18:28:30 +00:00
#if 0
if (ma->mode & MA_TANGENT_VN)
2012-03-09 18:28:30 +00:00
GPU_link(mat, "shade_tangent_v_spec", GPU_attribute(CD_TANGENT, ""), &vn);
#endif
/* this replaces if (i > 0.0) conditional until that is supported */
/* done in shade_visifac now, GPU_link(mat, "mtex_value_clamp_positive", i, &i); */
if ((ma->mode & MA_SHADOW) && GPU_lamp_has_shadow_buffer(lamp)) {
if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADOWS)) {
mat->dynproperty |= DYN_LAMP_PERSMAT;
if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
GPU_link(mat, "test_shadowbuf_vsm",
2016-01-10 07:12:10 +11:00
GPU_builtin(GPU_VIEW_POSITION),
GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias), inp, &shadfac);
2012-05-22 06:29:46 +00:00
}
else {
GPU_link(mat, "test_shadowbuf",
2016-01-10 07:12:10 +11:00
GPU_builtin(GPU_VIEW_POSITION),
GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
GPU_uniform(&lamp->bias), inp, &shadfac);
}
if (lamp->mode & LA_ONLYSHADOW) {
GPUNodeLink *shadrgb;
GPU_link(mat, "shade_only_shadow", i, shadfac,
GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob),
GPU_uniform(lamp->shadow_color), &shadrgb);
if (!(lamp->mode & LA_NO_DIFF)) {
GPU_link(mat, "shade_only_shadow_diffuse", shadrgb, shi->rgb,
2016-01-10 07:12:10 +11:00
shr->diff, &shr->diff);
}
2016-01-10 07:12:10 +11:00
if (!(lamp->mode & LA_NO_SPEC)) {
GPU_link(mat, "shade_only_shadow_specular", shadrgb, shi->specrgb,
2016-01-10 07:12:10 +11:00
shr->spec, &shr->spec);
}
add_user_list(&mat->lamps, lamp);
return;
}
}
}
else if ((mat->scene->gm.flag & GAME_GLSL_NO_SHADOWS) && (lamp->mode & LA_ONLYSHADOW)) {
add_user_list(&mat->lamps, lamp);
return;
}
else
GPU_link(mat, "set_value", GPU_uniform(&one), &shadfac);
if (GPU_link_changed(shi->refl) || ma->ref != 0.0f) {
if (!(lamp->mode & LA_NO_DIFF)) {
GPUNodeLink *rgb;
GPU_link(mat, "shade_mul_value", i, lcol, &rgb);
GPU_link(mat, "mtex_value_invert", shadfac, &shadfac);
GPU_link(mat, "mix_mult", shadfac, rgb, GPU_uniform(lamp->shadow_color), &rgb);
GPU_link(mat, "mtex_value_invert", shadfac, &shadfac);
2012-06-04 20:11:09 +00:00
add_to_diffuse(mat, ma, shi, is, rgb, &shr->diff);
}
}
2012-10-14 13:08:19 +00:00
if (mat->scene->gm.flag & GAME_GLSL_NO_SHADERS) {
/* pass */
}
else if (!(lamp->mode & LA_NO_SPEC) && !(lamp->mode & LA_ONLYSHADOW) &&
(GPU_link_changed(shi->spec) || ma->spec != 0.0f))
{
if (lamp->type == LA_HEMI) {
GPU_link(mat, "shade_hemi_spec", vn, lv, view, GPU_uniform(&ma->spec), shi->har, visifac, &t);
GPU_link(mat, "shade_add_spec", t, lcol, shi->specrgb, &outcol);
GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec);
}
else {
2016-01-10 07:12:10 +11:00
if (ma->spec_shader == MA_SPEC_PHONG) {
GPU_link(mat, "shade_phong_spec", vn, lv, view, shi->har, &specfac);
2016-01-10 07:12:10 +11:00
}
else if (ma->spec_shader == MA_SPEC_COOKTORR) {
GPU_link(mat, "shade_cooktorr_spec", vn, lv, view, shi->har, &specfac);
2016-01-10 07:12:10 +11:00
}
else if (ma->spec_shader == MA_SPEC_BLINN) {
GPU_link(mat, "shade_blinn_spec", vn, lv, view,
GPU_uniform(&ma->refrac), shi->har, &specfac);
}
else if (ma->spec_shader == MA_SPEC_WARDISO) {
GPU_link(mat, "shade_wardiso_spec", vn, lv, view,
GPU_uniform(&ma->rms), &specfac);
}
else {
GPU_link(mat, "shade_toon_spec", vn, lv, view,
GPU_uniform(&ma->param[2]), GPU_uniform(&ma->param[3]), &specfac);
}
if (lamp->type == LA_AREA)
GPU_link(mat, "shade_spec_area_inp", specfac, inp, &specfac);
GPU_link(mat, "shade_spec_t", shadfac, shi->spec, visifac, specfac, &t);
if (ma->mode & MA_RAMP_SPEC) {
GPUNodeLink *spec;
do_specular_ramp(shi, specfac, t, &spec);
GPU_link(mat, "shade_add_spec", t, lcol, spec, &outcol);
GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec);
}
else {
GPU_link(mat, "shade_add_spec", t, lcol, shi->specrgb, &outcol);
GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec);
}
}
}
add_user_list(&mat->lamps, lamp);
}
static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
{
Base *base;
Scene *sce_iter;
for (SETLOOPER(shi->gpumat->scene, sce_iter, base)) {
Object *ob = base->object;
if (ob->type == OB_LAMP) {
GPULamp *lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob, NULL);
if (lamp)
shade_one_light(shi, shr, lamp);
}
if (ob->transflag & OB_DUPLI) {
Threaded object update and EvaluationContext Summary: Made objects update happening from multiple threads. It is a task-based scheduling system which uses current dependency graph for spawning new tasks. This means threading happens on object level, but the system is flexible enough for higher granularity. Technical details: - Uses task scheduler which was recently committed to trunk (that one which Brecht ported from Cycles). - Added two utility functions to dependency graph: * DAG_threaded_update_begin, which is called to initialize threaded objects update. It will also schedule root DAG node to the queue, hence starting evaluation process. Initialization will calculate how much parents are to be evaluation before current DAG node can be scheduled. This value is used by task threads for faster detecting which nodes might be scheduled. * DAG_threaded_update_handle_node_updated which is called from task thread function when node was fully handled. This function decreases num_pending_parents of node children and schedules children with zero valency. As it might have become clear, task thread receives DAG nodes and decides which callback to call for it. Currently only BKE_object_handle_update is called for object nodes. In the future it'll call node->callback() from Ali's new DAG. - This required adding some workarounds to the render pipeline. Mainly to stop using get_object_dm() from modifiers' apply callback. Such a call was only a workaround for dependency graph glitch when rendering scene with, say, boolean modifiers before displaying this scene. Such change moves workaround from one place to another, so overall hackentropy remains the same. - Added paradigm of EvaluaitonContext. Currently it's more like just a more reliable replacement for G.is_rendering which fails in some circumstances. Future idea of this context is to also store all the local data needed for objects evaluation such as local time, Copy-on-Write data and so. There're two types of EvaluationContext: * Context used for viewport updated and owned by Main. In the future this context might be easily moved to Window or Screen to allo per-window/per-screen local time. * Context used by render engines to evaluate objects for render purposes. Render engine is an owner of this context. This context is passed to all object update routines. Reviewers: brecht, campbellbarton Reviewed By: brecht CC: lukastoenne Differential Revision: https://developer.blender.org/D94
2013-12-26 17:24:42 +06:00
ListBase *lb = object_duplilist(G.main->eval_ctx, shi->gpumat->scene, ob);
for (DupliObject *dob = lb->first; dob; dob = dob->next) {
Object *ob_iter = dob->ob;
if (ob_iter->type == OB_LAMP) {
float omat[4][4];
copy_m4_m4(omat, ob_iter->obmat);
copy_m4_m4(ob_iter->obmat, dob->mat);
GPULamp *lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob_iter, ob);
if (lamp)
shade_one_light(shi, shr, lamp);
copy_m4_m4(ob_iter->obmat, omat);
}
}
free_object_duplilist(lb);
}
}
/* prevent only shadow lamps from producing negative colors.*/
GPU_link(shi->gpumat, "shade_clamp_positive", shr->spec, &shr->spec);
GPU_link(shi->gpumat, "shade_clamp_positive", shr->diff, &shr->diff);
}
2016-01-10 07:12:10 +11:00
static void texture_rgb_blend(
GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg,
int blendtype, GPUNodeLink **in)
{
switch (blendtype) {
2016-01-10 07:12:10 +11:00
case MTEX_BLEND:
GPU_link(mat, "mtex_rgb_blend", out, tex, fact, facg, in);
break;
case MTEX_MUL:
GPU_link(mat, "mtex_rgb_mul", out, tex, fact, facg, in);
break;
case MTEX_SCREEN:
GPU_link(mat, "mtex_rgb_screen", out, tex, fact, facg, in);
break;
case MTEX_OVERLAY:
GPU_link(mat, "mtex_rgb_overlay", out, tex, fact, facg, in);
break;
case MTEX_SUB:
GPU_link(mat, "mtex_rgb_sub", out, tex, fact, facg, in);
break;
case MTEX_ADD:
GPU_link(mat, "mtex_rgb_add", out, tex, fact, facg, in);
break;
case MTEX_DIV:
GPU_link(mat, "mtex_rgb_div", out, tex, fact, facg, in);
break;
case MTEX_DIFF:
GPU_link(mat, "mtex_rgb_diff", out, tex, fact, facg, in);
break;
case MTEX_DARK:
GPU_link(mat, "mtex_rgb_dark", out, tex, fact, facg, in);
break;
case MTEX_LIGHT:
GPU_link(mat, "mtex_rgb_light", out, tex, fact, facg, in);
break;
case MTEX_BLEND_HUE:
GPU_link(mat, "mtex_rgb_hue", out, tex, fact, facg, in);
break;
case MTEX_BLEND_SAT:
GPU_link(mat, "mtex_rgb_sat", out, tex, fact, facg, in);
break;
case MTEX_BLEND_VAL:
GPU_link(mat, "mtex_rgb_val", out, tex, fact, facg, in);
break;
case MTEX_BLEND_COLOR:
GPU_link(mat, "mtex_rgb_color", out, tex, fact, facg, in);
break;
case MTEX_SOFT_LIGHT:
GPU_link(mat, "mtex_rgb_soft", out, tex, fact, facg, in);
break;
case MTEX_LIN_LIGHT:
GPU_link(mat, "mtex_rgb_linear", out, tex, fact, facg, in);
break;
default:
GPU_link(mat, "set_rgb_zero", &in);
break;
}
}
2016-01-10 07:12:10 +11:00
static void texture_value_blend(
GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg,
int blendtype, GPUNodeLink **in)
{
switch (blendtype) {
2016-01-10 07:12:10 +11:00
case MTEX_BLEND:
GPU_link(mat, "mtex_value_blend", out, tex, fact, facg, in);
break;
case MTEX_MUL:
GPU_link(mat, "mtex_value_mul", out, tex, fact, facg, in);
break;
case MTEX_SCREEN:
GPU_link(mat, "mtex_value_screen", out, tex, fact, facg, in);
break;
case MTEX_SUB:
GPU_link(mat, "mtex_value_sub", out, tex, fact, facg, in);
break;
case MTEX_ADD:
GPU_link(mat, "mtex_value_add", out, tex, fact, facg, in);
break;
case MTEX_DIV:
GPU_link(mat, "mtex_value_div", out, tex, fact, facg, in);
break;
case MTEX_DIFF:
GPU_link(mat, "mtex_value_diff", out, tex, fact, facg, in);
break;
case MTEX_DARK:
GPU_link(mat, "mtex_value_dark", out, tex, fact, facg, in);
break;
case MTEX_LIGHT:
GPU_link(mat, "mtex_value_light", out, tex, fact, facg, in);
break;
default:
GPU_link(mat, "set_value_zero", &in);
break;
}
}
static void do_material_tex(GPUShadeInput *shi)
{
Material *ma = shi->mat;
GPUMaterial *mat = shi->gpumat;
MTex *mtex;
Tex *tex;
GPUNodeLink *texco, *tin, *trgb, *tnor, *tcol, *stencil, *tnorfac;
GPUNodeLink *texco_norm, *texco_orco, *texco_object;
GPUNodeLink *texco_global, *texco_uv = NULL;
GPUNodeLink *newnor, *orn;
2016-01-08 16:42:47 +11:00
float one = 1.0f;
int rgbnor, talpha;
bool init_done = false;
int iBumpSpacePrev = 0; /* Not necessary, quieting gcc warning. */
GPUNodeLink *vNorg, *vNacc, *fPrevMagnitude;
int iFirstTimeNMap = 1;
bool found_deriv_map = false;
GPU_link(mat, "set_value", GPU_uniform(&one), &stencil);
GPU_link(mat, "texco_norm", GPU_builtin(GPU_VIEW_NORMAL), &texco_norm);
GPU_link(mat, "texco_orco", GPU_attribute(CD_ORCO, ""), &texco_orco);
GPU_link(mat, "texco_object", GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
GPU_builtin(GPU_VIEW_POSITION), &texco_object);
#if 0
GPU_link(mat, "texco_tangent", GPU_attribute(CD_TANGENT, ""), &texco_tangent);
#endif
GPU_link(mat, "texco_global", GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
GPU_builtin(GPU_VIEW_POSITION), &texco_global);
orn = texco_norm;
/* go over texture slots */
for (int tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) {
/* separate tex switching */
if (ma->septex & (1 << tex_nr)) continue;
if (ma->mtex[tex_nr]) {
mtex = ma->mtex[tex_nr];
tex = mtex->tex;
if (tex == NULL) continue;
/* which coords */
if (mtex->texco == TEXCO_ORCO)
texco = texco_orco;
else if (mtex->texco == TEXCO_OBJECT)
texco = texco_object;
else if (mtex->texco == TEXCO_NORM)
texco = orn;
else if (mtex->texco == TEXCO_TANGENT)
texco = texco_object;
else if (mtex->texco == TEXCO_GLOB)
texco = texco_global;
else if (mtex->texco == TEXCO_REFL) {
GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref);
texco = shi->ref;
}
else if (mtex->texco == TEXCO_UV) {
if (1) { //!(texco_uv && strcmp(mtex->uvname, lastuvname) == 0)) {
GPU_link(mat, "texco_uv", GPU_attribute(CD_MTFACE, mtex->uvname), &texco_uv);
/*lastuvname = mtex->uvname;*/ /*UNUSED*/
}
texco = texco_uv;
}
else
continue;
/* in case of uv, this would just undo a multiplication in texco_uv */
if (mtex->texco != TEXCO_UV)
GPU_link(mat, "mtex_2d_mapping", texco, &texco);
if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f)
GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(mtex->size), &texco);
2016-01-08 16:42:47 +11:00
float ofs[3] = {
mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0],
mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1],
0.0f
};
if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f)
GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco);
talpha = 0;
if (tex && tex->ima &&
((tex->type == TEX_IMAGE) ||
((tex->type == TEX_ENVMAP) && (mtex->texco == TEXCO_REFL))))
{
if (tex->type == TEX_IMAGE) {
GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb);
}
else {
GPU_link(mat, "mtex_cube_map_refl",
GPU_cube_map(tex->ima, &tex->iuser, false), shi->view, shi->vn,
GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
GPU_builtin(GPU_VIEW_MATRIX), &tin, &trgb);
}
rgbnor = TEX_RGB;
talpha = ((tex->imaflag & TEX_USEALPHA) && tex->ima && (tex->ima->flag & IMA_IGNORE_ALPHA) == 0);
}
2012-07-07 22:51:57 +00:00
else {
continue;
}
/* texture output */
if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
GPU_link(mat, "mtex_rgbtoint", trgb, &tin);
rgbnor -= TEX_RGB;
}
if (mtex->texflag & MTEX_NEGATIVE) {
if (rgbnor & TEX_RGB)
GPU_link(mat, "mtex_rgb_invert", trgb, &trgb);
else
GPU_link(mat, "mtex_value_invert", tin, &tin);
}
if (mtex->texflag & MTEX_STENCIL) {
if (rgbnor & TEX_RGB)
GPU_link(mat, "mtex_rgb_stencil", stencil, trgb, &stencil, &trgb);
else
GPU_link(mat, "mtex_value_stencil", stencil, tin, &stencil, &tin);
}
/* mapping */
if (mtex->mapto & (MAP_COL | MAP_COLSPEC | MAP_COLMIR)) {
/* stencil maps on the texture control slider, not texture intensity value */
2016-01-10 07:12:10 +11:00
if ((rgbnor & TEX_RGB) == 0) {
GPU_link(mat, "set_rgb", GPU_uniform(&mtex->r), &tcol);
}
else {
GPU_link(mat, "set_rgba", trgb, &tcol);
if (mtex->mapto & MAP_ALPHA)
GPU_link(mat, "set_value", stencil, &tin);
else if (talpha)
GPU_link(mat, "mtex_alpha_from_col", trgb, &tin);
else
GPU_link(mat, "set_value_one", &tin);
}
if ((tex->type == TEX_IMAGE) ||
((tex->type == TEX_ENVMAP) && (mtex->texco == TEXCO_REFL)))
{
if (GPU_material_do_color_management(mat)) {
GPU_link(mat, "srgb_to_linearrgb", tcol, &tcol);
}
}
if (mtex->mapto & MAP_COL) {
GPUNodeLink *colfac;
if (mtex->colfac == 1.0f) colfac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->colfac), stencil, &colfac);
texture_rgb_blend(mat, tcol, shi->rgb, tin, colfac, mtex->blendtype, &shi->rgb);
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && (mtex->mapto & MAP_COLSPEC)) {
GPUNodeLink *colspecfac;
if (mtex->colspecfac == 1.0f) colspecfac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->colspecfac), stencil, &colspecfac);
texture_rgb_blend(mat, tcol, shi->specrgb, tin, colspecfac, mtex->blendtype, &shi->specrgb);
}
2016-03-23 04:47:16 +11:00
if (mtex->mapto & MAP_COLMIR) {
GPUNodeLink *colmirfac;
if (mtex->mirrfac == 1.0f) colmirfac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->mirrfac), stencil, &colmirfac);
/* exception for envmap only */
if (tex->type == TEX_ENVMAP && mtex->blendtype == MTEX_BLEND) {
GPU_link(mat, "mtex_mirror", tcol, shi->refcol, tin, colmirfac, &shi->refcol);
}
else
texture_rgb_blend(mat, tcol, shi->mir, tin, colmirfac, mtex->blendtype, &shi->mir);
}
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && (mtex->mapto & MAP_NORM)) {
if (tex->type == TEX_IMAGE) {
found_deriv_map = tex->imaflag & TEX_DERIVATIVEMAP;
if (tex->imaflag & TEX_NORMALMAP) {
/* normalmap image */
GPU_link(mat, "mtex_normal", texco, GPU_image(tex->ima, &tex->iuser, true), &tnor);
if (mtex->norfac < 0.0f)
GPU_link(mat, "mtex_negate_texnormal", tnor, &tnor);
2012-03-07 04:53:43 +00:00
if (mtex->normapspace == MTEX_NSPACE_TANGENT) {
if (iFirstTimeNMap != 0) {
// use unnormalized normal (this is how we bake it - closer to gamedev)
GPUNodeLink *vNegNorm;
2016-01-10 07:12:10 +11:00
GPU_link(mat, "vec_math_negate",
GPU_builtin(GPU_VIEW_NORMAL), &vNegNorm);
GPU_link(mat, "mtex_nspace_tangent",
GPU_attribute(CD_TANGENT, ""), vNegNorm, tnor, &newnor);
iFirstTimeNMap = 0;
}
2012-03-07 04:53:43 +00:00
else { /* otherwise use accumulated perturbations */
2016-01-10 07:12:10 +11:00
GPU_link(mat, "mtex_nspace_tangent",
GPU_attribute(CD_TANGENT, ""), shi->vn, tnor, &newnor);
}
}
else if (mtex->normapspace == MTEX_NSPACE_OBJECT) {
/* transform normal by object then view matrix */
GPU_link(mat, "mtex_nspace_object", tnor, &newnor);
}
else if (mtex->normapspace == MTEX_NSPACE_WORLD) {
/* transform normal by view matrix */
GPU_link(mat, "mtex_nspace_world", GPU_builtin(GPU_VIEW_MATRIX), tnor, &newnor);
}
2012-03-07 04:53:43 +00:00
else {
/* no transform, normal in camera space */
newnor = tnor;
2012-03-07 04:53:43 +00:00
}
float norfac = min_ff(fabsf(mtex->norfac), 1.0f);
if (norfac == 1.0f && !GPU_link_changed(stencil)) {
shi->vn = newnor;
}
else {
tnorfac = GPU_uniform(&norfac);
if (GPU_link_changed(stencil))
GPU_link(mat, "math_multiply", tnorfac, stencil, &tnorfac);
GPU_link(mat, "mtex_blend_normal", tnorfac, shi->vn, newnor, &shi->vn);
}
2012-03-07 04:53:43 +00:00
}
2016-01-10 07:12:10 +11:00
else if (found_deriv_map ||
(mtex->texflag & (MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)))
{
/* ntap bumpmap image */
int iBumpSpace;
float ima_x, ima_y;
float imag_tspace_dimension_x = 1024.0f; /* only used for texture space variant */
float aspect = 1.0f;
GPUNodeLink *vR1, *vR2;
GPUNodeLink *dBs, *dBt, *fDet;
2011-12-09 23:26:06 +00:00
float hScale = 0.1f; /* compatibility adjustment factor for all bumpspace types */
if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
hScale = 13.0f; /* factor for scaling texspace bumps */
else if (found_deriv_map)
2011-12-09 23:26:06 +00:00
hScale = 1.0f;
/* resolve texture resolution */
if ((mtex->texflag & MTEX_BUMP_TEXTURESPACE) || found_deriv_map) {
ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
ima_x = 512.0f; ima_y = 512.0f; /* prevent calling textureSize, glsl 1.3 only */
if (ibuf) {
ima_x = ibuf->x;
ima_y = ibuf->y;
aspect = (float)ima_y / ima_x;
2011-12-09 23:26:06 +00:00
}
BKE_image_release_ibuf(tex->ima, ibuf, NULL);
2011-12-09 23:26:06 +00:00
}
/* The negate on norfac is done because the
* normal in the renderer points inward which corresponds
* to inverting the bump map. Should this ever change
* this negate must be removed. */
float norfac = -hScale * mtex->norfac;
2012-03-07 04:53:43 +00:00
if (found_deriv_map) {
float fVirtDim = sqrtf(fabsf(ima_x * mtex->size[0] * ima_y * mtex->size[1]));
norfac /= MAX2(fVirtDim, FLT_EPSILON);
}
2011-12-09 23:26:06 +00:00
tnorfac = GPU_uniform(&norfac);
2011-12-09 23:26:06 +00:00
if (found_deriv_map)
2011-12-09 23:26:06 +00:00
GPU_link(mat, "math_multiply", tnorfac, GPU_builtin(GPU_AUTO_BUMPSCALE), &tnorfac);
if (GPU_link_changed(stencil))
GPU_link(mat, "math_multiply", tnorfac, stencil, &tnorfac);
if (!init_done) {
/* copy shi->vn to vNorg and vNacc, set magnitude to 1 */
GPU_link(mat, "mtex_bump_normals_init", shi->vn, &vNorg, &vNacc, &fPrevMagnitude);
iBumpSpacePrev = 0;
init_done = true;
}
// find current bump space
if (mtex->texflag & MTEX_BUMP_OBJECTSPACE)
iBumpSpace = 1;
else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
iBumpSpace = 2;
else
iBumpSpace = 4; /* ViewSpace */
/* re-initialize if bump space changed */
if (iBumpSpacePrev != iBumpSpace) {
GPUNodeLink *surf_pos = GPU_builtin(GPU_VIEW_POSITION);
if (mtex->texflag & MTEX_BUMP_OBJECTSPACE)
GPU_link(mat, "mtex_bump_init_objspace",
surf_pos, vNorg,
2016-01-10 07:12:10 +11:00
GPU_builtin(GPU_VIEW_MATRIX),
GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
GPU_builtin(GPU_OBJECT_MATRIX),
GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
fPrevMagnitude, vNacc,
&fPrevMagnitude, &vNacc,
&vR1, &vR2, &fDet);
else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
GPU_link(mat, "mtex_bump_init_texturespace",
surf_pos, vNorg,
fPrevMagnitude, vNacc,
&fPrevMagnitude, &vNacc,
&vR1, &vR2, &fDet);
else
GPU_link(mat, "mtex_bump_init_viewspace",
surf_pos, vNorg,
fPrevMagnitude, vNacc,
&fPrevMagnitude, &vNacc,
&vR1, &vR2, &fDet);
iBumpSpacePrev = iBumpSpace;
}
if (found_deriv_map) {
GPU_link(mat, "mtex_bump_deriv",
2016-01-10 07:12:10 +11:00
texco, GPU_image(tex->ima, &tex->iuser, true),
GPU_uniform(&ima_x), GPU_uniform(&ima_y), tnorfac,
&dBs, &dBt);
}
else if (mtex->texflag & MTEX_3TAP_BUMP)
GPU_link(mat, "mtex_bump_tap3",
texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
&dBs, &dBt);
else if (mtex->texflag & MTEX_5TAP_BUMP)
GPU_link(mat, "mtex_bump_tap5",
texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
&dBs, &dBt);
else if (mtex->texflag & MTEX_BICUBIC_BUMP) {
if (GPU_bicubic_bump_support()) {
GPU_link(mat, "mtex_bump_bicubic",
texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
&dBs, &dBt);
}
else {
GPU_link(mat, "mtex_bump_tap5",
texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
&dBs, &dBt);
}
}
if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) {
float imag_tspace_dimension_y = aspect * imag_tspace_dimension_x;
GPU_link(mat, "mtex_bump_apply_texspace",
fDet, dBs, dBt, vR1, vR2,
GPU_image(tex->ima, &tex->iuser, true), texco,
2016-01-10 07:12:10 +11:00
GPU_uniform(&imag_tspace_dimension_x),
GPU_uniform(&imag_tspace_dimension_y), vNacc,
&vNacc, &shi->vn);
}
else
GPU_link(mat, "mtex_bump_apply",
fDet, dBs, dBt, vR1, vR2, vNacc,
&vNacc, &shi->vn);
}
}
GPU_link(mat, "vec_math_negate", shi->vn, &orn);
}
if ((mtex->mapto & MAP_VARS)) {
if (rgbnor & TEX_RGB) {
if (talpha)
GPU_link(mat, "mtex_alpha_from_col", trgb, &tin);
else
GPU_link(mat, "mtex_rgbtoint", trgb, &tin);
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_REF) {
GPUNodeLink *difffac;
if (mtex->difffac == 1.0f) difffac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->difffac), stencil, &difffac);
2016-01-10 07:12:10 +11:00
texture_value_blend(
mat, GPU_uniform(&mtex->def_var), shi->refl, tin, difffac,
mtex->blendtype, &shi->refl);
GPU_link(mat, "mtex_value_clamp_positive", shi->refl, &shi->refl);
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_SPEC) {
GPUNodeLink *specfac;
if (mtex->specfac == 1.0f) specfac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->specfac), stencil, &specfac);
2016-01-10 07:12:10 +11:00
texture_value_blend(
mat, GPU_uniform(&mtex->def_var), shi->spec, tin, specfac,
mtex->blendtype, &shi->spec);
GPU_link(mat, "mtex_value_clamp_positive", shi->spec, &shi->spec);
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_EMIT) {
GPUNodeLink *emitfac;
if (mtex->emitfac == 1.0f) emitfac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->emitfac), stencil, &emitfac);
2016-01-10 07:12:10 +11:00
texture_value_blend(
mat, GPU_uniform(&mtex->def_var), shi->emit, tin, emitfac,
mtex->blendtype, &shi->emit);
GPU_link(mat, "mtex_value_clamp_positive", shi->emit, &shi->emit);
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_HAR) {
GPUNodeLink *hardfac;
if (mtex->hardfac == 1.0f) hardfac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->hardfac), stencil, &hardfac);
GPU_link(mat, "mtex_har_divide", shi->har, &shi->har);
2016-01-10 07:12:10 +11:00
texture_value_blend(
mat, GPU_uniform(&mtex->def_var), shi->har, tin, hardfac,
mtex->blendtype, &shi->har);
GPU_link(mat, "mtex_har_multiply_clamp", shi->har, &shi->har);
}
if (mtex->mapto & MAP_ALPHA) {
GPUNodeLink *alphafac;
if (mtex->alphafac == 1.0f) alphafac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->alphafac), stencil, &alphafac);
2016-01-10 07:12:10 +11:00
texture_value_blend(
mat, GPU_uniform(&mtex->def_var), shi->alpha, tin, alphafac,
mtex->blendtype, &shi->alpha);
GPU_link(mat, "mtex_value_clamp", shi->alpha, &shi->alpha);
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_AMB) {
GPUNodeLink *ambfac;
if (mtex->ambfac == 1.0f) ambfac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->ambfac), stencil, &ambfac);
2016-01-10 07:12:10 +11:00
texture_value_blend(
mat, GPU_uniform(&mtex->def_var), shi->amb, tin, ambfac,
mtex->blendtype, &shi->amb);
GPU_link(mat, "mtex_value_clamp", shi->amb, &shi->amb);
}
}
}
}
}
void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
{
float one = 1.0f;
memset(shi, 0, sizeof(*shi));
shi->gpumat = mat;
shi->mat = ma;
GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, ma), &shi->rgb);
GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, ma), &shi->specrgb);
GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->mirr, GPU_DYNAMIC_MAT_MIR, ma), &shi->mir);
GPU_link(mat, "set_rgba_zero", &shi->refcol);
GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &shi->vn);
if (mat->alpha)
GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, ma), &shi->alpha);
else
GPU_link(mat, "set_value", GPU_uniform(&one), &shi->alpha);
GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, ma), &shi->refl);
GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, ma), &shi->spec);
GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, ma), &shi->emit);
GPU_link(mat, "set_value", GPU_dynamic_uniform((float *)&ma->har, GPU_DYNAMIC_MAT_HARD, ma), &shi->har);
GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, ma), &shi->amb);
GPU_link(mat, "set_value", GPU_uniform(&ma->spectra), &shi->spectra);
GPU_link(mat, "shade_view", GPU_builtin(GPU_VIEW_POSITION), &shi->view);
GPU_link(mat, "vcol_attribute", GPU_attribute(CD_MCOL, ""), &shi->vcol);
if (GPU_material_do_color_management(mat))
GPU_link(mat, "srgb_to_linearrgb", shi->vcol, &shi->vcol);
GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref);
}
void GPU_mist_update_enable(short enable)
{
GPUWorld.mistenabled = (float)enable;
}
void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3])
{
GPUWorld.mistype = (float)type;
GPUWorld.miststart = start;
GPUWorld.mistdistance = dist;
GPUWorld.mistintensity = inten;
copy_v3_v3(GPUWorld.mistcol, color);
GPUWorld.mistcol[3] = 1.0f;
}
void GPU_horizon_update_color(float color[3])
{
copy_v3_v3(GPUWorld.horicol, color);
}
void GPU_ambient_update_color(float color[3])
{
copy_v3_v3(GPUWorld.ambcol, color);
GPUWorld.ambcol[3] = 1.0f;
}
void GPU_zenith_update_color(float color[3])
{
copy_v3_v3(GPUWorld.zencol, color);
}
void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
{
GPUMaterial *mat = shi->gpumat;
GPUNodeLink *emit, *ulinfac, *ulogfac, *mistfac;
Material *ma = shi->mat;
World *world = mat->scene->world;
float linfac, logfac;
memset(shr, 0, sizeof(*shr));
if (ma->mode & MA_VERTEXCOLP)
shi->rgb = shi->vcol;
do_material_tex(shi);
if ((mat->scene->gm.flag & GAME_GLSL_NO_LIGHTS) || (ma->mode & MA_SHLESS)) {
GPU_link(mat, "set_rgb", shi->rgb, &shr->diff);
GPU_link(mat, "set_rgb_zero", &shr->spec);
GPU_link(mat, "set_value", shi->alpha, &shr->alpha);
shr->combined = shr->diff;
}
else {
if (GPU_link_changed(shi->emit) || ma->emit != 0.0f) {
2016-01-10 07:12:10 +11:00
if ((ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == MA_VERTEXCOL) {
GPU_link(mat, "shade_add", shi->emit, shi->vcol, &emit);
GPU_link(mat, "shade_mul", emit, shi->rgb, &shr->diff);
}
else
GPU_link(mat, "shade_mul_value", shi->emit, shi->rgb, &shr->diff);
}
else
GPU_link(mat, "set_rgb_zero", &shr->diff);
GPU_link(mat, "set_rgb_zero", &shr->spec);
material_lights(shi, shr);
shr->combined = shr->diff;
GPU_link(mat, "set_value", shi->alpha, &shr->alpha);
if (world) {
/* exposure correction */
if (world->exp != 0.0f || world->range != 1.0f) {
linfac = 1.0f + powf((2.0f * world->exp + 0.5f), -10);
logfac = logf((linfac - 1.0f) / linfac) / world->range;
GPU_link(mat, "set_value", GPU_uniform(&linfac), &ulinfac);
GPU_link(mat, "set_value", GPU_uniform(&logfac), &ulogfac);
GPU_link(mat, "shade_exposure_correct", shr->combined,
ulinfac, ulogfac, &shr->combined);
GPU_link(mat, "shade_exposure_correct", shr->spec,
ulinfac, ulogfac, &shr->spec);
}
/* environment lighting */
2016-07-08 00:48:03 +10:00
if (!(mat->scene->gm.flag & GAME_GLSL_NO_ENV_LIGHTING) &&
(world->mode & WO_ENV_LIGHT) &&
(mat->scene->r.mode & R_SHADOW) &&
!BKE_scene_use_new_shading_nodes(mat->scene))
{
if ((world->ao_env_energy != 0.0f) && (GPU_link_changed(shi->amb) || ma->amb != 0.0f) &&
2016-07-08 00:48:03 +10:00
(GPU_link_changed(shi->refl) || ma->ref != 0.0f))
{
if (world->aocolor != WO_AOPLAIN) {
2016-07-14 13:37:49 +10:00
if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr))) {
GPUNodeLink *fcol, *f;
GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f);
GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f);
GPU_link(mat, "shade_mul_value", f, shi->rgb, &fcol);
2016-07-08 00:48:03 +10:00
GPU_link(mat, "env_apply", shr->combined,
GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL),
GPU_dynamic_uniform(GPUWorld.zencol, GPU_DYNAMIC_ZENITH_COLOR, NULL), fcol,
GPU_builtin(GPU_VIEW_MATRIX), shi->vn, &shr->combined);
}
}
else {
GPUNodeLink *f;
GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f);
GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f);
GPU_link(mat, "shade_maddf", shr->combined, f, shi->rgb, &shr->combined);
}
}
}
/* ambient color */
if (GPU_link_changed(shi->amb) || ma->amb != 0.0f) {
GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb),
GPU_dynamic_uniform(GPUWorld.ambcol, GPU_DYNAMIC_AMBIENT_COLOR, NULL),
&shr->combined);
}
}
2016-01-10 07:12:10 +11:00
if (ma->mode & MA_TRANSP && (ma->mode & (MA_ZTRANSP | MA_RAYTRANSP))) {
if (GPU_link_changed(shi->spectra) || ma->spectra != 0.0f) {
GPU_link(mat, "alpha_spec_correction", shr->spec, shi->spectra,
2016-01-10 07:12:10 +11:00
shi->alpha, &shr->alpha);
}
}
if (ma->mode & MA_RAMP_COL) ramp_diffuse_result(shi, &shr->combined);
if (ma->mode & MA_RAMP_SPEC) ramp_spec_result(shi, &shr->spec);
if (GPU_link_changed(shi->refcol))
GPU_link(mat, "shade_add_mirror", shi->mir, shi->refcol, shr->combined, &shr->combined);
if (GPU_link_changed(shi->spec) || ma->spec != 0.0f)
GPU_link(mat, "shade_add", shr->combined, shr->spec, &shr->combined);
}
GPU_link(mat, "mtex_alpha_to_col", shr->combined, shr->alpha, &shr->combined);
if (ma->shade_flag & MA_OBCOLOR)
GPU_link(mat, "shade_obcolor", shr->combined, GPU_builtin(GPU_OBCOLOR), &shr->combined);
if (!(ma->mode & MA_NOMIST)) {
GPU_link(mat, "shade_mist_factor", GPU_builtin(GPU_VIEW_POSITION),
GPU_dynamic_uniform(&GPUWorld.mistenabled, GPU_DYNAMIC_MIST_ENABLE, NULL),
GPU_dynamic_uniform(&GPUWorld.miststart, GPU_DYNAMIC_MIST_START, NULL),
GPU_dynamic_uniform(&GPUWorld.mistdistance, GPU_DYNAMIC_MIST_DISTANCE, NULL),
GPU_dynamic_uniform(&GPUWorld.mistype, GPU_DYNAMIC_MIST_TYPE, NULL),
GPU_dynamic_uniform(&GPUWorld.mistintensity, GPU_DYNAMIC_MIST_INTENSITY, NULL), &mistfac);
GPU_link(mat, "mix_blend", mistfac, shr->combined,
GPU_dynamic_uniform(GPUWorld.mistcol, GPU_DYNAMIC_MIST_COLOR, NULL), &shr->combined);
}
if (!mat->alpha) {
if (world && (GPU_link_changed(shr->alpha) || ma->alpha != 1.0f))
GPU_link(mat, "shade_world_mix", GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL),
shr->combined, &shr->combined);
GPU_link(mat, "shade_alpha_opaque", shr->combined, &shr->combined);
}
if (ma->shade_flag & MA_OBCOLOR) {
mat->obcolalpha = 1;
GPU_link(mat, "shade_alpha_obcolor", shr->combined, GPU_builtin(GPU_OBCOLOR), &shr->combined);
}
}
static GPUNodeLink *GPU_blender_material(GPUMaterial *mat, Material *ma)
{
GPUShadeInput shi;
GPUShadeResult shr;
GPU_shadeinput_set(mat, ma, &shi);
GPU_shaderesult_set(&shi, &shr);
return shr.combined;
}
static GPUNodeLink *gpu_material_diffuse_bsdf(GPUMaterial *mat, Material *ma)
{
static float roughness = 0.0f;
GPUNodeLink *outlink;
2016-01-10 07:12:10 +11:00
GPU_link(mat, "node_bsdf_diffuse",
GPU_uniform(&ma->r), GPU_uniform(&roughness), GPU_builtin(GPU_VIEW_NORMAL), &outlink);
return outlink;
}
static GPUNodeLink *gpu_material_preview_matcap(GPUMaterial *mat, Material *ma)
{
GPUNodeLink *outlink;
/* some explanations here:
* matcap normal holds the normal remapped to the 0.0 - 1.0 range. To take advantage of flat shading, we abuse
* the built in secondary color of opengl. Color is just the regular color, which should include mask value too.
* This also needs flat shading so we use the primary opengl color built-in */
2016-01-10 07:12:10 +11:00
GPU_link(mat, "material_preview_matcap", GPU_uniform(&ma->r), GPU_image_preview(ma->preview),
GPU_opengl_builtin(GPU_MATCAP_NORMAL), GPU_opengl_builtin(GPU_COLOR), &outlink);
return outlink;
}
/* new solid draw mode with glsl matcaps */
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv)
{
GPUMaterial *mat;
GPUNodeLink *outlink;
LinkData *link;
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
for (link = ma->gpumaterial.first; link; link = link->next) {
2016-01-10 07:12:10 +11:00
GPUMaterial *current_material = (GPUMaterial *)link->data;
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
if (current_material->scene == scene &&
current_material->is_opensubdiv == use_opensubdiv)
{
return current_material;
}
}
/* allocate material */
mat = GPU_material_construct_begin(ma);
mat->scene = scene;
mat->type = GPU_MATERIAL_TYPE_MESH;
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
mat->is_opensubdiv = use_opensubdiv;
if (ma->preview && ma->preview->rect[0]) {
outlink = gpu_material_preview_matcap(mat, ma);
}
else {
outlink = gpu_material_diffuse_bsdf(mat, ma);
}
GPU_material_output_link(mat, outlink);
gpu_material_construct_end(mat, "matcap_pass");
/* note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simple do not use
* the actual shader on drawing */
link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
link->data = mat;
BLI_addtail(&ma->gpumaterial, link);
return mat;
}
static void do_world_tex(GPUShadeInput *shi, struct World *wo, GPUNodeLink **hor, GPUNodeLink **zen, GPUNodeLink **blend)
{
GPUMaterial *mat = shi->gpumat;
GPUNodeLink *texco, *tin, *trgb, *stencil, *tcol, *zenfac;
MTex *mtex;
Tex *tex;
float ofs[3], zero = 0.0f;
int tex_nr, rgbnor;
GPU_link(mat, "set_value_one", &stencil);
/* go over texture slots */
for (tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) {
if (wo->mtex[tex_nr]) {
mtex = wo->mtex[tex_nr];
tex = mtex->tex;
if (tex == NULL || !tex->ima || (tex->type != TEX_IMAGE && tex->type != TEX_ENVMAP))
continue;
/* which coords */
if (mtex->texco == TEXCO_VIEW || mtex->texco == TEXCO_GLOB) {
if (tex->type == TEX_IMAGE)
texco = GPU_builtin(GPU_VIEW_POSITION);
else if (tex->type == TEX_ENVMAP)
GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &texco);
}
else if (mtex->texco == TEXCO_EQUIRECTMAP || mtex->texco == TEXCO_ANGMAP) {
if ((tex->type == TEX_IMAGE && wo->skytype & WO_SKYREAL) || tex->type == TEX_ENVMAP)
GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &texco);
else
texco = GPU_builtin(GPU_VIEW_POSITION);
}
else
continue;
GPU_link(mat, "texco_norm", texco, &texco);
if (tex->type == TEX_IMAGE && !(wo->skytype & WO_SKYREAL)) {
GPU_link(mat, "mtex_2d_mapping", texco, &texco);
}
if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f) {
float size[3] = { mtex->size[0], mtex->size[1], mtex->size[2] };
if (tex->type == TEX_ENVMAP) {
size[1] = mtex->size[2];
size[2] = mtex->size[1];
}
GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(size), &texco);
}
ofs[0] = mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0];
if (tex->type == TEX_ENVMAP) {
ofs[1] = -mtex->ofs[2] + 0.5f - 0.5f * mtex->size[2];
ofs[2] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1];
}
else {
ofs[1] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1];
ofs[2] = 0.0;
}
if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f)
GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco);
if (mtex->texco == TEXCO_EQUIRECTMAP) {
GPU_link(mat, "node_tex_environment_equirectangular", texco, GPU_image(tex->ima, &tex->iuser, false), &trgb);
}
else if (mtex->texco == TEXCO_ANGMAP) {
GPU_link(mat, "node_tex_environment_mirror_ball", texco, GPU_image(tex->ima, &tex->iuser, false), &trgb);
}
else {
if (tex->type == TEX_ENVMAP)
GPU_link(mat, "mtex_cube_map", texco, GPU_cube_map(tex->ima, &tex->iuser, false), &tin, &trgb);
else if (tex->type == TEX_IMAGE)
GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb);
}
rgbnor = TEX_RGB;
if (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP)
if (GPU_material_do_color_management(mat))
GPU_link(mat, "srgb_to_linearrgb", trgb, &trgb);
/* texture output */
if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
GPU_link(mat, "mtex_rgbtoint", trgb, &tin);
rgbnor -= TEX_RGB;
}
if (mtex->texflag & MTEX_NEGATIVE) {
if (rgbnor & TEX_RGB)
GPU_link(mat, "mtex_rgb_invert", trgb, &trgb);
else
GPU_link(mat, "mtex_value_invert", tin, &tin);
}
if (mtex->texflag & MTEX_STENCIL) {
if (rgbnor & TEX_RGB)
GPU_link(mat, "mtex_rgb_stencil", stencil, trgb, &stencil, &trgb);
else
GPU_link(mat, "mtex_value_stencil", stencil, tin, &stencil, &tin);
}
else {
if (rgbnor & TEX_RGB)
GPU_link(mat, "mtex_alpha_multiply_value", trgb, stencil, &trgb);
else
GPU_link(mat, "math_multiply", stencil, tin, &tin);
}
/* color mapping */
if (mtex->mapto & (WOMAP_HORIZ + WOMAP_ZENUP + WOMAP_ZENDOWN)) {
if ((rgbnor & TEX_RGB) == 0)
GPU_link(mat, "set_rgb", GPU_uniform(&mtex->r), &trgb);
else
GPU_link(mat, "mtex_alpha_from_col", trgb, &tin);
GPU_link(mat, "set_rgb", trgb, &tcol);
if (mtex->mapto & WOMAP_HORIZ) {
texture_rgb_blend(mat, tcol, *hor, tin, GPU_uniform(&mtex->colfac), mtex->blendtype, hor);
}
if (mtex->mapto & (WOMAP_ZENUP + WOMAP_ZENDOWN)) {
GPU_link(mat, "set_value_zero", &zenfac);
if (wo->skytype & WO_SKYREAL) {
if (mtex->mapto & WOMAP_ZENUP) {
if (mtex->mapto & WOMAP_ZENDOWN) {
GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&mtex->zenupfac),
2016-01-28 17:23:12 +11:00
GPU_uniform(&mtex->zendownfac), &zenfac);
}
else {
GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&mtex->zenupfac),
2016-01-28 17:23:12 +11:00
GPU_uniform(&zero), &zenfac);
}
}
2016-01-28 17:23:12 +11:00
else if (mtex->mapto & WOMAP_ZENDOWN) {
GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&zero),
2016-01-28 17:23:12 +11:00
GPU_uniform(&mtex->zendownfac), &zenfac);
}
}
else {
if (mtex->mapto & WOMAP_ZENUP)
GPU_link(mat, "set_value", GPU_uniform(&mtex->zenupfac), &zenfac);
else if (mtex->mapto & WOMAP_ZENDOWN)
GPU_link(mat, "set_value", GPU_uniform(&mtex->zendownfac), &zenfac);
}
texture_rgb_blend(mat, tcol, *zen, tin, zenfac, mtex->blendtype, zen);
}
}
if (mtex->mapto & WOMAP_BLEND && wo->skytype & WO_SKYBLEND) {
if (rgbnor & TEX_RGB)
GPU_link(mat, "mtex_rgbtoint", trgb, &tin);
texture_value_blend(mat, GPU_uniform(&mtex->def_var), *blend, tin, GPU_uniform(&mtex->blendfac), mtex->blendtype, blend);
}
}
}
}
static void gpu_material_old_world(struct GPUMaterial *mat, struct World *wo)
{
GPUShadeInput shi;
GPUShadeResult shr;
GPUNodeLink *hor, *zen, *ray, *blend;
shi.gpumat = mat;
for (int i = 0; i < MAX_MTEX; i++) {
if (wo->mtex[i] && wo->mtex[i]->tex) {
wo->skytype |= WO_SKYTEX;
break;
}
}
if ((wo->skytype & (WO_SKYBLEND + WO_SKYTEX)) == 0) {
GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->horr, GPU_DYNAMIC_HORIZON_COLOR, NULL), &shr.combined);
}
else {
GPU_link(mat, "set_rgb_zero", &shi.rgb);
GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &ray);
if (wo->skytype & WO_SKYPAPER)
GPU_link(mat, "world_paper_view", GPU_builtin(GPU_VIEW_POSITION), &shi.view);
else
GPU_link(mat, "shade_view", ray, &shi.view);
if (wo->skytype & WO_SKYBLEND) {
if (wo->skytype & WO_SKYPAPER) {
if (wo->skytype & WO_SKYREAL)
GPU_link(mat, "world_blend_paper_real", GPU_builtin(GPU_VIEW_POSITION), &blend);
else
GPU_link(mat, "world_blend_paper", GPU_builtin(GPU_VIEW_POSITION), &blend);
}
else {
if (wo->skytype & WO_SKYREAL)
GPU_link(mat, "world_blend_real", ray, &blend);
else
GPU_link(mat, "world_blend", ray, &blend);
}
}
else {
GPU_link(mat, "set_value_zero", &blend);
}
GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->horr, GPU_DYNAMIC_HORIZON_COLOR, NULL), &hor);
GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->zenr, GPU_DYNAMIC_ZENITH_COLOR, NULL), &zen);
do_world_tex(&shi, wo, &hor, &zen, &blend);
if (wo->skytype & WO_SKYBLEND)
GPU_link(mat, "node_mix_shader", blend, hor, zen, &shi.rgb);
else
GPU_link(mat, "set_rgb", hor, &shi.rgb);
GPU_link(mat, "set_rgb", shi.rgb, &shr.combined);
}
GPU_material_output_link(mat, shr.combined);
}
GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
{
LinkData *link;
GPUMaterial *mat;
for (link = wo->gpumaterial.first; link; link = link->next)
2016-01-10 07:12:10 +11:00
if (((GPUMaterial *)link->data)->scene == scene)
return link->data;
/* allocate material */
mat = GPU_material_construct_begin(NULL);
mat->scene = scene;
mat->type = GPU_MATERIAL_TYPE_WORLD;
/* create nodes */
if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes) {
ntreeGPUMaterialNodes(wo->nodetree, mat, NODE_NEW_SHADING);
}
else {
gpu_material_old_world(mat, wo);
}
if (GPU_material_do_color_management(mat))
if (mat->outlink)
GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink);
gpu_material_construct_end(mat, wo->id.name);
/* note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simple do not use
* the actual shader on drawing */
link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
link->data = mat;
BLI_addtail(&wo->gpumaterial, link);
return mat;
}
GPUMaterial *GPU_material_from_nodetree_find(
ListBase *gpumaterials, const void *engine_type, int options)
{
for (LinkData *link = gpumaterials->first; link; link = link->next) {
GPUMaterial *current_material = (GPUMaterial *)link->data;
if (current_material->engine_type == engine_type &&
current_material->options == options)
{
return current_material;
}
}
return NULL;
}
/**
* TODO: This is supposed to replace GPU_material_from_blender/_world in the future
*
* \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials,
* This is enforced since constructing other arguments to this function may be expensive
* so only do this when they are needed.
*/
GPUMaterial *GPU_material_from_nodetree(
Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options,
const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines)
{
GPUMaterial *mat;
GPUNodeLink *outlink;
LinkData *link;
/* Caller must re-use materials. */
BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
/* allocate material */
mat = GPU_material_construct_begin(NULL); /* TODO remove GPU_material_construct_begin */
mat->scene = scene;
mat->engine_type = engine_type;
mat->options = options;
ntreeGPUMaterialNodes(ntree, mat, NODE_NEWER_SHADING);
/* Let Draw manager finish the construction. */
if (mat->outlink) {
outlink = mat->outlink;
mat->pass = GPU_generate_pass_new(
&mat->nodes, outlink, &mat->attribs, vert_code, geom_code, frag_lib, defines);
}
/* note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simple do not use
* the actual shader on drawing */
link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
link->data = mat;
BLI_addtail(gpumaterials, link);
return mat;
}
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv)
{
GPUMaterial *mat;
GPUNodeLink *outlink;
LinkData *link;
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
for (link = ma->gpumaterial.first; link; link = link->next) {
2016-01-10 07:12:10 +11:00
GPUMaterial *current_material = (GPUMaterial *)link->data;
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
if (current_material->scene == scene &&
current_material->is_opensubdiv == use_opensubdiv)
{
return current_material;
}
}
/* allocate material */
mat = GPU_material_construct_begin(ma);
mat->scene = scene;
mat->type = GPU_MATERIAL_TYPE_MESH;
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
mat->is_opensubdiv = use_opensubdiv;
/* render pipeline option */
bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
if (!new_shading_nodes && (ma->mode & MA_TRANSP))
GPU_material_enable_alpha(mat);
else if (new_shading_nodes && ma->alpha < 1.0f)
GPU_material_enable_alpha(mat);
if (!(scene->gm.flag & GAME_GLSL_NO_NODES) && ma->nodetree && ma->use_nodes) {
/* create nodes */
if (new_shading_nodes)
ntreeGPUMaterialNodes(ma->nodetree, mat, NODE_NEW_SHADING);
else
ntreeGPUMaterialNodes(ma->nodetree, mat, NODE_OLD_SHADING);
}
else {
if (new_shading_nodes) {
/* create simple diffuse material instead of nodes */
outlink = gpu_material_diffuse_bsdf(mat, ma);
}
else {
/* create blender material */
outlink = GPU_blender_material(mat, ma);
}
GPU_material_output_link(mat, outlink);
}
if (GPU_material_do_color_management(mat))
if (mat->outlink)
GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink);
gpu_material_construct_end(mat, ma->id.name);
/* note that even if building the shader fails in some way, we still keep
2012-03-09 18:28:30 +00:00
* it to avoid trying to compile again and again, and simple do not use
* the actual shader on drawing */
link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
link->data = mat;
BLI_addtail(&ma->gpumaterial, link);
return mat;
}
void GPU_materials_free(void)
{
Object *ob;
Material *ma;
World *wo;
extern Material defmaterial;
for (ma = G.main->mat.first; ma; ma = ma->id.next)
GPU_material_free(&ma->gpumaterial);
for (wo = G.main->world.first; wo; wo = wo->id.next)
GPU_material_free(&wo->gpumaterial);
GPU_material_free(&defmaterial.gpumaterial);
for (ob = G.main->object.first; ob; ob = ob->id.next)
GPU_lamp_free(ob);
}
/* Lamps and shadow buffers */
2016-01-10 07:12:10 +11:00
GPUNodeLink *GPU_lamp_get_data(
GPUMaterial *mat, GPULamp *lamp,
GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy)
{
GPUNodeLink *visifac;
2016-01-10 07:12:10 +11:00
*r_col = GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob);
*r_energy = GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob);
visifac = lamp_get_visibility(mat, lamp, r_lv, r_dist);
2016-01-10 07:12:10 +11:00
shade_light_textures(mat, lamp, r_col);
if (GPU_lamp_has_shadow_buffer(lamp)) {
GPUNodeLink *vn, *inp;
GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &vn);
2016-01-10 07:12:10 +11:00
GPU_link(mat, "shade_inp", vn, *r_lv, &inp);
mat->dynproperty |= DYN_LAMP_PERSMAT;
if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
GPU_link(mat, "shadows_only_vsm",
2015-02-11 18:38:41 +11:00
GPU_builtin(GPU_VIEW_POSITION),
GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
2016-01-10 07:12:10 +11:00
GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
2015-02-11 18:38:41 +11:00
GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias),
2016-01-10 07:12:10 +11:00
GPU_uniform(lamp->shadow_color), inp, r_shadow);
}
else {
GPU_link(mat, "shadows_only",
2015-02-11 18:38:41 +11:00
GPU_builtin(GPU_VIEW_POSITION),
GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
2016-01-10 07:12:10 +11:00
GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
GPU_uniform(&lamp->bias), GPU_uniform(lamp->shadow_color), inp, r_shadow);
}
}
else {
2016-01-10 07:12:10 +11:00
GPU_link(mat, "set_rgb_one", r_shadow);
}
/* ensure shadow buffer and lamp textures will be updated */
add_user_list(&mat->lamps, lamp);
return visifac;
}
/* export the GLSL shader */
GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
{
static struct {
GPUBuiltin gputype;
GPUDynamicType dynamictype;
GPUDataType datatype;
} builtins[] = {
{ GPU_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_VIEWMAT, GPU_DATA_16F },
{ GPU_INVERSE_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_VIEWIMAT, GPU_DATA_16F },
{ GPU_OBJECT_MATRIX, GPU_DYNAMIC_OBJECT_MAT, GPU_DATA_16F },
{ GPU_INVERSE_OBJECT_MATRIX, GPU_DYNAMIC_OBJECT_IMAT, GPU_DATA_16F },
{ GPU_LOC_TO_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_LOCTOVIEWMAT, GPU_DATA_16F },
{ GPU_INVERSE_LOC_TO_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_LOCTOVIEWIMAT, GPU_DATA_16F },
{ GPU_OBCOLOR, GPU_DYNAMIC_OBJECT_COLOR, GPU_DATA_4F },
2011-12-09 23:26:06 +00:00
{ GPU_AUTO_BUMPSCALE, GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE, GPU_DATA_1F },
{ 0 }
};
GPUShaderExport *shader = NULL;
GPUInput *input;
int liblen, fraglen;
/* TODO(sergey): How to determine whether we need OSD or not here? */
GPUMaterial *mat = GPU_material_from_blender(scene, ma, false);
2016-01-10 07:12:10 +11:00
GPUPass *pass = (mat) ? mat->pass : NULL;
if (pass && pass->fragmentcode && pass->vertexcode) {
shader = MEM_callocN(sizeof(GPUShaderExport), "GPUShaderExport");
for (input = pass->inputs.first; input; input = input->next) {
GPUInputUniform *uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform");
if (input->ima) {
/* image sampler uniform */
uniform->type = GPU_DYNAMIC_SAMPLER_2DIMAGE;
uniform->datatype = GPU_DATA_1I;
uniform->image = input->ima;
uniform->texnumber = input->texid;
BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname));
}
else if (input->tex) {
/* generated buffer */
uniform->texnumber = input->texid;
uniform->datatype = GPU_DATA_1I;
BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname));
switch (input->textype) {
2016-01-10 07:12:10 +11:00
case GPU_SHADOW2D:
uniform->type = GPU_DYNAMIC_SAMPLER_2DSHADOW;
uniform->lamp = input->dynamicdata;
break;
case GPU_TEX2D:
if (GPU_texture_opengl_bindcode(input->tex)) {
uniform->type = GPU_DYNAMIC_SAMPLER_2DBUFFER;
glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(input->tex));
uniform->texsize = GPU_texture_width(input->tex) * GPU_texture_height(input->tex);
uniform->texpixels = MEM_mallocN(uniform->texsize * 4, "RGBApixels");
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, uniform->texpixels);
glBindTexture(GL_TEXTURE_2D, 0);
}
break;
case GPU_NONE:
case GPU_TEXCUBE:
2016-01-10 07:12:10 +11:00
case GPU_FLOAT:
case GPU_VEC2:
case GPU_VEC3:
case GPU_VEC4:
case GPU_MAT3:
case GPU_MAT4:
case GPU_CLOSURE:
2016-01-10 07:12:10 +11:00
case GPU_ATTRIB:
break;
}
}
else {
uniform->type = input->dynamictype;
BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname));
switch (input->type) {
2016-01-10 07:12:10 +11:00
case GPU_FLOAT:
uniform->datatype = GPU_DATA_1F;
break;
case GPU_VEC2:
uniform->datatype = GPU_DATA_2F;
break;
case GPU_VEC3:
uniform->datatype = GPU_DATA_3F;
break;
case GPU_VEC4:
uniform->datatype = GPU_DATA_4F;
break;
case GPU_MAT3:
uniform->datatype = GPU_DATA_9F;
break;
case GPU_MAT4:
uniform->datatype = GPU_DATA_16F;
break;
case GPU_NONE:
case GPU_CLOSURE:
2016-01-10 07:12:10 +11:00
case GPU_TEX2D:
case GPU_TEXCUBE:
2016-01-10 07:12:10 +11:00
case GPU_SHADOW2D:
case GPU_ATTRIB:
break;
}
if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_LAMP)
uniform->lamp = input->dynamicdata;
if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_MAT)
uniform->material = input->dynamicdata;
}
if (uniform->type != GPU_DYNAMIC_NONE)
BLI_addtail(&shader->uniforms, uniform);
else
MEM_freeN(uniform);
}
/* process builtin uniform */
for (int i = 0; builtins[i].gputype; i++) {
if (mat->builtins & builtins[i].gputype) {
GPUInputUniform *uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform");
uniform->type = builtins[i].dynamictype;
uniform->datatype = builtins[i].datatype;
BLI_strncpy(uniform->varname, GPU_builtin_name(builtins[i].gputype), sizeof(uniform->varname));
BLI_addtail(&shader->uniforms, uniform);
}
}
2012-04-21 14:14:58 +00:00
/* now link fragment shader with library shader */
/* TBD: remove the function that are not used in the main function */
liblen = (pass->libcode) ? strlen(pass->libcode) : 0;
fraglen = strlen(pass->fragmentcode);
shader->fragment = (char *)MEM_mallocN(liblen + fraglen + 1, "GPUFragShader");
if (pass->libcode)
memcpy(shader->fragment, pass->libcode, liblen);
memcpy(&shader->fragment[liblen], pass->fragmentcode, fraglen);
shader->fragment[liblen + fraglen] = 0;
// export the attribute
for (int i = 0; i < mat->attribs.totlayer; i++) {
GPUInputAttribute *attribute = MEM_callocN(sizeof(GPUInputAttribute), "GPUInputAttribute");
attribute->type = mat->attribs.layer[i].type;
attribute->number = mat->attribs.layer[i].glindex;
BLI_snprintf(attribute->varname, sizeof(attribute->varname), "att%d", mat->attribs.layer[i].attribid);
switch (attribute->type) {
2016-01-10 07:12:10 +11:00
case CD_TANGENT:
attribute->datatype = GPU_DATA_4F;
break;
case CD_MTFACE:
attribute->datatype = GPU_DATA_2F;
attribute->name = mat->attribs.layer[i].name;
break;
case CD_MCOL:
attribute->datatype = GPU_DATA_4UB;
attribute->name = mat->attribs.layer[i].name;
break;
case CD_ORCO:
attribute->datatype = GPU_DATA_3F;
break;
}
if (attribute->datatype != GPU_DATA_NONE)
BLI_addtail(&shader->attributes, attribute);
else
MEM_freeN(attribute);
}
/* export the vertex shader */
shader->vertex = BLI_strdup(pass->vertexcode);
}
return shader;
}
void GPU_free_shader_export(GPUShaderExport *shader)
{
if (shader == NULL)
return;
for (GPUInputUniform *uniform = shader->uniforms.first; uniform; uniform = uniform->next)
if (uniform->texpixels)
MEM_freeN(uniform->texpixels);
BLI_freelistN(&shader->uniforms);
BLI_freelistN(&shader->attributes);
if (shader->vertex)
MEM_freeN(shader->vertex);
if (shader->fragment)
MEM_freeN(shader->fragment);
MEM_freeN(shader);
}
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
#ifdef WITH_OPENSUBDIV
void GPU_material_update_fvar_offset(GPUMaterial *gpu_material,
DerivedMesh *dm)
{
GPUPass *pass = gpu_material->pass;
GPUShader *shader = (pass != NULL ? pass->shader : NULL);
ListBase *inputs = (pass != NULL ? &pass->inputs : NULL);
GPUInput *input;
if (shader == NULL) {
return;
}
GPU_shader_bind(shader);
for (input = inputs->first;
input != NULL;
input = input->next)
{
if (input->source == GPU_SOURCE_ATTRIB &&
input->attribtype == CD_MTFACE)
{
char name[64];
/* TODO(sergey): This will work for until names are
* consistent, we'll need to solve this somehow in the future.
*/
int layer_index;
int location;
if (input->attribname[0] != '\0') {
layer_index = CustomData_get_named_layer(&dm->loopData,
CD_MLOOPUV,
input->attribname);
}
else {
layer_index = CustomData_get_active_layer(&dm->loopData,
CD_MLOOPUV);
}
BLI_snprintf(name, sizeof(name),
"fvar%d_offset",
input->attribid);
location = GPU_shader_get_uniform(shader, name);
GPU_shader_uniform_int(shader, location, layer_index);
OpenSubdiv: Commit of OpenSubdiv integration into Blender This commit contains all the remained parts needed for initial integration of OpenSubdiv into Blender's subdivision surface code. Includes both GPU and CPU backends which works in the following way: - When SubSurf modifier is the last in the modifiers stack then GPU pipeline of OpenSubdiv is used, making viewport performance as fast as possible. This also requires graphscard with GLSL 1.5 support. If this requirement is not met, then no GPU pipeline is used at all. - If SubSurf is not a last modifier or if DerivesMesh is being evaluated for rendering then CPU limit evaluation API from OpenSubdiv is used. This only replaces the legacy evaluation code from CCGSubSurf_legacy, but keeps CCG structures exactly the same as they used to be for ages now. This integration is fully covered with ifdef and not enabled by default because there are several TODOs to be solved first: - Face varying data interpolation is not really cleanly implemented for GPU in OpenSubdiv 3.0. It is also not implemented for limit evaluation API. This basically means we'll have really hard time supporting UVs. - Limit evaluation only works with adaptivly subdivided meshes so far, which basically means all the points of CCG are pushed to the limit. This gives different result from old code. - There are some serious optimizations possible on the topology refiner creation, which would speed up initial OpenSubdiv mesh creation. - There are some hardcoded asumptions in the GPU and DerivedMesh areas which could be generalized. That's something where Antony and Campbell can help, making it so the code is structured in a way which is reusable by all planned viewport projects. - There are also some workarounds in the dependency graph to make sure OpenGL buffers are only freed from the main thread. Those who'll be wanting to make experiments with this code should grab dev branch (NOT master) from https://github.com/Nazg-Gul/OpenSubdiv/tree/dev There are some patches applied in there which we're working on on getting into upstream.
2015-07-20 16:08:06 +02:00
}
}
GPU_shader_unbind();
}
#endif