From: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Fri, 11 Feb 2011 18:59:09 +0000 (+0000)
Subject: added iris adaptation experiment
X-Git-Tag: xonotic-v0.5.0~438^2~2
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=e4d020c2d97b34a62758e94a13bde3a4753e9415;p=xonotic%2Fdarkplaces.git

added iris adaptation experiment


git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10839 d7cf8633-e32d-0410-b094-e92efae38249
---

diff --git a/cl_screen.c b/cl_screen.c
index 266ba4d8..f52b143f 100644
--- a/cl_screen.c
+++ b/cl_screen.c
@@ -2163,6 +2163,7 @@ static double cl_updatescreen_quality = 1;
 extern void Sbar_ShowFPS_Update(void);
 void CL_UpdateScreen(void)
 {
+	vec3_t vieworigin;
 	double rendertime1;
 	float conwidth, conheight;
 	float f;
@@ -2228,6 +2229,9 @@ void CL_UpdateScreen(void)
 			sb_lines = 24+16+8;
 	}
 
+	Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, vieworigin);
+	R_HDR_UpdateIrisAdaptation(vieworigin);
+
 	r_refdef.view.colormask[0] = 1;
 	r_refdef.view.colormask[1] = 1;
 	r_refdef.view.colormask[2] = 1;
diff --git a/gl_rmain.c b/gl_rmain.c
index 9f7005d4..59693c3b 100644
--- a/gl_rmain.c
+++ b/gl_rmain.c
@@ -178,6 +178,12 @@ cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effec
 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
 cvar_t r_hdr_range = {CVAR_SAVE, "r_hdr_range", "4", "how much dynamic range to render bloom with (equivalent to multiplying r_bloom_brighten by this value and dividing r_bloom_colorscale by this value)"};
+cvar_t r_hdr_irisadaptation = {CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
+cvar_t r_hdr_irisadaptation_multiplier = {CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
+cvar_t r_hdr_irisadaptation_minvalue = {CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
+cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
+cvar_t r_hdr_irisadaptation_value = {0, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
+cvar_t r_hdr_irisadaptation_fade = {CVAR_SAVE, "r_hdr_irisadaptation_fade", "1", "fade rate at which value adjusts"};
 
 cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
 
@@ -6851,6 +6857,12 @@ void GL_Main_Init(void)
 	Cvar_RegisterVariable(&r_hdr_scenebrightness);
 	Cvar_RegisterVariable(&r_hdr_glowintensity);
 	Cvar_RegisterVariable(&r_hdr_range);
+	Cvar_RegisterVariable(&r_hdr_irisadaptation);
+	Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
+	Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
+	Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
+	Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
+	Cvar_RegisterVariable(&r_hdr_irisadaptation_fade);
 	Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
 	Cvar_RegisterVariable(&developer_texturelogging);
 	Cvar_RegisterVariable(&gl_lightmaps);
@@ -7329,10 +7341,10 @@ static void R_View_UpdateEntityLighting (void)
 			{
 				if (ent->model->sprite.sprnum_type == SPR_OVERHEAD) // apply offset for overhead sprites
 					org[2] = org[2] + r_overheadsprites_pushback.value;
-				R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, ent->modellight_lightdir, org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT);
+				R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal, org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT);
 			}
 			else
-				r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
+				R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal, org, LP_LIGHTMAP);
 
 			if(ent->flags & RENDER_EQUALIZE)
 			{
@@ -7574,6 +7586,35 @@ static void R_DrawModelsAddWaterPlanes(void)
 	}
 }
 
+void R_HDR_UpdateIrisAdaptation(const vec3_t point)
+{
+	if (r_hdr_irisadaptation.integer)
+	{
+		vec3_t ambient;
+		vec3_t diffuse;
+		vec3_t diffusenormal;
+		vec_t brightness;
+		vec_t goal;
+		vec_t adjust;
+		vec_t current;
+		R_CompleteLightPoint(ambient, diffuse, diffusenormal, point, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT);
+		brightness = (ambient[0] + ambient[1] + ambient[2] + diffuse[0] + diffuse[1] + diffuse[2]) * (1.0f / 3.0f);
+		brightness = max(0.0000001f, brightness);
+		goal = r_hdr_irisadaptation_multiplier.value / brightness;
+		goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
+		adjust = r_hdr_irisadaptation_fade.value * cl.realframetime;
+		current = r_hdr_irisadaptation_value.value;
+		if (current < goal)
+			current = min(current + adjust, goal);
+		else if (current > goal)
+			current = max(current - adjust, goal);
+		if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
+			Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
+	}
+	else if (r_hdr_irisadaptation_value.value != 1.0f)
+		Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
+}
+
 static void R_View_SetFrustum(const int *scissor)
 {
 	int i;
@@ -9119,7 +9160,7 @@ void R_RenderView(void)
 		return; //Host_Error ("R_RenderView: NULL worldmodel");
 	}
 
-	r_refdef.view.colorscale = r_hdr_scenebrightness.value;
+	r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
 
 	R_RenderView_UpdateViewVectors();
 
diff --git a/model_shared.c b/model_shared.c
index 559de9e8..52bf0ed8 100644
--- a/model_shared.c
+++ b/model_shared.c
@@ -3428,8 +3428,8 @@ static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos
 			continue;
 		lightiradius = 1.0f / lightradius;
 		dist = sqrt(dist2) * lightiradius;
