It is currently Sat Aug 22, 2020 4:14 am


All times are UTC




Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post subject: For those who interested, some DirectX 9 code
PostPosted: Sat Mar 19, 2011 10:21 pm 

Joined: Fri Feb 18, 2011 8:41 pm
Posts: 173
Hi!

So I been struggling with evil evil DirectX 9 code, HLSL and texture atlas. While I still haven't completely figured the texture atlas to work 100% right, I've got everything else:
Image

Now, considering there was a request before, I am going to share my code here, please note, some of it can still be optimized, I just finished.

Let us start with the way I construct my vertex buffers:

1. Before I begin, a class or two which may need some explanation, take a look at these two lines:
Code:
m_VertexBuffer.Create(sizeof(PolyVox::PositionMaterialNormal) * (mesh.getNoOfVertices()));

      m_IndexBuffer.Create((mesh.getNoOfIndices() - problemVertices.size()) * sizeof(DWORD), 8UL, D3DFMT_INDEX32);


All you need to know is what they do in DirectX 9, here is a simplified version deleting most of the internal parts:
Code:
bool VertexBuffer::Create(UINT size, DWORD usage, DWORD FVF, D3DPOOL pool)
{
if(FAILED(gEngine->GraphicsDevice()->GetDeviceCOM()->CreateVertexBuffer( size,
                           usage, FVF,
                           pool, &m_VertexBuffer, NULL )))
      {
         Logger << "VertexBuffer: Failed creating vertex buffer!\n";
         return false;
      }
}


Now for the index buffer:
Code:
bool IndexBuffer::Create(UINT size, DWORD usage, D3DFORMAT format, D3DPOOL pool)
{
HRESULT hr;
      if(FAILED(hr = gEngine->GraphicsDevice()->GetDeviceCOM()->CreateIndexBuffer(size, usage, format, pool, &m_IndexBuffer, NULL)))
      {
         Logger << "IndexBuffer: Failed creating index buffer!\n";
         return false;
      }
}


Ok, so now we know what those buffers do and how they really create the DX9 buffers, very simple so far.

Now for the next part, our mesh creation, I will first explain the mesh creation and the problems involved with it due to using triplanar texturing and texture atlas so keep this in mind, then I will go on to showing the shaders such as the atlas shader and triplanar texturing shader:
Code:
bool VoxelMesh::Construct(PolyVox::Volume<PolyVox::MaterialDensityPair44>& volume, PolyVox::Region region)


Here is what this is, my VoxelMesh represent part of a volume, not the whole volume (although they can, just pass them a full region), this function creates it.

Ok, now let's see how it works.
Code:
PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> mesh;
      PolyVox::SurfaceExtractor<PolyVox::MaterialDensityPair44> surfaceExtractor(&volume, region, &mesh);

      surfaceExtractor.execute();

      const vector<uint32_t>& vecIndicest = mesh.getIndices();
      
      const vector<PolyVox::PositionMaterialNormal>& vecVerticest = mesh.getVertices();


So far all should be familiar, we tell polyvox to create us a mesh.

Now comes the tricky part, with triplanar texturing AND texture atlas combined in DirectX 9 there will be some major artifacts if just rendered as-is, such as:
Image

This is cause because of the following - imagine you have a triangle with one vertex having material 0 which represents grass and two other vertices having material 3, representing dirt.

Now in a 4x4 texture atlas that means that the first vertex would have texture coordinate between 0.0 to 0.25, the second and third vertices would have coordinates between 0.75 to 1.0, since everything that is between the differing materials' vertices gets interpolated this means that color values which are in between the two textures slots would also get it and the values would range anywhere from 0 to 1 interpolating 4 textures into one triangle. This whole a lot of data is also what causes it to appear stretched.

So this kind of a triangle we will now call a problematic triangle and its vertices would be "problemVertices".

