Thanks.
This version is nicer.
Now uses a cube map, so can zoom out more, and see greater than 180 degrees. You can zoom in and out with the mouse wheel. You can switch between special "spherical" camera and standard flat one for quick comparison. Note how if you zoom in, the two cameras are basically the same. Zoomed out, the spherical cam sees a wider angle.
Please be aware that to achieve a flat camera perspective, using a standard single camera in DBP will be much more efficient. Also for a spherical camera, for small FOV, it is better to use a single extra camera (as in previous example). Note the pixellation in this version when you zoom in.
I'm tempted to make a version with seamless unblurred zoom combining these two techniques next. Also add other camera types, and seamless transitions. For example, a hybrid of flat and spherical cameras could achieve a balance between the distortions of each.
Compressed folder containing .dbpro, .dba and .fx files is attached. No external media apart from the shader. For quick reference, i append the DBP code and the shader:
DBP program:
Rem Project: spherical camera using shader
Rem Created: 17/05/2010 00:08:12
Rem ***** Main Source File *****
`By DR TANK aka Ed Filby. Demo posted 18/05/10
`Demonstration of a "spherical" angle preserving camera using a shader. Also known as a sterographic projection.
`use mouse to look around, move using the left/right mouse buttons, and zoom with the mouse wheel.
`press space to switch between camera types.
sync on:sync rate 0
autocam off
hide mouse
`set display mode desktop width(),desktop height(),32,1
set display mode desktop width(),desktop height(),32,0
`set display mode 800,600,32
`backdrop on:color backdrop rgb(255,0,0) `should never be seen
backdrop off
set normalization on `so scaled cubes have correct normals
`setup cam 0 to show object 1 filling the screen.
`set camera aspect 1 `setting for standard widescreen 16:9 ratio
`very cheap solution to different aspect ratios. the shader think screen is 16:9. don't think can
`send 2vectors to shader, so just use the following trick.
`assumes square pixels. cuts off sides for 4:3 etc
set camera aspect desktop width()/(1.7777777777*desktop height())
`set camera aspect 800/(1.7777777777*600) `test 800x600
set camera fov 90
make object plain 1,20,20
set object mask 1,1 `only render to cam 0
position object 1,0,0,10
for n=1 to 6
make camera n
set camera to image n,n,512,512
set camera range n,0.1,1000
set camera aspect n,1
`color backdrop n,rgb(100,0,100)
next n
color backdrop 1,rgb(255,0,0)
color backdrop 2,rgb(0,255,0)
color backdrop 3,rgb(0,0,255)
color backdrop 4,rgb(255,255,0)
color backdrop 5,rgb(255,0,255)
color backdrop 6,rgb(0,255,255)
`sync:sync `running out of ideas how to get shader working!
cube_eff=1
load effect "FX/flat switch.fx",cube_eff,1
set object effect 1,cube_eff
set cube mapping on 1,5,6,3,4,1,2
`something to paste controls to screen
ink rgb(255,255,0),0
create bitmap 1,256,256
line 0,0,0,255
text 5,0,"SPHERICAL CAMERA SHADER"
text 5,20,"MOUSE TO LOOK"
text 5,35,"MOUSE WHEEL TO ZOOM"
text 5,50,"SPACE TO SWITCH BETWEEN"
text 5,60,"FLAT AND SPHERICAL CAMERAS"
get image 20,0,0,255,255
delete bitmap 1
set current bitmap 0
textobj=3
make object plain textobj,8,8
position object textobj,4.5,-11,9.9
texture object textobj,20
set object mask textobj,1
set object light textobj,0
set object transparency textobj,1
`ghost object on textobj
`SCENE ================================================
`LIGHT SETTINGS
set directional light 0,1,-10,2
color light 0,rgb(300,300,300)
set ambient light 50
`TEXTURE FOR WORLD OBJECTS (boxes and room)
`load image "3334.jpg",10
ink rgb(250,250,250),0
create bitmap 1,16,16
set current bitmap 1
cls
line 0,0,15,0
box 5,5,10,10
line 0,0,0,15
get image 10,0,0,15,15
delete bitmap 1
`"ROOM" (big inverted cube)
`make object plain 10,100,100
`position object 10,50,-1,50
make object cube 10,100
position object 10,50,50-1,50
scale object 10,-100,-100,-100
texture object 10,10
scale object texture 10,20,20
xrotate object 10,90
`set object mask 10,2
set object mask 10,126
`CUBES
for n=11 to 60
x=rnd(19):z=rnd(19)
if rnd(1)
make object cube n,4
h=1+(int(x+z)^1.2) mod 10 `random random function. means dependent on x,z, so if 2 in 1 square, no z-fighting because
`same height!
scale object n,100,100*h,100
else
make object sphere n,4
endif
texture object n,10
position object n,5*x+2.5,1,5*z+2.5
`set object mask n,2 `allow only to be seen by cam 1
set object mask n,126
next n
`make a dummy object to move around as camera
camobj=2
make object cube camobj,1
exclude object on camobj
`INITIAL VIEW SETTINGS
position object camobj,50,20,50
camwide#=2.0
`============================================================
timenow as dword
timelast as dword
timediff as dword
timenow=timer()
`Start loop
do
timelast=timenow
timenow=timer()
timediff=timenow-timelast
`MOVE AND LOOK
mx#=wrapvalue(mx#+0.1*mousemovey())
my#=wrapvalue(my#+0.1*mousemovex())
rotate object camobj,180.0-mx#,-my#,0.0
mc=mouseclick()
move object camobj, ((((mc&&1)<<1)-(mc&&2))*0.01 +0.1*(leftkey()-rightkey()))*timediff
camheight#=object position y(camobj)
`camheight#=camheight#*(1.0+(upkey()-downkey())*0.01)
if camheight#<1.0 then camheight#=1.0
cx#=object position x(camobj)
cz#=object position z(camobj)
position object camobj,cx#,camheight#,cz#
for n=1 to 6
position camera n,cx#,camheight#,cz#
set camera to object orientation n, camobj
set camera aspect n,1
set camera fov n,90
next n
turn camera left 5,-90
turn camera left 6,90
pitch camera up 4,-90
pitch camera up 3,90
turn camera left 2,180
`SWITCH TECHNIQUES WITH SPACEBAR
spkey=spacekey()
if spkey>last_spkey
techn=1-techn
if techn
set effect technique 1,"Flat"
else
set effect technique 1,"Spherical"
endif
endif
last_spkey=spkey
`ZOOM
camwide#=camwide#*(1.0-0.001*mousemovez())
set effect constant float cube_eff,"Wide",camwide#
`==============================================================
`RENDERING
sync mask 126:fastsync `cams 1 to 6 = 2^7 -2
sync mask 1:sync `render cam0, viewing spherical camera shader object
sync
loop
end
shader "FX/flat switch.fx":
// The following lines are variables which are recognised and passed by the
// application and often referred to as "untweaks".
matrix wvp : WorldViewProjection;
float4 lightColour = {0.5, 0.0, 1.5, 1.0}; // {red, green, blue, alpha}
float Wide =4.0f;
// The following lines are variables which can be set by the application
// (these are usually variables which the user may want to adjust from
// their program).
//float2 uvaspect = {1.6667, 1.0}; //uv on square- scale to get real world.
//scale from real world back onto world cam- here fov is important- make as set in dbp
float2 uvaspect = {1.777777, 1.0};
// The following lines define structures that are used as input and output
// to the vertex and pixel shader functions.
struct VSInput {
float4 Pos : Position;
float2 UV : TEXCOORD0;
};
struct VSOutput {
float4 Pos : Position;
float2 UV : TEXCOORD0;
};
// The pixel shader does not need an input structure for this example.
struct PSOutput { float4 Col : Color; };
//texture stuff
texture bumpTexture < string ResourceName = ""; > ; //need to have dummy tex, but now am specifying register for the other, i needn't
//sample from it, or even declare a sampler!
//the actual texture we want to use:
texture cubeTexture
< string ResourceName = "";
string Type = "CUBE";
>;
samplerCUBE cubeSample:register(s1) = sampler_state { texture = <cubeTexture>; };
// The vertex shader code:
VSOutput VShader (VSInput In, VSOutput Out)
{ // Transforms the objects model coordinates to
// screen space coordinates
Out.Pos = mul(In.Pos, wvp); //for sphr cam, obj is fixed relative to cam, so can avoid this step.
//(may matter if using large mesh)
Out.UV = Wide*uvaspect*(In.UV - 0.5); //change 0-1 to -0.5 to +0.5. could just scroll texture in DBP if want to lose this step
//Wide: bigger value= wider angle.
//now change so that UV co-ord represents "y" on paper calculations - scaling here is pretty unimportant - it
//sets fov of final camera. ratio is important as sets fov.
return Out;
};
// The pixel shader code:
PSOutput PShader (VSOutput In,PSOutput Out)
{
float2 UV2=In.UV;
//float rsq=UV2.x*UV2.x + UV2.y*UV2.y;
//float z=0.5*(1-rsq);
float z = 0.5*(1-(UV2.x*UV2.x + UV2.y*UV2.y));
float3 cubeuvw=z;
cubeuvw.xy=UV2;
Out.Col = 1.5*texCUBE(cubeSample, cubeuvw); //brighten scene also!
//Out.Col.xyz+=cubeuvw+0.5; //test
return Out;
};
PSOutput PShaderFlat (VSOutput In,PSOutput Out)
{
float2 UV2=In.UV;
float3 cubeuvw=0.5f;
cubeuvw.xy=UV2;
Out.Col = 1.5*texCUBE(cubeSample, cubeuvw); //brighten scene also!
//Out.Col.xyz+=cubeuvw+0.5; //test
return Out;
};
// The following lines just put this together as a single technique
// with a single pass.
technique Spherical
{ pass p1
{ VertexShader = compile vs_2_0 VShader();
PixelShader = compile ps_2_0 PShader();
}
}
technique Flat
{ pass p1
{ VertexShader = compile vs_2_0 VShader();
PixelShader = compile ps_2_0 PShaderFlat();
}
}