Jump to content
gammadust

Alternative Midrange Detail Texture experiments

Recommended Posts

This thread tries to make room for all the Midrange Detail textures experimentation and feedback anyone wants to contribute. It may be looked at also as a gallery and pre release chamber for the hopefully many alternatives that may appear. When contributing keep in mind forum rules regarding image/file size.

Having felt compelled to create my own midrange detail textures for Stratis after the great work by Bad Benson and keeping in mind the very useful discussion on this topic iniciated by NordKindchen, here's some of my trials:

Scene 1

Default

Yta7rD4l.jpg

Alternate 1

06v2R1ol.jpg

Default (Sighted)

bFqjhJrl.jpg

Alternate 1 (Sighted)

LzTyqhql.jpg

Scene 2

Default

7CEVjOLl.jpg

Alternate 1

G84ZerWl.jpg

Default (Sighted)

XwUv9Jbl.jpg

Alternate 1 (Sighted)

uBRPQdKl.jpg

Related gallery 1 and gallery 2 with different grounds/scenes. Download example. I'll also try to make these views more uniform so that they overlay better for pixel-to-pixel comparisons.

I would like to leave some personal observations:

  • Textures require versatility (the same texture is used to detail grass, dry grass, sand, rocky grounds, concrete - urban settings, the hardest to satisfy)
  • Detail scale should approximate soldier sizes (in order to better break their silhuettes and help camouflage)
  • Shadows if any should be projected northwards (down when editing), never too long (fitting a Stratis northern hemisphere average projection)
  • They should have a level of very low frequency noise (to diversify the landscape in zoomed out views - breaks the most the urban setting)
  • The above has the side effect of making repeating patterns more noticeable at distance, never darken it too much
  • There's a compromise between abstraction and naturalness (make them too natural and they get less fit for disparate grounds, too abstract and mere noise would bring the same effect)
  • Increasing the resolution above 1024x1024 has no apparent benefit
  • Performance appears to suffer no impact with new textures in my tests and others
  • To evaluate results: having the default texture in view is handy, testing the different grounds, both sighted and unsighted views, placed soldiers for camouflage effectiveness

Want to give it a shot?

Template config.cpp (update to a leaner version)

class CfgPatches
{
class GAM_Stratis_MRDT_A2 // Make unique reference
{
	units[] = {"Stratis"};
	weapons[] = {};
	requiredVersion = 0.1;
	RequiredAddons[] = {"A3_Map_Stratis"};
};
};

class CfgWorlds
{
class CAWorld; // Import class which Startis inherits from

class Stratis: CAWorld // Overwriting Stratis midDetailTexture
{
	midDetailTexture = "GAM\GAM_stratis_midrangedetail_a2\data\mid_range_mco.paa"; // change your tag/folder structure accordingly
};
};

Texture example jpg (not upping the default one of course)

Create a 1024x1024 texture, save it in tga. Open it in BI Texture Viewer, keep RGBA, change to DXT1, save it back to "mid_range_mco.paa"

Follow Wiki guidelines:

_MCO - multiply color, texture should be color neutral, same as CDT with difference of no fading in mipmaps

Binpbo it along with config and texture.


Dynamic Texturing Script

Description:

- Dynamicaly updates the transition between Mid and Close range textures on the fly

(dependent on Field of View)

Download:

GAM_DynamicTexturing

Full effect depends on the following

Textures:

  • Mid Range download (version *_a2 used in video - check zip for variations)
  • Close Range download (dry grass for Stratis and Altis)*
    To install them, you must unpack original map_data.pbo to a folder, extract these textures from zip and overwrite the original ones, finally repack it all up again and put it in one mod folder.
    *Unfortunately, i'm unable to easily share thess texture as a mod which implies uploading the full set of surface textures (+200Mb)

Video:

Edited by gammadust

Share this post


Link to post
Share on other sites

I would have liked to see the airport from a > 100m range from above, as thats the hardest part overall, like you already stated.

But I do like what Ive seen so far.

edit its in the link, thx

Share this post


Link to post
Share on other sites

Yep, the urban setting is really hard to please. It is at odds with the generally organic appearance in other places. Currently I can't imagine a way to adapt it better without losing the variations one gets at long distances with a more "contrasty" texture. Urban is less than 5% of the map, so i go for the compromise.