Now after we had PolyVox create our mesh and we retrieved this data, we need to deal with our "problemVertices".
Code:
vector<uint32_t> problemVertices;

      float mat1;
      float mat2;
      float mat3;

      for (vector<uint32_t>::const_iterator iter = vecIndicest.begin(); iter != vecIndicest.end(); iter++)
      {
         mat1 = vecVerticest[*iter].getMaterial();
         mat2 = vecVerticest[*(iter+1)].getMaterial();
         mat3 = vecVerticest[*(iter+2)].getMaterial();


         if (floatComparsion(mat1, mat2) == false || floatComparsion(mat1, mat3) == false)
         {
            
            problemVertices.push_back(*iter);
            problemVertices.push_back(*(iter+1));
            problemVertices.push_back(*(iter+2));
         }

         iter++;
         iter++;
      }


Here I initialize a vector to store the indices of our problematicVertices, or triangles actually. floatComparsion is just comparing floats with a slight epsilon to see if they are close enough to count as the same due to floating point precisions. I actually had incorrect identification of "problematicVertices" due to this imprecision, so here is the function:
Code:
inline bool floatComparsion(float one, float two)
   {
      if ( fabs(one-two) < 0.0001f )
         return true;

      return false;
   }


Now that we have identified our offenders, it is time to have a fix. And how do we fix them? Well, there trick is to first render the offender triangles black, we do this by adding the triangle to the original mesh with a black material, in my case I set the material to be 300 and in the shader I check if a material is over 200 and return a black color if it is (feel free to play with those numbers as suits your use of PolyVox and the number of materials you might have).

Then we render the offender triangles up to 3 more times, each time with one of the different materials (textures) a vertex of the triangle has, with the other two vertices also set to have the same material but an alpha of 1, then the alpha is interpolated over from the vertex shader to the pixel shader and a smooth transition happens when using additive blend.

Here is how I set up our new meshes (please ignore the un-used count value):
Code:
if (!problemVertices.empty())
      {
         vector<uint32_t> vecIndices;
         vecIndices.reserve(problemVertices.size() * 3);

         vector<PolyVox::PositionMaterialNormal> vecVertices;
         vecVertices.reserve(problemVertices.size() * 3);
         
         PolyVox::PositionMaterialNormal fixVert1;
         PolyVox::PositionMaterialNormal fixVert2;
         PolyVox::PositionMaterialNormal fixVert3;

         for (vector<uint32_t>::iterator iter = problemVertices.begin(); iter != problemVertices.end();)
         {
            
            float mat1;
            float mat2;
            float mat3;
            
            fixVert1 = vecVerticest[*iter];
            iter++;
            fixVert2 = vecVerticest[*iter];
            iter++;
            fixVert3 = vecVerticest[*iter];
            iter++;

            mat1 = fixVert1.getMaterial();
            mat2 = fixVert2.getMaterial();
            mat3 = fixVert3.getMaterial();

            fixVert1.setMaterial(300);
            fixVert2.setMaterial(300);
            fixVert3.setMaterial(300);

            mesh.addTriangle(mesh.addVertex(fixVert1), mesh.addVertex(fixVert2), mesh.addVertex(fixVert3));

         
            
            fixVert1.setMaterial(mat3+16);
            fixVert2.setMaterial(mat3+16);
            fixVert3.setMaterial(mat3);

            vecIndices.push_back(vecVertices.size());
            vecVertices.push_back(fixVert1);
            vecIndices.push_back(vecVertices.size());
            vecVertices.push_back(fixVert2);
            vecIndices.push_back(vecVertices.size());
            vecVertices.push_back(fixVert3);

            fixVert1.setMaterial(mat2+16);
            fixVert2.setMaterial(mat2);
            fixVert3.setMaterial(mat2+16);

            vecIndices.push_back(vecVertices.size());
            vecVertices.push_back(fixVert1);
            vecIndices.push_back(vecVertices.size());
            vecVertices.push_back(fixVert2);
            vecIndices.push_back(vecVertices.size());
            vecVertices.push_back(fixVert3);

            fixVert1.setMaterial(mat1);
            fixVert2.setMaterial(mat1+16);
            fixVert3.setMaterial(mat1+16);

            vecIndices.push_back(vecVertices.size());
            vecVertices.push_back(fixVert1);
            vecIndices.push_back(vecVertices.size());
            vecVertices.push_back(fixVert2);
            vecIndices.push_back(vecVertices.size());
            vecVertices.push_back(fixVert3);


         }

         m_NumVerticesFix = vecVertices.size();
         m_NumFacesFix = vecIndices.size() / 3 ;

         m_VertexBufferFix.Create(sizeof(PolyVox::PositionMaterialNormal) * (vecVertices.size()));

         m_IndexBufferFix.Create(vecIndices.size() * sizeof(DWORD), 8UL, D3DFMT_INDEX32);

         void* pVoid;
         m_IndexBufferFix.Lock(&pVoid);
         

         const void* pIndices = static_cast<const void*>(&(vecIndices[0]));      

         uint32_t count = 0;

         memcpy((pVoid), pIndices, sizeof(uint32_t) * vecIndices.size());
         


         m_IndexBufferFix.Unlock();

         const void* pVertices = static_cast<const void*>(&(vecVertices[0]));   

         m_VertexBufferFix.Lock(&pVoid);

         count = 0;

         memcpy((pVoid), pVertices, sizeof(PolyVox::PositionMaterialNormal) * vecVertices.size());
         m_VertexBufferFix.Unlock();
      }


