Direct3D9 / HLSL Depth semantic not working - c#

i have o problem with my shader code (HLSL). I use "DirectX for Managed Code" and Shader Model 3.0. I try to write a custom depth value into the depth buffer by using the DEPTH semantic in the pixel shader output struct:
struct PSOutput
{
float4 col : COLOR0;
float dept : DEPTH;
};
and i use this struct as return value in my pixel shader:
PSOutput PSFunction(VertexShaderOutput input)
{
PSOutput output;
...
output.col = float4(...);
output.dept = ...;
return output;
}
DirectX throws an exeption when i try to compile this shader, but gives no detailed information why. But when i remove the depth variable from the output struct it works! I also tried to write DEPTH0 as semantic, but no success. I hope anyone can help my with that.
EDIT:
If i write the following, it fails:
PSOutput PSFunction(VertexShaderOutput input)
{
PSOutput output;
float resDepth = input.Position[2] / input.Position[3];
if(...)
{
resDepth = ...;
}
output.col = float4(...);
output.dept = resDepth;
return output;
}
but if i write this code, it compiles:
PSOutput PSFunction(VertexShaderOutput input)
{
PSOutput output;
float resDepth = input.Position[2] / input.Position[3];
if(...)
{
resDepth = ...;
}
output.col = float4(...);
output.dept = 0.5;
return output;
}
any ideas?
Here's the full code:
float4x4 World;
float4x4 View;
float4x4 Projection;
float4 CamPos;
float4 LightDir;
float4 ObjColor;
static const float PI = 3.14159265f;
static const int MAX_FU = 32;
float fuPercent[MAX_FU];
float4 fuColor[MAX_FU];
int buildDir;
static int fuCount = 2;
float4 boxMin;
float4 boxMax;
struct VertexShaderInput
{
float4 Position : POSITION0;
float3 Normal : NORMAL;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float3 Normal : NORMAL;
float3 ExactPos : TEXCOORD1;
};
struct PSOutput
{
float4 col : COLOR0;
//float dept : DEPTH;
};
VertexShaderOutput VSFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.Normal = mul(input.Normal, World);
output.ExactPos = input.Position;
return output;
}
PSOutput PSFunction(VertexShaderOutput input)
{
PSOutput output;
float4 resColor = ObjColor;
float resDepth = input.Position[2] / input.Position[3];
float prpos = 0;
if (buildDir == 0)
{
prpos = (input.ExactPos[1] - boxMin[1]) / (boxMax[1] - boxMin[1]);
}
else if (buildDir == 1)
{
prpos = 1.0 - ((input.ExactPos[1] - boxMin[1]) / (boxMax[1] - boxMin[1]));
}
else if (buildDir == 2)
{
prpos = (input.ExactPos[2] - boxMin[2]) / (boxMax[2] - boxMin[2]);
}
else if (buildDir == 3)
{
prpos = 1.0 - ((input.ExactPos[2] - boxMin[2]) / (boxMax[1] - boxMin[2]));
}
else if (buildDir == 4)
{
prpos = (input.ExactPos[0] - boxMin[0]) / (boxMax[0] - boxMin[0]);
}
else if (buildDir == 5)
{
prpos = 1.0 - ((input.ExactPos[0] - boxMin[0]) / (boxMax[0] - boxMin[0]));
}
float currPerc = 1.1;
for (int i = 0; i < fuCount; i++)
{
if (prpos - 0.0001 <= fuPercent[i])
{
if (fuPercent[i] < currPerc)
{
currPerc = fuPercent[i];
resColor = fuColor[i];
}
}
else
{
resDepth = 1.0;
resColor[3] = 0.0;
}
}
float3 nor = input.Normal;
float3 pos = input.ExactPos;
float glo = 0.5;
float id = (acos(dot(LightDir,nor) / pow(dot(LightDir,LightDir) * dot(nor, nor), 0.5)) / PI );
id = pow(id,2);
float3 look = reflect(normalize(pos - CamPos), nor);
float gl = (acos(dot(LightDir,look) / pow(dot(LightDir,LightDir) * dot(look, look), 0.5)) / PI );
gl = max(gl * 10.0 - 9.0, 0.0);
gl = pow(gl,2) * glo;
output.col = float4(resColor[0] * id + gl, resColor[1] * id + gl, resColor[2] * id + gl, resColor[3]);
//output.dept = resDepth;
return output;
}
technique MyTechnique
{
pass Pass1
{
VertexShader = compile vs_3_0 VSFunction();
PixelShader = compile ps_3_0 PSFunction();
}
}

