ProjectionTexture

From GameStudio Wiki

Jump to: navigation, search

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 Image:ModelTree.jpg and terrain Image:XdivoTer.jpg

#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

Image:PTexScreen.jpg


Have Fun ;) Xd1Vo

Personal tools