• Home Mesh to voxel shaders and script

Mesh to voxel shaders and script

I wrote a real-time directx geometry shader that converts mesh objects into voxel-like cubes:

voxelteapot

In action:

I also wrote a python version for Blender:

http://www.luxrender.net/gallery/main.php?g2_view=core.DownloadItem&g2_itemId=17757&g2_serialNumber=1

 

Code for the real-time shader… no comments, no explanation… sorry.


float Script : STANDARDSGLOBAL < string UIWidget = "none"; string ScriptClass = "object"; string ScriptOrder = "standard"; string ScriptOutput = "color"; string Script = "Technique=Lambert?Main:Main10;"; > = 0.8;

//// UN-TWEAKABLES - AUTOMATICALLY-TRACKED TRANSFORMS ////////////////

float4x4 WorldITXf : WorldInverseTranspose < string UIWidget="None"; >;
float4x4 WvpXf : WorldViewProjection < string UIWidget="None"; >;
float4x4 WorldXf : World < string UIWidget="None"; >;
float4x4 ViewIXf : ViewProjection < string UIWidget="None"; >;

//// TWEAKABLE PARAMETERS ////////////////////

/// Point Lamp 0 ////////////
float3 Lamp0Pos : Position < string Object = "PointLight0"; string UIName = "Lamp 0 Position"; string Space = "World"; > = {-0.5f,2.0f,1.25f};
float3 Lamp0Color : Specular < string UIName = "Lamp 0"; string Object = "Pointlight0"; string UIWidget = "Color"; > = {2.0f,2.0f,2.0f};

//////// COLOR & TEXTURE /////////////////////

texture ColorTexture : DIFFUSE < string ResourceName = "default_color.dds"; string UIName = "Diffuse Texture"; string ResourceType = "2D"; >;

sampler2D ColorSampler = sampler_state {
Texture = ;
FILTER = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};

// shared shadow mapping supported in Cg version

//////// CONNECTOR DATA STRUCTURES ///////////

/* data from application vertex buffer */
struct appdata {
float3 Position : POSITION;
float4 UV : TEXCOORD0;
float4 Normal : NORMAL;
float4 Tangent : TANGENT0;
float4 Binormal : BINORMAL0;
};

/* data passed from vertex shader to pixel shader */
struct vertexOutput {
float4 HPosition : POSITION;
float2 UV : TEXCOORD0;
// The following values are passed in "World" coordinates since
// it tends to be the most flexible and easy for handling
// reflections, sky lighting, and other "global" effects.
// float3 LightVec : TEXCOORD1;
// float3 WorldNormal : TEXCOORD2;
float3 WorldTangent : TEXCOORD3;
float3 WorldBinormal : TEXCOORD4;
float3 WorldView : TEXCOORD5;
float3 Norm : NORMAL;
//float3 Color : COLOR1;
};
struct geoOutput {
float4 HPosition : POSITION;
float2 UV : TEXCOORD0;
float4 Color : COLOR1 ;
//float4 Cubes[100];
//float3 LightVec : TEXCOORD1;
//float3 WorldNormal : TEXCOORD2;
//float3 Norm : NORMAL;
};

///////// VERTEX SHADING /////////////////////

/*********** Generic Vertex Shader ******/

vertexOutput std_VS(appdata IN) {
vertexOutput OUT = (vertexOutput)0;
float4 Po = float4(IN.Position.xyz,1);
OUT.HPosition = Po;
OUT.UV = IN.UV;
OUT.Norm = IN.Normal;
//OUT.Color = tex2D(ColorSampler,IN.UV);
//OUT.WorldNormal = mul(IN.Normal,WorldITXf).xyz;
//OUT.Norm = IN.Normal;
//float3 Pw = mul(Po,WorldXf).xyz;
// OUT.LightVec = (Lamp0Pos - Pw);

return OUT;
}
bool SameSide(float4 p1,float4 p2,float4 a,float4 b){
float3 cp1 = cross(b-a, p1-a);
float3 cp2 = cross(b-a, p2-a);
if(dot(cp1, cp2) >= 0){return true;}
else return false;
}

bool PointInTriangle(float4 p, float4 a,float4 b,float4 c){

if(SameSide(p,a, b,c) && SameSide(p,b, a,c) && SameSide(p,c, a,b))
{
return true;
}
else {return false;}
}
[maxvertexcount(102)]