-		intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
-		if (intensity <= 0)
+		intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
+		if (intensity <= 0.0f)
 			continue;
 		if (model && model->TraceLine)
 		{
diff --git a/r_shadow.c b/r_shadow.c
index ecba4b32..ba4ca14a 100644
--- a/r_shadow.c
+++ b/r_shadow.c
@@ -6032,26 +6032,60 @@ LIGHT SAMPLING
 =============================================================================
 */
 
-void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, const int flags)
+void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
 {
 	int i, numlights, flag;
-	float f, relativepoint[3], dist, dist2, lightradius2;
 	rtlight_t *light;
 	dlight_t *dlight;
+	float relativepoint[3];
+	float color[3];
+	float dir[3];
+	float dist;
+	float dist2;
+	float intensity;
+	float sample[5*3];
+	float lightradius2;
 
-	VectorClear(diffusecolor);
-	VectorClear(diffusenormal);
+	if (r_fullbright.integer)
+	{
+		VectorSet(ambient, 1, 1, 1);
+		VectorClear(diffuse);
+		VectorClear(lightdir);
+		return;
+	}
 
 	if (flags & LP_LIGHTMAP)
 	{
-		if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
-		{
-			ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
-			r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
-		}
-		else
-			VectorSet(ambientcolor, 1, 1, 1);
+		VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
+		VectorClear(diffuse);
+		VectorClear(lightdir);
+		if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
+			r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
+		return;
 	}
+
+	memset(sample, 0, sizeof(sample));
+	VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
+
+	if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
+	{
+		vec3_t tempambient;
+		VectorClear(tempambient);
+		VectorClear(color);
+		VectorClear(relativepoint);
+		r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
+		VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
+		VectorScale(color, r_refdef.lightmapintensity, color);
+		VectorAdd(sample, tempambient, sample);
+		VectorMA(sample    , 0.5f            , color, sample    );
+		VectorMA(sample + 3, relativepoint[0], color, sample + 3);
+		VectorMA(sample + 6, relativepoint[1], color, sample + 6);
+		VectorMA(sample + 9, relativepoint[2], color, sample + 9);
+		// calculate a weighted average light direction as well
+		intensity = VectorLength(color);
+		VectorMA(sample + 12, intensity, relativepoint, sample + 12);
+	}
+
 	if (flags & LP_RTWORLD)
 	{
 		flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
@@ -6071,14 +6105,25 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu
 			if (dist2 >= lightradius2)
 				continue;
 			dist = sqrt(dist2) / light->radius;
-			f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
-			if (f <= 0)
+			intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
+			if (intensity <= 0.0f)
 				continue;
-			// todo: add to both ambient and diffuse
-			if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
-				VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
+			if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
+				continue;
+			// scale down intensity to add to both ambient and diffuse
+			//intensity *= 0.5f;
+			VectorNormalize(relativepoint);
+			VectorScale(light->currentcolor, intensity, color);
+			VectorMA(sample    , 0.5f            , color, sample    );
+			VectorMA(sample + 3, relativepoint[0], color, sample + 3);
+			VectorMA(sample + 6, relativepoint[1], color, sample + 6);
+			VectorMA(sample + 9, relativepoint[2], color, sample + 9);
+			// calculate a weighted average light direction as well
+			intensity *= VectorLength(color);
+			VectorMA(sample + 12, intensity, relativepoint, sample + 12);
 		}
 	}
+
 	if (flags & LP_DYNLIGHT)
 	{
 		// sample dlights
@@ -6092,12 +6137,35 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu
 			if (dist2 >= lightradius2)
 				continue;
 			dist = sqrt(dist2) / light->radius;
-			f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
-			if (f <= 0)
+			intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
+			if (intensity <= 0.0f)
 				continue;
-			// todo: add to both ambient and diffuse
-			if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
-				VectorMA(ambientcolor, f, light->color, ambientcolor);
+			if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
+				continue;
+			// scale down intensity to add to both ambient and diffuse
+			//intensity *= 0.5f;
+			VectorNormalize(relativepoint);
+			VectorScale(light->currentcolor, intensity, color);
+			VectorMA(sample    , 0.5f            , color, sample    );
+			VectorMA(sample + 3, relativepoint[0], color, sample + 3);
+			VectorMA(sample + 6, relativepoint[1], color, sample + 6);
+			VectorMA(sample + 9, relativepoint[2], color, sample + 9);
+			// calculate a weighted average light direction as well
+			intensity *= VectorLength(color);
+			VectorMA(sample + 12, intensity, relativepoint, sample + 12);
 		}
 	}
+
+	// calculate the direction we'll use to reduce the sample to a directional light source
+	VectorCopy(sample + 12, dir);
+	//VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
+	VectorNormalize(dir);
+	// extract the diffuse color along the chosen direction and scale it
+	diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
+	diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
+	diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
+	// subtract some of diffuse from ambient
+	VectorMA(sample, -0.333f, diffuse, ambient);
+	// store the normalized lightdir
+	VectorCopy(dir, lightdir);
 }
diff --git a/render.h b/render.h
index 8ae52248..c1911e08 100644
--- a/render.h
+++ b/render.h
@@ -401,6 +401,8 @@ rsurfacestate_t;
 
 extern rsurfacestate_t rsurface;
 
+void R_HDR_UpdateIrisAdaptation(const vec3_t point);
+
 void RSurf_ActiveWorldEntity(void);
 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass);
 void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents);