Files
test2/source/blender/render/intern/source/pixelshading.c
Alexander Romanov 5371102039 BI "Real Sky" option works incorrectly for environment texture.
How to check?

1) Set Rendered mode for 3d View
2) Set "Blend Sky" and "Real Sky" flags for world.
Rotate view you will see right color blending from Horizon to Zenith color.
3) Add environment texture
Rotate view and you will see incorrect texture mapping that is not correspond to color blending that was observed in previous step.

So I conclude that this is a bug.

This issue must be solved before the patch D1414 because BI behavior is the viewport target.

Example: {F273051}

Alexander (Blend4Web Team)

Reviewers: sergey

Reviewed By: sergey

Subscribers: Evgeny_Rodygin, AlexKowel, yurikovelenov

Differential Revision: https://developer.blender.org/D1729
2016-01-13 11:38:48 +03:00

642 lines
15 KiB
C

/*
* ***** 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* Contributor(s): 2004-2006, Blender Foundation, full recode
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/render/intern/source/pixelshading.c
* \ingroup render
*/
#include <float.h>
#include <math.h>
#include <string.h>
#include "BLI_math.h"
#include "BLI_utildefines.h"
/* External modules: */
#include "DNA_group_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_image_types.h"
#include "DNA_texture_types.h"
#include "DNA_lamp_types.h"
#include "BKE_material.h"
/* own module */
#include "render_types.h"
#include "renderdatabase.h"
#include "texture.h"
#include "rendercore.h"
#include "shadbuf.h"
#include "pixelshading.h"
#include "sunsky.h"
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
/* only to be used here in this file, it's for speed */
extern struct Render R;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
extern const float hashvectf[];
static void render_lighting_halo(HaloRen *har, float col_r[3])
{
GroupObject *go;
LampRen *lar;
float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn;
float ir, ig, ib, shadfac, soft, lacol[3];
ir= ig= ib= 0.0;
copy_v3_v3(rco, har->co);
dco[0]=dco[1]=dco[2]= 1.0f/har->rad;
vn= har->no;
for (go=R.lights.first; go; go= go->next) {
lar= go->lampren;
/* test for lamplayer */
if (lar->mode & LA_LAYER) if ((lar->lay & har->lay)==0) continue;
/* lampdist cacluation */
if (lar->type==LA_SUN || lar->type==LA_HEMI) {
copy_v3_v3(lv, lar->vec);
lampdist= 1.0;
}
else {
lv[0]= rco[0]-lar->co[0];
lv[1]= rco[1]-lar->co[1];
lv[2]= rco[2]-lar->co[2];
ld = len_v3(lv);
lv[0]/= ld;
lv[1]/= ld;
lv[2]/= ld;
/* ld is re-used further on (texco's) */
if (lar->mode & LA_QUAD) {
t= 1.0;
if (lar->ld1>0.0f)
t= lar->dist/(lar->dist+lar->ld1*ld);
if (lar->ld2>0.0f)
t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld);
lampdist= t;
}
else {
lampdist= (lar->dist/(lar->dist+ld));
}
if (lar->mode & LA_SPHERE) {
t= lar->dist - ld;
if (t<0.0f) continue;
t/= lar->dist;
lampdist*= (t);
}
}
lacol[0]= lar->r;
lacol[1]= lar->g;
lacol[2]= lar->b;
if (lar->mode & LA_TEXTURE) {
ShadeInput shi;
/* Warning, This is not that nice, and possibly a bit slow,
* however some variables were not initialized properly in, unless using shade_input_initialize(...),
* we need to do a memset */
memset(&shi, 0, sizeof(ShadeInput));
/* end warning! - Campbell */
copy_v3_v3(shi.co, rco);
shi.osatex= 0;
do_lamp_tex(lar, lv, &shi, lacol, LA_TEXTURE);
}
if (lar->type==LA_SPOT) {
if (lar->mode & LA_SQUARE) {
if (lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0f) {
float x, lvrot[3];
/* rotate view to lampspace */
copy_v3_v3(lvrot, lv);
mul_m3_v3(lar->imat, lvrot);
x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
/* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
inpr = 1.0f / (sqrtf(1.0f + x * x));
}
else inpr= 0.0;
}
else {
inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
}
t= lar->spotsi;
if (inpr<t) continue;
else {
t= inpr-t;
soft= 1.0;
if (t<lar->spotbl && lar->spotbl!=0.0f) {
/* soft area */
i= t/lar->spotbl;
t= i*i;
soft= (3.0f*t-2.0f*t*i);
inpr*= soft;
}
if (lar->mode & LA_ONLYSHADOW) {
/* if (ma->mode & MA_SHADOW) { */
/* dot product positive: front side face! */
inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
if (inp>0.0f) {
/* testshadowbuf==0.0 : 100% shadow */
shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
if ( shadfac>0.0f ) {
shadfac*= inp*soft*lar->energy;
ir -= shadfac;
ig -= shadfac;
ib -= shadfac;
continue;
}
}
/* } */
}
lampdist*=inpr;
}
if (lar->mode & LA_ONLYSHADOW) continue;
}
/* dot product and reflectivity*/
inp = 1.0f - fabsf(dot_v3v3(vn, lv));
/* inp= cos(0.5*M_PI-acos(inp)); */
i= inp;
if (lar->type==LA_HEMI) {
i= 0.5f*i+0.5f;
}
if (i>0.0f) {
i*= lampdist;
}
/* shadow */
if (i> -0.41f) { /* heuristic valua! */
if (lar->shb) {
shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
if (shadfac==0.0f) continue;
i*= shadfac;
}
}
if (i>0.0f) {
ir+= i*lacol[0];
ig+= i*lacol[1];
ib+= i*lacol[2];
}
}
if (ir<0.0f) ir= 0.0f;
if (ig<0.0f) ig= 0.0f;
if (ib<0.0f) ib= 0.0f;
col_r[0]*= ir;
col_r[1]*= ig;
col_r[2]*= ib;
}
/**
* Converts a halo z-buffer value to distance from the camera's near plane
* \param z The z-buffer value to convert
* \return a distance from the camera's near plane in blender units
*/
static float haloZtoDist(int z)
{
float zco = 0;
if (z >= 0x7FFFFF)
return 10e10;
else {
zco = (float)z/(float)0x7FFFFF;
if (R.r.mode & R_ORTHO)
return (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]);
else
return (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco);
}
}
/**
* \param col (float[4]) Store the rgb color here (with alpha)
* The alpha is used to blend the color to the background
* color_new = (1-alpha)*color_background + color
* \param zz The current zbuffer value at the place of this pixel
* \param dist Distance of the pixel from the center of the halo squared. Given in pixels
* \param xn The x coordinate of the pixel relaticve to the center of the halo. given in pixels
* \param yn The y coordinate of the pixel relaticve to the center of the halo. given in pixels
*/
int shadeHaloFloat(HaloRen *har, float col[4], int zz,
float dist, float xn, float yn, short flarec)
{
/* fill in col */
float t, zn, radist, ringf=0.0f, linef=0.0f, alpha, si, co;
int a;
if (R.wrld.mode & WO_MIST) {
if (har->type & HA_ONLYSKY) {
alpha= har->alfa;
}
else {
/* a bit patchy... */
alpha= mistfactor(-har->co[2], har->co)*har->alfa;
}
}
else alpha= har->alfa;
if (alpha==0.0f)
return 0;
/* soften the halo if it intersects geometry */
if (har->mat && har->mat->mode & MA_HALO_SOFT) {
float segment_length, halo_depth, distance_from_z /* , visible_depth */ /* UNUSED */, soften;
/* calculate halo depth */
segment_length= har->hasize*sasqrt(1.0f - dist/(har->rad*har->rad));
halo_depth= 2.0f*segment_length;
if (halo_depth < FLT_EPSILON)
return 0;
/* calculate how much of this depth is visible */
distance_from_z = haloZtoDist(zz) - haloZtoDist(har->zs);
/* visible_depth = halo_depth; */ /* UNUSED */
if (distance_from_z < segment_length) {
soften= (segment_length + distance_from_z)/halo_depth;
/* apply softening to alpha */
if (soften < 1.0f)
alpha *= soften;
if (alpha <= 0.0f)
return 0;
}
}
else {
/* not a soft halo. use the old softening code */
/* halo being intersected? */
if (har->zs> zz-har->zd) {
t= ((float)(zz-har->zs))/(float)har->zd;
alpha*= sqrtf(sqrtf(t));
}
}
radist = sqrtf(dist);
/* watch it: not used nicely: flarec is set at zero in pixstruct */
if (flarec) har->pixels+= (int)(har->rad-radist);
if (har->ringc) {
const float *rc;
float fac;
int ofs;
/* per ring an antialised circle */
ofs= har->seed;
for (a= har->ringc; a>0; a--, ofs+=2) {
rc= hashvectf + (ofs % 768);
fac = fabsf(rc[1] * (har->rad * fabsf(rc[0]) - radist));
if (fac< 1.0f) {
ringf+= (1.0f-fac);
}
}
}
if (har->type & HA_VECT) {
dist= fabsf(har->cos * (yn) - har->sin * (xn)) / har->rad;
if (dist>1.0f) dist= 1.0f;
if (har->tex) {
zn= har->sin*xn - har->cos*yn;
yn= har->cos*xn + har->sin*yn;
xn= zn;
}
}
else dist= dist/har->radsq;
if (har->type & HA_FLARECIRC) {
dist = 0.5f + fabsf(dist - 0.5f);
}
if (har->hard>=30) {
dist = sqrtf(dist);
if (har->hard>=40) {
dist = sinf(dist*(float)M_PI_2);
if (har->hard>=50) {
dist = sqrtf(dist);
}
}
}
else if (har->hard<20) dist*=dist;
if (dist < 1.0f)
dist= (1.0f-dist);
else
dist= 0.0f;
if (har->linec) {
const float *rc;
float fac;
int ofs;
/* per starpoint an antialiased line */
ofs= har->seed;
for (a= har->linec; a>0; a--, ofs+=3) {
rc= hashvectf + (ofs % 768);
fac = fabsf((xn) * rc[0] + (yn) * rc[1]);
if (fac< 1.0f )
linef+= (1.0f-fac);
}
linef*= dist;
}
if (har->starpoints) {
float ster, angle;
/* rotation */
angle = atan2f(yn, xn);
angle *= (1.0f+0.25f*har->starpoints);
co= cosf(angle);
si= sinf(angle);
angle= (co*xn+si*yn)*(co*yn-si*xn);
ster = fabsf(angle);
if (ster>1.0f) {
ster= (har->rad)/(ster);
if (ster<1.0f) dist*= sqrtf(ster);
}
}
/* disputable optimize... (ton) */
if (dist<=0.00001f)
return 0;
dist*= alpha;
ringf*= dist;
linef*= alpha;
/* The color is either the rgb spec-ed by the user, or extracted from */
/* the texture */
if (har->tex) {
col[0]= har->r;
col[1]= har->g;
col[2]= har->b;
col[3]= dist;
do_halo_tex(har, xn, yn, col);
col[0]*= col[3];
col[1]*= col[3];
col[2]*= col[3];
}
else {
col[0]= dist*har->r;
col[1]= dist*har->g;
col[2]= dist*har->b;
if (har->type & HA_XALPHA) col[3]= dist*dist;
else col[3]= dist;
}
if (har->mat) {
if (har->mat->mode & MA_HALO_SHADE) {
/* we test for lights because of preview... */
if (R.lights.first) render_lighting_halo(har, col);
}
/* Next, we do the line and ring factor modifications. */
if (linef!=0.0f) {
Material *ma= har->mat;
col[0]+= linef * ma->specr;
col[1]+= linef * ma->specg;
col[2]+= linef * ma->specb;
if (har->type & HA_XALPHA) col[3]+= linef*linef;
else col[3]+= linef;
}
if (ringf!=0.0f) {
Material *ma= har->mat;
col[0]+= ringf * ma->mirr;
col[1]+= ringf * ma->mirg;
col[2]+= ringf * ma->mirb;
if (har->type & HA_XALPHA) col[3]+= ringf*ringf;
else col[3]+= ringf;
}
}
/* alpha requires clip, gives black dots */
if (col[3] > 1.0f)
col[3]= 1.0f;
return 1;
}
/* ------------------------------------------------------------------------- */
/* Only view vector is important here. Result goes to col_r[3] */
void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const float dxyview[2], short thread)
{
float zen[3], hor[3], blend, blendm;
int skyflag;
/* flag indicating if we render the top hemisphere */
skyflag = WO_ZENUP;
/* Some view vector stuff. */
if (R.wrld.skytype & WO_SKYREAL) {
blend = dot_v3v3(view, R.grvec);
if (blend<0.0f) skyflag= 0;
blend = fabsf(blend);
}
else if (R.wrld.skytype & WO_SKYPAPER) {
blend= 0.5f + 0.5f * view[1];
}
else {
/* the fraction of how far we are above the bottom of the screen */
blend = fabsf(0.5f + view[1]);
}
copy_v3_v3(hor, &R.wrld.horr);
copy_v3_v3(zen, &R.wrld.zenr);
/* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */
/* SKYBLEND is active, the texture and color blend are added. */
if (R.wrld.skytype & WO_SKYTEX) {
do_sky_tex(rco, view, dxyview, hor, zen, &blend, skyflag, thread);
}
if (blend>1.0f) blend= 1.0f;
blendm= 1.0f-blend;
/* No clipping, no conversion! */
if (R.wrld.skytype & WO_SKYBLEND) {
col_r[0] = (blendm*hor[0] + blend*zen[0]);
col_r[1] = (blendm*hor[1] + blend*zen[1]);
col_r[2] = (blendm*hor[2] + blend*zen[2]);
}
else {
/* Done when a texture was grabbed. */
col_r[0]= hor[0];
col_r[1]= hor[1];
col_r[2]= hor[2];
}
}
/* shade sky according to sun lamps, all parameters are like shadeSkyView except sunsky*/
void shadeSunView(float col_r[3], const float view[3])
{
GroupObject *go;
LampRen *lar;
float sview[3];
bool do_init = true;
for (go=R.lights.first; go; go= go->next) {
lar= go->lampren;
if (lar->type==LA_SUN && lar->sunsky && (lar->sunsky->effect_type & LA_SUN_EFFECT_SKY)) {
float sun_collector[3];
float colorxyz[3];
if (do_init) {
normalize_v3_v3(sview, view);
mul_m3_v3(R.imat, sview);
if (sview[2] < 0.0f)
sview[2] = 0.0f;
normalize_v3(sview);
do_init = false;
}
GetSkyXYZRadiancef(lar->sunsky, sview, colorxyz);
xyz_to_rgb(colorxyz[0], colorxyz[1], colorxyz[2], &sun_collector[0], &sun_collector[1], &sun_collector[2],
lar->sunsky->sky_colorspace);
ramp_blend(lar->sunsky->skyblendtype, col_r, lar->sunsky->skyblendfac, sun_collector);
}
}
}
/*
* Stuff the sky color into the collector.
*/
void shadeSkyPixel(float collector[4], float fx, float fy, short thread)
{
float view[3], dxyview[2];
/*
* The rules for sky:
* 1. Draw an image, if a background image was provided. Stop
* 2. get texture and color blend, and combine these.
*/
float fac;
if ((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
/* 1. solid color */
copy_v3_v3(collector, &R.wrld.horr);
collector[3] = 0.0f;
}
else {
/* 2. */
/* This one true because of the context of this routine */
if (R.wrld.skytype & WO_SKYPAPER) {
view[0]= -1.0f + 2.0f*(fx/(float)R.winx);
view[1]= -1.0f + 2.0f*(fy/(float)R.winy);
view[2]= 0.0;
dxyview[0]= 1.0f/(float)R.winx;
dxyview[1]= 1.0f/(float)R.winy;
}
else {
calc_view_vector(view, fx, fy);
fac= normalize_v3(view);
if (R.wrld.skytype & WO_SKYTEX) {
dxyview[0]= -R.viewdx/fac;
dxyview[1]= -R.viewdy/fac;
}
}
/* get sky color in the collector */
shadeSkyView(collector, NULL, view, dxyview, thread);
collector[3] = 0.0f;
}
calc_view_vector(view, fx, fy);
shadeSunView(collector, view);
}
/* aerial perspective */
void shadeAtmPixel(struct SunSky *sunsky, float collector[3], float fx, float fy, float distance)
{
float view[3];
calc_view_vector(view, fx, fy);
normalize_v3(view);
/*mul_m3_v3(R.imat, view);*/
AtmospherePixleShader(sunsky, view, distance, collector);
}
/* eof */