If FXC is throwing an exception during compilation rather than giving you a compilation error it's probably not anything you've done wrong.
If you're using the DirectX SDK make sure you're using the most recent version (June 2010). If you're using the Windows Kit 8.0 SDK then you may have found a compiler bug. What version of the SDK / fxc are you using?
Can you post a shader that actually compiles (one with the missing VertexShaderOutput struct and without ...'s in place of actual code)? I've filled in the missing code and have no problem compiling it using fxc from Windows Kit 8.0.
EDIT:
Nope, I hadn't spotted you'd commented out the code that made it not compile.
Sure enough, it doesn't compile, but that's because it's not valid code (as reported by the compile errors). You're using the POSITION semantic as an input to your pixel shader, which is not valid. If you want to use the outputted position from a vertex shader as input to a pixel shader, copy it into a second attribute and use that instead. If I substitute the following code into your shader it then compiles:
struct VertexShaderOutput
{
float4 ClipPosition : POSITION; // Renamed this to ClipPosition.
float4 Position : TEXCOORD0; // This is valid to use as an input to the pixel shader.
float3 Normal : NORMAL;
float3 ExactPos : TEXCOORD1;
};
struct PSOutput
{
float4 col : COLOR0;
float dept : DEPTH;
};
VertexShaderOutput VSFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.ClipPosition = mul(viewPosition, Projection);
output.Position = output.ClipPosition; // Copy output position to our other attribute.
output.Normal = mul(input.Normal, World);
output.ExactPos = input.Position;
return output;
}

Related

How to make Shader(unity) interact with lights with specific intensity?

I am working on a cel shader for a uni project that I would like to only be affected by scene lights over x intensity. I am struggling in figuring out how to implement this within the code. The code I have been working with I found online, and have been using it to test and understand how shaders work. I am unsure if I need to implement some kind of conditional statement? Some of the information I have read has said that using conditional statements within shaders makes for poor performance.
I am new to shaders and any help would be greatly appreciated.
Thank you in advance :)
ps. I am limited to using Unity 2018.3.8
Properties {
[Header(Base Parameters)]
_Color ("Tint", Color) = (0, 0, 0, 1)
_MainTex ("Texture", 2D) = "white" {}
[HDR] _Emission ("Emission", color) = (0, 0, 0, 1)
[HDR]
_SpecularColor("Specular Color", Color) = (0.9, 0.9, 0.9, 1)
// Controls the size of the specular reflection.
_Glossiness("Glossiness", Float) = 32
[HDR]
_RimColor("Rim Color", Color) = (1,1,1,1)
_RimAmount("Rim Amount", Range(0, 1)) = 0.716
// Control how smoothly the rim blends when approaching unlit
// parts of the surface.
_RimThreshold("Rim Threshold", Range(0, 1)) = 0.1
}
SubShader {
Tags{ "RenderType"="Opaque" "Queue"="Geometry"}
CGPROGRAM
#pragma surface surf Stepped fullforwardshadows
#pragma target 3.0
sampler2D _MainTex;
fixed4 _Color;
half3 _Emission;
float4 _SpecularColor;
float _Glossiness;
float4 _RimColor;
float _RimAmount;
float _RimThreshold;
float3 worldPos;
float4 LightingStepped(SurfaceOutput s, float3 lightDir, half3 viewDir, float shadowAttenuation){
float shadow = shadowAttenuation;
s.Normal=normalize(s.Normal);
float diff = dot(s.Normal, lightDir);
float towardsLightChange = fwidth(diff);
float lightIntensity = smoothstep(0, towardsLightChange, diff);
float3 diffuse = _LightColor0.rgb * lightIntensity * s.Albedo;
float diffussAvg = (diffuse.r + diffuse.g + diffuse.b) / 3;
float3 halfVector = normalize(viewDir + lightDir);
float NdotH = dot(s.Normal, halfVector);
float specularIntensity = pow(NdotH * lightIntensity, _Glossiness * _Glossiness);
float specularIntensitySmooth = smoothstep(0.005, 0.01, specularIntensity);
float3 specular = specularIntensitySmooth * _SpecularColor.rgb * diffussAvg;
float rimDot = 1 - dot(viewDir, s.Normal);
float rimIntensity = rimDot * pow(dot(lightDir, s.Normal), _RimThreshold);
rimIntensity = smoothstep(_RimAmount - 0.01, _RimAmount + 0.01, rimIntensity);
float3 rim = rimIntensity * _RimColor.rgb * diffussAvg;
float4 color;
color.rgb = (diffuse + specular + rim) * shadow;
color.a = s.Alpha;
return color;
}
struct Input {
float2 uv_MainTex;
float3 worldPos;
};
void surf (Input i, inout SurfaceOutput o) {
worldPos = i.worldPos;
fixed4 col = tex2D(_MainTex, i.uv_MainTex);
col *= _Color;
o.Albedo = col.rgb;
o.Alpha = col.a;
o.Emission = _Emission;
}
ENDCG
}
FallBack "Standard"
}