Ok, so here what we do is first create arrays and reserve the predicted amount of values to be inserted into them.

Next we go over our problematic vertices, save their materials, set the materials to 300 and add them to the original mesh. That will take care of them being rendered as black later on.

Next what we do is set the three corners as I explained earlier, we add the triangle three times, each time with a different material when the corner who originally had that material has it again in its material's triangle (it will have the other materials in the other two triangles [+16]) and the other two vertices have the same material but with 16 added. Why 16 is added? Because I didn't feel like creating and switching over additional FVFs, as well as creating a new structure to add the alpha value in it. This means that in the shader, if a material is greater or equal 16 then it will set the alpha to be 0 in the vertex shader so it is sent to be interpolated in the pixel shader (it will also reduce the material's value by 16 so it can actually be used).

Do note that you should change that number (16) if your application is going to use more than 16 materials/textures.

Next all we do is create the vertex buffer and index buffer for the "fixed" triangles and save the number of faces and number of vertices.

Now two tasks are left for us:
1. Create the original mesh's buffers.
2. Remove the offender triangles' indices from the mesh so they won't be rendered. Remember we added additional black triangles to replace them anyway (the black is so the fixed triangles will render with additive blending over it instead of add with the environment).

Hurray, let's continue with our code then:
Code:
const vector<uint32_t>& vecIndices = mesh.getIndices();

      const vector<PolyVox::PositionMaterialNormal>& vecVertices = mesh.getVertices();

      m_VertexBuffer.Create(sizeof(PolyVox::PositionMaterialNormal) * (mesh.getNoOfVertices()));

      m_IndexBuffer.Create((mesh.getNoOfIndices() - problemVertices.size()) * sizeof(DWORD), 8UL, D3DFMT_INDEX32);

      if (vecIndices.empty())
         return false;

      void* pVoid;
      m_IndexBuffer.Lock(&pVoid);

      const void* pIndices = static_cast<const void*>(&(vecIndices[0]));      

      uint32_t count = 0;

      uint32_t* newIndices = (uint32_t*)pVoid;
      for (vector<uint32_t>::const_iterator iter = vecIndicest.begin(); iter != vecIndicest.end(); iter++)
      {
         mat1 = vecVerticest[*iter].getMaterial();
         mat2 = vecVerticest[*(iter+1)].getMaterial();
         mat3 = vecVerticest[*(iter+2)].getMaterial();


         if (floatComparsion(mat1, mat2) == false || floatComparsion(mat1, mat3) == false)
         {


            iter++;
            iter++;
         }
         else
         {
            newIndices[count] = *iter;
            iter++;
            count++;
            newIndices[count] = *iter;
            iter++;
            count++;
            newIndices[count] = *iter;
            count++;
         }

            
      }
      

      m_IndexBuffer.Unlock();


Simple here, retrieve our mesh indices and mesh vertices (we changed it a bit, but probably no need to do this again as we did get a reference to it last time, not a copy, optimization note).

Create vertex buffer and index buffer big enough, when creating the index buffer remember we intend to remove some indices (shown in the code)

Now copy the indices to the locked buffer (to the GPU), skip the offenders (room for optimization in this loop).

For the next bit of code all we are left with is copying our vertices to the buffer and obviously saving the number of faces and number of vertices we have:
Code:
const void* pVertices = static_cast<const void*>(&(vecVertices[0]));   

      m_VertexBuffer.Lock(&pVoid);

      count = 0;

      memcpy((pVoid), pVertices, sizeof(PolyVox::PositionMaterialNormal) * vecVertices.size());


      PolyVox::PositionMaterialNormal* vert = (PolyVox::PositionMaterialNormal*)pVoid;

      m_VertexBuffer.Unlock();

      m_NumVertices = vecVertices.size();
      m_NumFaces =   (vecIndices.size() - problemVertices.size()) / 3 ;
}


