Sign in to follow this  
Scottehy

Using a shader on a Sphere

Recommended Posts

Scottehy    215
Hey guys. I was wondering how exactly I could use a shader to make something like this on a sphere. http://freespace.virgin.net/hugo.elias/models/p4_b.gif - I'm using hlsl with gamebryo and did it like this for a flat grid with a height map attached - to apply 4 different textures. But I'm unsure on how I'd go about it with a sphere that has elevated mountains on it etc.
VS_OUTPUT VS(float4 inPos: POSITION, float2 inTex0: TEXCOORD0, float4 inNormal: NORMAL)
{
    VS_OUTPUT Out;

	Out.Pos = mul(float4(inPos.xyz, 1.0f), WorldViewProj);
	Out.Normal = inNormal;
	
    Out.TexCoord = inTex0 * 10;
    Out.VecEye = normalize(inPos - float4(EyePos,1));

    // Store the position of the untransformed vertex in the color
    Out.Color = float4(1, 0, 0, clamp(inPos.z/50, 0, 1));
    return Out;
}

float4 PS(VS_OUTPUT In) : COLOR
{   
	float4 returnColor = 0;

    float4 BlendBaseColor = tex2D(BaseSampler, In.TexCoord).rgba;
    float4 BlendDarkColor = tex2D(DarkSampler, In.TexCoord).rgba;
    float4 BlendDetailColor = tex2D(DetailSampler, In.TexCoord).rgba;
    float4 BlendGlossColor = tex2D(GlossSampler, In.TexCoord).rgba;
    float4 BlendGlowColor = tex2D(GlowSampler, In.TexCoord).rgba;
    float4 BlendNormalColor = tex2D(NormalSampler, In.TexCoord).rgba;	
	
	if(In.Color.a <= 0.05f)// Dirt
	{
		returnColor = lerp(BlendNormalColor, BlendGlowColor, In.Color.a * 20);
	}
	else if(In.Color.a >= 0.05 && In.Color.a <= 0.40)// Stone
	{
		returnColor = lerp(BlendGlowColor, BlendDetailColor, (In.Color.a - 0.05) * 3);
	}
	else if(In.Color.a >= 0.40 && In.Color.a <= 0.75)// Grass
	{
		returnColor = lerp(BlendDetailColor, BlendBaseColor, (In.Color.a - 0.40) * 3);
	}
	else if(In.Color.a >= 0.75 && In.Color.a <= 1.00)// Dirt
	{
		returnColor = lerp(BlendBaseColor, BlendNormalColor,  (In.Color.a - 0.75) * 4);
	}

	return returnColor;
}
Hope you understand my question. It's probably really simple to do it with a sphere but I can't get anything working. Thanks heaps, Scott.

Share this post


Link to post
Share on other sites
Scottehy    215
I think I might try to make the question a little clearer possibly.

I've been trying to texture a sphere like this one using a HLSL shader in gamebryo.
Textured Planet

I've procedurally built this sphere and created a spherical landscape on it with these functions.
void Sphere::BuildSphere()
{
printf("Generating Spheres - Structure\n");
int tDiv = this->m_NumSlices;
int pDiv = this->m_NumStacks;
float dt = (PI * 2) / tDiv;
float dp = PI / pDiv;

for (int pi = 0; pi <= pDiv; pi++)
{
float phi = pi * dp;

for (int ti = 0; ti <= tDiv; ti++)
{
// we want to start the mesh on the x axis
float theta = ti * dt;

m_Vertices.push_back(GetPosition(theta, phi, m_Radius));
m_Normals.push_back(GetNormal(theta, phi));
m_UVs.push_back(GetTextureCoordinate(theta, phi));
}
}

for (int pi = 0; pi < pDiv; pi++)
{
for (int ti = 0; ti < tDiv; ti++)
{
int x0 = ti;
int x1 = (ti + 1);
int y0 = pi * (tDiv + 1);
int y1 = (pi + 1) * (tDiv + 1);

m_Indices.push_back(x0 + y0);
m_Indices.push_back(x0 + y1);
m_Indices.push_back(x1 + y0);

m_Indices.push_back(x1 + y0);
m_Indices.push_back(x0 + y1);
m_Indices.push_back(x1 + y1);
}
}
}