Why am I getting a for-loop error in Unity RayMarching shader?

This is my first shader so it's probably some dumb tiny error.
I'm following a tutorial on YouTube:
https://www.youtube.com/watch?v=S8AWd66hoCo&t=83s&pbjreload=10
I'm stuck with the distance function (for a sphere) and simply can't get it to work without some weird error going with my for loop. Everything before that worked perfectly. I rewrote the for-loop but get this error over and over.
Thank you in advance!
(Unity 2019.2.19f1)
ERRORS:
+Shader error in 'Unlit/RayMarchOne': syntax error: unexpected token ')' at line 58 (on d3d11)
+Shader error in 'Unlit/RayMarchOne': syntax error: unexpected token '=' at line 58 (on d3d11)
+Shader error in 'Unlit/RayMarchOne': 'GetDist': no matching 1 parameter function at line 60 (on d3d11)
+Shader error in 'Unlit/RayMarchOne': undeclared identifier 'p' at line 60 (on d3d11)
CODE:
Shader "Unlit/RayMarchOne"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#define MAX_STEPS = 100
#define MIN_DIST = .001
#define MAX_DIST = 100.
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
float GetDist(float3 p)
{
float d = length(p) - .5;
return d;
}
float RayMarch(float3 ro, float3 rd)
{
float dO = 0;
float dS;
for (int i = 0; i < MAX_STEPS; i++) {
float3 p = ro + dO * rd;
dS = GetDist(p);
dO += dS;
if (dS<MIN_DIST || dO>MAX_DIST) break;
}
return dO;
}
fixed4 frag(v2f i) : SV_Target
{
float2 uv = i.uv-.5;
float3 ro = float3(0,0,-3);
float3 rd = normalize(float3(uv.x, uv.y, 1));
float d = RayMarch(ro, rd);
fixed4 col = 0;
if (d < maxDist)
{
col.r = 1;
}
return col;
}
ENDCG
}
}
}
Remove the = signes from your defines.
#define MAX_STEPS = 100
#define MIN_DIST = .001
#define MAX_DIST = 100.
should be
#define MAX_STEPS 100
#define MIN_DIST .001
#define MAX_DIST 100.
And one more maxDist instead of MAX_DIST, and it compiles.
( I have that = in my defines also sometimes. :-) )

How to create a shader that can display a texture made out of many small images in Unity