Done! (additional bit I did was also create a translation matrix to move the mesh from local space to region.getLowerCorner()'s position)

Now we are left with the rendering code (and the shaders):
Code:
void VoxelMesh::RenderImmediate()


Here we assign our world's position, assign our texture atlas to the appropriate texture slot, set our material (the color, not the PolyVox related) and then just set our index buffer, vertex buffer and deal with the offender triangles. Here is how we do that.

First we render the original mesh, no alpha blending, no alpha testing, nothing.
Code:
if (!m_NumFaces)
         return;

      m_WorldPosition.Assign();

      if (m_pTexture)
         gEngine->SetTexture(0, m_pTexture);

      Material mat;
      mat.Apply();

      gEngine->GraphicsDevice()->GetDeviceCOM()->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1);

      gEngine->GraphicsDevice()->GetDeviceCOM()->SetStreamSource(0, *m_VertexBuffer.GetVertexBuffer(), 0, sizeof(PolyVox::PositionMaterialNormal));


      gEngine->GraphicsDevice()->GetDeviceCOM()->SetIndices(*m_IndexBuffer.GetIndexBuffer());
      gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
      gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
      gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
      gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
      gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
      gEngine->GraphicsDevice()->GetDeviceCOM()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0, m_NumVertices, 0,m_NumFaces);


Now we need to render our offenders, this we do with alpha blending mode set to additive, source blend would be source alpha and destination blend value would be dest alpha.
Code:
if (m_NumFacesFix != 0)
      {
         gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
         gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
         gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
         gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_DESTALPHA);

         gEngine->GraphicsDevice()->GetDeviceCOM()->SetIndices(*m_IndexBufferFix.GetIndexBuffer());
         gEngine->GraphicsDevice()->GetDeviceCOM()->SetStreamSource(0, *m_VertexBufferFix.GetVertexBuffer(), 0, sizeof(PolyVox::PositionMaterialNormal));

         gEngine->GraphicsDevice()->GetDeviceCOM()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0, m_NumVerticesFix, 0,m_NumFacesFix);

         gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
         gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
         gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
         gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
         



      }
      gEngine->GraphicsDevice()->GetDeviceCOM()->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);



That's it for the DirectX part of the program! Rest is HLSL and I will continue this in the next post.


Last edited by Shanee on Sun Mar 20, 2011 6:27 am, edited 4 times in total.

Top
Offline Profile  
Reply with quote  
 Post subject: Re: For those who interested, some DirectX 9 code