void Sphere::AddLandScapeMirror(int iterations, float push)
{
printf("Generating Spheres - Landscape\n");
for( int i = 0; i < iterations; i++ )
{
NiPoint3 n = NiPoint3(RandomFloat(-1, 1), RandomFloat(-1, 1), RandomFloat(-1, 1));
while( NiPoint3::VectorLength(n) >= 1 )
{
n = NiPoint3(RandomFloat(-1, 1), RandomFloat(-1, 1), RandomFloat(-1, 1));
}

for( unsigned int j = 0; j < m_Vertices.size(); j++ )
{
float d = n.Dot(m_Vertices[j]);
// Good movement amount = 0.0005f
//float movement = 0.0005f;
if( d > 0 )
{
m_Vertices[j] += m_Vertices[j] * push;
}
else
{
m_Vertices[j] -= m_Vertices[j] * push;
}
}
}
}


Everything builds and works fine in terms of, vertices, indices, normals, and texture uv's. When I apply a single texture of the sphere it works perfectly. The texture wraps around beautiful. But this is not how I want this project to work. Considering I have made the sphere have a landscape on it's surface, I want to be able to apply a brown texture for the raised bumps on the surface and a blue texture for the areas that are not raised as much on the surface.

I've no clue how to even get a HLSL shader to do what I want here. On a project I finished the other week I made a simple shader to color a grid according to how high each vert was in the grid. This allowed me to have 4 different textures accross the gird. Checking to see how high a vertex was, then texturing that vertex the appropriate texture.

My vertex and pixel shader looked like this in the grid example
Terrain NSF
// EMERGENT GAME TECHNOLOGIES PROPRIETARY INFORMATION
//
// This software is supplied under the terms of a license agreement or
// nondisclosure agreement with Emergent Game Technologies and may not
// be copied or disclosed except in accordance with the terms of that
// agreement.
//
// Copyright (c) 1996-2008 Emergent Game Technologies.
// All Rights Reserved.
//
// Emergent Game Technologies, Chapel Hill, North Carolina 27517
// http://www.emergent.net

NSFShader Terrain
{
"This shader is a simple example of warping a mesh"
"based on a sin() wave modulated by the AnimationTime"

// Attribute list
Attributes
{
Attrib_Float AnimationTime Artist 0.0
// Attrib_Point3 EyePos Artist 0.0
}
Global_Attributes
{
Attrib_Point3 EyePos Artist 0.0,0.0,0.0
}

// Packing Definition
PackingDef PosNormUV0
{
PD_Stream 0
PDP_Position 0 PDT_Float3
PDP_Normal 3 PDT_Float3
PDP_TexCoord0 7 PDT_Float2
}

// Implementation
Implementation VS11_PS20
{
"This implementation is intended for hardware "
"that supports Vertex Shader v1.1 and Pixel Shader v2.0"

// Requirements for this implementation
Requirements
{
Platform = DX9
VSVersion = v3.0
UserVersion = v0.0
PSVersion = v3.0
UsesNiRenderState = true
}

// Packing Definition it uses
PackingDef PosNormUV0

// First pass
Pass Pass0
{
// Vertex shader program
VSProgram "Terrain.hlsl" VS vs_3_0

// Vertex Shader constant map
VS_Constantmap
{
CM_Defined WorldViewProj WorldViewProj 0
CM_Attribute AnimationTime 4 1 0
CM_Global EyePos 5 3
}

PSProgram "Terrain.hlsl" PS ps_3_0

// Sampler Base Texture
Sampler 0 BaseSampler
{
TSS_Texture = NTM_Base
TSAMP_AddressU = TADDR_Wrap
TSAMP_AddressV = TADDR_Wrap
TSAMP_AddressW = TADDR_Wrap
TSAMP_MagFilter = TEXF_Linear
TSAMP_MinFilter = TEXF_Linear
TSAMP_MipFilter = TEXF_None
}

// Sampler for Dark Texture
Sampler 1 DarkSampler
{
TSS_Texture = NTM_Dark
TSAMP_AddressU = TADDR_Wrap
TSAMP_AddressV = TADDR_Wrap
TSAMP_AddressW = TADDR_Wrap
TSAMP_MagFilter = TEXF_Linear
TSAMP_MinFilter = TEXF_Linear
TSAMP_MipFilter = TEXF_None
}

// Sampler for Detail Texture
Sampler 2 DetailSampler
{
TSS_Texture = NTM_Detail
TSAMP_AddressU = TADDR_Wrap
TSAMP_AddressV = TADDR_Wrap
TSAMP_AddressW = TADDR_Wrap
TSAMP_MagFilter = TEXF_Linear
TSAMP_MinFilter = TEXF_Linear
TSAMP_MipFilter = TEXF_None
}

// Sampler for Gloss Texture
Sampler 3 GlossSampler
{
TSS_Texture = NTM_Gloss
TSAMP_AddressU = TADDR_Wrap
TSAMP_AddressV = TADDR_Wrap
TSAMP_AddressW = TADDR_Wrap
TSAMP_MagFilter = TEXF_Linear
TSAMP_MinFilter = TEXF_Linear
TSAMP_MipFilter = TEXF_None
}

// Sampler for Glow Texture
Sampler 4 GlowSampler
{
TSS_Texture = NTM_Glow
TSAMP_AddressU = TADDR_Wrap
TSAMP_AddressV = TADDR_Wrap
TSAMP_AddressW = TADDR_Wrap
TSAMP_MagFilter = TEXF_Linear
TSAMP_MinFilter = TEXF_Linear
TSAMP_MipFilter = TEXF_None
}

// Sampler for Bump Texture
Sampler 5 BumpSampler
{
TSS_Texture = NTM_Bump
TSAMP_AddressU = TADDR_Wrap
TSAMP_AddressV = TADDR_Wrap
TSAMP_AddressW = TADDR_Wrap
TSAMP_MagFilter = TEXF_Linear
TSAMP_MinFilter = TEXF_Linear
TSAMP_MipFilter = TEXF_None
}

// Sampler for Normal Texture
Sampler 6 NormalSampler
{
TSS_Texture = NTM_Normal
TSAMP_AddressU = TADDR_Wrap
TSAMP_AddressV = TADDR_Wrap
TSAMP_AddressW = TADDR_Wrap
TSAMP_MagFilter = TEXF_Linear
TSAMP_MinFilter = TEXF_Linear
TSAMP_MipFilter = TEXF_None
}

// Sampler for Parallax Texture
Sampler 7 ParallaxSampler
{
TSS_Texture = NTM_Parallax
TSAMP_AddressU = TADDR_Wrap
TSAMP_AddressV = TADDR_Wrap
TSAMP_AddressW = TADDR_Wrap
TSAMP_MagFilter = TEXF_Linear
TSAMP_MinFilter = TEXF_Linear
TSAMP_MipFilter = TEXF_None
}
}
}
}


