Jump to content

  • Log In with Google      Sign In   
  • Create Account

Quick Multitexturing Question - Why is it necessary here to divide by the number of textures?

  • You cannot reply to this topic
4 replies to this topic

#1 Sean_Seanston   Members   -  Reputation: 287


Posted 21 August 2014 - 09:08 AM

I followed this tutorial:




Though it's worth nothing that the shader provided doesn't actually work right (I think it completely omits the 2nd texture when multitexturing, as well as the 1st being too bright), but someone in the comments fixed it.


Briefly, here's how the relevant part of the fixed fragment shader looks:

void main()
	outputColor = vec4(0.0, 0.0, 0.0, 0.0);
	if (numTextures > 1)
		vec4 vTexColor = texture2D(gSamplers[0], texCoord);
		outputColor += vTexColor*fTextureContributions[0];
		vTexColor = texture2D(gSamplers[1], texCoord);
		outputColor += vTexColor*fTextureContributions[1];
		outputColor /= 2;
		vec4 vTexColor = texture2D(gSamplers[0], texCoord);
		outputColor += vTexColor*fTextureContributions[0];
	float fDiffuseIntensity = max(0.0, dot(normalize(vNormal), -sunLight.vDirection));
	outputColor *= vColor*vec4(sunLight.vColor*(sunLight.fAmbientIntensity+fDiffuseIntensity), 1.0);

With the really important bit in bold.


It works and looks like it should, and when outputColor isn't divided by 2, the result is a texture that's noticeably much brighter than the original texture file.


Now, while I realize we're combining the values of 2 textures here...  the fTextureContributions values are used to decide how much of each texture shows through, and I've checked that they definitely always add up to 1.0f (with a small bit of inaccuracy once it gets to 1.0f and 0.0f).


My problem/question is: I would have thought that multiplying 2 textures by numbers that add up to 1 and then adding them together would result in the correct value, but it doesn't. Dividing the result by 2 works as it should.

Why exactly is that? What have I missed? Am I looking in the wrong place perhaps? It's not something to do with the lighting afterwards is it?


I see that outputColor is having 2 values directly added to it... but I can't get my head around why that's a problem that needs to be corrected by a later division by 2 when those values are being multiplied as they are.


#2 iwoplaza   Members   -  Reputation: 171


Posted 21 August 2014 - 09:22 AM

You have to devide it by two, because you are actually trying to get the average of these two textures.

Imagine that you have a red texture and a black texture. By mixing these two you would expect it to turn out as a darker red. It wouldn't, because you are not getting the average of them, you are just adding them together, so:

(red: 1.0, green: 0.0, blue: 0.0) + (red: 0.0, green: 0.0, blue: 0.0) ==(red: 1.0, green: 0.0, blue: 0.0)


(red: 1.0, green: 0.0, blue: 0.0)/2 + (red: 0.0, green: 0.0, blue: 0.0)/2 ==(red: 0.5, green: 0.0, blue: 0.0)


I hope it helped :).

#3 Sean_Seanston   Members   -  Reputation: 287


Posted 21 August 2014 - 10:22 AM

You have to devide it by two, because you are actually trying to get the average of these two textures.


Ohhh right... well that stands to reason then.


I think I understand it better now...




Yes, I do actually! tongue.png


I wasn't completely clear, and had a longer reply typed up, but then I went through another example and now I see it works out fine when you considering you're averaging the colour values.


Thanks for that.

#4 L. Spiro   Crossbones+   -  Reputation: 13297


Posted 21 August 2014 - 04:04 PM

The site claims that you cannot access array uniforms except via a constant.
This is incorrect.
Since the first version of GLSL you have been able to dynamically access any array (uniform or not) as long as the array size is specified.
If this was not the case, my engine wouldn’t work at all, as I store my lights in uniform arrays and access them all dynamically.

Variables of the same type can be aggregated into arrays by declaring a name followed by brackets ( [ ] )
enclosing an optional size. When an array size is specified in a declaration, it must be an integral constant
expression (see Section 4.3.3 “Constant Expressions” ) greater than zero. If an array is indexed with an
expression that is not an integral constant expression, or if an array is passed as an argument to a function,
then its size must be declared before any such use. It is legal to declare an array without a size and then
later re-declare the same name as an array of the same type and specify a size. It is illegal to declare an
array with a size, and then later (in the same shader) index the same array with an integral constant
expression greater than or equal to the declared size. It is also illegal to index an array with a negative
constant expression. Arrays declared as formal parameters in a function declaration must specify a size.
Undefined behavior results from indexing an array with a non-constant expression that’s greater than or
equal to the array’s size or less than 0. Only one-dimensional arrays may be declared. All basic types and
structures can be formed into arrays. Some examples are:

float frequencies[3];
uniform vec4 lightPosition[4];
light lights[];
const int numLights = 2;
light lights[numLights];

You should stop mangling your code with if/else nonsense immediately. Not only is it a mess, it is terribly slow.

L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#5 DementedCarrot   Members   -  Reputation: 467


Posted 21 August 2014 - 08:01 PM

Also, don't let color averaging stop you there with texture blending!

If you use a linear interpolation you can blend any amount of a texture into another. With a lerp you can blend more or less of a texture in to taste as long as the interpolate value is between 0 and 1.

vec3 red = vec3(1,0,0);
vec3 black = vec3(0,0,0);
vec3 mixedColor = mix(red, black, 0.25);

// This gives you 75% Red and 25% Black.

Another cool application is smooth texture blending. You can use color lerping on outdoor terrain to seamlessly blend different textures together, like grass and dirt, in irregular ways that break up the texture on a mesh so that it isn't solid. You give different vertices on a mesh different lerp parameters, and vertex interpolation will give you all of the interpolation values in between so it fades from one blend percentage to the other. Check out the screenshot of the day and notice the texture blending on the ground in the back. http://www.gamedev.net/page/showdown/view.html/_/slush-games-r46850


Texture blending is pretty handy.

Edited by DementedCarrot, 22 August 2014 - 09:03 AM.