Share this post


Link to post
Share on other sites

This looks god, but I think what it really needs in conjunction with better midrage is a further rendering distance for the tiled textures (the ones you see up close) because those fade very fast (go to the airfield and take off in a helo while looking down) or at least add a slider for that.

Share this post


Link to post
Share on other sites

It looks good in one sense, but there's clear patterning occurring over the landscape at distance, which is lacking in the BIS default since it's so subtle (allowing the satmap, etc, textures and terrain features to be more prominent). Really need that logicmap of Nord's for this to work successfully.

Share this post


Link to post
Share on other sites
It looks good in one sense, but there's clear patterning occurring over the landscape at distance, which is lacking in the BIS default since it's so subtle (allowing the satmap, etc, textures and terrain features to be more prominent). Really need that logicmap of Nord's for this to work successfully.

Similarly we could remove patterning entirely by removing all textures from the game! ;)

I think this is a vast improvement, though more work needs to be done. A one size fits all texture will never work, look at the airport for example, the taxi ways at least need a different texture, and by varying what textures we use we can remove some of the more obvious patterning AND give some variety.

For example: Mid tex for: Roads, grass, concrete, dirt, sand, riverbed.

Share this post


Link to post
Share on other sites

Problem with the patterning is that it's overriding the impression of a landscape. I'm not seeing rolling hills, etc, as much as "high contrast pattern repeated 1000 times over different colors" now. Needs balancing still.

Share this post


Link to post
Share on other sites

I wish I found this thread earlier, downloading the example now, the screenshots look brilliant.

Share this post


Link to post
Share on other sites

Thanks for the feedback guys. I really have to agree with the patterning effect being still too much, you should have seen the intermediary steps, i do think there is room for improvement, no doubt. I tried to find what Bushlurker exacly meant about the "stretched on a per-landgrid basis (usually about 40x40m) and provide yet another "mid-range bridge". How much one stretches this tiling might too be interesting to explore. I'll try and bring another version later this weekend. :)

Share this post


Link to post
Share on other sites
I'll try and bring another version later this weekend. :)

I look forward to it, I think it's an area that's really worthwhile experimenting with because it can have a dramatic effect on gameplay. BTW I tried to test your download example but got an error message soon as the game loaded.

Your 'alternate sighted' screenshots are definitely a step in the right direction. I think for long and medium ranges it's almost impossible to surpass the ULTRA texture mod -

but when the textures are viewed through optics (zoomed in) your 'alternate sighted' examples are the best I've seen so far. Please keep experimenting when you get some free time, your efforts are appreciated mate.

Share this post


Link to post
Share on other sites
BTW I tried to test your download example but got an error message soon as the game loaded.

!

I am not getting any, what kind of error did you got? (Did you by any remote chance left a previous midrange mod activated? I had test this with and without Landtex with no issues, i did try to simplify the config maybe i overlooked something)

Share this post


Link to post
Share on other sites

This is the error message I get on startup -

Cannot load texture gam\gam_stratis_midrangedetail\data\mid_range_mco.paa.

Share this post


Link to post
Share on other sites

^^ yep, finally reproduced it here. I have re uploaded a corrected file, same link. (pbo prefix was using an older filestruture of which i still had leftovers, enabling the confusion)

Share this post


Link to post
Share on other sites

Thanks gammadust I got it working now. When viewed through a scope at mid range the textures look very nice, but I have to agree with the comment DNK made earlier about patterning occurring over the landscape when viewed from a distance, you can clearly see it in this video -

Please don't be discouraged mate, I'm confident that if you keep experimenting you will get great results.

Share this post


Link to post
Share on other sites

Ok... attempt in fixing the patterning effect while keeping same detail. Alternative 2 (no ss for now)

@Kuskov

no discouragement at all. This is absolutely a feedback thread. It's the whole point. hope you like this version better :)

Share this post


Link to post
Share on other sites

The patterning effect is fixed now but in my opinion there isn't enough contrast, I feel that the infantry don't blend in enough with the environment -

You can really notice the difference here with Bad Benson's Sharp1 version, in my opinion the high contrast makes the terrain appear more natural and helps to camouflage infantry -

Share this post


Link to post
Share on other sites

