C Board  

Go Back   C Board > General Programming Boards > Game Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 02-07-2005, 09:06 PM   #1
mustang benny
 
bennyandthejets's Avatar
 
Join Date: Jul 2002
Posts: 1,401
Lighting a Direct3D 9 mesh sphere

I'm lighting a sphere as described in the title with diffuse and specular lighting. I have used, individually and in conjunction, directional and point lighting, but each time I try, a strange effect occurs. The way the sphere vertices are lit depends on the angle I am looking at it from, and if you could see this you would appreciate how ridiculous it looks. Has anyone succeeded in lighting a mesh sphere before?

Code:
mSphere=Mesh.Sphere(device,1.0f,32,16);
mSphere.ComputeNormals();

SphereCol=new Material();
SphereCol.Ambient=Color.DarkRed;
SphereCol.Diffuse=Color.Red;
SphereCol.Specular=Color.White;
.
.
.
device.Lights[0].Type=LightType.Directional;
device.Lights[0].Specular=Color.White;
device.Lights[0].Diffuse=Color.White;
device.Lights[0].Position=new Vector3(0.0f,0.0f, -4.0f);
device.Lights[0].Direction=new Vector3(0.0f,0.0f, 1.0f);
device.Lights[0].Enabled=true;

device.Material=SphereCol;
mSphere.DrawSubset(0);
As you can see from the attachments, the 90 degree shot has the shadow on the wrong side.
Attached Images
   
__________________
benforbes@optusnet.com.au
Microsoft Visual Studio .NET 2003 Enterprise Architect
Windows XP Pro

Code Tags
Programming FAQ
Tutorials
bennyandthejets is offline   Reply With Quote
Old 02-07-2005, 09:15 PM   #2
Super Moderator
 
Bubba's Avatar
 
Join Date: Aug 2001
Posts: 7,472
Yes I have. Are you normalizing the normals?
Bubba is offline   Reply With Quote
Old 02-07-2005, 09:18 PM   #3
Super Moderator
 
Bubba's Avatar
 
Join Date: Aug 2001
Posts: 7,472
And another shot.
Bubba is offline   Reply With Quote
Old 02-07-2005, 09:21 PM   #4
Super Moderator
 
Bubba's Avatar
 
Join Date: Aug 2001
Posts: 7,472
And this one shows it well.
Bubba is offline   Reply With Quote
Old 02-07-2005, 09:28 PM   #5
Super Moderator
 
Bubba's Avatar
 
Join Date: Aug 2001
Posts: 7,472
Here is the code I'm using. CPlanet uses a CSphere object. I separated them for rendering reasons and I'll spare you the details.

CSphere.cpp
Code:
#define CSPHERE

#include "d3dx9.h"
#include "CQuickCom.h"
#include "CFileLog.h"
#include "d3dx9mesh.h"


//Converts degrees to radians
#define DEGTORAD(x)  (x*D3DX_PI/180.0f)

struct CSphereVertex
{
  D3DXVECTOR3 pos;
  D3DXVECTOR3 normal;
  float   u,v;
  static const DWORD FVF;  

  CSphereVertex(D3DXVECTOR3 tpos,D3DXVECTOR3 tnormal,float tu,float tv):
                pos(tpos),normal(tnormal),u(tu),v(tv){}

};

class CSphere
{
  
  protected:
    CFileLog                  SphereLog;
   
    IDirect3DDevice9          *Device;
    
    ID3DXMesh                 *SphereMesh;

    unsigned int              NumTris;
    unsigned int              NumFaces;
    unsigned int              NumVertices;
    unsigned int              NumVertsPerRow;
    unsigned int              NumVertsPerCol;
    
    float                     Radius;

  public:
    CSphere(void) {Device=NULL,NumTris=0,NumFaces=0,
      NumVertices=0,NumVertsPerRow=0,NumVertsPerCol=0,Radius=0.0f;};
    
    ~CSphere(void)
    {
       if (SphereMesh) SphereMesh->Release();

    }

    //Old deprecated function
    //void CreateSphere(IDirect3DDevice9 *_device,
    //                  float _radius,
    //                  unsigned int _faces,
    //                  float _texmag,
    //                  D3DXVECTOR3 &pos);
    
    void CreateMeshSphere(IDirect3DDevice9 *_device,
                          float _radius,
                          unsigned int _faces);
    
    ID3DXMesh *GetMesh(void) {return SphereMesh;};

    unsigned int GetNumTris(void) {return NumTris;};
    unsigned int GetNumVertices(void) {return NumVertices;};
   
};

