ProjectionTexture
From GameStudio Wiki
Code for creating projection shadows in Fixed Functions Pipeline also this code show how to use DirectX functions for creating projection matrix. Working for all A7 edtitors, tested on Lite-c 7.70 Free
Projection shaders pMat.c
D3DXMATRIX mMatrices[8];// 8 matrices for FFP
function set_mat_pointer (float** mMat,float** pointer) {*pointer = mMat;}
function set_material_matrices ()
{
set_mat_pointer(mMatrices[0],mat_effect1);
set_mat_pointer(mMatrices[1],mat_effect2);
set_mat_pointer(mMatrices[2],mat_effect3);
set_mat_pointer(mMatrices[3],mat_effect4);
set_mat_pointer(mMatrices[4],mat_effect5);
}
//1 projected texture + diffuse light
MATERIAL* mtl_pTex1 = {effect = "
float4x4 matEffect1;
texture mtlSkin1;
texture entSkin1;
technique proj_tex
{
pass p0
{
Texture[0] = <entSkin1>;
Texture[1] = <mtlSkin1>; // projected
ColorArg1[0] = Texture;
ResultArg[0] = Temp;
ColorArg2[1] = Texture;
ColorArg1[1] = Diffuse;
ColorOp[1] = AddSigned2x;
ColorArg1[2] = Current;
ColorArg2[2] = Temp;
ColorOp[2] = Modulate;
TexCoordIndex[0] = 1;
AddressU[1] = BORDER;
AddressV[1] = BORDER;
BorderColor[1] = 0xffffff;
texcoordindex[1] = cameraspaceposition ;
TextureTransformFlags[1] = count3 | projected;
TextureTransform[1] = <matEffect1>;
}
}";}
//2 projected textures + diffuse light
MATERIAL* mtl_pTex2 = {effect = "
float4x4 matEffect1;
float4x4 matEffect2;
texture mtlSkin1;
texture mtlSkin2;
texture entSkin1;
technique proj_tex
{
pass p0
{
Texture[0] = <entSkin1>;
Texture[1] = <mtlSkin1>; // projected texture
Texture[2] = <mtlSkin2>; // projected texture
ColorArg1[0] = Texture;
ColorArg2[0] = Diffuse;
ColorOp[0] = Modulate2x;
ResultArg[0] = Temp;
ColorArg1[1] = Texture;
ColorOp[1] = SelectArg1;
ColorArg1[2] = Texture;
ColorArg2[2] = Current;
ColorOp[2] = Modulate;
ColorArg2[3] = Current;
ColorArg1[3] = Diffuse;
ColorOp[3] = AddSigned2x;
ColorArg1[4] = Current;
ColorArg2[4] = Temp;
ColorOp[4] = Modulate;
texcoordindex[0] = 1;
AddressU[1] = BORDER;
AddressV[1] = BORDER;
BorderColor[1] = 0xffffff;
texcoordindex[1] = cameraspaceposition ;
TextureTransformFlags[1] = count3 | projected;
TextureTransform[1] = <matEffect1>;
AddressU[2] = BORDER;
AddressV[2] = BORDER;
BorderColor[2] = 0xffffff;
texcoordindex[2] = cameraspaceposition ;
TextureTransformFlags[2] = count3 | projected;
TextureTransform[2] = <matEffect2>;
}
}";}
//3 projected textures, 2 shadow 1 light
MATERIAL* mtl_pTex3 = {effect = "
float4x4 matEffect1;
float4x4 matEffect2;
float4x4 matEffect3;
texture mtlSkin1;
texture mtlSkin2;
texture mtlSkin3;
texture entSkin1;
technique proj_tex
{
pass p0
{
Texture[0] = <entSkin1>;
Texture[1] = <mtlSkin1>; // projected shadow
Texture[2] = <mtlSkin2>; // projected shadow
Texture[3] = <mtlSkin3>; // projected spotlight
ColorArg1[0] = Texture;
ColorArg2[0] = Diffuse;
ColorOp[0] = Modulate2x;
ResultArg[0] = Temp;
ColorArg1[1] = Texture;
ColorOp[1] = SelectArg1;
ColorArg1[2] = Texture;
ColorArg2[2] = Current;
ColorOp[2] = Modulate;
ColorArg1[3] = Current;
ColorArg2[3] = Texture;
ColorOp[3] = Add;
ColorArg1[4] = Current;
ColorArg2[4] = Temp;
ColorOp[4] = Modulate2x;
texcoordindex[0] = 1;
AddressU[1] = BORDER;
AddressV[1] = BORDER;
BorderColor[1] = 0xffffff;
texcoordindex[1] = cameraspaceposition ;
TextureTransformFlags[1] = count3 | projected;
TextureTransform[1] = <matEffect1>;
AddressU[2] = BORDER;
AddressV[2] = BORDER;
BorderColor[2] = 0xffffff;
texcoordindex[2] = cameraspaceposition ;
TextureTransformFlags[2] = count3 | projected;
TextureTransform[2] = <matEffect2>;
AddressU[3] = BORDER;
AddressV[3] = BORDER;
BorderColor[3] = 0x000001;
texcoordindex[3] = cameraspaceposition ;
TextureTransformFlags[3] = count3 | projected;
TextureTransform[3] = <matEffect3>;
}
}";}
// material using for creating shadow
MATERIAL* mtl_black = {effect = "texture entSkin1;
technique black
{
pass p0
{
AlphaBlendEnable=True;
Zenable = True;
ZwriteEnable = True;
BlendOp=Add;
Lighting=False;
FogEnable = True;
FogColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
FogStart = 60000;
FogEnd = 50000;
ShadeMode = Flat;
Texture[0] = <entSkin1>;
ColorArg1[0] = Diffuse;
ColorOp[0] = SelectArg1;
}
}
";}
Create projection matrix projMain.c
typedef struct
{
// useful struct for storing position and angle of projection texture
VECTOR Pos;
VECTOR Ang;
var Fov;
} PSystem;
PSystem pSys[8];
var debug_pMatrix = 1; // if == 1 debug projection matrix
function debug_projection (VECTOR* pPos,VECTOR* pAng,var fov,var dist,VECTOR* col)
{
VECTOR dpos;
VECTOR aang;
vec_set(dpos,vector(dist,0,0));
vec_rotate (dpos,pAng);vec_add(dpos,pPos);vec_rotate (aang,pAng);vec_add(aang,pPos);
draw_line3d(dpos,NULL,100);
draw_line3d(pPos,vector(0,255,0),100);
aang.x = fov/2;aang.y = fov/(2+(fov*fov/15000));
vec_set(dpos,vector(dist,0,0));vec_rotate(dpos,vector(aang.x,aang.y,0));
vec_rotate(dpos,pAng);vec_add(dpos,pPos);
draw_line3d(pPos,NULL,100);
draw_line3d(pPos,col,100);
draw_line3d(dpos,col,100);
vec_set(dpos,vector(dist,0,0));vec_rotate (dpos,vector(-aang.x,aang.y,0));
vec_rotate (dpos,pAng);vec_add(dpos,pPos);
draw_line3d(pPos,NULL,100);
draw_line3d(dpos,col,100);
vec_set(dpos,vector(dist,0,0));vec_rotate (dpos,vector(aang.x,-aang.y,0));
vec_rotate (dpos,pAng);vec_add(dpos,pPos);
draw_line3d(pPos,NULL,100);
draw_line3d(dpos,col,100);
vec_set(dpos,vector(dist,0,0));vec_rotate (dpos,vector(-aang.x,-aang.y,0));
vec_rotate (dpos,pAng);vec_add(dpos,pPos);
draw_line3d(pPos,NULL,100);
draw_line3d(dpos,col,100);
}
function create_dxmat(D3DXMATRIX* mMain,VECTOR* Ppos,VECTOR* pAng,var fov,BMAP* projBmap)
{
//create DX projection matrix for camera from given parametrs
D3DXMATRIX mAng,mPos,mCAng,mProj;
D3DXMATRIX mRX,mRY,mRZ;
float posProj[3];
float aCam[3];
float aSelf[3];
proc_mode = PROC_LATE;
float fTexAdj[16] =
{ 0.5, 0.0, 0.0, 0.0,
0.0,-0.5, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 };
if (projBmap) {
fTexAdj[12] = 0.5 + (0.5/(float)bmap_width(projBmap));
fTexAdj[13] = 0.5 + (0.5/(float)bmap_width(projBmap));
}
posProj[0] = -camera.y+Ppos.y;posProj[1] = camera.z-Ppos.z;posProj[2] = camera.x-Ppos.x;
aCam[0] = -camera.pan*D3DX_PI/180;
aCam[1] = -camera.tilt*D3DX_PI/180;
aCam[2] = -camera.roll*D3DX_PI/180;
aSelf[0] = pAng.x*D3DX_PI/180;
aSelf[1] = pAng.y*D3DX_PI/180;
aSelf[2] = pAng.z*D3DX_PI/180;
//D3DXMatrixOrthoOffCenterLH (mProj,-fov,fov,-fov,fov,0,1);////only for isometric projection count4
D3DXMatrixPerspectiveFovLH (mProj,fov*D3DX_PI/180,1,0,1); //only for perspective projection count3
D3DXMatrixTranslation(mPos,posProj[0],posProj[1],posProj[2]);
D3DXMatrixRotationYawPitchRoll(mCAng ,aCam[0],aCam[1],aCam[2]);
D3DXMatrixRotationX(mRX,aSelf[1]);
D3DXMatrixRotationY(mRY,aSelf[0]);
D3DXMatrixRotationZ(mRZ,aSelf[2]);
D3DXMatrixMultiply(mAng,mRY,mRX);
D3DXMatrixMultiply(mAng,mAng,mRZ);
//D3DXMatrixRotationYawPitchRoll(mAng ,aSelf[0],aSelf[1],aSelf[2]); //dont work for Eulen angles
D3DXMatrixMultiply(mProj,mProj,fTexAdj);
D3DXMatrixMultiply(mProj,mAng,mProj);
D3DXMatrixMultiply(mProj,mPos,mProj);
D3DXMatrixMultiply(mMain,mCAng,mProj);
if (debug_pMatrix)
{
debug_projection(Ppos,pAng,fov,10000,vector(255,0,0));
debug_projection(Ppos,pAng,fov,-10000,vector(0,0,255));
}
}
function debug_pMatrix_switch () {debug_pMatrix = !debug_pMatrix;} //enable,disable
function proj_fromFile (STRING* name,VECTOR* pos,VECTOR* aang,var* fov,BMAP** pShadow)
{
//function load projection texture and parametrs from disk
//load projection texture from name+.png
//set pos,aang,fov from name+.txt
STRING* fname = "#20";
var file_handle ;
BMAP* bLoad = "#128x128x24";
str_cpy(fname,name);str_cat(fname,".png");bmap_load(bLoad,fname,1);*pShadow = bLoad;
str_cpy(fname,name);str_cat(fname,".txt");
file_handle = file_open_read (fname);
pos.x = file_var_read(file_handle);pos.y = file_var_read(file_handle);
pos.z = file_var_read(file_handle);
aang.x = file_var_read(file_handle);aang.y = file_var_read(file_handle);
aang.z = file_var_read(file_handle);
*fov = file_var_read(file_handle);
file_close (file_handle);
}
Render bitmap for shadow projection eRender.c
VIEW* rView = {layer=1000;material = mtl_black;flags = NOFLAG1 ;}// view for rendering shadows
ENTITY* rEnt[100];// list of entities that render for shadows
STRING* rFile = "rScreen"; // def name for saving projection shadows bmap and parametrs
BMAP* rBmap; //in this bmap render shadow for entities
void get_points (VECTOR* vset,ENTITY* this,var num)
{
VECTOR vMin,vMax;
vec_for_min (vMin,this);vec_for_max (vMax,this);
if (num==0) vec_set(vset,vector(vMin.x,vMin.y,vMin.z));
if (num==1) vec_set(vset,vector(vMax.x,vMin.y,vMin.z));
if (num==2) vec_set(vset,vector(vMax.x,vMax.y,vMin.z));
if (num==3) vec_set(vset,vector(vMin.x,vMax.y,vMin.z));
if (num==4) vec_set(vset,vector(vMin.x,vMin.y,vMax.z));
if (num==5) vec_set(vset,vector(vMax.x,vMin.y,vMax.z));
if (num==6) vec_set(vset,vector(vMax.x,vMax.y,vMax.z));
if (num==7) vec_set(vset,vector(vMin.x,vMax.y,vMax.z));
vset.x *= this.scale_x;vset.y *= this.scale_y;vset.z *= this.scale_z;
vec_rotate(vset,this.pan);vec_add(vset,this.x);
}
function is_points_visible (var num)
{
var c,cp;VECTOR tmp;
for (c=0;c<=num;c++)
for(cp=0;cp<=7;cp++) {
get_points(tmp,rEnt[c],cp);if (vec_to_screen(tmp,rView)==NULL) return(0);
}
return(1);
}
function pixel_blur (BMAP* sor,var dx,var dy,var pas)
{
VECTOR col,fcol;
var x1,y1,pixel;
var count=0;
var cp = maxv(minv(pas,1),0.1);
vec_set(fcol,nullvector);
for (y1=dy-pas;y1<=(dy+pas);y1+=cp) for (x1=dx-pas;x1<=(dx+pas);x1+=cp)
{
pixel = pixel_for_bmap(sor,clamp(x1,0,bmap_width(sor)-1),clamp(y1,0,bmap_height(sor)-1));
pixel_to_vec(col,NULL,888,pixel);
vec_add(fcol,col);count++;
}
fcol.x /= count;fcol.y /= count;fcol.z /= count;
pixel = pixel_for_vec(fcol,NULL,888);
return (pixel);
}
function screen_to_1024 (var blur)// this function create 1024x1024 projection texture from screen
{
var pixel,x1,y1;
var sy;
BMAP* dest = bmap_createblack(1024,1024,24);
BMAP* sor = bmap_createblack(screen_size.x,screen_size.y,24);
bmap_for_screen(sor,0,1);
bmap_lock(dest,888);bmap_lock(sor,888);
sy = bmap_height(sor);
for (y1=0;y1<1024;y1++) for(x1=0;x1<1024;x1++)
{
pixel = pixel_blur(sor,(x1/1024)*sy,(y1/1024)*sy,blur);
pixel_to_bmap(dest,x1,y1,pixel);
}
bmap_unlock(dest);bmap_unlock(sor);
return(dest);
}
function screen_render_entities (VECTOR* lPos,VECTOR* aang,var* fov,var cent)
{
// lPos light position; cent - count of render entities(rEnt[cent]);
// aang,fov - to be set by this function;
var c,cp;
VECTOR tmp;
VECTOR vMin,vMax;
VECTOR eMin,eMax;
you = ent_next(NULL);
while (you!=NULL) {set(you,FLAG1);you = ent_next(you);}
//hide enitities what not in list (rEnt[]) for rView
for (c=0;c<=cent;c++)
{
//find bounding box and center of all entities what in the list (rEnt[])
reset(rEnt[c],FLAG1);c_setminmax(rEnt[c]);
if (c==0) {get_points(tmp,rEnt[c],0);vec_set(vMin,tmp);vec_set(vMax,tmp);}
for (cp=0;cp<=7;cp++)
{
get_points(tmp,rEnt[c],cp);
if (vMin.x>tmp.x) vMin.x=tmp.x;if (vMin.y>tmp.y) vMin.y=tmp.y;
if (vMin.z>tmp.z) vMin.z=tmp.z;if (vMax.x<tmp.x) vMax.x=tmp.x;
if (vMax.y<tmp.y) vMax.y=tmp.y;if (vMax.z<tmp.z) vMax.z=tmp.z;
}
}
vec_lerp(eMin,vMin,vMax,0.5);//find center position of all entities (rEnt[])
draw_box3d(vMin,vMax,vector(0,0,255),100);//debug bounding box
draw_point3d(eMin,vector(10,200,0),100,5);//debug center
vec_set(rView.x,lPos);vec_set(tmp,rView.x);vec_sub(eMin,rView.x);//set position of rView
vec_to_angle(tmp,eMin);tmp.z=0;
set(rView,VISIBLE);vec_set(rView.pan,tmp);//now rView look at entity (rEnt[])
rView.size_x = screen_size.y;rView.size_y = screen_size.y; // set symmetrical borders for rView
rView.arc = 60;wait(1);//render rView
if (is_points_visible(cent)) //find Fov there all entities visible
while(is_points_visible(cent)&&rView.arc>2) {rView.arc--;wait(1);}
else while(!is_points_visible(cent)&&rView.arc<175) {rView.arc++;wait(1);}
vec_set(sky_color,vector(255,255,255));wait(1);//set background to white
reset(rView,VISIBLE);vec_set(sky_color,vector(128,0,0));//back background to normal
rBmap = screen_to_1024(0.5);//render shadow for entities, with blur factor
STRING* name = "#20";
str_cpy(name,rFile);str_cat(name,".png");
bmap_save(rBmap,name); // save shadow bmap
str_cpy(name,rFile);str_cat(name,".txt");
c=0; c = file_open_write(name);
file_var_write(c,lPos.x);file_var_write(c,lPos.y);file_var_write(c,lPos.z);
file_var_write(c,tmp.x);file_var_write(c,tmp.y);file_var_write(c,tmp.z);
file_var_write(c,rView.arc);file_close(c);// save parametrs for projection texture to file
vec_set(aang,tmp);*fov=rView.arc;//return fov and angle
}
For demonstration how its works you must have tree model
and terrain
#include <acknex.h>
#include <default.c>
#include <d3d9.h> // DX functions
#include "pMat.c" // projection materials
#include "projMain.c" //code for creating matrix
#include "eRender.c" //render bitmap for projection texture
void main()
{
level_load("");video_switch(8,32,1);def_move();
vec_set(sun_color,vector(128,200,255));sun_light=60;// set sun color
//ent_createlayer("blood_gorge+6.tga",SKY | CUBE | VISIBLE,1);//load sky
you = ent_create("helymap1.hmp",vector(0,0,-500),NULL); //create terrain
you.material = mtl_pTex1;
//load trees
rEnt[0] = ent_create("tree.mdl",vector(255,0,-250),NULL);set(rEnt[0],OVERLAY | PASSABLE);
rEnt[1] = ent_create("tree.mdl",vector(0,0,-250),NULL);set(rEnt[1],OVERLAY | PASSABLE);
rEnt[2] = ent_create("tree.mdl",vector(0,200,-250),NULL);set(rEnt[2],OVERLAY | PASSABLE);
rEnt[3] = ent_create("tree.mdl",vector(-300,300,-250),NULL);set(rEnt[3],OVERLAY | PASSABLE);
rEnt[4] = ent_create("tree.mdl",vector(-300,32,-250),NULL);set(rEnt[4],OVERLAY | PASSABLE);
rEnt[3].pan = 90;rEnt[2].pan = 180;
//load trees
vec_set(pSys.Pos,vector(29,-695,1700)); //set position of light that cast projection shadows
str_cpy(rFile,"simple01");//name of saving bmap and projection parametrs
screen_render_entities (pSys[0].Pos,pSys[0].Ang,pSys[0].Fov,4);//create projection bmap(render 5 trees)
while(proc_status(screen_render_entities)) wait(1);// wait until render is finish
mtl_pTex1.skin1 = rBmap ;// set material skin to shadow bmap
set_material_matrices();// set all mat_effect pointers that uses in shader
while (1)
{
create_dxmat(mat_effect1,pSys[0].Pos,pSys[0].Ang,pSys[0].Fov,mtl_pTex1.skin1);
//create projection matrix(for shader) each frame for screen coordinates
wait(1);
}
}
In game you must see something like this
Have Fun ;)
Xd1Vo

