Page 7 of 46
Posted: Thu Aug 13, 2009 6:25 pm
by Ramirez
Here's the entire shader code:
Code: Select all
// Texture Information from Oolite.
uniform sampler2D tex0; // Difuse and Illumination map
uniform sampler2D tex1; // Decal Texture
// Uniforms from Oolite
uniform float uDecalSelect; // used to decide which decal to select
// Information from vertex shader.
varying vec3 v_normal; // Surface normal
varying vec3 v_pos; // Vertex/fragment position in eye space
// Constants
const float specExponent = 12.0;
const float kDecal1Size = 5.0; // Sets the Decal Size - smaller number is bigger
const float kDecal1S = 0.50;
const float kDecal1T = 0.30;
const float kDecal2Size = 12.0; // Sets the Decal Size - smaller number is bigger
const float kDecal2S = 0.10;
const float kDecal2T = 0.60;
const float kDecalCount = 4.0; //Match the number of Decals in your texture
const float kOrientation1 = 1.57079633; // pi / 2
const float kOrientation2 = 3.6651914; // 210 degrees
// the diffuseColor function takes your diffuse map and your decal map, selects,
// scales & positions the decal image then adds it into the diffuse texturemap
vec4 diffuseColor()
{
vec2 baseTexCoord = gl_TexCoord[0].st;
// Calculate decal texture co-ordinates.
vec2 decal1TexCoord = baseTexCoord;
decal1TexCoord -= vec2(kDecal1S, kDecal1T - (0.5 / kDecal1Size));
float 1s = sin(kOrientation1);
float 1c = cos(kOrientation1);
decal1TexCoord *= mat2(1c, 1s, -1s, 1c);
decal1TexCoord += vec2(0.5 / kDecal1Size);
decal1TexCoord *= vec2(kDecal1Size / kDecalCount, kDecal1Size);
vec2 decal2TexCoord = baseTexCoord;
decal2TexCoord -= vec2(kDecal2S, kDecal2T - (0.5 / kDecal2Size));
float 2s = sin(kOrientation2);
float 2c = cos(kOrientation2);
decal2TexCoord *= mat2(2c, 2s, -2s, 2c);
decal2TexCoord += vec2(0.5 / kDecal2Size);
decal2TexCoord *= vec2(kDecal2Size / kDecalCount, kDecal2Size);
// Select the desired decal from the set.
float offset = floor(uDecalSelect * kDecalCount) / kDecalCount;
decal1TexCoord.s += offset;
decal2TexCoord.s += offset;
// Get texture values.
vec4 baseTex = texture2D(tex0, baseTexCoord);
vec4 decal1Tex = texture2D(tex1, decal1TexCoord);
decal1Tex *= step(offset, decal1TexCoord.s) *
step(0.0, decal1TexCoord.t) *
step(-1.0 / kDecalCount - offset, -decal1TexCoord.s) *
step(-1.0, -decal1TexCoord.t);
vec4 decal2Tex = texture2D(tex1, decal2TexCoord);
decal2Tex *= step(offset, decal2TexCoord.s) *
step(0.0, decal2TexCoord.t) *
step(-1.0 / kDecalCount - offset, -decal2TexCoord.s) *
step(-1.0, -decal2TexCoord.t);
// Composite decal over base.
return baseTex + decal1Tex + decal2Tex;
}
// Calculate the contribution of a single light. Ought to be a function, but OS X's GLSlang implementation isn't sufficiently clever.
#define LIGHT(idx) \
{ \
vec3 lightVector = normalize(gl_LightSource[idx].position.xyz); \
vec3 reflection = normalize(-reflect(lightVector, v_normal)); \
diffuse += gl_FrontMaterial.diffuse * gl_LightSource[idx].diffuse * max(dot(v_normal, lightVector), 0.0); \
specular += gl_LightSource[idx].diffuse * pow(max(dot(reflection, eyeVector), 0.0), specExponent); \
}
void main(void)
{
vec4 diffuse = vec4(0.0), specular = vec4(0.0);
vec3 eyeVector = normalize(-v_pos);
// Load texture data
vec2 texCoord = gl_TexCoord[0].st;
vec4 colorMap = texture2D(tex0, texCoord);
// calculate specular effects
float specIntensity = 0.5;
/* Light 0 is the "showroom" light, used in the demo screen and shipyard.
Light 1 is the sun.
*/
#ifdef OO_LIGHT_0_FIX
LIGHT(0);
#endif
LIGHT(1);
diffuse += gl_FrontMaterial.ambient * gl_LightModel.ambient;
// Calculate the lighting for full shader mode
#ifndef OO_REDUCED_COMPLEXITY
vec4 color = diffuse * diffuseColor() + specular * specIntensity;
#endif
// Calculate the lighting for simple shader mode
#ifdef OO_REDUCED_COMPLEXITY
vec4 color = diffuse * colorMap + specular * specIntensity;
#endif
// Output final color
gl_FragColor = vec4(color.rgb, 1.0);
}
Posted: Fri Aug 14, 2009 12:10 am
by Griff
edit: *deleted massive post*
Don't mind me, i'm rambling
Posted: Fri Aug 14, 2009 8:14 am
by Griff
*deleted part of the post*
edit: drat, i thought i'd solved the shader error, but annoyingly it's just turned out to be that the graphics card in 1 pc i'm testing it on copes OK with the shader, whilst the other pc can't.
-----
I'm going to try and modify this shader so that all the position, scale & orientation data for each decal gets placed into a single Vec4 rather than 4 seperate 'constant floats', it should make it easier to read, plus having all this in a vec4 it could be set up as an uniform so the same shader can bu used for different ships as the decal placement data won't be hard coded into the shader anymore, i'm aiming for something like this
const float Decal_1_S_pos = 0.38; will be Decal1Settings.s
const float Decal_1_T_pos = 0.9 will be Decal1Settings.t
const float kDecal_1_Size = 9.0 will be Decal1Settings.p
decal_1_kOrientation = 0.7853 will be Decal1Settings.q
and those 4 lines will be written as
vec4 Decal1Settings = vec4(0.38, 0.9, 9.0, 0.7853);
I'm also hopeing that once this is done we won't need to double up on all the code in the 'diffuseColor' function, maybe we could just call it twice in a row using 2 different vec4's to position the decals, eg
vec4 color = diffuse * diffuseColor(Decal1settings) + diffuseColor(Decal1settings) + specular * specIntensity;
------
One thing i've notice and it's really important to check, is to make sure that there are no spaces after the \ at the end of every line in the LIGHT macro (starting at line 104 in the shader), even though there are none in the shader, when i paste them up here in code tags it's adding a blank space at the end, make sure you delete them or the shader will not run.
Posted: Fri Aug 14, 2009 10:01 am
by Griff
I've taken out all the hard coded decal size/position stuff from the previous shader and set it all up as a uniform you can pass to the shader from your ships shipdata.plist, this means that the same shader can now be used for different ships and you take care of the decal placement in the shipdata.plist.
Suprisingly i think i managed to do the stuff i was on about in the post above, ie change the decal placement code into a more generic function that can be called as many times as you like in your main shader code, and each time you call it you can pass it different decal placement info, this cuts down the length of the shader as we now don't have to duplicate lines of code for each decal we want to place. I'm absolutely flabbergasted that it seems to work, or at least. it's working OK on my work PC in rendermonkey, whether it's going to work on my home pc is another matter
vertex shader (it's the same same as before)
Code: Select all
varying vec3 v_normal; // Surface normal
varying vec3 v_pos; // Vertex/fragment position in eye space
void main()
{
v_normal = normalize(gl_NormalMatrix * gl_Normal);
v_pos = vec3(gl_ModelViewMatrix * gl_Vertex);
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
fragment shader
Code: Select all
// Texture Information from Oolite.
uniform sampler2D tex0; // Difuse and Illumination map
uniform sampler2D tex1; // Decal Texture
// Uniforms from Oolite
uniform float uDecalSelect; // used to decide which decal to select
uniform vec4 Decal1SettingsUniform; // position settings for decal 1
uniform vec4 Decal2SettingsUniform; // position settings for decal 2
/*
the decal settings vec4's should be made up of the following data - in this order!
vec4(Decal_S_pos, Decal_T_pos, Decal Size, Decal Orientation) eg
in the shader/uniforms setion of shipdata.plist you'd write something like
Decal1SettingsUniform = { type = vector; value = "0.38 0.9 9.0 0.78540"; };
Decal2SettingsUniform = { type = vector; value = "0.98 0.9 9.0 -0.78540"; };
Decal_S_pos & Decal_T_pos controll where your decal will be placed on your ships
unfolded UV map and thus where it will appear on your ships hull in the game
Decal Size controls how big to draw the decal (smaller number = bigger decal)
Decal Orientation controls the amount of rotation to apply to the decal
*/
// Information from vertex shader.
varying vec3 v_normal; // Surface normal
varying vec3 v_pos; // Vertex/fragment position in eye space
// Constants
const float specExponent = 2.0;
const float kDecalCount = 4.0; // Number of decals in your idecal image texture
/*
"the_decaliser" - this function scales & positions the decal image using data passed
to it from the main shader (see lines 105 & 106 below)
*/
vec4 the_decaliser(vec4 Your_Decal_Settings)
{
vec2 baseTexCoord = gl_TexCoord[0].st;
// Setup the basic texture co-ords for the decals
vec2 decal_TexCoord = baseTexCoord;
// Position the decal
decal_TexCoord -= vec2(Your_Decal_Settings.s, Your_Decal_Settings.t - (0.5 / Your_Decal_Settings.p));
// Orientate & scale the decal
float decal_s = sin(Your_Decal_Settings.q);
float decal_c = cos(Your_Decal_Settings.q);
decal_TexCoord *= mat2(decal_c, decal_s, -decal_s, decal_c);
decal_TexCoord += vec2(0.5 / Your_Decal_Settings.p);
decal_TexCoord *= vec2(Your_Decal_Settings.p / kDecalCount, Your_Decal_Settings.p);
// Select the desired decal from the set.
float offset = floor(uDecalSelect * kDecalCount) / kDecalCount;
decal_TexCoord.s += offset;
// Get texture values.
vec4 decal_Tex = texture2D(tex1, decal_TexCoord);
// Modify the Decals texture co-oords
decal_Tex *= step(offset, decal_TexCoord.s) *
step(0.0, decal_TexCoord.t) *
step(-1.0 / kDecalCount - offset, -decal_TexCoord.s) *
step(-1.0, -decal_TexCoord.t);
// Use the Alpha in the decal as a transparency mask so you can 'cutout' your decal from it's background
float alpha = decal_Tex.a;
// Return the scaled, position & rotated decal, it's mixed into the colour texture further on in the shader .
return alpha * decal_Tex; // decal_Tex;
}
// Calculate the contribution of a single light. Ought to be a function, but OS X's GLSlang implementation isn't sufficiently clever.
#define LIGHT(idx) \
{ \
vec3 lightVector = normalize(gl_LightSource[idx].position.xyz); \
vec3 reflection = normalize(-reflect(lightVector, v_normal)); \
diffuse += gl_FrontMaterial.diffuse * gl_LightSource[idx].diffuse * max(dot(v_normal, lightVector), 0.0); \
specular += gl_LightSource[idx].diffuse * pow(max(dot(reflection, eyeVector), 0.0), specExponent); \
}
void main(void)
{
vec4 diffuse = vec4(0.0), specular = vec4(0.0);
vec3 eyeVector = normalize(-v_pos);
// Load texture data
vec2 texCoord = gl_TexCoord[0].st;
vec4 colorMap = texture2D(tex0, texCoord);
// calculate specular effects
float specIntensity = 0.1;
/* Light 0 is the "showroom" light, used in the demo screen and shipyard.
Light 1 is the sun.
*/
#ifdef OO_LIGHT_0_FIX
LIGHT(0);
#endif
LIGHT(1);
diffuse += gl_FrontMaterial.ambient * gl_LightModel.ambient;
// Calculate the lighting for full shader mode, (adds in the decals)
#ifndef OO_REDUCED_COMPLEXITY
vec4 color = diffuse * colorMap; // set up the basic colour texture...
/* .. then apply the decals on top of it, if you need more decals , set up extra DecalXSettingsUniforms
// and duplicate the line below modifying the 'Decal2SettingsUniform' so it's the same as
// your new uniform */
color += diffuse * the_decaliser(Decal1SettingsUniform); // apply decal 2
color += diffuse * the_decaliser(Decal2SettingsUniform); // apply decal 2
color += specular * specIntensity; // add in the lighting
#endif
// Calculate the lighting for simple shader mode
#ifdef OO_REDUCED_COMPLEXITY
vec4 color = diffuse * colorMap + specular * specIntensity;
#endif
// Output final color
gl_FragColor = vec4(color.rgb, 1.0);
}
if you need more decals, add more uniforms and edit the fragment shader so it runs the 'the_decaliser' function for each new decal (see lines 106 & 107 for examples, add your new lines below these.)
As before, check there's no spaces after the \ at the end of every line in the LIGHT macro, ther must be nothing after the \ or the shader won't work and you'll get a flood of syntax errors reported in the log
Posted: Fri Aug 14, 2009 5:49 pm
by Ramirez
Almost there. I had to add an #endif to the last Output final color section, but once done both decals show up one the ship. However, while the size and position controls in the shipdata work, the orientation doesn't seem to have any effect. With those values set to zero, the shader seems to apply a default rotation of 45 degrees.
Here's a quick screenie - I pasted the shield over one of the shady cobra decals hence the blobs either side:
In the shipdata, the big one had a rotation of half pi, the small one had zero.
Posted: Fri Aug 14, 2009 7:35 pm
by Griff
Oops, sorry there were some bugs in the shader, there was an unwanted
'#ifndef OO_REDUCED_COMPLEXITY '
at the end which as you found out didn't have a closing #endif and I also forgot to add lighting to the 2nd decal so it will appear to be glowing as it doesn't recieve any shadowing, i've fixed these now and uploaded a test oxp in the 'shaders outpost' thread, but it doesn't look as if you need it now
try downloading the text oxp to check if the rotation is working in that, the smilies on the cobra should be at different angles
edit - you're right, they're not... i think this is because Oolite clamps the 4th component in every uniform vector to 1.0. I'll ask in the bugs& testing forum if there is a way to stop oolite doing this, or maybe we could just add another uniform float into the shader to control the rotation.
Posted: Sat Aug 15, 2009 8:32 am
by Griff
Ah, i should have RTFM, Oolite doesn't support vec 4's for shader uniforms, so I've split the rotation from the vec4 into it's own float, there's a test oxp here
http://www.box.net/shared/4h8aykmzjg
and i've also posted the shader and example uniforms for the shipdata.plist in the 'shaders outpost' thread.
Posted: Mon Aug 17, 2009 11:03 am
by Ramirez
That's great, Griff. Look's like I've got lots of work to do, but already I've managed to set up an array with 11 decals that seem to get selected OK.
Here's a rather poorly-lit example:
Posted: Mon Aug 17, 2009 2:06 pm
by Cmd. Cheyd
(thanks to a little brightening in Photoshop) - Looks great man! Can't wait to see this when it's done!
Posted: Thu Aug 20, 2009 3:50 pm
by Ramirez
I forgot how addictive OXP-ing was! Decals are more or less sorted and I've been giving some thought to the tournament side of things. Some points have come up that I'd appreciate views on - it's a bit of a rambling stream of consciousness but I need to provide some context:
1. role arrays
One of the events in the tournament is the melee, an elimination contest where a load of ships fight each other. I want to generate a number of ships whose feudal house is selected at random. To do this I've given each ship a handfull of roles in the shipdata - in the case of a knight representing Aronar, this would be
Code: Select all
roles = "Aronar-knight escort(0) feudal-knight"
(note: the escort role is there to support some of the OXP's missions)
In the world script I do a legacy_addSystemShips function for 'feudal-knight', and it populates a load of knights with different randomly-selected houses.
I don't care about which ships are chosen initially - I specifically don't want to set up a load of mission or local variables just to populate them; all I need is to log the details of the ship that's remaining, particularly the house it's representing. Once I get the house, I can then generate an appropriate name and rank for the competitor.
Now, using the ship's own ship script, with an appropriate trigger I can record some of its details as a mission variable. The bit I particularly need is the [house]-knight part. As the ship was created using a primary role of 'feudal-knight' I need to use the this.ship.roles function to pick up the other role. I can select the bit I need using code like this
Code: Select all
var list = this.ship.roles
var house = list[1]
However, I've discovered that the results of this.ship.role always get arranged alphabetically. This means in one case I'll get:
Code: Select all
Aronar-knight,escort,feudal-knight
while in another I'll get:
Code: Select all
escort,feudal-knight,Tibecea-knight
So I can't guarantee to select the correct part of the list, and therefore any subsequent uses of this house var would be problematic. Is there a way to get around this?
I suppose one alternative is to do some 'if' checks within the ship script, e.g.
Code: Select all
if(this.ship.hasRole: aronar-knight == true)
{missionVariables.feudal_tournament_house = Aronar}
but this means bulking up the ship script more than I'd like, also I'd prefer not to have to resort to using specific house names outside of the world scripts.
2. messages to multiple ships
There are some instances where it's useful to send an AI message to more than one ship at the same time, often without the recipients having been targetted and without having prior knowledge of their roles. For example, in a tournament event you may have several ships that all need to be told to cease firing at a certain moment. I've latched onto using ECM pulses to achieve this (as seen in the Purple Strand device in Missiles & Bombs) but I wondered if there's another way? What I'm after is a way to send a message to all ships in range, which can then be used to trigger an AI or ship script function.
Posted: Thu Aug 20, 2009 3:59 pm
by Thargoid
What I would do is the following:
1) Rather than use aronar-knight as the role, I would use knight-aronar or something like that. Then even if things get alphabetised, they will still be in the same sequence as it's based on the "knight-" bit.
2) Do a scan for the ships within range, filter as necessary and then step through the produced array and for each use <ship>.AIState or <ship>.reactToAIMessage to either change the AI state of the ship or send the given AI state a message - depending on how you want to do it.
Posted: Sun Aug 23, 2009 6:00 pm
by Ramirez
I've just been converting my shipdata from XML to ASCII and something strange cropped up. I accidentally left a buoy with an empty beacon code in the shipdata.plist:
and this is what appeared on the compass:
Does this mean I can use the feudal systems' castle symbol to identify the feudal lodges in this OXP?
Posted: Sun Aug 23, 2009 6:04 pm
by DaddyHoggy
Now that's what I call Serendipitous!
Posted: Sun Aug 23, 2009 6:19 pm
by ZygoUgo
Cool, is that from WingDings or some such?
Edit:
http://fontstruct.fontshop.com/news/200 ... creencast/ The gallery shows it can produce detailed fonts once you know how, so I presume producing symbols on it wouldn't be beyond it's scope.
If not, there's this..
http://fontforge.sourceforge.net/overview.html#intro
Posted: Sun Aug 23, 2009 6:22 pm
by Kaks
_ds_ submitted a patch - it's been in trunk for a while now - that allows you to create your own icons for any beacon, instead of using letters... It's a bit fiddly, but Thargoid already has his fuel stations marked out with a petrol pump icon, IIRC. Sadly my forum search skills are very rusty atm...
Needless to say, the anarchy system symbol is wholly unexpected. and I wouln't even hazard a guess on how to get the other political system symbols / economy symbols to display as beacons!