I am thinking if there wouldn't be a better way to deal with the patterning, since it is most noticeable at longer distances, where smaller mipmaps should be in use, then instead of reducing the low frequency contrast for all mipmaps just do it for for those smaller ones, keeping the bigger scale variations affecting when close up.

The thing is, i am not sure the midrange texture (DXT1) accepts custom mipmaps (they could be generated on the fly), or if even BI Texture Viewer allows such editing... any texture gurus around?

Lacking that it really is a matter of compromise. But these experimentations teach a lot, i am sure the next one i build from scratch i'll be able keep more relevant things in mind.

Share this post


Link to post
Share on other sites

its still a good improvement right now already! sharp1 but looks really a bit better though through scope ;)

Share this post


Link to post
Share on other sites

Updating with some possibilities:

  • Mid Range detail map, same as previous but using the 2nd less pattern prone option (gam_stratis_midrangedetail_a2.pbo)
  • New customized close range texture for dry grass, removes patterning effect if used at high distances with default
    Unable to easily share this texture as a mod which implies uploading the full set of surface textures (+200Mb), you can only observe it's effect in the video.
    *** @Bohemia *** an appeal to allow modders to update that surface textures via config (override cfgSurfaces config without the need to repack all textures from map_data.pbo)
  • A custom script which dynamicaly updates the transition between Mid and Close range textures on the fly (dependent on Field of View) - uses new setDetailMapBlendPars command

Video: ***warning lengthy video*** bare with me on some comments regarding texturing from the beggining or skip to 6m35 to go straight to the meat of it

Textures: download (dry grass for Stratis and Altis)

To install them, you must unpack original map_data.pbo to a folder, extract these textures from zip and overwrite the original ones, finally repack it all up again and put it in one mod folder.

Script: (still very experimental)

/*	Dynamic Mid Close Range Texturing
by gamma

Description:
- Dynamicaly updates the transition between Mid and Close range textures on the fly
(dependent on Field of View)

*********************************
**** LICENSE CC BY-NC-SA 3.0 ****
Creative Commons Attribution-Non-Commercial-Share Alike 3.0 License
*/

GAM_dynamicTexturingPars = true;
GAM_Debug = true;
GAM_updateRate = 4;
GAM_keyScreenPoints = [0,9,18];
GAM_keyScreenPointsTemp = GAM_keyScreenPoints;

_npoints = floor(safeZoneH / 0.1);
GAM_screenPoints = [0.5 + (0.1 * _npoints / 2)];
for "_i" from 1 to _npoints do {
_lastp = GAM_screenPoints select ((count GAM_screenPoints) - 1);
GAM_screenPoints set [count GAM_screenPoints, round((_lastp - 0.1) * 10) / 10];
};


GAM_pointObjects = [];
GAM_setDebugObjects = {
_np = 0;
{
	if (count GAM_pointObjects < count GAM_screenPoints) then {GAM_pointObjects set [count GAM_pointObjects, createVehicle ["Sign_Sphere100cm_F", [0,0,0], [], 0, "NONE"]];};
	GAM_pointObjects select _np setObjectTexture [0,'#(rgb,8,8,3)color(1,0,1,0.1)'];

	if (_np == GAM_keyScreenPoints select 0) then {GAM_pointObjects select _np setObjectTexture [0,'#(rgb,8,8,3)color(0,0,1,1)']};
	if (_np == GAM_keyScreenPoints select 1) then {GAM_pointObjects select _np setObjectTexture [0,'#(rgb,8,8,3)color(0,1,0,1)']};
	if (_np == GAM_keyScreenPoints select 2) then {GAM_pointObjects select _np setObjectTexture [0,'#(rgb,8,8,3)color(1,0,0,1)']};
	_np = _np + 1;
}forEach GAM_screenPoints;
};

_nil = [] call GAM_setDebugObjects;

GAM_pointData = [];

GAM_linearReg = {
_dataset = _this select 0;
_i = 0; _sx = 0; _sy = 0; _sxy = 0; _sxx = 0;
{
	_xy = _i * _x;
	_xx = _i * _i;
	_sx = _sx + _i; _sy = _sy + _x; _sxy = _sxy + _xy; _sxx = _sxx + _XX;
	_i = _i + 1;
}forEach _dataset;

_n = count _dataset;
_bslope = ((_n * _sxy) - _sx * _sy) / (_n * _sxx - (_sx ^ 2));
_aintercept = (_sy - _bslope * _sx) / _n;

[_n, _bslope, _aintercept]
};

