temperamental ID3D10EffectVectorVariable - c++

I am setting an HLSL effect variable in the following way in a number of places.
extern ID3D10EffectVectorVariable* pColour;
pColour = pEffect->GetVariableByName("Colour")->AsVector();
pColour->SetFloatVector(temporaryLines[i].colour);
In one of the places it is set in a loop, each line in the vector temporaryLines has a D3DXCOLOR variable associated with it. The most annoying thing about this problem is that it actually works on rare occasions, but most of the time it doesn't. Are there any known issues with this kind of code?
Here it works:
void GameObject::Draw(D3DMATRIX matView, D3DMATRIX matProjection)
{
device->IASetInputLayout(pVertexLayout);
mesh.SetTopology();//TODO should not be done multiple times
// select which vertex buffer and index buffer to display
UINT stride = sizeof(VERTEX);
UINT offset = 0;
device->IASetVertexBuffers(0, 1, mesh.PBuffer(), &stride, &offset);
device->IASetIndexBuffer(mesh.IBuffer(), DXGI_FORMAT_R32_UINT, 0);
pColour->SetFloatVector(colour);
// create a scale matrix
D3DXMatrixScaling(&matScale, scale.x, scale.y, scale.z);
// create a rotation matrix
D3DXMatrixRotationYawPitchRoll(&matRotate, rotation.y, rotation.x, rotation.z);
// create a position matrix
D3DXMatrixTranslation(&matTranslation, position.x, position.y, position.z);
// combine the matrices and render
matFinal =
matScale *
matRotate *
matTranslation *
matView * matProjection;
pTransform->SetMatrix(&matFinal._11);
pRotation->SetMatrix(&matRotate._11); // set the rotation matrix in the effect
pPass->Apply(0);
device->DrawIndexed(mesh.Indices(), 0, 0); //input specific
}
Here is occasionally works:
void BatchLineRenderer::RenderLines(D3DXMATRIX matView, D3DXMATRIX matProjection)
{
device->IASetInputLayout(pVertexLayout);
device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP);
// select which vertex buffer and index buffer to display
UINT stride = sizeof(LINE);
UINT offset = 0;
device->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset);
device->IASetIndexBuffer(iBuffer, DXGI_FORMAT_R32_UINT, 0);
allLines = temporaryLines.size();
for(int i = 0; i < allLines; i++)
{
pColour->SetFloatVector(temporaryLines[i].colour); // in the line loop too?
// combine the matrices and render
D3DXMATRIX matFinal =
temporaryLines[i].scale *
temporaryLines[i].rotation *
temporaryLines[i].position *
matView * matProjection;
pTransform->SetMatrix(&matFinal._11);
pRotation->SetMatrix(&temporaryLines[i].rotation._11); // set the rotation matrix in the effect
pPass->Apply(0);
device->DrawIndexed(2, 0, 0);
}
temporaryLines.clear();
}
the effect file:
float4x4 Transform; // a matrix to store the transform
float4x4 Rotation; // a matrix to store the rotation transform
float4 LightVec = {0.612f, 0.3535f, 0.612f, 0.0f}; // the light's vector
float4 LightCol = {1.0f, 1.0f, 1.0f, 1.0f}; // the light's color
float4 AmbientCol = {0.3f, 0.3f, 0.3f, 1.0f}; // the ambient light's color
float4 Colour;
// a struct for the vertex shader return value
struct VSOut
{
float4 Col : COLOR; // vertex normal
float4 Pos : SV_POSITION; // vertex screen coordinates
};
// the vertex shader
VSOut VS(float4 Norm : NORMAL, float4 Pos : POSITION)
{
VSOut Output;
Output.Pos = mul(Pos, Transform); // transform the vertex from 3D to 2D
Output.Col = AmbientCol; // set the vertex color to the input's color
float4 Normal = mul(Norm, Rotation);
Output.Col += saturate(dot(Normal, LightVec)) * LightCol * Colour; // add the diffuse and passed in light
return Output; // send the modified vertex data to the Rasterizer Stage
}
// the pixel shader
float4 PS(float4 Col : COLOR) : SV_TARGET
{
return Col; // set the pixel color to the color passed in by the Rasterizer Stage
}
// the primary technique
technique10 Technique_0
{
// the primary pass
pass Pass_0
{
SetVertexShader(CompileShader(vs_4_0, VS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0, PS()));
}
}

So the Colour HLSL variable has not been defined inside a ConstantBuffer, just a normal shader variable.
Perhaps the variable should rather be defined in a Constant buffer, updateblae per frame? Similar to how the world and view matrices should be defined in. At least then the GPU knows you want to update the colour variable each time you render. (As you are updating the value before you draw).
cbuffer cbChangesEveryFrame
{
//The MVP matrices.
matrix World;
matrix View;
float4 Colour;
}
Another point I would consider is to get the pointer to the technique desc everytime before the draw call (or pass through loop),
and not reuse it, seems to also make a difference.
//Initiate the pass through loop for the shader effect.
technique->GetDesc(&desc);
for (UINT p=0; p<desc.Passes; p++)
{
//Apply this pass through.
technique->GetPassByIndex(p)->Apply(0);
//draw indexed, instanced.
device->device->DrawIndexedInstanced(indicesCount, (UINT) instanceCount, 0, 0, 0);
}

Related

GPU ray casting (single pass) with 3d textures in spherical coordinates