#endif
CSphere.h
Code:
#include "CSphere.h"



const DWORD CSphereVertex::FVF=D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;


//Create mesh
void CSphere::CreateMeshSphere(IDirect3DDevice9 *_device,float _radius,unsigned int _faces)
{
  //Class vars
  Device=_device;
  Radius=_radius;
  NumFaces=_faces;

  //Create temp mesh
  LPD3DXMESH temp;
  if (FAILED(D3DXCreateSphere(Device,Radius,NumFaces,NumFaces,&temp,NULL)))
  {
    ::MessageBox(0,"Failed to create sphere",0,0);
  }

  //Clone mesh with new FVF
  if (FAILED(temp->CloneMeshFVF(D3DXMESH_SYSTEMMEM,CSphereVertex::FVF,Device,&SphereMesh)))
  {
    ::MessageBox(0,"Failed to clone mesh",0,0);
  }

  //Lock vertex buffer
  CSphereVertex *Vertices;
  SphereMesh->LockVertexBuffer(0,(void **)&Vertices);

  //Setup mapping vars
  float angleinc_alpha=360.0f/_faces;
  float angleinc_beta=180.0f/_faces;
  float alpha=0.0f;
  float beta=-180.0f;
  float u=0.0f,v=0.0f;

  unsigned int vertex_count;
  
  //Set 2*PI - no mul in for loop
  float PI2=D3DX_PI*2.0f;

  //Map U,V coords
  //Produces very good results for 2:1 texture ratios
  for (unsigned int i=0;i<SphereMesh->GetNumVertices();i++)
  {
    u=(DEGTORAD(alpha)+D3DX_PI)/(PI2);
    v=DEGTORAD(beta)/D3DX_PI;

    Vertices[i].u=u;
    Vertices[i].v=v;

    alpha+=angleinc_alpha;
    vertex_count++;
    if (vertex_count>=(_faces))
    {
      alpha=0.0f;
      beta+=angleinc_beta;
      
      //Disabled test area
      //Vertices[i+1].v=0.0f;
      //Vertices[i+1].u=0.0f;
      
      vertex_count=0;
    }
  }
  //Unlock vertex buffer
  SphereMesh->UnlockVertexBuffer();

  //Discard temp mesh
  temp->Release();
  
}
CPlanet.cpp
Code:
#include "CPlanet.h"


//Constructor - self explanatory
CPlanet::CPlanet(void)
{
  Device=NULL;
  Pos=D3DXVECTOR3(0.0f,0.0f,0.0f);
  Rotation=D3DXVECTOR3(0.0f,0.0f,0.0f);
  RotationVelocity=D3DXVECTOR3(0.0f,0.0f,0.0f);
  Texture=NULL;
  BumpMap=NULL;
  Radius=0.0f;
}

//Destructor - release COM objects - decrement their reference counts
CPlanet::~CPlanet(void)
{
  if (Texture)  Texture->Release();
  if (BumpMap)  BumpMap->Release();
}

//Set planet texture
void CPlanet::SetTexture(std::string PlanetFile)
{
  if (FAILED(D3DXCreateTextureFromFile(Device,PlanetFile.c_str(),&Texture)))
  {
    ::MessageBox(0,"Failed to load planet texture",0,0);
    return;
  }
}

//Set bump map -> fake bump mapping not per-pixel
void CPlanet::SetBumpMap(std::string PlanetFile)
{
  if (FAILED(D3DXCreateTextureFromFile(Device,PlanetFile.c_str(),&BumpMap)))
  {
    ::MessageBox(0,"Failed to load planet texture",0,0);
    return;
  }
}

//Create the model -> call CSphere::CreateMeshSphere()
void CPlanet::CreateModel(IDirect3DDevice9 *_Device,float _Radius,int _Faces,D3DXVECTOR3 &pos)
{
  Device=_Device;
  Radius=_Radius;
  Faces=_Faces;
  SetPosition(&pos);
  

  Planet.CreateMeshSphere(Device,Radius,_Faces);
}


//Disabled - unsure of atmospheres at this time
void CPlanet::SetAtmosphere(D3DMATERIAL9 *_material,float _radius)
{
  //AMaterial=*_material;
  //ARadius=_radius;
  
  //AtmosphereFlag=true;

  //Atmosphere.CreateMeshSphere(Device,ARadius,Faces);
}