So what I'm trying to do is load satellite images from an SQL table and wrap them around a sphere to create a globe. I know I've got loading the images covered, I'm just not sure how to make my shader display the images in the correct orientation.
I've gone to the Unity Forums as well as checked out this code from the Unity Docs.
Using the linked shader code and the help I received on the forums, here's the code I've ended up with:
Properties
{
_MainTexArray("Tex", 2DArray) = "" {}
_SliceRange("Slices", Range(0,32)) = 6
_UVScale("UVScale", Float) = 1
_COLUMNS("Columns", Range(0, 5)) = 1
_ROWS("Rows", Range(0, 5)) = 1
_CELLS("Cells", Range(0, 32)) = 16
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// texture arrays are not available everywhere,
// only compile shader on platforms where they are
#pragma require 2darray
#include "UnityCG.cginc"
struct v2f
{
float3 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float _SliceRange;
float _UVScale;
v2f vert(float4 vertex : POSITION)
{
v2f o;
o.vertex = UnityObjectToClipPos(vertex);
o.uv.xy = (vertex.xy + 0.5) * _UVScale;
o.uv.z = (vertex.z + 0.5) * _SliceRange;
return o;
}
float _COLUMNS; //Columns and rows only go between 0 and 1
float _ROWS;
float _CELLS;
UNITY_DECLARE_TEX2DARRAY(_MainTexArray);
half4 frag(v2f i) : SV_Target
{
float3 uv = float3(i.uv.x * _CELLS, i.uv.y * _CELLS, 0);
uv.z = floor(i.uv.x / _COLUMNS) * floor(i.uv.y / _ROWS);
return UNITY_SAMPLE_TEX2DARRAY(_MainTexArray, uv / _CELLS);
}
ENDCG
}
}
Using that I've gotten my materials to look like this:
Here's the code that I'm using to load the SQL images:
textures = new Texture2D[size];
for (int x = 0; x <= 7; x++)
{
for (int y = 0; y <= 3; y++)
{
textures[count] = tiler.Read(x, y, 2); //The z determines the zoom level, so I wouldn't want them all loaded at once
if (textures[count] != null) TextureScale.Bilinear(textures[count], 256, 256);
count++;
}
}
texArr = new Texture2DArray(256, 256, textures.Length, TextureFormat.RGBA32, true, true);
texArr.filterMode = FilterMode.Bilinear;
texArr.wrapMode = TextureWrapMode.Repeat;
for (int i = 0; i < textures.Length; i++)
{
if (textures[i] == null) continue;
texArr.SetPixels(textures[i].GetPixels(0), i, 0);
}
texArr.Apply();
mat.SetTexture("_MainTexArray", texArr);
In the SQL Table, the x and y determines the position of the tile and the z determines the zoom level. I'm just working with one zoom level for now.
Sorry for linking the whole shader class, but I'm not very experienced with shaders so I don't quite know where the problem lies.
If you can index into the array of photos such that you effectively have an equirectangular projection of the globe, you could try using a modified form of the shader code by Farfarer from the Unity forums copied and modified slightly below:
Shader "Custom/Equirectangular" {
Properties{
_MainTexArray("Tex", 2DArray) = "" {}
_COLUMNS("Columns", Int) = 2
_ROWS("Rows", Int) = 2
}
SubShader{
Pass {
Tags {"LightMode" = "Always"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma require 2darray
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal : TEXCOORD0;
};
v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.normal = v.normal;
return o;
}
UNITY_DECLARE_TEX2DARRAY(_MainTexArray);
int _ROWS;
int _COLUMNS;
#define PI 3.141592653589793
inline float2 RadialCoords(float3 a_coords)
{
float3 a_coords_n = normalize(a_coords);
float lon = atan2(a_coords_n.z, a_coords_n.x);
float lat = acos(a_coords_n.y);
float2 sphereCoords = float2(lon, lat) * (1.0 / PI);
return float2(sphereCoords.x * 0.5 + 0.5, 1 - sphereCoords.y);
}
float4 frag(v2f IN) : COLOR
{
float2 equiUV = RadialCoords(IN.normal);
float2 texIndex;
float2 uvInTex = modf(equiUV * float2(_COLUMNS,_ROWS), texIndex);
int flatTexIndex = texIndex.x * _ROWS + texIndex.y;
return UNITY_SAMPLE_TEX2DARRAY(_MainTexArray,
float3(uvInTex, flatTexIndex));
}
ENDCG
}
}
FallBack "VertexLit"
}
You also need to use
texArr = new Texture2DArray(256, 256, textures.Length, TextureFormat.RGBA32, false, true);
instead of
texArr = new Texture2DArray(256, 256, textures.Length, TextureFormat.RGBA32, true, false);
It works for me if I attach this script to a sphere:
Material myMat;
public List<Texture2D> texes;
IEnumerator Start()
{
yield return null;
myMat = GetComponent<Renderer>().material;
Texture2DArray texArr = new Texture2DArray(256, 256, 9,
TextureFormat.RGBA32, false, true);
texArr.filterMode = FilterMode.Bilinear;
texArr.wrapMode = TextureWrapMode.Clamp;
for (int i = 0 ; i < texes.Count ; i++)
{
texArr.SetPixels(texes[i].GetPixels(), i, 0);
}
texArr.Apply();
myMat.SetTexture("_MainTexArray", texArr);
}
and in texes I add these textures in order:
0:
1:
2:
3:
4:
5:
6:
7:
8:
and set 3 for Rows and Columns, it produces decent results:
If bilinear filtering is enabled, there are still some artifacts at the borders of the textures. But these artifacts have to be zoomed in quite close to see. Due to the lack of adjacent pixels for bilinear filtering they mostly appear as improperly blended or missing pixels:
Of course this example doesn't properly tile so there is an obvious seam along one longitude line:
Since this setup expects normals from a sphere, this only works on things with normals that approximate those of a sphere. So it would not render properly on a plane, for instance.