void GS( triangle vertexOutput In[3], inout TriangleStream TriStream )
{
geoOutput Out;

float size = .5;
float UV = In[0].UV;
float3 normal;// = mul((In[0].HPosition+In[1].HPosition+In[2].HPosition),0.33);
float4 position;// = mul((In[0].HPosition+In[1].HPosition+In[2].HPosition),0.33);

float4 wpos1 = mul(In[0].HPosition, WorldXf);
float4 wpos2 = mul(In[1].HPosition, WorldXf);
float4 wpos3 = mul(In[2].HPosition, WorldXf);
//Trouver Ax et Bx
int Ax = wpos1.x;
int Bx;
if(Ax>wpos2.x){
Bx = Ax;
Ax = wpos2.x;
}
else{
Bx=wpos2.x;
}
if(Ax>wpos3.x){
Ax = wpos3.x;
}
if(Bx<wpos3.x){ Bx=wpos3.x; } //Trouver Ay et By int Ay = wpos1.y; int By; if(Ay>wpos2.y){
By = Ay;
Ay = wpos2.y;
}
else{
By=wpos2.y;
}
if(Ay>wpos3.y){
Ay = wpos3.y;
}
if(By<wpos3.y){ By=wpos3.y; } //Trouver Az et Bz int Az = wpos1.z; int Bz; if(Az>wpos2.z){
Bz = Az;
Az = wpos2.z;
}
else{
Bz=wpos2.z;
}
if(Az>wpos3.z){
Az = wpos3.z;
}
if(Bz<wpos3.z){
Bz=wpos3.z;
}

float4 cubes[100];
int numCubes = 0;
/*cubes[0] = float4(Ax, Ay, Az, 1);
cubes[1] = float4(Bx, By, Bz, 1);
cubes[2] = wpos1;
cubes[3] = wpos2;
cubes[4] = wpos3;*/

//Calculer delta du plan formé par le triangle
//D'abord, trouver la normale du triangle
float4 edgeA = wpos2-wpos1;
float4 edgeB = wpos3-wpos1;
float3 wNormal = normalize(cross(edgeA,edgeB));
float delta = dot(wpos1,wNormal);

//Trouver les boxels dans le triangle
float3 curPos;
float3 tempPos;
for(int x=Ax;x<Bx+1;x++){
for(int y=Ay;y<By+1;y++){
for(int z=Az;z<Bz+1;z++){
//Trouver le point le plus proche sur le plan du triangle
curPos = float3(x,y,z);
tempPos = curPos+(delta-dot(curPos,wNormal))*wNormal;
//garder si distance entre original et nouveau < size
float tempDist = distance(curPos,tempPos);
if(tempDist<(1)){
// Est-ce que le point est à l'intérieur du triangle?
// (faire)
if(PointInTriangle(float4(curPos,0), wpos1,wpos2,wpos3)){
cubes[numCubes]=float4(curPos,1-tempDist);
numCubes++;
}

}
}
}
}
/*if(numCubes==0){
numCubes++;
cubes[0] = float4(Ax,Ay,Az,1); }*/