//Render object
void CPlanet::Render(float timeDelta,D3DXVECTOR3 cameraPos)
{
  
  //Set U,V wrapping to true - must do this to get rid of render artifacts
  Device->SetRenderState(D3DRS_WRAP0,true);
  Device->SetRenderState(D3DRS_WRAP1,true);
  
  
  
  
  //Change model rotation based on velocity presets and time from last frame
  Rotation.x+=(RotationVelocity.x*timeDelta);
  Rotation.y+=(RotationVelocity.y*timeDelta);
  Rotation.z+=(RotationVelocity.z*timeDelta);
  
  //Setup world rotation matrix
  D3DXMATRIX rot;
  D3DXMatrixRotationYawPitchRoll(&rot,Rotation.x,Rotation.y,Rotation.z);

  //Setup translation -> no mul here
  rot._41=Pos.x;
  rot._42=Pos.y;
  rot._43=Pos.z;

  //Set transform
  Device->SetTransform(D3DTS_WORLD,&rot);
  
  //Set material
  D3DXVECTOR3 distvect;
  D3DXVec3Subtract(&distvect,&Pos,&cameraPos);

  float length=D3DXVec3Length(&distvect);

  
  float actualdist=10000.0f-(length-8000.0f);
  if (actualdist>0.0f)
  {

    AlphaValue=actualdist/10000.0f;
  } else AlphaValue=0.0f;

  
  if (AlphaValue>=1.0f) AlphaValue=1.0f;
  if (AlphaValue<=0.0f) AlphaValue=0.0f;
  
  Material.Diffuse.a=AlphaValue;
  Device->SetMaterial(&Material);
  
  //Set texture
  //Device->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_DIFFUSE);
  //Device->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);
  Device->SetTexture(0,Texture);

  //Check pointer -> prob disabled on release build
  if (!Planet.GetMesh())
  {
    ::MessageBox(0,0,"Null pointer in mesh",0);
  }

  //Render object
  if (FAILED(Planet.GetMesh()->DrawSubset(0)))
  {
    ::MessageBox(0,0,"Cannot draw mesh",0);
  }
  
  
  //Restore render states
  Device->SetRenderState(D3DRS_WRAP0,false);
  Device->SetRenderState(D3DRS_WRAP1,false);
  //Device->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_DISABLE);
  //Device->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
  
}
CPlanet.h
Code:

#ifndef CPLANET
#define CPLANET

#include "CPrimitives.h"
#include "d3dx9.h"
#include <String>
#include "CQuickCom.h"
#include "CSphere.h"


class CPlanet
{
  //Device interface pointer
  IDirect3DDevice9    *Device;
  
  //Sphere object
  CSphere             Planet;
  
  //Model properties
  D3DXVECTOR3         Pos;
  D3DXVECTOR3         Rotation;
  D3DXVECTOR3         RotationVelocity;
  
  
  //Textures
  IDirect3DTexture9   *Texture;
  IDirect3DTexture9   *BumpMap;
  
  
  //Materials
  D3DMATERIAL9        Material;
  D3DMATERIAL9        AMaterial;

    
  float               Radius;
  float               ARadius;
  
  int                 Faces;
  bool                AtmosphereFlag;

  public:
    float               AlphaValue;
    
    CPlanet(void);
    ~CPlanet(void);

    void SetTexture(std::string PlanetFile);
    void SetBumpMap(std::string PlanetFile);

    
    void SetPosition(D3DXVECTOR3 *_newpos) {Pos=*_newpos;};
    void GetPosition(D3DXVECTOR3 *_curpos) {*_curpos=Pos;};
    
    void SetRotationParams(D3DXVECTOR3 *_rotation,D3DXVECTOR3 *_rotation_velocity)
    {
      Rotation=*_rotation;
      RotationVelocity=*_rotation_velocity;
    }
    
    void GetRotationParams(D3DXVECTOR3 *_rotation,D3DXVECTOR3 *_rotation_velocity)
    {
      *_rotation=Rotation;
      *_rotation_velocity=RotationVelocity;
    }
    
    void CreateModel(IDirect3DDevice9 *_Device,float _Radius,int _Faces,D3DXVECTOR3 &pos);
    
    void TestCreateModel(IDirect3DDevice9 *_device,float _radius,unsigned int _faces)
    {
      Device=_device;
      Radius=_radius;
      Faces=_faces;

      
      Planet.CreateMeshSphere(_device,_radius,_faces);
      D3DXComputeNormals(Planet.GetMesh(),NULL);

    }