Add Alpha to Shader

I have the following shader,
I'm trying to add an alpha to the white, however all attempts have proven to be difficult.
This is the project from which I obtained the shader for reference - github
I think it has to do with one of the passes overwriting.
Shader "Suibokuga/Suibokuga" {
Properties {
_MainTex ("Water Texture", 2D) = "white" {}
_Alpha ("Transfer/Diffusion coefficient for water particles", Range(0.01, 1.5)) = 1.0
_Evaporation ("a unit quantity of water for evaporation", Range(0.0001, 0.005)) = 0.00015
_PaperTex ("Paper Texture", 2D) = "white" {}
_Brush ("brush", Vector) = (-1, -1, -1, -1)
_Prev ("previous brush position", Vector) = (-1, -1, -1, -1)
}
CGINCLUDE
#include "UnityCG.cginc"
#pragma target 3.0
/*
* r : water particles
* b : capacities of water
* a : the heights of the bottoms
*/
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float _Alpha;
float _Evaporation;
sampler2D _PaperTex;
float2 _Prev;
float3 _Brush; // x,y : position, z : size
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
v2f vert (appdata IN) {
v2f OUT;
OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
OUT.uv = IN.uv;
return OUT;
}
void sample (float2 uv, out float4 o, out float4 l, out float4 t, out float4 r, out float4 b) {
float2 texel = _MainTex_TexelSize.xy;
o = tex2D(_MainTex, uv);
l = tex2D(_MainTex, uv + float2(-texel.x, 0));
t = tex2D(_MainTex, uv + float2( 0, -texel.y));
r = tex2D(_MainTex, uv + float2( texel.x, 0));
b = tex2D(_MainTex, uv + float2( 0, texel.y));
}
float waterDelta (float4 k, float4 o) {
float ld = (k.w + k.x) - (o.w + o.x); // level difference
float transfer = (k.w + k.x) - max(o.w, k.w + k.z); // transferable water particles
return max(
0.0,
0.25 * _Alpha * min(ld, transfer)
);
}
float waterFlow (float2 uv) {
float4 o, l, t, r, b;
sample(uv, o, l, t, r, b);
float nw = o.r;
nw += (waterDelta(l, o) - waterDelta(o, l));
nw += (waterDelta(t, o) - waterDelta(o, t));
nw += (waterDelta(r, o) - waterDelta(o, r));
nw += (waterDelta(b, o) - waterDelta(o, b));
return max(nw, 0);
}
float evaporation (float wo) {
return max(wo - _Evaporation, 0.0);
}
float brush (float2 uv) {
const int count = 10;
float2 dir = _Brush.xy - _Prev.xy;
float l = length(dir);
if(l <= 0) {
float d = length(uv - _Brush.xy);
return smoothstep(0.0, _Brush.z, _Brush.z - d);
}
float ld = l / count;
float2 norm = normalize(dir);
float md = 100;
for(int i = 0; i < count; i++) {
float2 p = _Prev.xy + norm * ld * i;
float d = length(uv - p);
if(d < md) {
md = d;
}
}
return smoothstep(0.0, _Brush.z, _Brush.z - md);
// float d = length(uv - _Brush.xy);
// return smoothstep(0.0, _Brush.z, _Brush.z - d);
}
ENDCG
SubShader {
Cull Off ZWrite Off ZTest Always
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment init
float4 init (v2f IN) : SV_Target {
float4 paper = tex2D(_PaperTex, IN.uv);
return float4(
0,
0,
paper.r,
paper.r
);
}
ENDCG
}
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment waterUpdate
float4 waterUpdate (v2f IN) : SV_Target {
float4 col = tex2D(_MainTex, IN.uv);
col.x = evaporation(waterFlow(IN.uv));
float dw = brush(IN.uv);
// if(dw > 0) {
col.x = min(col.x + brush(IN.uv), 1.0);
// }
return col;
}
ENDCG
}
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment visualize
float4 visualize (v2f IN) : SV_Target {
float4 col = tex2D(_MainTex, IN.uv);
return float4(1.0 - col.xxx, 1.0);
}
ENDCG
}
}
}
You seem to miss a blending step.
Try adding this line to the end of the last pass
Blend SrcAlpha OneMinusSrcAlpha
Check this page to learn about alpha blending for Unity shaders.
The line I attached is for standard transparency, you might want to try different blending options.