Terrain HLSL
sampler2D BaseSampler : register(s0);
sampler2D DarkSampler : register(s1);
sampler2D DetailSampler : register(s2);
sampler2D GlossSampler : register(s3);
sampler2D GlowSampler : register(s4);
sampler2D BumpSampler : register(s5);
sampler2D NormalSampler : register(s6);
sampler2D ParallaxSampler : register(s7);

//---------------------------------------------------------------------------
// Constants
//---------------------------------------------------------------------------
float4x4 WorldViewProj;
float AnimationTime;
float3 EyePos;

//---------------------------------------------------------------------------
// Vertex Shaders
//---------------------------------------------------------------------------
struct VS_OUTPUT
{
float4 Pos : POSITION;
float4 Normal : NORMAL;
float4 Color : COLOR;
float2 TexCoord : TEXCOORD;
float4 VecEye : TEXCOORD1;
};

VS_OUTPUT VS(float4 inPos: POSITION, float2 inTex0: TEXCOORD0, float4 inNormal: NORMAL)
{
VS_OUTPUT Out;

Out.Pos = mul(float4(inPos.xyz, 1.0f), WorldViewProj);
Out.Normal = inNormal;

Out.TexCoord = inTex0 * 10;
Out.VecEye = normalize(inPos - float4(EyePos,1));

// Store the position of the untransformed vertex in the color
Out.Color = float4(1, 0, 0, clamp(inPos.z/50, 0, 1));
return Out;
}

//---------------------------------------------------------------------------
// Pixel Shaders
//---------------------------------------------------------------------------
float4 PS(VS_OUTPUT In) : COLOR
{
float4 returnColor = 0; //Return Reset

float4 BlendBaseColor = tex2D(BaseSampler, In.TexCoord).rgba;
float4 BlendDarkColor = tex2D(DarkSampler, In.TexCoord).rgba;
float4 BlendDetailColor = tex2D(DetailSampler, In.TexCoord).rgba;
float4 BlendGlossColor = tex2D(GlossSampler, In.TexCoord).rgba;
float4 BlendGlowColor = tex2D(GlowSampler, In.TexCoord).rgba;
float4 BlendNormalColor = tex2D(NormalSampler, In.TexCoord).rgba;

if(In.Color.a <= 0.05f)// Dirt
{
returnColor = lerp(BlendNormalColor, BlendGlowColor, In.Color.a * 20);
}
else if(In.Color.a >= 0.05 && In.Color.a <= 0.40)// Stone
{
returnColor = lerp(BlendGlowColor, BlendDetailColor, (In.Color.a - 0.05) * 3);
}
else if(In.Color.a >= 0.40 && In.Color.a <= 0.75)// Grass
{
returnColor = lerp(BlendDetailColor, BlendBaseColor, (In.Color.a - 0.40) * 3);
}
else if(In.Color.a >= 0.75 && In.Color.a <= 1.00)// Dirt
{
returnColor = lerp(BlendBaseColor, BlendNormalColor, (In.Color.a - 0.75) * 4);
}

return returnColor;
}