PostPosted: Sat Mar 19, 2011 10:21 pm 

Joined: Fri Feb 18, 2011 8:41 pm
Posts: 173
Ok, my "VoxelAtlasShader.fx" requires two shaders, let us start by going over those two before the rest. Do note I have not yet worked much toward fixing the problems coming with texture atlases everywhere, unrelated to PolyVox.

Let us start with our light, basic blinn-phong lighting, which I will not bother to explain:

Filename: BlinnPhong.fx
Code:
#ifndef BLINNPHON_FX
#define BLINNPHON_FX

struct Lighting
{
    float3 Diffuse;
    float3 Specular;
};

struct PointLight
{
   float3 position;
   float3 diffuseColor;
   float diffusePower;
   float3 specularColor;
   float specularPower;
};

struct DirectionalLight
{
   float3 Diffuse;
   float DiffusePower;
   float3 Specular;
   float SpecularPower;
   float3 Direction; 
   
};

struct Mtrl
{
   float4 Diffuse;
   float4 Ambient;
   float4 Specular;
   float4 Emissive;
   float  SpecularPower;
};




uniform extern Mtrl     Material;

DirectionalLight gDirectionalLight;

#define MAX_LIGHTS 8
uniform extern PointLight gLights[MAX_LIGHTS];
float3 AmbientLight = float3(0.2,0.2,0.2);

static float specularHardness = 25.0f;



Lighting GetDirectionalLight(float3 viewDir, float3 normal)
{
   Lighting OUT;
   
   normal = normalize(normal);
   float3 lightVec = normalize(gDirectionalLight.Direction);

   // Compute the reflection vector.
    float3 r = reflect(lightVec, normal);

    // Determine how much (if any) specular light makes it
    // into the eye.
    float t  = pow(max(dot(r, viewDir), 0.0f), gDirectionalLight.SpecularPower);

    // Determine the diffuse light intensity that strikes the vertex.
    float s = max(dot(-lightVec, normal), 0.0f);

    // Compute the ambient, diffuse, and specular terms separately.
    OUT.Specular = t*(gDirectionalLight.Specular).rgb;
    OUT.Diffuse = s*(gDirectionalLight.Diffuse).rgb;

   return OUT;
}


Lighting GetPointLight(PointLight light, float3 viewDir, float3 normal, float3 lightDir)
{
Lighting OUT;
      normal = normalize(normal);
      float distance = length(lightDir); // GET THE DISTANCE OF THIS VECTOR
      distance = distance * distance; // USES INVERSE SQUARE FOR DISTANCE ATTENUATION
      lightDir = normalize(lightDir); // NORMALIZE THE VECTOR

      float3 halfVec = normalize(lightDir + viewDir);

      OUT.Diffuse = saturate(dot(normal, lightDir)) * light.diffuseColor * light.diffusePower / distance;
      OUT.Specular = pow(saturate(dot(normal, halfVec)), specularHardness) * light.specularColor * light.specularPower / distance;
   return OUT;
}



#endif


Now let us continue with the texture atlas function, this is in the "TextureAtlas.fx" file:
Code:
#ifndef TEXTUREATLAS
#define TEXTUREATLAS

float2 GetAtlasUV(float2 uv, float material, float numMatsX, float numMatsY)
{
   // First make sure u/v are between 0 and 1.
   while (uv.x > 1)
   {
      uv.x -= 1;
   }

   while (uv.x < 0)
   {
      uv.x += 1;
   }

   while (uv.y > 1)
   {
      uv.y -= 1;
   }

   while (uv.y < 0)
   {
      uv.y += 1;
   }


   // Divide by the number of materials to get proper texture UV coordinates
   uv.x /= numMatsX;
   uv.y /= numMatsY;

   float yPos = 0;

   while (material >= numMatsX)
   {
      yPos += 1;
      material -= numMatsX;
   }

   uv.x += 1 / numMatsX * material;
   uv.y += 1 / numMatsY * yPos;

   return uv;
}