    void SetMaterial(D3DMATERIAL9 *_material) {Material=*_material;};
    void GetMaterial(D3DMATERIAL9 *_material) {*_material=Material;};
    float GetRadius(void) {return Radius;};
    float GetAtmosphereRadius(void) {return ARadius;};
    void SetAtmosphere(D3DMATERIAL9 *_material,float _radius);
    void Render(float timeDelta,D3DXVECTOR3 cameraPos);
    void TestRender(float timeDelta);
};

#endif
Hope that helps.

Not the fastest way to do things and I'm reworking the code to use a much better rendering system, but you get the idea.
This is the most important section:

Code:
void TestCreateModel(IDirect3DDevice9 *_device,float _radius,unsigned int _faces)
    {
      Device=_device;
      Radius=_radius;
      Faces=_faces;

      
      Planet.CreateMeshSphere(_device,_radius,_faces);
      D3DXComputeNormals(Planet.GetMesh(),NULL);

    }
You must tell Direct3D to compute the normals for your mesh. This is a simple (upper left vertex is vnum -> clockwise from there)

Code:
D3DXVECTOR v1=Vertex[vnum+1]-Vertex[vnum];
D3DXVECTOR v2=Vertex[vnum+2]-Vertex[vnum+1];
D3DXVECTOR Cross;
D3DXVec3Cross(&Cross,&v1,&v2);
D3DXVec3Normalize(&Cross,&Cross);

//No normal averaging
Vertex[vnum].normal=Cross;
Vertex[vnum+1].normal=Cross;
Vertex[vnum+2].normal=Cross;
But D3DX does this for you.

There is an easier way to compute the normals on a sphere. Since all points are equidistant from the center the normal will always be the normalized distance between the vertex on the sphere and the center of the sphere. Since your sphere's are centered around 0,0,0 in model space you can simply normalize the Vertex to get the normal. You are essentially then clamping the vertex to the surface of a unit sphere.

Code:
D3DXVECTOR3 vNormal;
D3DXVec3Normalize(&vNormal,Vertex[vnum]);
Vertex[vnum].normal=vNormal;
Note that this is per vertex normals, not per triangle face. So this sets your system up quite nicely to do some per-pixel dot3 lighting in a shader.

Code:
mSphere=Mesh.Sphere(device,1.0f,32,16);
mSphere.ComputeNormals();
I wouldn't do it that way. There is a possibility that even though your code works your sphere object might be going out of scope upon returning from Mesh::Sphere(). Also you might be creating a COM resource leak.

Last edited by Bubba; 02-07-2005 at 09:50 PM.
Bubba is offline   Reply With Quote
Old 02-09-2005, 07:36 PM   #6
mustang benny
 
bennyandthejets's Avatar
 
Join Date: Jul 2002
Posts: 1,401
Thanks heaps for the code, I haven't found anything nearly as good on the net. Unfortunately it's a bit above my level so it will take some time to work out.

As for the scope and resource leak issues, remember I'm using C#, everything should technically be managed for me. I think I will however go back to using C++. The only reason I was using C# was to learn a .NET language, but I do sorely miss the satisfaction of good C++ code.

Once I've finished I'll let you know.
__________________
benforbes@optusnet.com.au
Microsoft Visual Studio .NET 2003 Enterprise Architect
Windows XP Pro

Code Tags
Programming FAQ
Tutorials
bennyandthejets is offline   Reply With Quote
Old 02-10-2005, 04:22 AM   #7
Confused
 
Magos's Avatar
 
Join Date: Sep 2001
Location: Sweden
Posts: 3,122
From the screenies it looks like the camera is rotating, but the light source is still in the same spot which should give the effect shown in those screenies. You sure this is not the case?
__________________
MagosX.com

Give a man a fish and you feed him for a day.
Teach a man to fish and you feed him for a lifetime.
Magos is offline   Reply With Quote
Old 02-10-2005, 05:44 AM   #8
mustang benny
 
bennyandthejets's Avatar
 
Join Date: Jul 2002
Posts: 1,401
The light is fixed and the camera is moving around in a circle. Maybe the pictures don't illustrate the problem, but believe me if you ran the program you would see what I mean. I can post the binary if you trust me not to infect you.
__________________
benforbes@optusnet.com.au
Microsoft Visual Studio .NET 2003 Enterprise Architect
Windows XP Pro

Code Tags
Programming FAQ
Tutorials
bennyandthejets is offline   Reply With Quote
Old 02-10-2005, 03:08 PM   #9
Confused
 
Magos's Avatar
 
Join Date: Sep 2001
Location: Sweden
Posts: 3,122
How 'bout posting both the binary and the source and someone could give a more accurate solution.
__________________
MagosX.com