Snipet Of the Shader in cpp
void ObjectShader::CreateTerrain(NiMeshPtr spMesh)
{
// dirt, stone, grass, snow
NiTexturingPropertyPtr spTerrainTexture = NiNew NiTexturingProperty("Data/dirt.bmp");

//--------------------------------------Terrain Shaders In Use-----------------------------------------------
spTerrainTexture->SetNormalMap(NiNew NiTexturingProperty::Map(NiSourceTexture::Create("Data/dirt.bmp"), 0));//0.75 - 1.00
spTerrainTexture->SetBaseMap(NiNew NiTexturingProperty::Map(NiSourceTexture::Create("Data/grass.bmp"), 0));//0.40 - 0.75
spTerrainTexture->SetDetailMap(NiNew NiTexturingProperty::Map(NiSourceTexture::Create("Data/stone.bmp"), 0));//0.05 - 0.40
spTerrainTexture->SetGlowMap(NiNew NiTexturingProperty::Map(NiSourceTexture::Create("Data/dirt.bmp"), 0));//0.0 - 0.05

spMesh->AttachProperty(spTerrainTexture);
// Set the shader on the model
NiMaterialPtr spTerrainMaterial = NiSingleShaderMaterial::Create("Terrain");
spMesh->ApplyAndSetActiveMaterial(spTerrainMaterial);

m_spAnimationTime = NiNew NiFloatExtraData(0.0f);
spMesh->AddExtraData("AnimationTime", m_spAnimationTime);
}

void ObjectShader::UpdateTerrain(NiPoint3 cameraPosition, float DT)
{
m_spAnimationTime->SetValue(m_spAnimationTime->GetValue() + (DT * 30)); //Updates the Shader to allow Wave motion
NiShaderFactory::UpdateGlobalShaderConstant("EyePos", sizeof(cameraPosition), &cameraPosition); //Updates the Camera Position for Lighting.
}


I have a theory that if I calculated the distance of each vertex from the center of the sphere, then I could possibly figure out how high each point is from the center. This allowing me work out what texture to texture it. But I've no idea how to approach this idea in a shader as I've no real grasp on shaders yet. Especially with doing something like this.

Thanks to anyone who can help me out with this. It's driving me insane. I need to complete this section before I can move on to the next part of my project.

Thanks,
Scott.

Share this post


Link to post
Share on other sites
lingfors    149
In the vertex shader, you get the vertex position in object space. Assuming you created your sphere centered at the origin, it's trivial to calculate the "height" of the vertex: just calculate the length of the vertex position vector.

You can then store this height value in a TEXCOORD, say TEXCOORD1. The GPU will then automagically interpolate the height value for you, and you will have access to the specific height of the fragment in the fragment shader.

Share this post


Link to post
Share on other sites
Scottehy    215
Thanks a heap for that. This is how I thought It might be done but I'm unsure on if I need any special function calls in the shader. As I'm not sure how I can call getLength on a vertex insider a shader. Thanks so much for you're help though :)

Share this post


Link to post
Share on other sites
Nanoha    2682
Quote:
Original post by Scottehy
Thanks a heap for that. This is how I thought It might be done but I'm unsure on if I need any special function calls in the shader. As I'm not sure how I can call getLength on a vertex insider a shader. Thanks so much for you're help though :)


length = sqrt(x*x + y*y + z*z);

Theres probably some function (magnitude) that does this for you in HLSL but its been a long time since I've used HLSL so I can't recall what it is.

Share this post


Link to post
Share on other sites
Scottehy    215
I know that the function is distance(,) and it takes in 2 vectors. The maths isn't my issue. But it just crashes and dies when I change anything. I tried to change my structure to:

struct VS_OUTPUT
{
float4 Pos : POSITION;
float4 Normal : NORMAL;
float4 Color : COLOR;
float2 TexCoord : TEXCOORD;
float4 VecEye : TEXCOORD1;
float dist : TEXCOORD2;
};

So i could store it in a TEXCOORD like lingfors said but no luck. As soon as I'm editing anything in there it just crashes.

Share this post


Link to post
Share on other sites
Scottehy    215
Yup, i realize that and found that function. But wouldn't I have to store my value inside the structure? Yet as soon as I'm adding something else to it. It basically just screws up. Or am I able to change it and store it else where?

Share this post


Link to post
Share on other sites
Scottehy    215
I store my actual texture coord in there though. So changing that wont help me. Don't I need to add another one like float dist : TEXCOORD0 - Or something like that to store the length of the vector?

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