GAM_slopes = {
_dataset = _this select 0;
_slopes = [0];
for "_i" from 1 to (count _dataset - 1) do {
	_slope = ((_dataset select _i) - (_dataset select (_i - 1))) / _i;
	_slopes set [count _slopes, _slope];
};
_slopes
};

GAM_currFrame = 0;
onEachFrame {
if ((GAM_dynamicTexturingPars) AND ((GAM_currFrame % GAM_updateRate) == 0)) then {
	_posCamera = ATLtoASL positionCameraToWorld [0,0,0];

	_np = 0;
	{
		_point = ATLtoASL screenToWorld [0.5, _x];
		_pointDistance = _posCamera distance _point;
		if (GAM_Debug) then {
			GAM_pointObjects select _np setPosATL [_point select 0, _point select 1, 0];
		};

		/*_pointVec = [(_point select 0) - (_posCamera select 0), (_point select 1) - (_posCamera select 1), (_point select 2) - (_posCamera select 2)];
		_pointVecM = sqrt((_pointVec select 0) ^ 2 + (_pointVec select 1) ^ 2);
		_pointAlt = _pointVecM atan2 (_pointVec select 2);*/

		if (_pointDistance > 1000) then {_pointDistance = 1000};
		GAM_pointData set [_np, _pointDistance];
		//if (_pointDistance > 1000) then {GAM_pointData set [_np, 1500]};
		_np = _np + 1;
	} forEach GAM_screenPoints;

	_lrPD = [GAM_pointData] call GAM_linearReg;
	nPD = _lrPD select 0; bslopePD = _lrPD select 1; ainterceptPD = _lrPD select 2;

	/*slopeData = [GAM_pointData] call GAM_slopes;

	_lrSD = [slopeData] call GAM_linearReg;
	nSD = _lrSD select 0; bslopeSD = _lrSD select 1; ainterceptSD = _lrSD select 2;

	outliers = [];
	_i = 0;
	{
		if ((bslopeSD * _i + ainterceptSD) < _x) then {outliers set [count outliers, _i]};
		_i = _i + 1;
	}forEach slopeData;*/

	_bottom = bslopePD * (GAM_keyScreenPoints select 0) + ainterceptPD;
	_center = bslopePD * (GAM_keyScreenPoints select 1) + ainterceptPD;
	_top = bslopePD * (GAM_keyScreenPoints select 2) + ainterceptPD;


	if (((GAM_keyScreenPoints select 0) != (GAM_keyScreenPointsTemp select 0)) OR ((GAM_keyScreenPoints select 2) != (GAM_keyScreenPointsTemp select 2))) then {_nil = [] call GAM_setDebugObjects;};

	setDetailMapBlendPars [_bottom, _top];
	hintSilent format ["%1fps\n\nDistance\nMin: %2 | Med: %3 | Max: %4", round(diag_fps), round(_bottom), round(_center), round(_top)];
};
GAM_currFrame = GAM_currFrame + 1;
};

Edited by gammadust
correction

Share this post


Link to post
Share on other sites
Can we test this ourselves using the script?

Yes... just put the script directly in the init.sqf of a mission. The only limitation is in regards to the custom close range texture which must overwrite the original ones. It must be repacked into a pbo along with the remaining default textures. Unfortunately there is no better way that i know of to make this texture replacement mod without all this hassle (afaik).

Share this post


Link to post
Share on other sites

Thanks for your kind words guys :)

HEre's hoping BIS listen to your appeal.

Until then, i'll try and provide more detailed instructions in regards to using the custom close range texture, or finally when i have a full set of custom surface textures i may provide the direct download and the +200Mb becomes worthwhile.

*UPDATE*

Script updated:

- moved it from init.sqf and added option to a side script.

- script does not use onEachFrame in order not to interfere with whatever mission uses it for other purposes

- code clean up and added some comments to allow easier customization

- significantly improved the smoothing of the transition (there are some very fringe cases where it still fails though)

init.sqf

