Our software currently uses the fixed function pipeline in Direct3D9 to offer our users an easily scriptable way of throwing lights and objects into a simple scene. We allow directional, point and spot lights. I'm trying to move us over to Direct3D11, but I want it to be as close to the Direct3D9 fixed function pipeline as possible as a baseline. We can add stuff like per-pixel lighting later. I'm brand new to shader coding and even though I've been doing C++ for years, I feel out of my element. I'm wondering if there is a DX11 supported shader out there which perfectly emulates the lighting offered by DX9 fixed function pipeline. I have seen the old point-light emulation example in FixedFuncEMUFX11, and I'll be trying to use that as a base, but I just know I'm not doing this as efficiently as it could be, and the math for proper spot light emulation is beyond me. Is there any open source out there which emulates the fixed function pipeline, or would contain directional, point, and spot light implementations for DirectX11/10? I think all I'd need are the .fx or .hlsl files. Even if it tops out at 8 light sources, that'd be fine.
I'm currently using DirectXTK as a guide to proper DirectX11 programming, but if there is a better standard to code to, I'd love to see an example of industry standard DirectX11 rendering engine programming methodology. Thank you for any advice you can give.
For basic rendering with Direct3D 11, the DirectX Tool Kit built-in shaders are based on the XNA Game Studio 4 which provides a good set of basic features including directional lighting and per-pixel lighting. They are designed to work with all Direct3D Feature Level hardware, so they don't implement things like spotlights which are easily done with more modern hardware.
The FixedFuncEMU11 sample is a Direct3D 11 port of the legacy DirectX SDK's FixedFuncEMU Direct3D 10 sample. The shaders are useful for understanding the various Direct3D 9 specific fixed-function pipeline, but doesn't cover 'standard' stuff like implementing standard lighting models in HLSL. Also note that this sample uses the Effects system for Direct3D 11 which has it's own issues. Still, it's useful for seeing:
Fixed-function Transformation Pipeline
Fixed-function Lighting Pipeline
AlphaTest
User Clip Planes
Pixel Fog
Gouraud and Flat shade modes
Projected texture lookups (texldp)
Multi-Texturing
D3DFILL_POINT fillmode
Screen space UI rendering
You might want to try some of the old Direct3D 9 era introductions to HLSL shader programming. While not 100% compatible with Direct3D 11, they are pretty close and HLSL itself is basically the same. I found this article for example.
There are also a number of excellent Direct3D 11 books all of which cover HLSL shaders since there's no fixed-function pipeline in Direct3D 11. See Book Recommendations for some details and notes as some of those books were written before the DirectX SDK was retired. In particular, you should look at Real-Time 3D Rendering with DirectX and HLSL by Varcholik as it's heavily focused on HLSL authoring.
For anyone who wound up here by searching for a Fixed Function Pipeline emulation in hlsl, this is pretty much exactly what I was looking for: http://www.3dgep.com/texturing-lighting-directx-11/ The shader in there is not very optimized, but is written for clarity and a good introduction for beginners to hlsl. There is very little extra cruft to sift through in order to see exactly what is going on and the bare minimum to get your scene running. The spotlight isn't an exact replication of DX9's FFP spotlight, but it is easily modified to become such.
#define MAX_LIGHTS 8
// Light types.
#define DIRECTIONAL_LIGHT 0
#define POINT_LIGHT 1
#define SPOT_LIGHT 2
Texture2D Texture : register(t0);
sampler Sampler : register(s0);
struct _Material
{
float4 Emissive; // 16 bytes
//----------------------------------- (16 byte boundary)
float4 Ambient; // 16 bytes
//------------------------------------(16 byte boundary)
float4 Diffuse; // 16 bytes
//----------------------------------- (16 byte boundary)
float4 Specular; // 16 bytes
//----------------------------------- (16 byte boundary)
float SpecularPower; // 4 bytes
bool UseTexture; // 4 bytes
float2 Padding; // 8 bytes
//----------------------------------- (16 byte boundary)
}; // Total: // 80 bytes ( 5 * 16 )
cbuffer MaterialProperties : register(b0)
{
_Material Material;
};
struct Light
{
float4 Position; // 16 bytes
//----------------------------------- (16 byte boundary)
float4 Direction; // 16 bytes
//----------------------------------- (16 byte boundary)
float4 Color; // 16 bytes
//----------------------------------- (16 byte boundary)
float SpotAngle; // 4 bytes
float ConstantAttenuation; // 4 bytes
float LinearAttenuation; // 4 bytes
float QuadraticAttenuation; // 4 bytes
//----------------------------------- (16 byte boundary)
int LightType; // 4 bytes
bool Enabled; // 4 bytes
int2 Padding; // 8 bytes
//----------------------------------- (16 byte boundary)
}; // Total: // 80 bytes (5 * 16 byte boundary)
cbuffer LightProperties : register(b1)
{
float4 EyePosition; // 16 bytes
//----------------------------------- (16 byte boundary)
float4 GlobalAmbient; // 16 bytes
//----------------------------------- (16 byte boundary)
Light Lights[MAX_LIGHTS]; // 80 * 8 = 640 bytes
}; // Total: // 672 bytes (42 * 16 byte boundary)
float4 DoDiffuse( Light light, float3 L, float3 N )
{
float NdotL = max( 0, dot( N, L ) );
return light.Color * NdotL;
}
float4 DoSpecular( Light light, float3 V, float3 L, float3 N )
{
// Phong lighting.
float3 R = normalize( reflect( -L, N ) );
float RdotV = max( 0, dot( R, V ) );
// Blinn-Phong lighting
float3 H = normalize( L + V );
float NdotH = max( 0, dot( N, H ) );
return light.Color * pow( RdotV, Material.SpecularPower );
}
float DoAttenuation( Light light, float d )
{
return 1.0f / ( light.ConstantAttenuation + light.LinearAttenuation * d + light.QuadraticAttenuation * d * d );
}
struct LightingResult
{
float4 Diffuse;
float4 Specular;
};
LightingResult DoPointLight( Light light, float3 V, float4 P, float3 N )
{
LightingResult result;
float3 L = ( light.Position - P ).xyz;
float distance = length(L);
L = L / distance;
float attenuation = DoAttenuation( light, distance );
result.Diffuse = DoDiffuse( light, L, N ) * attenuation;
result.Specular = DoSpecular( light, V, L, N ) * attenuation;
return result;
}
LightingResult DoDirectionalLight( Light light, float3 V, float4 P, float3 N )
{
LightingResult result;
float3 L = -light.Direction.xyz;
result.Diffuse = DoDiffuse( light, L, N );
result.Specular = DoSpecular( light, V, L, N );
return result;
}
float DoSpotCone( Light light, float3 L )
{
float spotMinAngle = cos( light.SpotAngle );
float spotMaxAngle = ( spotMinAngle + 1.0f ) / 2.0f;
float cosAngle = dot( light.Direction.xyz, L );
return smoothstep( spotMinAngle, spotMaxAngle, cosAngle );
}
LightingResult DoSpotLight( Light light, float3 V, float4 P, float3 N )
{
LightingResult result;
float3 L = ( light.Position - P ).xyz;
float distance = length(L);
L = L / distance;
float attenuation = DoAttenuation( light, distance );
float spotIntensity = DoSpotCone( light, -L );
result.Diffuse = DoDiffuse( light, L, N ) * attenuation * spotIntensity;
result.Specular = DoSpecular( light, V, L, N ) * attenuation * spotIntensity;
return result;
}
LightingResult ComputeLighting( float4 P, float3 N )
{
float3 V = normalize( EyePosition - P ).xyz;
LightingResult totalResult = { {0, 0, 0, 0}, {0, 0, 0, 0} };
[unroll]
for( int i = 0; i < MAX_LIGHTS; ++i )
{
LightingResult result = { {0, 0, 0, 0}, {0, 0, 0, 0} };
if ( !Lights[i].Enabled ) continue;
switch( Lights[i].LightType )
{
case DIRECTIONAL_LIGHT:
{
result = DoDirectionalLight( Lights[i], V, P, N );
}
break;
case POINT_LIGHT:
{
result = DoPointLight( Lights[i], V, P, N );
}
break;
case SPOT_LIGHT:
{
result = DoSpotLight( Lights[i], V, P, N );
}
break;
}
totalResult.Diffuse += result.Diffuse;
totalResult.Specular += result.Specular;
}
totalResult.Diffuse = saturate(totalResult.Diffuse);
totalResult.Specular = saturate(totalResult.Specular);
return totalResult;
}
struct PixelShaderInput
{
float4 PositionWS : TEXCOORD1;
float3 NormalWS : TEXCOORD2;
float2 TexCoord : TEXCOORD0;
};
float4 TexturedLitPixelShader( PixelShaderInput IN ) : SV_TARGET
{
LightingResult lit = ComputeLighting( IN.PositionWS, normalize(IN.NormalWS) );
float4 emissive = Material.Emissive;
float4 ambient = Material.Ambient * GlobalAmbient;
float4 diffuse = Material.Diffuse * lit.Diffuse;
float4 specular = Material.Specular * lit.Specular;
float4 texColor = { 1, 1, 1, 1 };
if ( Material.UseTexture )
{
texColor = Texture.Sample( Sampler, IN.TexCoord );
}
float4 finalColor = ( emissive + ambient + diffuse + specular ) * texColor;
return finalColor;
}
Related
I am currently learning shaders in OpenGL and finished writing my "drawText" geometry shader, so I can draw dynamic text ( content change every frame ), without recreating VBO every frame.
It's working nicely but it's limited to 28 chars, because of the GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS limitations that is equal 1024.
ATM I have 6 components per vertex emitted vec4 pos and vec2 texCoord.
Which give me 1024/6 = 170 vertices to use for my triangle strip.
I need 6 vertices per char ( instead first and last char ) to display a quad per char and 2 vertices to move to next char with degenerated triangle.
That gives me 170/6 = 28 chars.
So when I have a long text, I split it into text of 28 chars.
So now I try to optimize that and get my geometry shader to draw more than 28 chars.
So because I am in 2D, I was trying to find a way to store the texCoord in the pos.zw for the fragment shader. and remove the out vec2 texCoord in my geometry shader. Which will make me emit only 4 components per vertex, which would bring me to 42 chars.
But reading the fragment shader doc and fragment systems input I don't see who to do this.
So, is there a way to achieve that?
My code for reference
Vertex Shader
#version 330 core
layout (location = 0) in vec2 aPos;
uniform vec2 textPosition;
void main()
{
gl_Position = vec4(aPos ,0, 1) + vec4(textPosition, 0, 0);
}
Fragment Shader
#version 330 core
out vec4 fragColor;
in vec2 texCoord;
uniform vec4 textColor;
uniform sampler2D outTexture;
void main()
{
fragColor = texture(outTexture, texCoord) * textColor;
}
Geometry Shader
#version 330 core
layout (points) in;
layout (triangle_strip, max_vertices = 170) out;
// max components and vertices are 1024
// vec4 pos and vec2 text coord per vertex, that 6 components per vertex, 1024 / 6 = 170
out vec2 texCoord;
uniform float screenRatio = 1;
uniform float fontRatio = 1;
uniform float fontInterval = 0; // distance between letters
uniform float fontSize = 0.025f; // default value, screen coord range is -1f , 1f
uniform int textString[8]; // limited to 28 chars . 170 vertices / 6 = 28, 28 / 4 = 7 ints.
void main()
{
vec4 position = gl_in[0].gl_Position;
float fsx = fontSize * fontRatio * screenRatio;
float fsy = fontSize;
float tsy = 1.0f / 16.0f; // fixed in a 16x16 chars bitmap
float tsx = tsy;
float tw = tsx * fontRatio;
float to = ( tsx - tw ) * 0.5f;
vec4 ptl = position + vec4(0,0,0,0); // top left
vec4 ptr = position + vec4(fsx,0,0,0); // top right
vec4 pbl = position + vec4(0,fsy,0,0); // bottom left
vec4 pbr = position + vec4(fsx,fsy,0,0); // bottom right
vec2 tt; // tex coord top
vec2 tb; // tex coord bottom
fsx += fontInterval;
int i = 0; // index in int array
int si = 0; // sub index in int
int ti = textString[0];
int ch = 0;
do
{
// unpack a char, 4 chars per int
ch = (ti >> si) & (0xFF);
// string ends with \0 or end of array
if ( ch == 0 || i >= 8)
break;
// compute row and col of char in bitmaps 16x16 chars
int r = ch >> 4;
int c = ch - ( r << 4 );
// compute tex coord from row and column
tb = vec2(c * tsx + to, 1.0f - r * tsy);
tt = vec2(tb.x , tb.y - tsy);
texCoord = tt;
gl_Position = ptl;
EmitVertex();
EmitVertex();
texCoord = tb;
gl_Position = pbl;
EmitVertex();
tt.x += tw;
tb.x += tw;
texCoord = tt;
gl_Position = ptr;
EmitVertex();
texCoord = tb;
gl_Position = pbr;
EmitVertex();
EmitVertex();
// advance of 1 char
ptl.x += fsx;
ptr.x += fsx;
pbl.x += fsx;
pbr.x += fsx;
si += 8;
if ( si >= 32 )
{
si = 0;
++i;
ti = textString[i];
}
}
while ( true );
EndPrimitive();
}
The position of a vertex to be sent to the rasterizer, as defined through gl_Position, contains 4 components. Always. And the meaning of those components is defined by the rasterizer and the OpenGL rendering system.
You cannot bypass or otherwise get around it. The output position has 4 components, and you cannot hide texture coordinates or other arbitrary data within them.
If you need to output more stuff from the GS, then you need to more efficiently use your GS's vertex output. As it currently stands, you output degenerate strips between each quad. This means that for every 6 vertices, only 4 of them are meaningful. You're using degenerate strips to split quads.
Instead of doing that, you should use EndPrimitive to split your quads. That will remove 1/3rd of all of your vertex output, giving you more components to put to actual good use.
I have coded a fragment shader in vizard IDE and its not working. The code is free of compilation errors except for one which says, " ERROR: 0:? : 'variable' : is not available in current GLSL version gl_TexCoord."
FYI the gl_TexCoord is the output of the vertex shader which is in build to vizard. Can someone help me to fix it. here is the code:
#version 440
// All uniforms as provided by Vizard
uniform sampler2D vizpp_InputDepthTex; // Depth texture
uniform sampler2D vizpp_InputTex; // Color texture
uniform ivec2 vizpp_InputSize; // Render size of screen in pixels
uniform ivec2 vizpp_InputPixelSize; // Pixel size (1.0/vizpp_InputSize)
uniform mat4 osg_ViewMatrix; // View matrix of camera
uniform mat4 osg_ViewMatrixInverse; // Inverse of view matrix
// Your own uniforms
//uniform sampler2D u_texture;
//uniform sampler2D u_normalTexture;
uniform sampler2D g_FinalSSAO;
const bool onlyAO = false; //Only show AO pass for debugging
const bool externalBlur = false; //Store AO in alpha slot for a later blur
struct ASSAOConstants
{
vec2 ViewportPixelSize; // .zw == 1.0 / ViewportSize.xy
vec2 HalfViewportPixelSize; // .zw == 1.0 / ViewportHalfSize.xy
vec2 DepthUnpackConsts;
vec2 CameraTanHalfFOV;
vec2 NDCToViewMul;
vec2 NDCToViewAdd;
ivec2 PerPassFullResCoordOffset;
vec2 PerPassFullResUVOffset;
vec2 Viewport2xPixelSize;
vec2 Viewport2xPixelSize_x_025; // Viewport2xPixelSize * 0.25 (for fusing add+mul into mad)
float EffectRadius; // world (viewspace) maximum size of the shadow
float EffectShadowStrength; // global strength of the effect (0 - 5)
float EffectShadowPow;
float EffectShadowClamp;
float EffectFadeOutMul; // effect fade out from distance (ex. 25)
float EffectFadeOutAdd; // effect fade out to distance (ex. 100)
float EffectHorizonAngleThreshold; // limit errors on slopes and caused by insufficient geometry tessellation (0.05 to 0.5)
float EffectSamplingRadiusNearLimitRec; // if viewspace pixel closer than this, don't enlarge shadow sampling radius anymore (makes no sense to grow beyond some distance, not enough samples to cover everything, so just limit the shadow growth; could be SSAOSettingsFadeOutFrom * 0.1 or less)
float DepthPrecisionOffsetMod;
float NegRecEffectRadius; // -1.0 / EffectRadius
float LoadCounterAvgDiv; // 1.0 / ( halfDepthMip[SSAO_DEPTH_MIP_LEVELS-1].sizeX * halfDepthMip[SSAO_DEPTH_MIP_LEVELS-1].sizeY )
float AdaptiveSampleCountLimit;
float InvSharpness;
int PassIndex;
vec2 QuarterResPixelSize; // used for importance map only
vec4 PatternRotScaleMatrices[5];
float NormalsUnpackMul;
float NormalsUnpackAdd;
float DetailAOStrength;
float Dummy0;
mat4 NormalsWorldToViewspaceMatrix;
};
uniform ASSAOConstants g_ASSAOConsts;
float PSApply( in vec4 inPos, in vec2 inUV)
{ //inPos = gl_FragCoord;
float ao;
uvec2 pixPos = uvec2(inPos.xy);
uvec2 pixPosHalf = pixPos / uvec2(2, 2);
// calculate index in the four deinterleaved source array texture
int mx = int (pixPos.x % 2);
int my = int (pixPos.y % 2);
int ic = mx + my * 2; // center index
int ih = (1-mx) + my * 2; // neighbouring, horizontal
int iv = mx + (1-my) * 2; // neighbouring, vertical
int id = (1-mx) + (1-my)*2; // diagonal
vec2 centerVal = texelFetchOffset( g_FinalSSAO, ivec2(pixPosHalf), 0, ivec2(ic, 0 ) ).xy;
ao = centerVal.x;
if (true){ // change to 0 if you want to disable last pass high-res blur (for debugging purposes, etc.)
vec4 edgesLRTB = UnpackEdges( centerVal.y );
// convert index shifts to sampling offsets
float fmx = mx;
float fmy = my;
// in case of an edge, push sampling offsets away from the edge (towards pixel center)
float fmxe = (edgesLRTB.y - edgesLRTB.x);
float fmye = (edgesLRTB.w - edgesLRTB.z);
// calculate final sampling offsets and sample using bilinear filter
vec2 uvH = (inPos.xy + vec2( fmx + fmxe - 0.5, 0.5 - fmy ) ) * 0.5 * g_ASSAOConsts.HalfViewportPixelSize;
float aoH = textureLodOffset( g_FinalSSAO, uvH, 0, ivec2(ih , 0) ).x;
vec2 uvV = (inPos.xy + vec2( 0.5 - fmx, fmy - 0.5 + fmye ) ) * 0.5 * g_ASSAOConsts.HalfViewportPixelSize;
float aoV = textureLodOffset( g_FinalSSAO, uvV, 0, ivec2( iv , 0) ).x;
vec2 uvD = (inPos.xy + vec2( fmx - 0.5 + fmxe, fmy - 0.5 + fmye ) ) * 0.5 * g_ASSAOConsts.HalfViewportPixelSize;
float aoD = textureLodOffset( g_FinalSSAO, uvD, 0, ivec2( id , 0) ).x;
// reduce weight for samples near edge - if the edge is on both sides, weight goes to 0
vec4 blendWeights;
blendWeights.x = 1.0;
blendWeights.y = (edgesLRTB.x + edgesLRTB.y) * 0.5;
blendWeights.z = (edgesLRTB.z + edgesLRTB.w) * 0.5;
blendWeights.w = (blendWeights.y + blendWeights.z) * 0.5;
// calculate weighted average
float blendWeightsSum = dot( blendWeights, vec4( 1.0, 1.0, 1.0, 1.0 ) );
ao = dot( vec4( ao, aoH, aoV, aoD ), blendWeights ) / blendWeightsSum;
}
return ao;
}
void main(void)
{
// Get base values
vec2 texCoord = gl_TexCoord[0].st;
vec4 color = texture2D(vizpp_InputTex,texCoord);
float depth = texture2D(vizpp_InputDepthTex,texCoord).x;
// Do not calculate if nothing visible (for VR for instance)
if (depth>=1.0)
{
gl_FragColor = color;
return;
}
float ao = PSApply(gl_FragCoord, texCoord);
// Output the result
if(externalBlur) {
gl_FragColor.rgb = color.rgb;
gl_FragColor.a = ao;
}
else if(onlyAO) {
gl_FragColor.rgb = vec3(ao,ao,ao);
gl_FragColor.a = 1.0;
}
else {
gl_FragColor.rgb = ao*color.rgb;
gl_FragColor.a = 1.0;
}
}
gl_TexCoord is a deprecated Compatibility Profile Built-In Language Variables and is removed after GLSL Version 1.20.
If you want to use gl_TexCoord then you would have to use GLSL version 1.20 (#version 120).
But, you don't need the deprecated compatibility profile built-in language variable at all. Define a Vertex shader output texCoord and use this output rather than gl_TexCoord:
#version 440
out vec2 texCoord;
void main()
{
texCoord = ...;
// [...]
}
Specify a corresponding input in the fragment shader:
#version 440
in vec2 texCoord;
void main()
{
vec4 color = texture2D(vizpp_InputTex, texCoord.st);
// [...]
}
I refer to the OBS Studio 20.1.0 documentation and chroma_key_filter.effect on github. I have had a problem with the recent homemade obs-studio filter. I can't think of how to solve it. I want to ask everyone here, I hope I can get some suggestions or answers.
The first problem is that when the power point presentation is captured, the background is set to red (Figure 1), and then I can get the edge of the text with my own edge detection kernel, but the usual green(or blue) color will not show the effect (Figure 2)? (The OBS-studio resource uses a white background for the convenience of seeing the effect)
enter image description here
Figure 1.
enter image description here
Figure 2.
The second problem is that the filter has changed to other kernel. On the contrary, the parameterized horizontal scroll bar have no effect. Is it necessary to adjust the position to make the fullmask work (Figure 3)?
enter image description here
Figure 3.
The code show is as follows(Its programming language uses the HLSL or GLSL language):
uniform float4x4 ViewProj;
uniform texture2d image;
uniform float4x4 yuv_mat = { 0.182586, 0.614231, 0.062007, 0.062745,
-0.100644, -0.338572, 0.439216, 0.501961,
0.439216, -0.398942, -0.040274, 0.501961,
0.000000, 0.000000, 0.000000, 1.000000};
uniform float4 color;
uniform float contrast;
uniform float brightness;
uniform float gamma;
uniform float2 chroma_key;
uniform float4 key_rgb;
uniform float2 pixel_size;
uniform float similarity;
uniform float smoothness;
uniform float spill;
// 3x3 kernel for convolution edge detection.
uniform float3 kernel1 = { -1.0, -1.0, -1.0};
uniform float3 kernel2 = {-1.0, 8.0, -1.0};
uniform float3 kernel3 = {-1.0, -1.0, -1.0 };
sampler_state textureSampler {
Filter = Linear;
AddressU = Clamp;
AddressV = Clamp;
};
struct VertData {
float4 pos : POSITION;
float2 uv : TEXCOORD0; //Texture coordinates.
};
VertData VSDefault(VertData v_in)
{
VertData vert_out;
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
vert_out.uv = v_in.uv;
return vert_out;
}
float4 CalcColor(float4 rgba)
{
return float4(pow(rgba.rgb, float3(gamma, gamma, gamma)) * contrast + brightness, rgba.a);
}
float GetChromaDist(float3 rgb)
{
float4 yuvx = mul(float4(rgb.rgb, 1.0), yuv_mat); //rgb to yuv
return distance(chroma_key, yuvx.yz); // Take the distance scalar value of two vectors.
}
float4 SampleTexture(float2 uv)
{
return image.Sample(textureSampler, uv);
}
// 3x3 filter of Edge detection
float GetEdgeDetectionFilteredChromaDist(float3 rgb, float2 texCoord)
{
float distVal = SampleTexture(-texCoord-pixel_size).rgb * kernel1[0]; // Top left
distVal += SampleTexture(texCoord-pixel_size).rgb * kernel1[1]; // Top center
distVal += SampleTexture(texCoord-float2(pixel_size.x, 0.0)).rgb * kernel1[2]; // Top right
distVal += SampleTexture(texCoord-float2(pixel_size.x, -pixel_size.y)).rgb * kernel2[0]; // Middle left
distVal += SampleTexture(texCoord-float2(0.0, pixel_size.y)).rgb * kernel2[1]; // Current pixel
distVal += SampleTexture(texCoord+float2(0.0, pixel_size.y)).rgb * kernel2[2]; // Middle right
distVal += SampleTexture(texCoord+float2(pixel_size.x, -pixel_size.y)).rgb * kernel3[0]; // Bottom left
distVal += SampleTexture(texCoord+float2(pixel_size.x, 0.0)).rgb * kernel3[1]; // Bottom center
distVal += SampleTexture(texCoord+pixel_size).rgb * kernel3[2]; // Bottom right
return distVal;
}
float4 ProcessChromaKey(float4 rgba, VertData v_in)
{
float chromaDist = GetEdgeDetectionFilteredChromaDist(rgba.rgb, v_in.uv);//Edge detection filter function.
float baseMask = chromaDist - similarity;
float fullMask = pow(saturate(baseMask / smoothness), 1.5);
float spillVal = pow(saturate(baseMask / spill), 1.5);
rgba.rgba *= color;
rgba.a *= fullMask;
float desat = (rgba.r * 0.2126 + rgba.g * 0.7152 + rgba.b * 0.0722);
rgba.rgb = saturate(float3(desat, desat, desat)) * (1.0 - spillVal) + rgba.rgb * spillVal;
return CalcColor(rgba);
}
float4 PSChromaKeyRGBA(VertData v_in) : TARGET
{
float4 rgba = image.Sample(textureSampler, v_in.uv);
return ProcessChromaKey(rgba, v_in);
}
technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSChromaKeyRGBA(v_in);
}
}
Thank you!
I've been following along with the OpenGL 4 Shading Language cookbook and have gotten a teapot rendering with bezier surfaces. The next step I'm attempting is to draw a wireframe over the surfaces using a geometry shader. The directions can be found here on pages 228-230. Following the code that is given, I've gotten the wireframe to display, however, I also have multiple fragments that flicker different shades of my material color.
An image of this can be seen
I have narrowed down the possible issues and have discovered that for some reason, when I perform my triangle height calculations, I am getting variable side lengths for my calculations, as if I hard code the values in the edge distance for each vertex of the triangle within the geometry shader, the teapot no longer flickers, but neither does a wireframe display. (variables ha, hb, hc in the geo shader below)
I was wondering if anyone has run into this issue before or are aware of a workaround.
Below are some sections of my code:
Geometry Shader:
/*
* Geometry Shader
*
* CSCI 499, Computer Graphics, Colorado School of Mines
*/
#version 410 core
layout( triangles ) in;
layout( triangle_strip, max_vertices = 3 ) out;
out vec3 GNormal;
out vec3 GPosition;
out vec3 ghalfwayVec;
out vec3 GLight;
noperspective out vec3 GEdgeDistance;
in vec4 TENormal[];
in vec4 TEPosition[];
in vec3 halfwayVec[];
in vec3 TELight[];
uniform mat4 ViewportMatrix;
void main() {
// Transform each vertex into viewport space
vec3 p0 = vec3(ViewportMatrix * (gl_in[0].gl_Position / gl_in[0].gl_Position.w));
vec3 p1 = vec3(ViewportMatrix * (gl_in[1].gl_Position / gl_in[1].gl_Position.w));
vec3 p2 = vec3(ViewportMatrix * (gl_in[2].gl_Position / gl_in[2].gl_Position.w));
// Find the altitudes (ha, hb and hc)
float a = length(p1 - p2);
float b = length(p2 - p0);
float c = length(p1 - p0);
float alpha = acos( (b*b + c*c - a*a) / (2.0*b*c) );
float beta = acos( (a*a + c*c - b*b) / (2.0*a*c) );
float ha = abs( c * sin( beta ) );
float hb = abs( c * sin( alpha ) );
float hc = abs( b * sin( alpha ) );
// Send the triangle along with the edge distances
GEdgeDistance = vec3( ha, 0, 0 );
GNormal = vec3(TENormal[0]);
GPosition = vec3(TEPosition[0]);
gl_Position = gl_in[0].gl_Position;
EmitVertex();
GEdgeDistance = vec3( 0, hb, 0 );
GNormal = vec3(TENormal[1]);
GPosition = vec3(TEPosition[1]);
gl_Position = gl_in[1].gl_Position;
EmitVertex();
GEdgeDistance = vec3( 0, 0, hc );
GNormal = vec3(TENormal[2]);
GPosition = vec3(TEPosition[2]);
gl_Position = gl_in[2].gl_Position;
EmitVertex();
EndPrimitive();
ghalfwayVec = halfwayVec[0];
GLight = TELight[0];
}
Fragment Shader:
/*
* Fragment Shader
*
* CSCI 441, Computer Graphics, Colorado School of Mines
*/
#version 410 core
in vec3 ghalfwayVec;
in vec3 GLight;
in vec3 GNormal;
in vec3 GPosition;
noperspective in vec3 GEdgeDistance;
layout( location = 0 ) out vec4 FragColor;
uniform vec3 mDiff, mAmb, mSpec;
uniform float shininess;
uniform light {
vec3 lAmb, lDiff, lSpec, lPos;
};
// The mesh line settings
uniform struct LineInfo {
float Width;
vec4 Color;
} Line;
vec3 phongModel( vec3 pos, vec3 norm ) {
vec3 lightVec2 = normalize(GLight);
vec3 normalVec2 = -normalize(GNormal);
vec3 halfwayVec2 = normalize(ghalfwayVec);
float sDotN = max( dot(lightVec2, normalVec2), 0.0 );
vec4 diffuse = vec4(lDiff * mDiff * sDotN, 1);
vec4 specular = vec4(0.0);
if( sDotN > 0.0 ) {
specular = vec4(lSpec * mSpec * pow( max( 0.0, dot( halfwayVec2, normalVec2 ) ), shininess ),1);
}
vec4 ambient = vec4(lAmb * mAmb, 1);
vec3 fragColorOut = vec3(diffuse + specular + ambient);
// vec4 fragColorOut = vec4(0.0,0.0,0.0,0.0);
return fragColorOut;
}
void main() {
// /*****************************************/
// /******* Final Color Calculations ********/
// /*****************************************/
// The shaded surface color.
vec4 color=vec4(phongModel(GPosition, GNormal), 1.0);
// Find the smallest distance
float d = min( GEdgeDistance.x, GEdgeDistance.y );
d = min( d, GEdgeDistance.z );
// Determine the mix factor with the line color
float mixVal = smoothstep( Line.Width - 1, Line.Width + 1, d );
// float mixVal = 1;
// Mix the surface color with the line color
FragColor = vec4(mix( Line.Color, color, mixVal ));
FragColor.a = 1;
}
I ended up stumbling across the solution to my issue. In the geometry shader, I was passing the halfway vector and the light vector after ending the primitive, as such, the values of these vectors was never being correctly sent to the fragment shader. Since no data was given to the fragment shader, garbage values were used and the Phong shading model used random values to compute the fragment color. Moving the two lines after EndPrimative() to the top of the main function in the geometry shader resolved the issue.
Working my way through the "Introduction to 3D Game Programming with Directx 11". I am reworking the samples so as to not use the Effects Framework, so far all good.
However, I have come up with a problem that one of the constant buffers only partially updates.
CPU side CB struct:
struct CBPerFrame
{
DirectionalLight DirLight[3];
DirectX::XMFLOAT3 EyePositionW;
DirectX::XMFLOAT4 FogColour;
float FogStart;
float FogRange;
int LightNumber;
double Padding;
};
Where I update the CB prior to any drawing.
CBPerFrame cbPerFrame { };
cbPerFrame.DirLight[ 0 ] = mDirectionalLights[ 0 ];
cbPerFrame.DirLight[ 1 ] = mDirectionalLights[ 1 ];
cbPerFrame.DirLight[ 2 ] = mDirectionalLights[ 2 ];
cbPerFrame.EyePositionW = mEyePosW;
cbPerFrame.FogColour = XMFLOAT4( Colors::Black );
cbPerFrame.FogRange = 1.0F;
cbPerFrame.FogStart = 0.0F;
cbPerFrame.LightNumber = mLightCount;
cbPerFrame.Padding = 0.0;
mD3DImmediateContext->UpdateSubresource( mCBPerFrame.Get( ), 0, nullptr, &cbPerFrame, 0, 0 );
Pixel Shader:
cbuffer CBPerFrame : register( b0 )
{
DirectionalLight gDirectionalLights[ 3 ];
float3 gEyePosW;
float4 gFogColor;
float gFogStart;
float gFogRange;
int gLightCount;
double gPadding;
}
cbuffer CBPerObject : register( b1 )
{
matrix gWorld;
matrix gWorldInverseTranspose;
matrix gWorldViewProjection;
float4x4 gTextureTransform;
Material gMaterial;
}
float4 main( VertexOut input ) : SV_TARGET
{
// Interpolating normal can unnormalize it, so normalize it.
input.NormalW = normalize( input.NormalW );
// The toEye vector is used in lighting.
float3 toEye = normalize( gEyePosW - input.PositionW );
// Cache the distance to the eye from this surface point.
float distToEye = length( toEye );
// Normalize.
toEye /= distToEye;
//
// Lighting.
//
// Start with a sum of zero.
float4 ambient = float4( 0.0F, 0.0F, 0.0F, 0.0F );
float4 diffuse = float4( 0.0F, 0.0F, 0.0F, 0.0F );
float4 spec = float4( 0.0F, 0.0F, 0.0F, 0.0F );
// Sum the light contribution from each light source.
/* [unroll]*/
for ( int i = 0; i < gLightCount; i++ )
{
float4 A, D, S;
ComputeDirectionalLight( gMaterial, gDirectionalLights[ i ], input.NormalW, toEye, A, D, S );
ambient += A;
diffuse += D;
spec += S;
}
float4 litColour = ambient + diffuse + spec;
// Common to take alpha from diffuse material.
litColour.a = gMaterial.Diffuse.a;
return litColour;
}
gLightCount is always set to 0, even though it should be set to 2 at the start of the application. If I change the condition of the loop to a hardcoded 1/2/3 the shader works as it should.
I realise that there are extra variables in the CB, but the sample code has this and I believe it is used in further examples.
I think the issue is to do with how the CBPerFrame struct is padded, so it isn't been copied over to the GPU correctly. Any thoughts?
Thanks for any help.
It seems to be an issue with packing. According to Packing Rules for Constant Variables data should be packed at 4-byte boundaries but also so data blocks won't cross 16-byte boundary. In this case there will be definitely a padding after EyePositionW:
struct CBPerFrame
{
DirectionalLight DirLight[3];
DirectX::XMFLOAT3 EyePositionW;
float padding1;
DirectX::XMFLOAT4 FogColour;
Also i'm not sure why is there double gPadding; at the end. It should probably be another int.