//numCubes=2;
for(int i=0;i<numCubes;i++){
position = float4(cubes[i].rgb,1);
//Crée un cube, nécessite "position", "normal", "size".
float4 pos1 = position + float4(-size, size, -size,0);
float4 pos2 = position + float4(-size, -size, -size,0);
float4 pos3 = position + float4(size, size, -size,0);
float4 pos4 = position + float4(size, -size, -size,0);
float4 pos5 = position + float4(-size, size, size,0);
float4 pos6 = position + float4(-size, -size, size,0);
float4 pos7 = position + float4(size, size, size,0);
float4 pos8 = position + float4(size, -size, size,0);

//précalculer normales et éclairage (à faire)
float alpha = cubes[0].a;
alpha = 1;
//alpha = 0.5f;
float4 couleur = float4(1,1,1,1);
//face 1
edgeA = pos2-pos1;
edgeB = pos3-pos1;
float3 wNormal = normalize(cross(edgeA,edgeB));
float3 lightVector = normalize(Lamp0Pos - position);
float diffuseValue = dot(lightVector, wNormal);
diffuseValue = max(diffuseValue, 0.0);
float3 couleur1 = Lamp0Color*couleur*diffuseValue;

//face 2
edgeA = pos7-pos3;
edgeB = pos4-pos3;
wNormal = normalize(cross(edgeA,edgeB));
lightVector = normalize(Lamp0Pos - position);
diffuseValue = dot(lightVector, wNormal);
diffuseValue = max(diffuseValue, 0.0);
float3 couleur2 = Lamp0Color*couleur*diffuseValue;

//face 3
edgeA = pos8-pos4;
edgeB = pos2-pos4;
wNormal = normalize(cross(edgeA,edgeB));
lightVector = normalize(Lamp0Pos - position);
diffuseValue = dot(lightVector, wNormal);
diffuseValue = max(diffuseValue, 0.0);
float3 couleur3 = Lamp0Color*couleur*diffuseValue;

//face 4
edgeA = pos7-pos3;
edgeB = pos1-pos3;
wNormal = normalize(cross(edgeA,edgeB));
lightVector = normalize(Lamp0Pos - position);
diffuseValue = dot(lightVector, wNormal);
diffuseValue = max(diffuseValue, 0.0);
float3 couleur4 = Lamp0Color*couleur*diffuseValue;

//face 5
edgeA = pos5-pos1;
edgeB = pos2-pos1;
wNormal = normalize(cross(edgeA,edgeB));
lightVector = normalize(Lamp0Pos - position);
diffuseValue = dot(lightVector, wNormal);
diffuseValue = max(diffuseValue, 0.0);
float3 couleur5 = Lamp0Color*couleur*diffuseValue;

//face 6
edgeA = pos7-pos5;
edgeB = pos6-pos5;
wNormal = normalize(cross(edgeA,edgeB));
lightVector = normalize(Lamp0Pos - position);
diffuseValue = dot(lightVector, wNormal);
diffuseValue = max(diffuseValue, 0.0);
float3 couleur6 = Lamp0Color*couleur*diffuseValue;

//1
Out.HPosition = mul(pos4,ViewIXf);
Out.Color = float4((couleur1+couleur2+couleur3)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//2
Out.HPosition = mul(pos2,ViewIXf);
Out.Color = float4((couleur1+couleur3+couleur5)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//3
Out.HPosition = mul(pos3,ViewIXf);
Out.Color = float4((couleur1+couleur2+couleur4)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//4
Out.HPosition = mul(pos1,ViewIXf);
Out.Color = float4((couleur1+couleur4+couleur5)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//5
Out.HPosition = mul(pos5,ViewIXf);
Out.Color = float4((couleur4+couleur5+couleur6)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//6
Out.HPosition = mul(pos2,ViewIXf);
Out.Color = float4((couleur1+couleur3+couleur5)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//7
Out.HPosition = mul(pos6,ViewIXf);
Out.Color = float4((couleur3+couleur5+couleur6)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//8
Out.HPosition = mul(pos4,ViewIXf);
Out.Color = float4((couleur1+couleur2+couleur3)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//9
Out.HPosition = mul(pos8,ViewIXf);
Out.Color = float4((couleur2+couleur3+couleur6)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//10
Out.HPosition = mul(pos3,ViewIXf);
Out.Color = float4((couleur1+couleur2+couleur4)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//11
Out.HPosition = mul(pos7,ViewIXf);
Out.Color = float4((couleur1+couleur4+couleur5)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//12
Out.HPosition = mul(pos5,ViewIXf);
Out.Color = float4((couleur4+couleur5+couleur6)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//13
Out.HPosition = mul(pos8,ViewIXf);
Out.Color = float4((couleur2+couleur3+couleur6)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

//14
Out.HPosition = mul(pos6,ViewIXf);
Out.Color = float4((couleur3+couleur5+couleur6)/3,alpha);
Out.UV = UV;
TriStream.Append( Out );

TriStream.RestartStrip();//to end the 2nd triangle*/

}

}

///////// PIXEL SHADING //////////////////////

float4 std_PS(geoOutput IN) : COLOR {

/* //float3 Ln = normalize(IN.LightVec);
// float3 Nn = normalize(IN.WorldNormal);
float ldn = dot(Ln,Nn);
ldn = max(ldn,0.0);
float3 diffuseColor = (0.0f,1.0f,1.0f);
// float3 diffuseColor = tex2D(ColorSampler,IN.UV).rgb;
float3 result = diffuseColor * (ldn * Lamp0Color + AmbiColor);
// return as float4
return float4(result,1);
return float4(tex2D(ColorSampler,IN.UV).rgb,1);*/
return IN.Color*float4(tex2D(ColorSampler,IN.UV).rgb,1);
//float4 bob = (.1,.1,.11);
//return float4(0,1,0.5,1);
}

///// TECHNIQUES /////////////////////////////

RasterizerState DisableCulling
{
CullMode = 1;
};

DepthStencilState DepthEnabling
{
DepthEnable = TRUE;
};

BlendState DisableBlend
{
BlendEnable[0] = false;

};
BlendState SrcAlphaBlendingAdd
{
BlendEnable[0] = TRUE;
SrcBlend = SRC_ALPHA;
DestBlend = INV_SRC_ALPHA;
BlendOp = ADD;
SrcBlendAlpha = ONE;
DestBlendAlpha = ONE;
BlendOpAlpha = ADD;
RenderTargetWriteMask[0] = 0x0F;

};

technique10 Main10 < string Script = "Pass=p0;"; > {

pass p0 < string Script = "Draw=geometry;"; > {

SetVertexShader( CompileShader( vs_4_0, std_VS() ) );
/* ZEnable = true;
ZWriteEnable = true;
AlphaBlendEnable = true;
SrcBlend = One;
DestBlend = InvSrcColor;
CullMode = CW; */
SetGeometryShader( CompileShader( gs_4_0, GS() ) );

SetPixelShader( CompileShader( ps_4_0, std_PS() ) );

SetRasterizerState(DisableCulling);

SetDepthStencilState(DepthEnabling, 1);
SetBlendState( SrcAlphaBlendingAdd, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );

}
}

/////////////////////////////////////// eof //