// this in your init.sqf
GAM_DynamicTexturing = compile preProcessFileLineNumbers 'gam_dynamictexturing.sqf';
_nil = [true, 10, false] call GAM_DynamicTexturing;

gam_dynamictexturing.sqf

/*	Dynamic Mid Close Range Texturing
by gamma

Description:
- Dynamicaly updates the transition between Mid and Close range textures on the fly
(dependent on Field of View)

*********************************
**** LICENSE CC BY-NC-SA 3.0 ****
Creative Commons Attribution-Non-Commercial-Share Alike 3.0 License
*/

//_nil = [true, 10, true] call GAM_DynamicTexturing;

GAM_dynamicTexturingPars = _this select 0; // Activate script
GAM_updateRate = 1 / (_this select 1); // Rate of update
GAM_Debug = _this select 2; // Debug


GAM_keyScreenPoints = [0, 9, 18]; // Default Fov Width (it is adjusted in realtime)
GAM_kSlope = 1; // Manual calculated Slope adjustment (Divisor - useful for adjustments on unsual terrain topographies)

GAM_keyScreenPointsTemp = GAM_keyScreenPoints; // Required to check for changes

// Setup points of measure (accounts for different screen heights)
_npoints = floor(safeZoneH / 0.1);
GAM_screenPoints = [0.5 + (0.1 * _npoints / 2)];
for "_i" from 1 to _npoints do {
_lastp = GAM_screenPoints select ((count GAM_screenPoints) - 1);
GAM_screenPoints set [count GAM_screenPoints, round((_lastp - 0.1) * 10) / 10];
};

// Setup Debug Spheres
GAM_pointObjects = [];
GAM_setDebugObjects = {
_np = 0;
{
	if (count GAM_pointObjects < count GAM_screenPoints) then {GAM_pointObjects set [count GAM_pointObjects, createVehicle ["Sign_Sphere100cm_F", [0,0,0], [], 0, "NONE"]];};
	GAM_pointObjects select _np setObjectTexture [0,'#(rgb,8,8,3)color(1,0,1,0.1)'];

	if (_np == GAM_keyScreenPoints select 0) then {GAM_pointObjects select _np setObjectTexture [0,'#(rgb,8,8,3)color(0,0,1,1)']};
	if (_np == GAM_keyScreenPoints select 1) then {GAM_pointObjects select _np setObjectTexture [0,'#(rgb,8,8,3)color(0,1,0,1)']};
	if (_np == GAM_keyScreenPoints select 2) then {GAM_pointObjects select _np setObjectTexture [0,'#(rgb,8,8,3)color(1,0,0,1)']};
	_np = _np + 1;
}forEach GAM_screenPoints;
};

_nil = [] call GAM_setDebugObjects;

// Linear Regression
// [dataset array]
// Returns [number of points, slope of function, Y intercept]
GAM_linearReg = {
_dataset = _this select 0;
_i = 0; _sx = 0; _sy = 0; _sxy = 0; _sxx = 0;
{
	_xy = _i * _x;
	_xx = _i * _i;
	_sx = _sx + _i; _sy = _sy + _x; _sxy = _sxy + _xy; _sxx = _sxx + _XX;
	_i = _i + 1;
}forEach _dataset;

_n = count _dataset;
_bslope = ((_n * _sxy) - _sx * _sy) / (_n * _sxx - (_sx ^ 2));
_aintercept = (_sy - _bslope * _sx) / _n;

[_n, _bslope, _aintercept]
};

// Cosine Interpolation
// [begin coordinate Y, end coordinate Y, intermediate coordinate X normalized]
// Returns interpolated Y coordinate
GAM_CosInterpolation = {
_y1 = _this select 0; _y2 = _this select 1; _mu = _this select 2;

_mu2 = (1 - cos(_mu * 180)) / 2; //arma cos is degrees
(_y1 * (1 - _mu2) + _y2 * _mu2)
};

// Calculate slopes
// [dataset array]
// Returns [slopes of each pair of points]
GAM_slopes = {
_dataset = _this select 0;
_slopes = [0];
for "_i" from 1 to (count _dataset - 1) do {
	_slope = ((_dataset select _i) - (_dataset select (_i - 1))) / _i;
	_slopes set [count _slopes, _slope];
};
_slopes
};

