The "Montreal Gazette" has been running a series of articles about professional game designers, based on "Ubisoft," but which aim not to explain technical details as much as to explain the job interactions. Yet, I've been able to combine what I've read with technical knowledge I already had, and to glean technical details and ideas from one such article anyhow.
In question, one article yesterday (Sunday) explained that when the goal is to animate Las Vegas -style slot machines, Modellers create a general Model of the shape of the slot machine, while "Shadow Artists" create the blinking lights and displays on a slot machine that can make a large number of them look interesting and convincing. Because I already know something about "Shaders," I was able to infer that it's the function of a Shader, to produce such tiny blinking lights and displays. This idea actually makes a lot more sense to me today, days after I read it, than it did when I first read it. Because in my mind I've done the exercise in principle.
For my purposes I'll assume that I'd want to program this using my "3D Game Studio," even though this Shader project would probably be too big for me, ever to see the light of day. But, who knows? I was once so obsessed about animating a burning tree that it eventually drove me to implement one. Yet today, I don't have an open game project, to try this idea out. I *might* just plunk an arbitrary Model into the Demo Level that came with 3DGS, *if* I do decide to draw the required Skins as well.
If I wanted to, I'd need to face the fact that the entire panel needs to be done with the same Shader! Yet, I've devised a hypothetical way.
Entity Skin 1 would depict the colour of the display panel, by convention, when no blinking lights are lit. And Entity Skin 2 would be a 'DOT3 Bump-Map,' which means a Height-Map that looks like a relief pattern when lit by the environment. Even when working within the limited confines of 3D Game Studio v6.31.4, a Shader-programmer needs to know if each Entity Skin has one of two 16-bit colour formats. One format is a simple RGB colour, thus having 5+6+5 bits, and the other allows even Skins to have an additional Alpha channel to modulate how non-transparent the surface is. The RGBA pixels have 4+4+4+4 bits. But for my idea, Entity Skin 3 could simply store 1 out of 16 possible 1-bit colour values. My Shader would ignore what ugly colour this would represent, because it would carry out a logical AND operation between Entity Skin 3 and a single 16-bit parameter being passed from the code controlling the Model Entity. This parameter can then turn each of 12 lights on and off independently, while the Shader runs for the entire display panel, filtering all the available Entity Skin 3 colours through the (C-Scripted) parameter. If the result is not equal to zero, the next assembler instruction can add the colour value of Entity Skin 4 to that already produced.
This would imply a very versatile, reusable Shader, which my "SMEE2" tool isn't powerful enough to write for me. Instead, it would be a programmed Shader which I'd need to hand-code, but which my Commercial Edition of 3DGS would still pass to the DirectX interface and assemble. And it would allow numerous lamps to have an off state, in which they may be dull and rough, yet to be lit in different ways, described in full shape and colour by the graphics of Entity Skin 4. So blinking hieroglyphics would be possible against a dark, flat panel, or instead a dull half-sunk bulb could be, which reveals an internal filament when (instantly) lit. Surfaces which don't require blinking lights would have Entity Skin 3 set entirely to zero, and would continue to Bump-Map.
In the case of slot machines as well as 'mad-scientist devices,' there also need to be additional displays, that consists of mechanical cylinders, etc.. These could be implemented as Material Skins 1 through 4, where each Skin can be programmed to be addressed with an offset which normally already wraps around vertically or horizontally. To activate those, 4 special bits in Entity Skin 3 could have a different programmed effect from the other 12, in that they cause a separate Pass of the Shader to look to Entity Skin 4 not for light-information, but rather for Red, Green and Blue colour channels to be used differently. Red and Green would help scale the instances of the mechanical widget in U and V coordinates into position on the Entity. For widgets the low 4 bits of entSkin3 would select through which one of the Material Matrix elements the display panel will obtain its offset for that widget instance, passed from the Entity Actions again. Thus 16 widgets would be possible, each with a different position. So more than one slot-machine cylinder could use Material Skin 1 at once... And because graphics cards use parallel GPU-channels to run Shader Passes concurrently, this later Pass would not slow down the first one...
I've decided that only one single Entity Skin, number 3, would ever need to have exact colours, because these later Shader Passes for widgets would also extract the channel number from Entity Skin 3. In coding the Shader, the first Pass for the lights would additionally need to shut itself off, if any of the highest 4 bits are set, so that the use of the lowest 4 bits for widgets doesn't trip lights as well.
But then the drawing of Entity Skins would only entail, that the Shader-programmer supply the Shadow Artist with named colour swatches in the setup of ?PhotoShop? , telling him to use them on Entity Skin 3 for the named effects. And then Entity Skin 4 would contain graphic art for the most part, defining how lights would appear. Additionally Entity Skin 4 would then receive rectangles that can also be given to the ...Artist, regardless of which widget for, so that he can paste them into ...Skin 4, without having to modify them any further.
Tell me if this is wrong:
////////////////////////////////////////////////////////////////////////////////
// Slot-Machine Shader by Dirk Mittler
// November 7, 2006: Preliminary code.
// November 8, 2006: Made 2 ways for widgets to be off.
// Looked up c2[r0] notation.
// Corrected cmpz --> min 1
// November 9, 2006: Adjusted for FIXED register widths ...?
// v2: Diffuse widget colouring.
extern float4x4 matWorldViewProj;
extern float4x4 matMtl; // Display-position channel of each widget, as
// enumerated in low 4 bits of entSkin3 .
// Locked w mtlSkill1 = 1 as belonging to
// only 1 Entity. mtlSkill1 not used by Shader.
// mtlSkill1 = 0 -> Widgets available to new Ent.
extern vector entSkill41; // Receive parameter bits from Ent.
// Use pixel_for_vec()
extern texture entSkin1; // Normal colours.
extern texture entSkin2; // Normal-Map.
// Use bmap_to_normals()
extern texture entSkin3; // Control bits.
// Low 12 bits & entSkill41 bits for
// each light effect to be on.
// High 4 bits & entSkill41 bits for
// each widget-type on, lights off.
extern texture entSkin4; // Light effects OR (Widget rectangles:)
// Green = X, Red = Y fixed gradients.
extern texture mtlSkin1; // First designed widget.
extern texture mtlSkin2; // More widgets...
extern texture mtlSkin3;
extern texture mtlSkin4;
technique working // Author: DirkMittler
{
pass p0 // Regular Bump-Mapping.
{
//TEXTURE STAGE [0]
Texture[0] = <entSkin2>;
ColorOp[0] = DotProduct3;
//TEXTURE STAGE [1]
Texture[1] = <entSkin1>;
ColorOp[1] = Modulate;
}
pass p1 // Light Effects.
{
AlphaBlendEnable = true;
SrcBlend = SrcColor;
DestBlend = SrcColor;
PixelShaderConstant[0] = <entSkill41>;
Texture[0] = <entSkin3>;
Texture[1] = <entSkin4>;
PixelShader = asm {
ps.1.4
texld r0, t0; // Mapped bits.
and r0, r0, 61440; // Off if widgets.
min r2, r0, 1;
sub r2, 1, r2; // 1 if zero.
texld r0, t0;
mov r1, c0; // Mask w parameter bits.
and r0, r0, r1;
min r0, r0, 1; // True (1) if NOT zero.
mul r2, r2, r0; // Still active?
texld r0, t1; // Light effects.
mul r0, r0, r2; // Zero if off.
};
}
pass p2 // Widget type 1.
{
VertexShaderConstant[0] = <entSkill41>;
VertexShaderConstant[1] = <matWorldViewProj>;
VertexShaderConstant[2] = <matMtl>;
//PixelShaderConstant[0] = <entSkill41>;
Texture[0] = <entSkin3>;
Texture[1] = <entSkin4>;
Texture[2] = <mtlSkin1>;
VertexShader = asm {
vs.1.1
dcl_position v0;
dcl_normal v3;
dcl_texcoord0 v7;
dcl_texcoord1 v8;
// There are really 2 ways for the widget-effect to be
// switched off.
// The pixel could be outside the rectangle, or
// the parameter bit could deactivate the effect.
// In the second case, the widget must still be rendered
// in the default position, to make the surfaces look uniform.
texld r0, t0; // Load control bits.
and r0, r0, 4096; // Test 13th bit.
and r0, r0, c0; // Allow param bits to turn off.
min r2, r0, 1; // True (1) if not zero.
texld r0, t0;
and r0, r0, 15; // Get position channel.
mul r0, r0, r2; // Default to channel 0.
mov r3, c2[r0]; // Load position channel.
mul r3, r3, r2; // Freeze widget if off.
texld r0, t1; // Widget window.
mov r1, r0.r; // Y-coord 0-31.
add r1, r1, r3; // Offset.
mov r3, r0.g; // X-coord 0-63.
mov oT2.u, r3; // Widget-def =mtlSkin Index.
mov oT2.v, r1;
mov oT0, v7; // Same index.
m4x4 oPos v0, c1; // Put on screen.
// A separate pixel-shader in version 1...
texld r0, t0; // Load control bits.
and r0, r0, 4096; // Test 13th bit.
// Ignore param bits to turn off.
min r2, r0, 1; // True (1) if not zero.
texld r0, t2; // Load widget image.
mul r2, r2, -1; // Unknown Alpha width.
mov r0.a, r2; // Alpha if on.
mov oD0, r0; // Set diffuse colour.
};
}
};
technique not-working {
pass p0 // Regular Bump-Mapping.
{
//TEXTURE STAGE [0]
Texture[0] = <entSkin2>;
ColorOp[0] = DotProduct3;
//TEXTURE STAGE [1]
Texture[1] = <entSkin1>;
ColorOp[1] = Modulate;
}
};