Sign in to follow this  
JustinMcconnell

Custom Vertex Sky Boxes WO texturecube

Recommended Posts

hello so i have found this awesome texture but it is designed for a sphere and not a cube

[media]http://svs.gsfc.nasa.gov/vis/a000000/a003500/a003572/TychoSkymapII.t5_04096x02048_web.png[/media]

i have it running through a custom vertex at the moment and it looks awesome but i need to send it to the far clipping plane so i can turn it into a skybox

here is my custom vertex

public void Tesellate(GraphicsDeviceManager graphics)
{
VPNTT = new VertexPositionNormalTangentTexture[(slices + 1) * (stacks + 1)];
for (int slice = 0; slice <= slices; ++slice)
{
for (int stack = 0; stack <= stacks; ++stack)
{
VertexPositionNormalTangentTexture v = new VertexPositionNormalTangentTexture();
v.Position.Y = (float)Math.Sin(((double)stack / stacks - 0.5) * Math.PI);
if (v.Position.Y < -1) v.Position.Y = -1;
else if (v.Position.Y > 1) v.Position.Y = 1;
float l = radius * (float)Math.Sqrt(1 - v.Position.Y * v.Position.Y);
v.Position.X = l * (float)Math.Sin((double)slice / slices * Math.PI * 2);
v.Position.Z = l * (float)Math.Cos((double)slice / slices * Math.PI * 2);
v.Position.Y *= radius;
v.Normal = v.Position;
v.Tangent = new Vector3(l * (float)Math.Cos((double)slice / slices * Math.PI * 2),
0, -(float)Math.Sin((double)slice / slices * Math.PI * 2));
v.Texture = new Vector2((float)slice / slices, (float)stack / stacks);
VPNTT[slice * (stacks + 1) + stack] = v;
}
}
indices = new int[slices * stacks * 6];
int six = 0;
for (ushort slice = 0; slice < slices; ++slice)
{
for (ushort stack = 0; stack < stacks; ++stack)
{
ushort v = (ushort)(slice * (stacks + 1) + stack);
indices[six++] = v;
indices[six++] = (ushort)(v + 1);
indices[six++] = (ushort)(v + (stacks + 1));
indices[six++] = (ushort)(v + (stacks + 1));
indices[six++] = (ushort)(v + 1);
indices[six++] = (ushort)(v + (stacks + 1) + 1);
}
}
}

i have to say it is a really nice bit of work it makes the UV coordinates smaller the closer you get to the poles witch means i works great for the texture i found
but the skybox shader and the custom vertex shader dont look like thay mingle well... and i suck at HLSL it dosnt look right to me

here is my SkyBox Shader

uniform extern float4x4 ViewMatrix;
uniform extern float4x4 ProjectionMatrix;

void SkyboxVertexShader( float3 pos : POSITION0,
out float4 SkyPos : POSITION0,
out float3 SkyCoord : TEXCOORD0 )
{
// Calculate rotation. Using a float3 result, so translation is ignored
float3 rotatedPosition = mul(pos, ViewMatrix);
// Calculate projection, moving all vertices to the far clip plane
// (w and z both 1.0)
SkyPos = mul(float4(rotatedPosition, 1), ProjectionMatrix).xyww;

SkyCoord = pos;
};
uniform extern texture SkyboxTexture;
sampler SkyboxS = sampler_state
{
Texture = <SkyboxTexture>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = CLAMP;
AddressV = CLAMP;
};
float4 SkyboxPixelShader( float3 SkyCoord : TEXCOORD0 ) : COLOR
{
// grab the pixel color value from the skybox cube map
return texCUBE(SkyboxS, SkyCoord);
};
technique SkyboxTechnique
{
pass P0
{
vertexShader = compile vs_2_0 SkyboxVertexShader();
pixelShader = compile ps_2_0 SkyboxPixelShader();

// We're drawing the inside of a model
CullMode = None;
// We don't want it to obscure objects with a Z < 1
ZWriteEnable = false;
}
}

i used to like it because all i needed was a texture cube and any old model of a sphere but for my current application it will not do

so here is the shader i have for my custom vertex sphere

float4x4 World;
float4x4 View;
float4x4 Projection;
float3 LightDir;

texture DiffuseMap;
texture HeightMap;
texture NormalMap;

sampler Diffuse = sampler_state {
texture = (DiffuseMap);
MinFilter = Anisotropic;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};

sampler Height = sampler_state {
texture = (HeightMap);
MinFilter = Anisotropic;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};

sampler Normal = sampler_state {
texture = (NormalMap);
MinFilter = Anisotropic;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};


struct VertexShaderInput
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
float3 Tangent : Tangent0;
float2 UV : TEXCOORD0;
};

struct VertexShaderOutput
{
float4 Position : POSITION0;
float3 LightPosition : TexCoord1;
float3 Normal : TexCoord2;
float3 Tangent : TexCoord3;
float3 Bitangent : TexCoord4;
float2 UV : TEXCOORD0;
};