Normal mapping giving wierd results. (C# XNA)

Okay, so this problem is kinda huge, and for the same reason i would rather post as little code as possible, but rather have you come with ideas as to what it could be. I will post the codere where i feel the problem could be. If you would like to see more just ask and i will provide it.
So, i just "stole" a shader for my game. By stole i mean found a tutorial that i had done before, and just copied the end result. Thus i know the shader should work, because i've used it before.
I have a custom mesh class, and also a custom vertex struct. I have never done a xertex struct before so initially i thought this is where the problem was.
But i have some counterarguments i later found:
All of their variables seems to be right, and everything works except the bump-mapping.
Changing the Tangent and/or binormal seems to have no effect on the shading what-so-ever. So i think the mistake is not in how they are calulated, but rather how they are used.
http://imageshack.us/photo/my-images/838/w6kv.png/
This is the output i get. Keep in mind that this is a voxel engine. As you can see all the boxes has the same wierd normal-map shadow. However this is the normal map:
http://imageshack.us/photo/my-images/268/r7jt.jpg/
As you can see, they don't fit whatsoever. Now, this could be one of three things as i see it:
It could be the way i set up the shader in xna.
It could also be something in the vertex struct
It could also be the way i call the actual drawing function.
So here's the code for those three things (And the shader as well):
Shader Setup:
((Here i set up the data for the shader, and the draw the mesh))
// Bind the parameters with the shader.
BBS.Parameters["World"].SetValue(Matrix.Identity);
BBS.Parameters["View"].SetValue(camera.viewMatrix);
BBS.Parameters["Projection"].SetValue(camera.projectionMatrix);
BBS.Parameters["AmbientColor"].SetValue(Color.White.ToVector4());
BBS.Parameters["AmbientIntensity"].SetValue(0.5f);
Vector3 LD = new Vector3(0, 1, -1);
LD.Normalize();
BBS.Parameters["DiffuseColor"].SetValue(Color.White.ToVector4());
BBS.Parameters["DiffuseIntensity"].SetValue(0);
BBS.Parameters["LightDirection"].SetValue(LD);
BBS.Parameters["EyePosition"].SetValue(new Vector3(0.0f, 2.0f, 5.0f));
BBS.Parameters["SpecularColor"].SetValue(Color.White.ToVector4());
BBS.Parameters["ColorMap"].SetValue(cubeTexture);
BBS.Parameters["NormalMap"].SetValue(Content.Load<Texture2D>("images"));
BBS.CurrentTechnique = BBS.Techniques["Technique1"];
for (int i = 0; i < BBS.CurrentTechnique.Passes.Count; i++)
{
//EffectPass.Apply will update the device to
//begin using the state information defined in the current pass
BBS.CurrentTechnique.Passes[i].Apply();
//theMesh contains all of the information required to draw
//the current mesh
graphics.DrawUserPrimitives(PrimitiveType.TriangleList, Mesh.Vertices, 0, Mesh.NUM_TRIANGLES);
}
Vertex struct:
public struct VertexPositionNormalTangentBinormalTexture : IVertexType
{
public Vector3 Position;
public Vector3 Normal;
public Vector2 TextureCoordinate;
public Vector3 Tangent;
public Vector3 Binormal;
public static readonly VertexDeclaration VertexElements = new VertexDeclaration
(
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
new VertexElement(12, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0),
new VertexElement(24, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
new VertexElement(32, VertexElementFormat.Vector3, VertexElementUsage.Tangent, 0),
new VertexElement(44, VertexElementFormat.Vector3, VertexElementUsage.Binormal, 0)
);
VertexDeclaration IVertexType.VertexDeclaration { get { return VertexElements; } }
public static readonly int SizeInBytes = sizeof(float) * (3 + 3 + 2 + 3 + 3);
}
Shader:
// XNA 4.0 Shader Programming #4 - Normal Mapping
// Matrix
float4x4 World;
float4x4 View;
float4x4 Projection;
// Light related
float4 AmbientColor;
float AmbientIntensity;
float3 LightDirection;
float4 DiffuseColor;
float DiffuseIntensity;
float4 SpecularColor;
float3 EyePosition;
texture2D ColorMap;
sampler2D ColorMapSampler = sampler_state
{
Texture = <ColorMap>;
MinFilter = linear;
MagFilter = linear;
MipFilter = linear;
};
texture2D NormalMap;
sampler2D NormalMapSampler = sampler_state
{
Texture = <NormalMap>;
MinFilter = linear;
MagFilter = linear;
MipFilter = linear;
};
// The input for the VertexShader
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
float3 Normal : NORMAL0;
float3 Binormal : BINORMAL0;
float3 Tangent : TANGENT0;
};
// The output from the vertex shader, used for later processing
struct VertexShaderOutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
float3 View : TEXCOORD1;
float3x3 WorldToTangentSpace : TEXCOORD2;
};
// The VertexShader.
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.TexCoord = input.TexCoord;
output.WorldToTangentSpace[0] = mul(normalize(input.Tangent), World);
output.WorldToTangentSpace[1] = mul(normalize(input.Binormal), World);
output.WorldToTangentSpace[2] = mul(normalize(input.Normal), World);
output.View = normalize(float4(EyePosition,1.0) - worldPosition);
return output;
}
// The Pixel Shader
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float4 color = tex2D(ColorMapSampler, input.TexCoord);
float3 normalMap = 2.0 *(tex2D(NormalMapSampler, input.TexCoord)) - 1.0;
normalMap = normalize(mul(normalMap, input.WorldToTangentSpace));
float4 normal = float4(normalMap,1.0);
float4 diffuse = saturate(dot(-LightDirection,normal));
float4 reflect = normalize(2*diffuse*normal-float4(LightDirection,1.0));
float4 specular = pow(saturate(dot(reflect,input.View)),32);
return color * AmbientColor * AmbientIntensity +
color * DiffuseIntensity * DiffuseColor * diffuse +
color * SpecularColor * specular;
}
// Our Techinique
technique Technique1
{
pass Pass1
{
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
This Is Not Done In The Correct Order:
output.WorldToTangentSpace[0] = mul(normalize(input.Tangent), World);
output.WorldToTangentSpace[1] = mul(normalize(input.Binormal), World);
output.WorldToTangentSpace[2] = mul(normalize(input.Normal), World);
It Should Be Like This:
output.WorldToTangentSpace[0] = normalize(mul(input.Tangent, World));
output.WorldToTangentSpace[1] = normalize(mul(input.Binormal, World));
output.WorldToTangentSpace[2] = normalize(mul(input.Normal, World));
Otherwise, Your Normals Will Get Scaled From The World-space Transformation And Will Result In Very Bright And Very Dark Patches (Which Looks Like Your Problem). BTW, Seeing As You're Interested In Normal Mapping For Voxel Engines, Check Out The Following That I Had Made:
http://www.youtube.com/watch?v=roMlOmNgr_w
http://www.youtube.com/watch?v=qkfHoGzQ8ZY
Hope You Get Inspired And That You Complete Your Project.

Categories