#endif


First we make sure the UV is from 0 to 1 so there is no bleeding to other textures in the atlas, then we find the coordinates according to how many textures are in the atlas on the X and Y axes and we return it, pretty simple transformation.

Here is my "VoxelAtlasShader.fx", start with the includes and the vertex shader:
Code:
#include "BlinnPhong.fx"
#include "TextureAtlas.fx"

float4x4 World;
float4x4 View;
float4x4 Projection;
float textureScale;

uniform extern float3 gEyePos;
uniform extern float gNumMaterials = 200;

texture gTex0;
sampler ColorMapSampler = sampler_state
{
   Texture = <gTex0>;
   MinFilter = Linear;
   MagFilter = Linear;
   MipFilter = Linear;
   MaxAnisotropy = 4;
   AddressU  = Clamp;
   AddressV  = Clamp;
};

// TODO: add effect parameters here.

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float3 Normal : NORMAL0;
   float1 Material : TEXCOORD0;

    // TODO: add input channels such as texture
    // coordinates and vertex colors here.
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float3 Normal : TEXCOORD0;
    float3 worldPosition : TEXCOORD1;
   float1 Material : TEXCOORD2;
    float Alpha : COLOR0;

    // TODO: add vertex shader outputs such as colors and texture
    // coordinates here. These values will automatically be interpolated
    // over the triangle, and provided as input to your pixel shader.
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);   
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

   output.worldPosition = input.Position.xyz / input.Position.w;
   output.Normal = normalize(input.Normal);
   output.Material = input.Material;

   if (input.Material > 15.5)
   {
   output.Alpha = 0.0;
   output.Material -= 16;
   }

   else output.Alpha = 1.0;

    // TODO: add your vertex shader code here.

    return output;
}


Nothing much here, transform vertex, save world-space vertex divided by 1 (input.position.w) for triplanar texturing later on, save material and normal, also check if the material is >= 16 (well 5.5, extra worry due to floats but I guess it is the same) then set the alpha to 0 (and subtract material by 16), otherwise to 1. That's it.

Pixel Shader (and technique deceleration):
Code:
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
   // Clip pixels which shouldn't be there
   if (input.Material > gNumMaterials)
   return float4(0.0, 0.0, 0.0, 1.0);


   float3 Normal = normalize(input.Normal);
   float3 absNormal = abs(Normal);
   float3 blend_weights = absNormal;
   blend_weights = blend_weights - 0.2679f;
   blend_weights = max(blend_weights, 0);
   // force sum to 1.0
   blend_weights /= (blend_weights.x + blend_weights.y + blend_weights.z).xxx;

   float4 blended_color;
   float tex_scale = 0.1f;

   float2 coord1 = GetAtlasUV(input.worldPosition.yz * tex_scale, input.Material, 4, 4);
   float2 coord2 = GetAtlasUV(input.worldPosition.zx * tex_scale, input.Material, 4, 4);
   float2 coord3 = GetAtlasUV(input.worldPosition.xy * tex_scale, input.Material, 4, 4);

   float4 col1 = tex2D(ColorMapSampler, coord1);
   float4 col2 = tex2D(ColorMapSampler, coord2);
   float4 col3 = tex2D(ColorMapSampler, coord3);

   blended_color = col1.xyzw * blend_weights.xxxx + 
               col2.xyzw * blend_weights.yyyy + 
               col3.xyzw * blend_weights.zzzz;



   
   
   // Compute the vector from the vertex to the eye position.
      float3 viewDir = normalize(gEyePos - input.worldPosition);

     Lighting lightColor = GetDirectionalLight(viewDir, -Normal);
    

     float3 finalLight = float3(0,0,0);

     for (int i = 0; i < MAX_LIGHTS; i++)
     {
      float3 lightDir = gLights[i].position - input.worldPosition; // FIND THE VECTOR BETWEEN THE 3D POSITION IN SPACE OF THE SURFACE
      Lighting lightColor2 = GetPointLight(gLights[i], viewDir, -Normal, lightDir);
      lightColor.Diffuse += lightColor2.Diffuse;
      lightColor.Specular += lightColor2.Specular;       
     }

      // Combine texture color with color generated by lighting.
     finalLight += AmbientLight;
     finalLight += lightColor.Diffuse;
    
   return float4(finalLight * blended_color.xyz, input.Alpha);
}

