Using a shader on a Sphere

Started by
8 comments, last by Scottehy 13 years, 11 months ago
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.
Advertisement
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.netNSFShader 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.
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.
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 :)
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.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

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.
There is a method length to calculate a vector's length.

http://msdn.microsoft.com/en-us/library/bb509617(VS.85).aspx
Quote:Original post by Scottehy
    float2 TexCoord : TEXCOORD;



should probably be

    float2 TexCoord : TEXCOORD0;

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?
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?

This topic is closed to new replies.

Advertisement