GAM_pointData = [];
//GAM_currFrame = 0;
//onEachFrame {
while {true} do {
//if ((GAM_dynamicTexturingPars) AND ((GAM_currFrame % GAM_updateRate) == 0)) then { // Check if active and update rate
if (GAM_dynamicTexturingPars) then { // Check if active and update rate
	_posCamera = ATLtoASL positionCameraToWorld [0,0,0];

	_centerDistance = _posCamera distance (ATLtoASL screenToWorld [0.5, 0.5]);

	// Initial distance measurement
	_topKey = 18;
	_np = 0;
	{
		_point = ATLtoASL screenToWorld [0.5, _x];
		_pointDistance = (_posCamera distance _point);
		if (GAM_Debug) then {GAM_pointObjects select _np setPosATL [_point select 0, _point select 1, 0]};

		if ((_pointDistance > 0) AND (_pointDistance < 1250 )) then { // Cap value and save topmost
			GAM_pointData set [_np, _pointDistance]; _topKey = _np;
		} else {
			GAM_pointData set [_np, 1250];
		};
		_np = _np + 1;
	} forEach GAM_screenPoints;

	GAM_keyScreenPoints = [0, 9, _topKey];

	// Linear regression of distances *1st Pass*
	_lrPD = [GAM_pointData] call GAM_linearReg;
	nPD = _lrPD select 0; bslopePD = _lrPD select 1; ainterceptPD = _lrPD select 2;

	// Refill distances with neutral values
	for "_np" from _topKey to 18 do {
		if (_np > _topKey) then {GAM_pointData set [_np, (bslopePD * _np + ainterceptPD)]};
	};

	// Linear regression of distances *2nd Pass*
	_lrPD = [GAM_pointData] call GAM_linearReg;
	nPD = _lrPD select 0; bslopePD = _lrPD select 1; ainterceptPD = _lrPD select 2;

	_center = (bslopePD * (GAM_keyScreenPoints select 1) + ainterceptPD);

	// Vision weights - Bell curve (center is more important)
	_screenPointWeights = [0.001,0.05,0.25,0.45,0.6,0.7,0.8,0.90,0.96,1.0,0.9  6,0.90,0.8,0.7,0.6,0.45,0.25,0.05,0.001];
	_sum = 0;
	for "_np" from 0 to 18 do {
		_sum = _sum + ((_screenPointWeights select _np) * ((GAM_pointData select _np) - (bslopePD / GAM_kSlope * _np + ainterceptPD)));
	};
	_sum = _sum / 19;

	// Compute actual Texture Transition Values - Apply divisor and offset based on computed vision weights
	_bottom = 800 min ((bslopePD / GAM_kSlope * (GAM_keyScreenPoints select 0) + ainterceptPD + _sum));
	_top = 1000 min ((bslopePD / GAM_kSlope * (GAM_keyScreenPoints select 2) + ainterceptPD + _sum));

	// Update sphere colors limits changed
	if (((GAM_keyScreenPoints select 0) != (GAM_keyScreenPointsTemp select 0)) OR ((GAM_keyScreenPoints select 2) != (GAM_keyScreenPointsTemp select 2))) then {_nil = [] call GAM_setDebugObjects;};

	// Apply adjustment
	setDetailMapBlendPars [_bottom, _top];

	// Debug Hint
	if (GAM_Debug) then {
		hintSilent format ["%1fps\n\nDistance Med: %2 (%3)\nMin: %4 (%5)| Max: %6 (%7)", round(diag_fps), round(_centerDistance), round(_center), round(_bottom), (GAM_keyScreenPoints select 0), round(_top), (GAM_keyScreenPoints select 2)];
	};
};
sleep GAM_updateRate;
//GAM_currFrame = GAM_currFrame + 1;
};

Video:

OP Updated

Edited by gammadust

Share this post


Link to post
Share on other sites

Really nice work! Is there anything that can be done regarding the midrange texture being overlayed onto the concrete aprons and runways? I notice the road texures seem to overwrite whatever is beneath them, so I'm wondering if its possible to cheat the engine by defining areas we don't want to apply the midrange texture as roads? I suspect that would have to be done within the binarized island file, wouldn't it?

Share this post


Link to post
Share on other sites

indeed interesting approach

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×