technique Technique1
{
    pass Pass1
    {
        // TODO: set renderstates here.
      CULLMODE = CCW;
      ZENABLE = TRUE;


        ZWRITEENABLE = TRUE;
        VertexShader = compile vs_3_0 VertexShaderFunction();
        PixelShader = compile ps_3_0  PixelShaderFunction();
    }
}



First we check to see if we need to return black (remember we added triangles with material 300 to the "original mesh" to render as black so later we can blend on top of them?), if our material is larger than a value we set (200) then we return black.

Next part is about triplanar texturing, we get our texture coordinates from the normal, as well as the blend weights. We transform the texture coordinates to atlas texture coordinates with the function from the TextureAtlas.fx, then we sample the texture and add them multiplied by their weights.

Next we get our lights with our BlinnPhong.fx functions.

Last we return our color with the alpha from the vertex shader. The reason it was set in the vertex shader is so it gets interpolated across the vertices in the pixel shader.

Done! Enjoy :)
Image


Last edited by Shanee on Sat Mar 19, 2011 10:46 pm, edited 2 times in total.

Top
Offline Profile  
Reply with quote  
 Post subject: Re: For those who interested, some DirectX 9 code
PostPosted: Sat Mar 19, 2011 10:22 pm 

Joined: Fri Feb 18, 2011 8:41 pm
Posts: 173
Ok, some notes!

1. There might (probably) be a bug with the lighting because of the division by position.w in the vertex shader (forgot about that when added the usual lighting functions).

2. I do not deal with the usual problems associated with the usage of Texture Atlas, such as texture bleeding, filtering problems and mip mapping.

3. For still unknown reason, there are sometimes black vertices where 3 textures are being blended. The weird thing is that it only happens sometimes. If I will find the solution, I will edit the tutorial. Anyone who might have a solution please inform me :)

Now I have updated the MLE Tech Demo with the new version of this PolyVox "ground" editor and fixed texture blending. You are free to try it but note that you will still see low quality texture sampling due to the mipmaps problems with the texture atlas and low filtering levels.

(Apologies for the file size, it can be much smaller considering most unrelated features are disabled, but it is the same as the tech demo, where you can press F3 to see other functionalities of the MLE Engine)

Link: http://www.twilightempires.com/downloads/MLE.rar

I hope this tutorial helped someone and I will try to update it as I find solution for more problems.


Top
Offline Profile  
Reply with quote  
 Post subject: Re: For those who interested, some DirectX 9 code
PostPosted: Sun Mar 20, 2011 3:08 pm 
Developer
User avatar

Joined: Sun May 04, 2008 6:35 pm
Posts: 1827
That's a lot of information, thanks for contributing :) It was pretty long so I only skim read it but I noticed a couple of things:

You imply that the problems are a result of using triplanar texturing and/or texture atlases but is isn't really true (it would still happen with texture arrays). The problem is simply that if you have a matrial id of 1 at one vertexs and a material id of 100 at another vertex then when you interpolate the id across the triangle it passes through a whole bunch of materials you don't want. Even if you materials were just solid colours you would still see this problem.

Regarding your float comparisons and tolerance, actually I don't think you should need this. The meshes from the marching cubes surface extractor should not have duplicates anyway. You can probably just compare the index of the vertices rather than comparing their positions.

And a couple of typos I noticed:
but an alpha of 1 -> should be 0
well 5.5, extra worry -> should be 15.5


Top
Offline Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Theme created StylerBB.net