Give a man a fish and you feed him for a day.
Teach a man to fish and you feed him for a lifetime.
Magos is offline   Reply With Quote
Old 02-11-2005, 04:43 AM   #10
Super Moderator
 
Bubba's Avatar
 
Join Date: Aug 2001
Posts: 7,472
First people want the source, not the binary. Now they want the binary not just the source. Sheesh.

Sorry cannot post the binary. It's way over the board limit.
Bubba is offline   Reply With Quote
Old 02-13-2005, 01:01 AM   #11
Super Moderator
 
Bubba's Avatar
 
Join Date: Aug 2001
Posts: 7,472
I see that binary message was for him not me. Sorry.

Anyways if your camera is moving around the object and the object is part of your world then it is really the object that is moving, not the camera. Your calculations must be in world space not view space. It seems to me that they are in view space.

The camera is moving in space and rotating but to show this you really must rotate the world and move the world, not the camera. You always translate the camera back to 0,0,0 or the origin of the world since the camera is assumed to always be the origin of your world. Everything else is relative to the camera.
Bubba is offline   Reply With Quote
Old 02-13-2005, 05:21 PM   #12
mustang benny
 
bennyandthejets's Avatar
 
Join Date: Jul 2002
Posts: 1,401
I think my code does what your saying but I'm not sure. Here it is:
Code:
            CamLookAt.X=(float)Math.Sin((double)angle)+CamPos.X;
            CamLookAt.Z=(float)Math.Cos((double)angle)+CamPos.Z;

            device.Transform.World=Matrix.Identity;
            device.Transform.View=Matrix.LookAtLH(CamPos, CamLookAt, new Vector3(0.0f,1.0f,0.0f) );
            
            device.Transform.Projection=Matrix.PerspectiveFovLH((float)Math.PI/4.0f,1.0f,1.0f,100f);
EDIT: I keep reading your post and getting more confused. Can you give a quick example of the correct method?
__________________
benforbes@optusnet.com.au
Microsoft Visual Studio .NET 2003 Enterprise Architect
Windows XP Pro

Code Tags
Programming FAQ
Tutorials

Last edited by bennyandthejets; 02-13-2005 at 05:30 PM.
bennyandthejets is offline   Reply With Quote
Old 02-14-2005, 01:19 AM   #13
Super Moderator
 
Bubba's Avatar
 
Join Date: Aug 2001
Posts: 7,472
Set your camera to always look at the same spot.

This will compute the correct view matrix for a camera with 3 basis vectors..right, look, and up.

Code:
void Camera::getViewMatrix(D3DXMATRIX* V)
{
  // Keep camera's axes orthogonal to eachother
  D3DXVec3Normalize(&_look, &_look);
  D3DXVec3Cross(&_up, &_look, &_right);
  D3DXVec3Normalize(&_up, &_up);

  D3DXVec3Cross(&_right, &_up, &_look);
  D3DXVec3Normalize(&_right, &_right);

  // Build the view matrix:
  float x = -D3DXVec3Dot(&_right, &_pos);
  float y = -D3DXVec3Dot(&_up, &_pos);
  float z = -D3DXVec3Dot(&_look, &_pos);

  (*V)(0,0) = _right.x; (*V)(0, 1) = _up.x; (*V)(0, 2) = _look.x; (*V)(0, 3) = 0.0f;
  (*V)(1,0) = _right.y; (*V)(1, 1) = _up.y; (*V)(1, 2) = _look.y; (*V)(1, 3) = 0.0f;
  (*V)(2,0) = _right.z; (*V)(2, 1) = _up.z; (*V)(2, 2) = _look.z; (*V)(2, 3) = 0.0f;
  (*V)(3,0) = x;        (*V)(3, 1) = y;     (*V)(3, 2) = z;       (*V)(3, 3) = 1.0f;
}
This is straight from Intro to 3D Game Programming by Frank Luna. The camera class in that book works extremely well.

If you are just wanting a stationary camera then set it to look at the same spot at all times. I would have to see what is taking place in order to help you more.
Bubba is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Direct3D Alpha Blend with Lighting ? rocketman03 Game Programming 10 07-07-2009 04:04 PM
Lighting in Managed Direct3d Rune Hunter Game Programming 0 04-30-2006 07:40 AM
Mesh Rendering: Z-Buffer and Lighting Epo Game Programming 6 04-20-2005 07:11 AM
Sphere code not working Bubba Game Programming 2 10-03-2004 07:29 AM
need help with opengl lighting!! genghis37 Game Programming 1 06-22-2002 12:28 AM


All times are GMT -6. The time now is 01:40 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0 RC2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22