struct PixelShaderInput
{
float3 LightPosition : TexCoord1;
float3 Normal : TexCoord2;
float3 Tangent : TexCoord3;
float3 Bitangent : TexCoord4;
float2 UV : TEXCOORD0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput i)
{
VertexShaderOutput o;

o.LightPosition = mul(i.Position, mul(World, View));
o.Position = mul(float4(o.LightPosition, 1), Projection);
o.Normal = mul(i.Normal, (float3x3)World);
o.Tangent = mul(i.Tangent, (float3x3)World);
o.Bitangent = cross(o.Normal, o.Tangent);
o.UV = i.UV;

return o;
}

float SpecValue(float2 uv)
{
float h = tex2D(Height, uv).x;
if (h < 0.6)
return 1.0;
else if (h < 0.75)
return 0.0;
else
return saturate((h - 0.75) * 3);
}

float4 PixelShaderFunction(PixelShaderInput i) : COLOR0
{
float2 uv = i.UV;
float3 wp = i.LightPosition;
float4 diffuse = tex2D(Diffuse, uv);
float3 N = tex2D(Normal, uv) * 2 - 1;
N = normalize(N.r * i.Tangent + N.g * i.Bitangent + N.b * i.Normal);
float NdotL = saturate(dot(N, LightDir));
// the camera is at 0, 0, 0, so I don't need to reconstruct the lightspace ray explicitly
float3 R = normalize(wp - N * (dot(wp, N) * 2));
float RdotL = saturate(dot(R, LightDir));
float4 lightColor = diffuse * lerp(float4(0.25, 0.25, 0.25, 1), float4(1, 1, 1, 1), NdotL);
lightColor += float4(1, 1, 1, 0) * (pow(RdotL, 80) * SpecValue(uv));
return lightColor;
}

technique Technique1
{
pass Pass1
{
//ZEnable = TRUE;
//ZWriteEnable = TRUE;
//ZFunc = LessEqual;
AlphaBlendEnable = False;
//CullMode = CCW;
CullMode = CW;


AlphaTestEnable = FALSE;
VertexShader = compile vs_3_0 VertexShaderFunction();
PixelShader = compile ps_3_0 PixelShaderFunction();

//CullMode = None;
//ZWriteEnable = false;
}
}

i dont use C++ i know enough to build a clock and that is about it... i know i probably should but i havent gotten up the courage yet...
any help would be appreciated

Share this post


Link to post
Share on other sites
[font="Arial"]Hi there!

[/font][font="Arial"]I guess I would use a different approach to make a skybox out of that nice texture. I’m sure you eventually get yours working, so take the way I’ll now explain as little input for an alternative. (Sorry for not helping with yours.)

[/font][font="Arial"]All right! First, let’s render the skybox as box with object space coordinates [-1,-1,-1] to [1,1,1].
Use as world matrix something like this

[code]_Effect.Parameters["World"].SetValue(Matrix.CreateScale(_CubeSize) * Matrix.CreateTranslation(Camera.Position));[/code]
This will scale your cube (make sure the corners don’t leave the far plane) and move it to your camera position. Pass in the view and projection matrix as well.
[/font][font="Arial"]In the vertex shader we will transform the position to clipping space and additionally pass the object space position to the pixel shader. (Everything is very straightforward here.)

[/font][font="Arial"][code]struct VertexShaderInput
{
float4 Position : POSITION0;
};

struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 InputPosition : TEXCOORD0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.InputPosition = input.Position;
return output;
}[/code][/font] [font="Arial"]
Usually, in the pixel shader you could now simply look up the color from an environment map.

[/font][font="Arial"][code]float3 direction = normalize(input.InputPosition.xyz);
float4 color = texCUBE(EnvSampler, direction);[/code]
[/font][font="Arial"]In your case, however, I would upload the texture as Texture2D, since it is already parameterized in spherical coordinates.
You can transform the direction vector to spherical coordinates using (see [url="http://en.wikipedia.org/wiki/Spherical_coordinate_system"]wiki[/url]):

[code]
float theta = acos(direction.z); // make sure the direction is normalized!
float phi = atan2(direction.y, direction.x);
float2 texcoord = float2( phi / TwoPi, (theta + Pi) / TwoPi );[/code]
[/font][font="Arial"]Well, and this texcoord is the coord to look up in your Texture2D.
[/font][font="Arial"]Hope that helps![/font][font="Arial"] :)

[/font][font="Arial"]- Greetings

[/font]

Share this post


Link to post
Share on other sites
If you want to push it to the far clipping plane you could also change your depth range to minz 1 maxz 1, and draw it as a relatively small (start at 10x10x10, increase size gradually until it works) object centered on the viewpoint. Not too certain about how you'd do that in XNA though, but I've used this technique successfully in both D3D and OpenGL in the past.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this