i' am implementing an algorithm of volume rendering "GPU ray casting single pass". For this, i used a float array of intensity values as 3d textures ( this 3d textures describes a regular 3d grid in spherical coordinates ).
Here there are example of array values:
75.839354473071637,
64.083049468866022,
65.253933716444365,
79.992431196592577,
84.411485976957096,
0.0000000000000000,
82.020319431382831,
76.808403454586994,
79.974774618246158,
0.0000000000000000,
91.127273013466336,
84.009956557448433,
90.221356094672814,
87.567422484025627,
71.940263118478072,
0.0000000000000000,
0.0000000000000000,
74.487058398181944,
..................,
..................
(Here the complete data:[link] (https://drive.google.com/file/d/1lbXzRucUseF-ITzFgxqeLTd0WglJJOoz/view?usp=sharing))
the dimensions of spherical grid are (r,theta,phi)=(384,15,768), and this is the input format for load textures:
glTexImage3D(GL_TEXTURE_3D, 0, GL_R16F, 384, 15, 768, 0, GL_RED, GL_FLOAT, dataArray)
And This is an image of my visualization:
The problem is that the visuization should be a disk, or at least a similar form.
i think that the problme is i do not specify correctly the coordinates for textures( in spherical coordinates).
this is the vertex shader code:
#version 330 core
layout(location = 0) in vec3 vVertex; //object space vertex position
//uniform
uniform mat4 MVP; //combined modelview projection matrix
smooth out vec3 vUV; //3D texture coordinates for texture lookup in the fragment shader
void main()
{
//get the clipspace position
gl_Position = MVP*vec4(vVertex.xyz,1);
//get the 3D texture coordinates by adding (0.5,0.5,0.5) to the object space
//vertex position. Since the unit cube is at origin (min: (-0.5,-0.5,-0.5) and max: (0.5,0.5,0.5))
//adding (0.5,0.5,0.5) to the unit cube object space position gives us values from (0,0,0) to
//(1,1,1)
vUV = vVertex + vec3(0.5);
}
and this is the fragmen shader code:
#version 330 core
layout(location = 0) out vec4 vFragColor; //fragment shader output
smooth in vec3 vUV; //3D texture coordinates form vertex shader
//interpolated by rasterizer
//uniforms
uniform sampler3D volume; //volume dataset
uniform vec3 camPos; //camera position
uniform vec3 step_size; //ray step size
//constants
const int MAX_SAMPLES = 300; //total samples for each ray march step
const vec3 texMin = vec3(0); //minimum texture access coordinate
const vec3 texMax = vec3(1); //maximum texture access coordinate
vec4 colour_transfer(float intensity)
{
vec3 high = vec3(100.0, 20.0, 10.0);
// vec3 low = vec3(0.0, 0.0, 0.0);
float alpha = (exp(intensity) - 1.0) / (exp(1.0) - 1.0);
return vec4(intensity * high, alpha);
}
void main()
{
//get the 3D texture coordinates for lookup into the volume dataset
vec3 dataPos = vUV;
//Getting the ray marching direction:
//get the object space position by subracting 0.5 from the
//3D texture coordinates. Then subtraact it from camera position
//and normalize to get the ray marching direction
vec3 geomDir = normalize((vUV-vec3(0.5)) - camPos);
//multiply the raymarching direction with the step size to get the
//sub-step size we need to take at each raymarching step
vec3 dirStep = geomDir * step_size;
//flag to indicate if the raymarch loop should terminate
bool stop = false;
//for all samples along the ray
for (int i = 0; i < MAX_SAMPLES; i++) {
// advance ray by dirstep
dataPos = dataPos + dirStep;
stop = dot(sign(dataPos-texMin),sign(texMax-dataPos)) < 3.0;
//if the stopping condition is true we brek out of the ray marching loop
if (stop)
break;
// data fetching from the red channel of volume texture
float sample = texture(volume, dataPos).r;
vec4 c = colour_transfer(sample);
vFragColor.rgb = c.a * c.rgb + (1 - c.a) * vFragColor.a * vFragColor.rgb;
vFragColor.a = c.a + (1 - c.a) * vFragColor.a;
//early ray termination
//if the currently composited colour alpha is already fully saturated
//we terminated the loop
if( vFragColor.a>0.99)
break;
}
}
How can i specific the coordinates for i will visualize the information in the 3d textures, in spherical cordinates?
UPDATE:
vertex shader :
#version 330 core
layout(location = 0) in vec3 vVertex; //object space vertex position
//uniform
uniform mat4 MVP; //combined modelview projection matrix
smooth out vec3 vUV; //3D texture coordinates for texture lookup in the fragment shader
void main()
{
//get the clipspace position
gl_Position = MVP*vec4(vVertex.xyz,1);
//get the 3D texture coordinates by adding (0.5,0.5,0.5) to the object space
//vertex position. Since the unit cube is at origin (min: (-0.5,- 0.5,-0.5) and max: (0.5,0.5,0.5))
//adding (0.5,0.5,0.5) to the unit cube object space position gives us values from (0,0,0) to
//(1,1,1)
vUV = vVertex + vec3(0.5);
}
And fragment shader:
#version 330 core
#define Pi 3.1415926535897932384626433832795
layout(location = 0) out vec4 vFragColor; //fragment shader output
smooth in vec3 vUV; //3D texture coordinates form vertex shader
//interpolated by rasterizer
//uniforms
uniform sampler3D volume; //volume dataset
uniform vec3 camPos; //camera position
uniform vec3 step_size; //ray step size
//constants
const int MAX_SAMPLES = 200; //total samples for each ray march step
const vec3 texMin = vec3(0); //minimum texture access coordinate
const vec3 texMax = vec3(1); //maximum texture access coordinate
// transfer function that asigned a color and alpha from sample intensity
vec4 colour_transfer(float intensity)
{
vec3 high = vec3(100.0, 20.0, 10.0);
// vec3 low = vec3(0.0, 0.0, 0.0);
float alpha = (exp(intensity) - 1.0) / (exp(1.0) - 1.0);
return vec4(intensity * high, alpha);
}
// this function transform vector in spherical coordinates from cartesian
vec3 cart2Sphe(vec3 cart){
vec3 sphe;
sphe.x = sqrt(cart.x*cart.x+cart.y*cart.y+cart.z*cart.z);
sphe.z = atan(cart.y/cart.x);
sphe.y = atan(sqrt(cart.x*cart.x+cart.y*cart.y)/cart.z);
return sphe;
}
void main()
{
//get the 3D texture coordinates for lookup into the volume dataset
vec3 dataPos = vUV;
//Getting the ray marching direction:
//get the object space position by subracting 0.5 from the
//3D texture coordinates. Then subtraact it from camera position
//and normalize to get the ray marching direction
vec3 vec=(vUV-vec3(0.5));
vec3 spheVec=cart2Sphe(vec); // transform position to spherical
vec3 sphePos=cart2Sphe(camPos); //transform camPos to spherical
vec3 geomDir= normalize(spheVec-sphePos); // ray direction
//multiply the raymarching direction with the step size to get the
//sub-step size we need to take at each raymarching step
vec3 dirStep = geomDir * step_size ;
//flag to indicate if the raymarch loop should terminate
//for all samples along the ray
for (int i = 0; i < MAX_SAMPLES; i++) {
// advance ray by dirstep
dataPos = dataPos + dirStep;
float sample;
convert texture coordinates
vec3 spPos;
spPos.x=dataPos.x/384;
spPos.y=(dataPos.y+(Pi/2))/Pi;
spPos.z=dataPos.z/(2*Pi);
// get value from texture
sample = texture(volume,dataPos).r;
vec4 c = colour_transfer(sample)
// alpha blending function
vFragColor.rgb = c.a * c.rgb + (1 - c.a) * vFragColor.a * vFragColor.rgb;
vFragColor.a = c.a + (1 - c.a) * vFragColor.a;
if( vFragColor.a>1.0)
break;
}
// vFragColor.rgba = texture(volume,dataPos);
}
these are the point that generate a boundary cube:
glm::vec3 vertices[8] = {glm::vec3(-0.5f, -0.5f, -0.5f),
glm::vec3(0.5f, -0.5f, -0.5f),
glm::vec3(0.5f, 0.5f, -0.5f),
glm::vec3(-0.5f, 0.5f, -0.5f),
glm::vec3(-0.5f, -0.5f, 0.5f),
glm::vec3(0.5f, -0.5f, 0.5f),
glm::vec3(0.5f, 0.5f, 0.5f),
glm::vec3(-0.5f, 0.5f, 0.5f)};
//unit cube indices
GLushort cubeIndices[36] = {0, 5, 4,
5, 0, 1,
3, 7, 6,
3, 6, 2,
7, 4, 6,
6, 4, 5,
2, 1, 3,
3, 1, 0,
3, 0, 7,
7, 0, 4,
6, 5, 2,
2, 5, 1};
this is the visualization that it is generated:
I do not know what and how are you rendering. There are many techniques and configurations which can achieve them. I am usually using a single pass single quad render covering the screen/view while geometry/scene is passed as texture. As you have your object in a 3D texture then I think you should go this way too. This is how its done (Assuming perspective, uniform spherical voxel grid as a 3D texture):
CPU side code
simply render single QUAD covering the scene/view. To make this more simple and precise I recommend you to use your sphere local coordinate system for camera matrix which is passed to the shaders (it will ease up the ray/sphere intersections computations a lot).
Vertex
here you should cast/compute the ray position and direction for each vertex and pass it to the fragment so its interpolated for each pixel on the screen/view.
So the camera is described by its position (focal point) and view direction (usually Z- axis in perspective OpenGL). The ray is casted from the focal point (0,0,0) in camera local coordinates into the znear plane (x,y,-znear) also in camera local coordinates. Where x,y is the pixel screen position wit aspect ratio corrections applied if screen/view is not a square.
So you just convert these two points into sphere local coordinates (still Cartesian).
The ray direction is just substraction of the two points...
Fragment
first normalize ray direction passed from vertex (as due to interpolation it will not be unit vector). After that simply test ray/sphere intersection for each radius of the sphere voxel grid from outward to inward so test spheres from rmax to rmax/n where rmax is the max radius your 3D texture can have and n is ids resolution for axis corresponding to radius r.
On each hit convert the Cartesian intersection position to Spherical coordinates. Convert them to texture coordinates s,t,p and fetch the Voxel intensity and apply it to the color (how depends on what and how are you rendering).
So if your texture coordinates are (r,theta,phi)assuming phi is longitude and angles are normalized to <-Pi,Pi> and <0,2*Pi> and rmax is the max radius of the 3D texture then:
s = r/rmax
t = (theta+(Pi/2))/Pi
p = phi/(2*PI)
If your sphere is not transparent then stop on first hit with not empty Voxel intensity. Otherwise update ray start position and do this whole bullet again until ray goes out of the scene BBOX or no intersection occurs.
You can also add Snell's law (add reflection refraction) by splitting ray on object boundary hits...
Here are some related QAs using this technique or having valid info that will help you achieve this:
GLSL atmospheric scattering this is almost the same as you should do.
ray and ellipsoid intersection accuracy improvement math for the intersections
Curved Frosted Glass Shader? sub surface scattering
GLSL back raytrace through 3D mesh reflections and refractions in geometry inside 2D texture
GLSL back raytrace through 3D volume 3D Cartesian volume inside 3D texture
[Edit1] example (after the input 3D texture was finally posted
So when I put all the stuff above (and in comments) together I come up with this.
CPU side code:
//---------------------------------------------------------------------------
//--- GLSL Raytrace system ver: 1.000 ---------------------------------------
//---------------------------------------------------------------------------
#ifndef _raytrace_spherical_volume_h
#define _raytrace_spherical_volume_h
//---------------------------------------------------------------------------
class SphericalVolume3D
{
public:
bool _init; // has been initiated ?
GLuint txrvol; // SphericalVolume3D texture at GPU side
int xs,ys,zs;
float eye[16]; // direct camera matrix
float aspect,focal_length;
SphericalVolume3D() { _init=false; txrvol=-1; xs=0; ys=0; zs=0; aspect=1.0; focal_length=1.0; }
SphericalVolume3D(SphericalVolume3D& a) { *this=a; }
~SphericalVolume3D() { gl_exit(); }
SphericalVolume3D* operator = (const SphericalVolume3D *a) { *this=*a; return this; }
//SphericalVolume3D* operator = (const SphericalVolume3D &a) { ...copy... return this; }
// init/exit
void gl_init();
void gl_exit();
// render
void glsl_draw(GLint prog_id);
};
//---------------------------------------------------------------------------
void SphericalVolume3D::gl_init()
{
if (_init) return; _init=true;
// load 3D texture from file into CPU side memory
int hnd,siz; BYTE *dat;
hnd=FileOpen("Texture3D_F32.dat",fmOpenRead);
siz=FileSeek(hnd,0,2);
FileSeek(hnd,0,0);
dat=new BYTE[siz];
FileRead(hnd,dat,siz);
FileClose(hnd);
if (0)
{
int i,n=siz/sizeof(GLfloat);
GLfloat *p=(GLfloat*)dat;
for (i=0;i<n;i++) p[i]=100.5;
}
// copy it to GPU as 3D texture
// glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE);
// glClampColorARB(GL_CLAMP_READ_COLOR_ARB, GL_FALSE);
// glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE);
glGenTextures(1,&txrvol);
glEnable(GL_TEXTURE_3D);
glBindTexture(GL_TEXTURE_3D,txrvol);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
xs=384;
ys= 15;
zs=768;
glTexImage3D(GL_TEXTURE_3D, 0, GL_R16F, xs,ys,zs, 0, GL_RED, GL_FLOAT, dat);
glBindTexture(GL_TEXTURE_3D,0);
glDisable(GL_TEXTURE_3D);
delete[] dat;
}
//---------------------------------------------------------------------------
void SphericalVolume3D::gl_exit()
{
if (!_init) return; _init=false;
glDeleteTextures(1,&txrvol);
}
//---------------------------------------------------------------------------
void SphericalVolume3D::glsl_draw(GLint prog_id)
{
GLint ix;
const int txru_vol=0;
glUseProgram(prog_id);
// uniforms
ix=glGetUniformLocation(prog_id,"zoom" ); glUniform1f(ix,1.0);
ix=glGetUniformLocation(prog_id,"aspect" ); glUniform1f(ix,aspect);
ix=glGetUniformLocation(prog_id,"focal_length"); glUniform1f(ix,focal_length);
ix=glGetUniformLocation(prog_id,"vol_xs" ); glUniform1i(ix,xs);
ix=glGetUniformLocation(prog_id,"vol_ys" ); glUniform1i(ix,ys);
ix=glGetUniformLocation(prog_id,"vol_zs" ); glUniform1i(ix,zs);
ix=glGetUniformLocation(prog_id,"vol_txr" ); glUniform1i(ix,txru_vol);
ix=glGetUniformLocation(prog_id,"tm_eye" ); glUniformMatrix4fv(ix,1,false,eye);
glActiveTexture(GL_TEXTURE0+txru_vol);
glEnable(GL_TEXTURE_3D);
glBindTexture(GL_TEXTURE_3D,txrvol);
// this should be a VAO/VBO
glColor4f(1.0,1.0,1.0,1.0);
glBegin(GL_QUADS);
glVertex2f(-1.0,-1.0);
glVertex2f(-1.0,+1.0);
glVertex2f(+1.0,+1.0);
glVertex2f(+1.0,-1.0);
glEnd();
glActiveTexture(GL_TEXTURE0+txru_vol);
glBindTexture(GL_TEXTURE_3D,0);
glDisable(GL_TEXTURE_3D);
glUseProgram(0);
}
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
call init on app start when GL is already inited, exit before app exit while GL still works and draw when needed... The code is C++/VCL based so port to your environment (file access, strings, etc..) I also use the 3D texture in binary form as loading 85MByte ASCII file is a bit too much for my taste.
Vertex:
//------------------------------------------------------------------
#version 420 core
//------------------------------------------------------------------
uniform float aspect;
uniform float focal_length;
uniform float zoom;
uniform mat4x4 tm_eye;
layout(location=0) in vec2 pos;
out smooth vec3 ray_pos; // ray start position
out smooth vec3 ray_dir; // ray start direction
//------------------------------------------------------------------
void main(void)
{
vec4 p;
// perspective projection
p=tm_eye*vec4(pos.x/(zoom*aspect),pos.y/zoom,0.0,1.0);
ray_pos=p.xyz;
p-=tm_eye*vec4(0.0,0.0,-focal_length,1.0);
ray_dir=normalize(p.xyz);
gl_Position=vec4(pos,0.0,1.0);
}
//------------------------------------------------------------------
its more or less a copy from the volumetric ray tracer link.
Fragment:
//------------------------------------------------------------------
#version 420 core
//------------------------------------------------------------------
// Ray tracer ver: 1.000
//------------------------------------------------------------------
in smooth vec3 ray_pos; // ray start position
in smooth vec3 ray_dir; // ray start direction
uniform int vol_xs, // texture resolution
vol_ys,
vol_zs;
uniform sampler3D vol_txr; // scene mesh data texture
out layout(location=0) vec4 frag_col;
//---------------------------------------------------------------------------
// compute length of ray(p0,dp) to intersection with ellipsoid((0,0,0),r) -> view_depth_l0,1
// where r.x is elipsoid rx^-2, r.y = ry^-2 and r.z=rz^-2
float view_depth_l0=-1.0,view_depth_l1=-1.0;
bool _view_depth(vec3 _p0,vec3 _dp,vec3 _r)
{
double a,b,c,d,l0,l1;
dvec3 p0,dp,r;
p0=dvec3(_p0);
dp=dvec3(_dp);
r =dvec3(_r );
view_depth_l0=-1.0;
view_depth_l1=-1.0;
a=(dp.x*dp.x*r.x)
+(dp.y*dp.y*r.y)
+(dp.z*dp.z*r.z); a*=2.0;
b=(p0.x*dp.x*r.x)
+(p0.y*dp.y*r.y)
+(p0.z*dp.z*r.z); b*=2.0;
c=(p0.x*p0.x*r.x)
+(p0.y*p0.y*r.y)
+(p0.z*p0.z*r.z)-1.0;
d=((b*b)-(2.0*a*c));
if (d<0.0) return false;
d=sqrt(d);
l0=(-b+d)/a;
l1=(-b-d)/a;
if (abs(l0)>abs(l1)) { a=l0; l0=l1; l1=a; }
if (l0<0.0) { a=l0; l0=l1; l1=a; }
if (l0<0.0) return false;
view_depth_l0=float(l0);
view_depth_l1=float(l1);
return true;
}
//---------------------------------------------------------------------------
const float pi =3.1415926535897932384626433832795;
const float pi2=6.2831853071795864769252867665590;
float atanxy(float x,float y) // atan2 return < 0 , 2.0*M_PI >
{
int sx,sy;
float a;
const float _zero=1.0e-30;
sx=0; if (x<-_zero) sx=-1; if (x>+_zero) sx=+1;
sy=0; if (y<-_zero) sy=-1; if (y>+_zero) sy=+1;
if ((sy==0)&&(sx==0)) return 0;
if ((sx==0)&&(sy> 0)) return 0.5*pi;
if ((sx==0)&&(sy< 0)) return 1.5*pi;
if ((sy==0)&&(sx> 0)) return 0;
if ((sy==0)&&(sx< 0)) return pi;
a=y/x; if (a<0) a=-a;
a=atan(a);
if ((x>0)&&(y>0)) a=a;
if ((x<0)&&(y>0)) a=pi-a;
if ((x<0)&&(y<0)) a=pi+a;
if ((x>0)&&(y<0)) a=pi2-a;
return a;
}
//---------------------------------------------------------------------------
void main(void)
{
float a,b,r,_rr,c;
const float dr=1.0/float(vol_ys); // r step
const float saturation=1000.0; // color saturation voxel value
vec3 rr,p=ray_pos,dp=normalize(ray_dir);
for (c=0.0,r=1.0;r>1e-10;r-=dr) // check all radiuses inwards
{
_rr=1.0/(r*r); rr=vec3(_rr,_rr,_rr);
if (_view_depth(p,dp,rr)) // if ray hits sphere
{
p+=view_depth_l0*dp; // shift ray start position to the hit
a=atanxy(p.x,p.y); // comvert to spherical a,b,r
b=asin(p.z/r);
if (a<0.0) a+=pi2; // correct ranges...
b+=0.5*pi;
a/=pi2;
b/=pi;
// here do your stuff
c=texture(vol_txr,vec3(b,r,a)).r;// fetch voxel
if (c>saturation){ c=saturation; break; }
break;
}
}
c/=saturation;
frag_col=vec4(c,c,c,1.0);
}
//---------------------------------------------------------------------------
its a slight modification of the volumetric ray tracer link.
Beware that I assume that the axises inside the texture are:
latitude,r,longitude
implied by the resolutions (longitude should be double resolution of the latitude) so if it does not match your data just reorder the axises in fragment ... I have no clue what the values of the Voxel cell mean so I sum them like intensity/density for the final color and once saturation sum reached stop the raytrace but instead you should your computation stuff you intend.
Here preview:
I used this camera matrix eye for it:
// globals
SphericalVolume3D vol;
// init (GL must be already working)
vol.gl_init();
// render
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_CULL_FACE);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-2.5);
glGetFloatv(GL_MODELVIEW_MATRIX,vol.eye);
vol.glsl_draw(prog_id);
glFlush();
SwapBuffers(hdc);
// exit (GL must be still working)
vol.gl_init();
The ray/sphere hit is working properly, also the hit position in spherical coordinates are working as should so the only thing left is the axis order and color arithmetics ...

Direct3D11: Rendering 2D in 3D scene: how to make 2D objects not move on Viewport when camera changes position?

Images with examples of the problem: http://imgur.com/gallery/vmMyk
Hi,
I need some help with rendering 2D objects in 3D scene with 3D camera. I think I managed to solve 2D coordinates with LH world coordinates. However, my rendered 2D objects are in a correct place, only when camera is at [0.0f, 0.0f, 0.0f] coordinates. In every other position, the location of 2D objects on scene is malformed. I think my matrices are screwed up, but don't know where to look further. I'd appreciate good ideas, please comment if something's missing for you, I'll edit the main post to provide you more information.
I'm using simple 3D color HLSL (VS and PS ver: 4.0) shader with alpha blending for the bigger triangle:
cbuffer ConstantBuffer : register( b0 )
{
matrix World;
matrix View;
matrix Projection;
}
struct VS_INPUT
{
float4 Pos : POSITION;
float4 Color : COLOR;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float4 Color : COLOR;
};
PS_INPUT VS ( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
input.Pos.w = 1.0f;
output.Pos = mul ( input.Pos, World );
output.Pos = mul ( output.Pos, View );
output.Pos = mul ( output.Pos, Projection );
output.Color = input.Color;
return output;
}
float4 PS ( PS_INPUT input ) : SV_Target
{
return input.Color;
}
That's my Vertex data struct:
struct Vertex
{
DirectX::XMFLOAT3 position;
DirectX::XMFLOAT4 color;
Vertex() {};
Vertex(DirectX::XMFLOAT3 aPosition, DirectX::XMFLOAT4 aColor)
: position(aPosition)
, color(aColor)
{};
};
Render call for object:
bool PrimitiveMesh::Draw()
{
unsigned int stride = sizeof(Vertex);
unsigned int offset = 0;
D3DSystem::GetD3DDeviceContext()->IASetVertexBuffers(0, 1, &iVertexBuffer, &stride, &offset);
D3DSystem::GetD3DDeviceContext()->IASetIndexBuffer(iIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
D3DSystem::GetD3DDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
return true;
}
Draw call with initialization:
static PrimitiveMesh* mesh;
if (mesh == 0)
{
std::vector<PrimitiveMesh::Vertex> vertices;
mesh = new PrimitiveMesh();
DirectX::XMFLOAT4 color = { 186 / 256.0f, 186 / 256.0f, 186 / 256.0f, 0.8f };
vertices.push_back({ DirectX::XMFLOAT3(0.0f, 0.0f, 0.0f), color });
vertices.push_back({ DirectX::XMFLOAT3(0.0f, 600.0f, 0.0f), color });
vertices.push_back({ DirectX::XMFLOAT3(800.0f, 600.0f, 0.0f), color });
mesh->SetVerticesAndIndices(vertices);
}
// Getting clean matrices here:
D3D::Matrices(world, view, projection, ortho);
iGI->TurnZBufferOff();
iGI->TurnOnAlphaBlending();
mesh->Draw();
XMMATRIX view2D = Camera::View2D();
iColorShader->Render(iGI->GetContext(), 3, &world, &view2D, &ortho);
iGI->TurnZBufferOn();
These are my 2D calculations for camera:
up = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
lookAt = DirectX::XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
rotationMatrix = DirectX::XMMatrixRotationRollPitchYaw(0.0f, 0.0f, 0.0f); // (pitch, yaw, roll);
up = DirectX::XMVector3TransformCoord(up, rotationMatrix);
lookAt = DirectX::XMVector3TransformCoord(lookAt, rotationMatrix) + position;
view2D = DirectX::XMMatrixLookAtLH(position, lookAt, up);
I'll appreciate any help.
Kind regards.
With Shaders, you are not forced to use matrices, you have the flexibility to simplify the problem.
Let say you render 2d objects, using coordinates in pixels, the only requirement, is to scale offset them back into the normalized projective space.
A vertex shader could be as short as that :
cbuffer ConstantBuffer : register( b0 ) {
float2 rcpDim; // 1 / renderTargetSize
}
PS_INPUT VS ( VS_INPUT input ) {
PS_INPUT output;
output.Pos.xy = input.Pos.xy * rcpDim * 2; // from pixel to [0..2]
output.Pos.xy -= 1; // to [-1..1]
output.Pos.y *= -1; // because top left in texture space is bottom left in projective space
output.Pos.zw = float2(0,1);
output.Color = input.Color;
return output;
}
You can of course build a set of matrices achieving the same result with your original shader, just set World and View to identity and projection to an ortho projection with XMMatrixOrthographicOffCenterLH(0,width,0,height,0,1). But as you are beggining with 3D programming, you will soon have to learn to deal with multiple shaders anyway, so take it as an exercice.
Well, I fixed my problem. For some weird reason, DirectXMath was generating false XMMATRIX. My XMMatrixOrtographicLH() was completely incorrect for good parameters. I solved my problem with classic definition of Ortohraphic matrix, found in this article (definition in Fig. 10)
auto orthoMatrix = DirectX::XMMatrixIdentity();
orthoMatrix.r[0].m128_f32[0] = 2.0f / Engine::VideoSettings::Current()->WindowWidth();
orthoMatrix.r[1].m128_f32[1] = 2.0f / Engine::VideoSettings::Current()->WindowHeight();
orthoMatrix.r[2].m128_f32[2] = -(2.0f / (screenDepth - screenNear));
orthoMatrix.r[2].m128_f32[3] = -(screenDepth + screenNear) / (screenDepth - screenNear);
galop1n give a good solution but on my system
cbuffer ConstantBuffer : register( b0 ) {
float2 rcpDim; // 1 / renderTargetSize
}
NEED to be a multiple of 16 for made like here:
struct VS_CONSTANT_BUFFER
{
DirectX::XMFLOAT2 rcpDim;
DirectX::XMFLOAT2 rcpDim2;
};
// Supply the vertex shader constant data.
VS_CONSTANT_BUFFER VsConstData;
VsConstData.rcpDim = { 2.0f / w,2.0f / h};
// Fill in a buffer description.
D3D11_BUFFER_DESC cbDesc;
ZeroMemory(&cbDesc, sizeof(cbDesc));
cbDesc.ByteWidth = sizeof(VS_CONSTANT_BUFFER);
cbDesc.Usage = D3D11_USAGE_DYNAMIC;
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
cbDesc.MiscFlags = 0;
cbDesc.StructureByteStride = 0;
// Fill in the subresource data.
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = &VsConstData;
InitData.SysMemPitch = 0;
InitData.SysMemSlicePitch = 0;
// Create the buffer.
HRESULT hr = pDevice->CreateBuffer(&cbDesc, &InitData,
&pConstantBuffer11);
or aligned
__declspec(align(16))
struct VS_CONSTANT_BUFFER
{
DirectX::XMFLOAT2 rcpDim;
};

Background face is visible over foreground face in same mesh while using a diffuse shader in DirectX

I am trying to create a simple diffuse shader to paint primitive objects in DirectX 9 and faced following problem. When I used a DirectX primitive object like a Torus or Teapot, some faces in the foreground part of the mesh is invisible. I don't think this is the same thing as faces being invisible as I cannot reproduce this behavior for primitive objects like Sphere or Box where no two quads have the same normal. Following are some screenshots in fill and wire-frame modes.
torus fill-mode
Following is my vertex deceleration code.
// vertex position...
D3DVERTEXELEMENT9 element;
element.Stream = 0;
element.Offset = 0;
element.Type = D3DDECLTYPE_FLOAT3;
element.Method = D3DDECLMETHOD_DEFAULT;
element.Usage = D3DDECLUSAGE_POSITION;
element.UsageIndex = 0;
m_vertexElement.push_back(element);
// vertex normal
element.Stream = 0;
element.Offset = 12; //3 floats * 4 bytes per float
element.Type = D3DDECLTYPE_FLOAT3;
element.Method = D3DDECLMETHOD_DEFAULT;
element.Usage = D3DDECLUSAGE_NORMAL;
element.UsageIndex = 0;
m_vertexElement.push_back(element);
And shader code in development.
float4x4 MatWorld : register(c0);
float4x4 MatViewProj : register(c4);
float4 matColor : register(c0);
struct VS_INPUT
{
float4 Position : POSITION;
float3 Normal : NORMAL;
};
struct VS_OUTPUT
{
float4 Position : POSITION;
float3 Normal : TEXCOORD0;
};
struct PS_OUTPUT
{
float4 Color : COLOR0;
};
VS_OUTPUT vsmain(in VS_INPUT In)
{
VS_OUTPUT Out;
float4 wpos = mul(In.Position, MatWorld);
Out.Position = mul(wpos, MatViewProj);
Out.Normal = normalize(mul(In.Normal, MatWorld));
return Out;
};
PS_OUTPUT psmain(in VS_OUTPUT In)
{
PS_OUTPUT Out;
float4 ambient = {0.1, 0.0, 0.0, 1.0};
float3 light = {1, 0, 0};
Out.Color = ambient + matColor * saturate(dot(light, In.Normal));
return Out;
};
I have also tried setting different render states for Depth-Stencil but wasn't successful.
project files
I figure it out! this is a Depth Buffer(Z-Buffer) issue, you can enable Z-Buffer in your code, either by fixed pipeline or in the shader.
To enable z-buffer in fixed pipeline:
First add the following code when creating D3D deivce
d3dpp.EnableAutoDepthStencil = TRUE ;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16 ;
Then enable z-buffer before drawing
device->SetRenderState(D3DRS_ZENABLE, TRUE) ;
At last, clear z-buffer in render function
device->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

How to create Cubemap in DirectX 9

I'm trying to create a Cube Map in DirectX 9, but for some reason it's not working. I've used DirectX's Texture Utility to create a dds texture file for the cube, but when I draw it, it's only drawing a solid color. Here's the code I've done:
SkyBox.h
#pragma once
#include<D3DX9Mesh.h>
#include"DirectX.h"
class SkyBox{
public:
SkyBox(LPCSTR textureFile);
~SkyBox();
void Draw();
protected:
IDirect3DCubeTexture9* texture;
LPD3DXMESH mesh;
};
SkyBox.cpp
#include"SkyBox.h"
SkyBox::SkyBox(LPCSTR textureFile)
{
D3DXCreateBox(DirectX::device, 1.0f, 1.0f, 1.0f, &mesh, NULL);
D3DXCreateCubeTextureFromFile(DirectX::device, textureFile, &texture);
}
SkyBox::~SkyBox()
{
mesh->Release();
texture->Release();
}
void SkyBox::Draw()
{
D3DXHANDLE textureHandle = DirectX::currentShaderEffect->GetParameterByName(0, "tex0");
DirectX::currentShaderEffect->SetTexture(textureHandle, texture);
DirectX::currentShaderEffect->CommitChanges();
UINT passNum = 5;
DirectX::currentShaderEffect->Begin(&passNum, 0);
DirectX::currentShaderEffect->BeginPass(5);
mesh->DrawSubset(0);
DirectX::currentShaderEffect->EndPass();
DirectX::currentShaderEffect->End();
}
And this is my shader for the Cube Map:
uniform extern float4x4 mvp;
uniform extern texture tex0;
struct SkyboxVS
{
float4 pos : POSITION0;
float3 uv0 : TEXCOORD0;
};
sampler SkyBoxTex = sampler_state
{
Texture = <tex0>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};
SkyboxVS VertexSkybox(float3 position : POSITION0, float3 texCoord : TEXCOORD0)
{
SkyboxVS skyVS = (SkyboxVS)0;
skyVS.pos = mul(float4(position, 1.0f), mvp);
skyVS.uv0 = texCoord;
return skyVS;
}
float4 PixelSkybox(float3 texCoord: TEXCOORD0) : COLOR
{
float4 color = texCUBE(SkyBoxTex, texCoord);
return color;
}
technique TransformTech
{
pass P5
{
vertexShader = compile vs_2_0 VertexSkybox();
pixelShader = compile ps_2_0 PixelSkybox();
ZFunc = Always;
StencilEnable = true;
StencilFunc = Always;
StencilPass = Replace;
StencilRef = 0;
}
}
Here's some sample code:
Sky::Sky(const std::string& envmapFilename, float skyRadius)
: mRadius(skyRadius)
{
HR(D3DXCreateSphere(gd3dDevice, skyRadius, 30, 30, &mSphere, 0));
HR(D3DXCreateCubeTextureFromFile(gd3dDevice, envmapFilename.c_str(), &mEnvMap));
ID3DXBuffer* errors = 0;
HR(D3DXCreateEffectFromFile(gd3dDevice, "sky.fx", 0, 0, 0,
0, &mFX, &errors));
if( errors )
MessageBox(0, (char*)errors->GetBufferPointer(), 0, 0);
mhTech = mFX->GetTechniqueByName("SkyTech");
mhWVP = mFX->GetParameterByName(0, "gWVP");
mhEnvMap = mFX->GetParameterByName(0, "gEnvMap");
// Set effect parameters that do not vary.
HR(mFX->SetTechnique(mhTech));
HR(mFX->SetTexture(mhEnvMap, mEnvMap));
}
void Sky::draw()
{
// Sky always centered about camera's position.
D3DXMATRIX W;
D3DXVECTOR3 p = gCamera->pos();
D3DXMatrixTranslation(&W, p.x, p.y, p.z);
HR(mFX->SetMatrix(mhWVP, &(W*gCamera->viewProj())));
UINT numPasses = 0;
HR(mFX->Begin(&numPasses, 0));
HR(mFX->BeginPass(0));
HR(mSphere->DrawSubset(0));
HR(mFX->EndPass());
HR(mFX->End());
}
And shader code:
OutputVS EnvMapVS(float3 posL : POSITION0, float3 normalL : NORMAL0, float2 tex0: TEXCOORD0)
{
// Zero out our output.
OutputVS outVS = (OutputVS)0;
// Transform normal to world space.
outVS.normalW = mul(float4(normalL, 0.0f), gWorldInvTrans).xyz;
// Transform vertex position to world space.
float3 posW = mul(float4(posL, 1.0f), gWorld).xyz;
// Compute the unit vector from the vertex to the eye.
outVS.toEyeW = gEyePosW - posW;
// Transform to homogeneous clip space.
outVS.posH = mul(float4(posL, 1.0f), gWVP);
// Pass on texture coordinates to be interpolated in rasterization.
outVS.tex0 = tex0;
// Done--return the output.
return outVS;
}
float4 EnvMapPS(float3 normalW : TEXCOORD0,
float3 toEyeW : TEXCOORD1,
float2 tex0 : TEXCOORD2) : COLOR
{
// Interpolated normals can become unnormal--so normalize.
normalW = normalize(normalW);
toEyeW = normalize(toEyeW);
// Light vector is opposite the direction of the light.
float3 lightVecW = -gLight.dirW;
// Compute the reflection vector.
float3 r = reflect(-lightVecW, normalW);
// Determine how much (if any) specular light makes it into the eye.
float t = pow(max(dot(r, toEyeW), 0.0f), gMtrl.specPower);
// Determine the diffuse light intensity that strikes the vertex.
float s = max(dot(lightVecW, normalW), 0.0f);
// Get the texture color.
float4 texColor = tex2D(TexS, tex0);
// Get the reflected color.
float3 envMapTex = reflect(-toEyeW, normalW);
float3 reflectedColor = texCUBE(EnvMapS, envMapTex);
// Weighted average between the reflected color, and usual
// diffuse/ambient material color modulated with the texture color.
float3 ambientMtrl = gReflectivity*reflectedColor + (1.0f-gReflectivity)*(gMtrl.ambient*texColor);
float3 diffuseMtrl = gReflectivity*reflectedColor + (1.0f-gReflectivity)*(gMtrl.diffuse*texColor);
// Compute the ambient, diffuse and specular terms separately.
float3 spec = t*(gMtrl.spec*gLight.spec).rgb;
float3 diffuse = s*(diffuseMtrl*gLight.diffuse.rgb);
float3 ambient = ambientMtrl*gLight.ambient;
float3 final = ambient + diffuse + spec;
// Output the color and the alpha.
return float4(final, gMtrl.diffuse.a*texColor.a);
}

Pre-Pass Lighting OpenGL implementation artifact

I am implementing Pre-Pass Lighting algorithm in OpenGL for my master dissertation project, after implementing a Deferred renderer as well. The Deferred renderer works perfectly and I based the implementation of PPL on it. I got a very weird artifact after the lighting pass of the algorithm: the data contained in the L-buffer, where I accumulate the contributions of the lights in the scene, is correct, but results to be slightly off in respect to the geometry so when I apply it to the scene in the material pass the result it's clearly visible! (I can't post the image here but here it's a link to see it http://postimage.org/image/kxhlbnl9v/)
It looks like the light map cube is somehow computed with an offset (different in every axes) from the geometry. I checked the shaders and C++ code many times, I do not understand where this problem comes from. I am running out of ideas. Below there is the code for the 3 passes of the algorithm that are called in sequence. The code is experimental for now so I know it's not well designed at this stage. I also add the shaders I use in every stage to write to G-buffer, L-buffer and framebuffer in order.
C++ CODE:
// Draw geometry to g buffer
void GLPrePassLightingRendererV2::GeometryStage()
{
// Set GL states
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glDepthFunc(GL_LEQUAL);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
// Bind G-Buffer for geometry pass
mGBuffer->BindForWriting();
// Bind geometry stage shaders
mTargetRenderSystem->BindShader(mGeometryStageVS);
mTargetRenderSystem->BindShader(mGeometryStageFS);
// Clear the framebuffer
mTargetRenderSystem->ClearFrameBuffer(FBT_COLOUR | FBT_DEPTH);
// Iterate over all the Renderables in the previously built RenderQueue
RenderableList* visibles = mSceneManager->GetRenderQueue()->GetRenderables();
// Set shader params here
//[...]
// Get the transformation info from the node the renderable is attached to
for (RenderableList::iterator it = visibles->begin(); it != visibles->end(); ++it)
{
Renderable* renderable = *it;
Material* mat = renderable->GetMaterial();
mGeometryStageVS->Update();
mGeometryStageFS->Update();
// Render the object
RenderOperation rop;
renderable->GetRenderOperation(rop);
mTargetRenderSystem->Render(rop);
}
// Only the geometry pass will write to the depth buffer
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
}
// Accumulate lights contribs in L-buffer using G-buffer
void GLPrePassLightingRendererV2::LightingStage()
{
// Enable additive blending for lights
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
//glCullFace(GL_FRONT);
// Bind shader for light stage
mTargetRenderSystem->BindShader(mLightStageVS);
mTargetRenderSystem->BindShader(mLightStageFS);
// Bind G-Buffer for reading and L-Buffer for writing for lighting pass
mGBuffer->BindForReading();
mLBuffer->BindForWriting();
mTargetRenderSystem->ClearFrameBuffer(FBT_COLOUR);
// Set shader params
// [...]
// Get all the lights in frustum, not by renderable
const LightList& lights = mSceneManager->GetLightsInFrustum();
// For each light in the frustum
LightList::const_iterator front_light_it;
for (LightList::const_iterator lit = lights.begin(); lit != lights.end(); ++lit)
{
// Send per light parameters to the shader
Light* l = (*lit);
SetLight(*l);
// Calculate bounding sphere for light and scale accordingly to instensity
float lightSphereScale = GetPointLightSphereScale(l->GetColor(), l->GetDiffuseIntensity());
// TODO: Render a sphere for each point light, a full screen quad for each directional
worldMtx.Identity();
worldMtx.SetScale(lightSphereScale, lightSphereScale, lightSphereScale);
worldMtx.SetTranslation(l->GetPosition());
mLightStageVS->SetParameterValue("gWorldMtx", (float*)&worldMtx);
mLightStageVS->Update();
mLightStageFS->Update();
static MeshInstance* sphere = mSceneManager->CreateMeshInstance("LightSphere", MBT_LIGHT_SPHERE);
RenderOperation rop;
sphere->GetSubMeshInstance(0)->GetRenderOperation(rop);
mTargetRenderSystem->Render(rop);
}
// Disable additive blending
glDisable(GL_BLEND);
}
// Combine L-buffer and material information per object
void GLPrePassLightingRendererV2::MaterialStage()
{
// Set some GL states
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
//glCullFace(GL_BACK);
// Bind material stage shaders (TODO: actually every object will bind its own matarial, if not a default one is used)
mTargetRenderSystem->BindShader(mMaterialStageVS);
mTargetRenderSystem->BindShader(mMaterialStageFS);
// Bind L-Buffer for reading
mLBuffer->BindForReading();
mTargetRenderSystem->ClearFrameBuffer(FBT_COLOUR | FBT_DEPTH, Math::ColourValue::WHITE);
// Iterate over all the Renderables in the previously built RenderQueue
RenderableList* visibles = mSceneManager->GetRenderQueue()->GetRenderables();
// Set shader params here
// [...]
// Get the transformation info from the node the renderable is attached to
for (RenderableList::iterator it = visibles->begin(); it != visibles->end(); ++it)
{
Renderable* renderable = *it;
Material* mat = renderable->GetMaterial();
// Set texture units
if (mat)
{
for (unsigned short i = 0; i < mat->GetTextureUnitCount(); ++i)
{
const TextureUnit* unit = mat->GetTextureUnit(i);
GLTexture* t = static_cast<GLTexture*>(unit->GetTexture());
glActiveTexture(GL_TEXTURE1); // This is needed because the first texture map slot is hold by the LBuffer!
glBindTexture(GL_TEXTURE_2D, t->GetGLId());
}
}
mMaterialStageVS->Update();
mMaterialStageFS->Update();
// Render the object
RenderOperation rop;
renderable->GetRenderOperation(rop);
mTargetRenderSystem->Render(rop);
}
}
NVIDIA CG Shaders:
// Vertex shader for Deferred Rendering geometry stage.
float4x4 gWorldMtx;
float4x4 gViewMtx;
float4x4 gProjectionMtx;
struct a2v
{
float3 position : POSITION;
float3 normal : NORMAL;
float2 texCoord : TEXCOORD0;
};
struct v2f
{
float4 position : POSITION;
float3 normal : TEXCOORD0;
float3 wPosition : TEXCOORD1;
float2 texCoord : TEXCOORD2;
};
v2f PPL_geometry_stage_vs(a2v IN)
{
v2f OUT;
// Transform to world space
OUT.wPosition = mul(gWorldMtx, float4(IN.position, 1.0f)).xyz;
OUT.normal = mul(gWorldMtx, float4(IN.normal, 0.0f)).xyz;
// Transform to homogeneous clip space
OUT.position = mul(gViewMtx, float4(OUT.wPosition, 1.0f));
OUT.position = mul(gProjectionMtx, OUT.position);
OUT.texCoord = IN.texCoord;
return OUT;
}
// Fragment shader for Pre-pass Lighing geometry stage.
struct f2a
{
float4 position : COLOR0;
float4 normal : COLOR1;
};
f2a PPL_geometry_stage_fs(v2f IN)
{
f2a OUT;
OUT.position = float4(IN.wPosition, 1.0f);
OUT.normal = float4(normalize(IN.normal), 1.0f);
return OUT;
}
// Vertex shader for Pre-pass lighing light stage.
float4x4 gWorldMtx;
float4x4 gViewMtx;
float4x4 gProjectionMtx;
struct a2v
{
float3 position : POSITION;
};
struct v2f
{
float4 position : POSITION;
float4 lightPos : TEXCOORD0;
};
v2f PPL_light_stage_vs(a2v IN)
{
v2f OUT;
float4x4 wv = mul(gWorldMtx, gViewMtx);
float4x4 wvp = mul(gViewMtx, gProjectionMtx);
wvp = mul(wvp, gWorldMtx);
// Only transforms position to world space
OUT.position = mul(wvp, float4(IN.position, 1.0f));
// Copy light position to calculate fragment coordinate
OUT.lightPos = OUT.position;
return OUT;
}
// Fragment shader for Pre-pass lighing light stage.
// Light structures
struct BaseLight
{
float3 color;
float ambientIntensity;
float diffuseIntensity;
};
struct DirectionalLight
{
struct BaseLight base;
float3 direction;
};
struct Attenuation
{
float constant;
float linearr;
float quadratic;
};
struct PointLight
{
struct BaseLight base;
float3 position;
Attenuation atten;
};
struct SpotLight
{
struct PointLight base;
float3 direction;
float cutoff;
};
// G-Buffer textures
sampler2D gPositionMap : TEXUNIT0;
sampler2D gNormalMap : TEXUNIT1;
// Light variables
float3 gEyePosition;
DirectionalLight gDirectionalLight;
PointLight gPointLight;
SpotLight gSpotLight;
int gLightType;
float gSpecularPower;
float4 PPL_light_stage_point_light_fs(v2f IN) : COLOR0
{
// Get fragment coordinate, from NDC space [-1, 1] to [0, 1].
float2 fragcoord = ((IN.lightPos.xy / IN.lightPos.w) + 1.0f) / 2.0f;
// Calculate lighting with G-Buffer textures
float3 position = tex2D(gPositionMap, fragcoord).xyz;
float3 normal = tex2D(gNormalMap, fragcoord).xyz;
normal = normalize(normal);
// Attenuation
float3 lightDirection = position - gPointLight.position;
float dist = length(lightDirection);
float att = gPointLight.atten.constant + gPointLight.atten.linearr * dist + gPointLight.atten.quadratic * dist * dist;
// NL
lightDirection = normalize(lightDirection);
float NL = dot(normal, -lightDirection);
// Specular (Blinn-Phong)
float specular = 0.0f;
//if (NL > 0)
//{
// float3 vertexToEye = normalize(gEyePosition - position);
// float3 lightReflect = normalize(reflect(lightDirection, normal));
// specular = pow(saturate(dot(vertexToEye, lightReflect)), gSpecularPower);
//}
// Apply attenuation to NL
NL = NL / min(1.0, att);
float3 lightColor = gPointLight.base.color * gPointLight.base.diffuseIntensity;
return float4(lightColor.r, lightColor.g, lightColor.b, 1.0f) * NL;
}
// Vertex shader for Pre-pass lighing material stage.
float4x4 gWorldMtx;
float4x4 gViewMtx;
float4x4 gProjectionMtx;
struct a2v
{
float3 position : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float3 normal : TEXCOORD1;
float4 projPos : TEXCOORD2;
};
v2f PPL_material_stage_vs(a2v IN)
{
v2f OUT;
float4x4 wv = mul(gWorldMtx, gViewMtx);
float4x4 wvp = mul(gViewMtx, gProjectionMtx);
wvp = mul(wvp, gWorldMtx);
// Only transforms position to world space
OUT.position = mul(wvp, float4(IN.position, 1.0f));
// Normal (It's not necessary, but i have to see if it influences the execution)
OUT.normal = mul(gWorldMtx, float4(IN.normal, 0.0f)).xyz;
// Copy texture coordinates
OUT.texcoord = IN.texcoord;
// Copy projected position to get the fragment coordinate
OUT.projPos = OUT.position;
return OUT;
}
// Fragment shader for Pre-pass lighing material stage.
// L-buffer texture
sampler2D gLightMap : TEXUNIT0;
// Object's material specific textures
sampler2D gColorMap : TEXUNIT1;
float4 PPL_material_stage_fs(v2f IN) : COLOR0
{
float2 fragcoord = ((IN.projPos.xy / IN.projPos.w) + 1.0f) / 2.0f;
// Get all light contributions for this pixel
float4 light = tex2D(gLightMap, fragcoord);
float3 combined = saturate(light.rgb);// + light.aaa);
// Get material albedo from texture map
float4 diffuse = tex2D(gColorMap, IN.texcoord);
return float4(combined, 1.0f) * diffuse;
}
Any suggestions?
You may want to use the WPOS register (VPOS in HLSL) instead of calculating the screen locations.