⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shader_lighting.cpp

📁 游戏编程精华02-含有几十个游戏编程例子
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************

  Copyright (C) 1999, 2000 NVIDIA Corporation
  This file is provided without support, instruction, or implied warranty of any
  kind.  NVIDIA makes no guarantee of its fitness for a particular purpose and is
  not liable under any circumstances for any damages or loss whatsoever arising
  from the use or inability to use this file or items derived from it.
  
    Comments:
    
      
        
******************************************************************************/

#include "eb_effect.h"
#include "nvinc.h"
#include "nvdevice.h"
#include "nvmesh.h"
#include "shader_Lighting.h"
#include "lighting.h"

using namespace nv_objects;
using namespace std;

DECLARE_EFFECT_MAIN()

extern "C"
{

__declspec(dllexport) unsigned int GetNumEffects() { return 4; }

__declspec(dllexport) EBEffect* CreateEffect(unsigned int iEffectNum)
{
	switch (iEffectNum)
	{
		case 0:
			return new CShaderDirectionalLight();
		case 1:
			return new CShaderPointLight();
		case 2:
			return new CShaderManyPointLight();
		case 3:
			return new CShaderTwoSideLight();
		default:
			return NULL;
	}

	return NULL;
}


}

// Old-style D3D vertices
class Vertex
{
public:
	Vertex(const D3DXVECTOR3& Pos, const D3DXVECTOR3& Norm, const D3DXVECTOR2& Tex)
		: Position(Pos), Normal(Norm), Texture(Tex)
	{}

	Vertex()
	{}

	D3DXVECTOR3 Position;
	D3DXVECTOR3 Normal;
	D3DXVECTOR2 Texture;
};

class TLVertex
{
public:
	D3DXVECTOR4 Position;
	DWORD Diffuse;
	DWORD Specular;
	D3DXVECTOR2 Texture;
};

#define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
#define D3DFVF_TLVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1)

CShaderLighting::CShaderLighting(LightType Type)
	: m_LightType(Type),
	m_pSphereBuffer(NULL),
	m_fAngle(0.0f),
	m_pShapeMesh(NULL),
	m_pLightMesh(NULL),
	m_pNVDevice(NULL),
	m_dwCurrentLightDraw(-1),
	m_bWireframe(false),
	m_bPause(false),
	m_pUI(NULL)
{
}

CShaderLighting::~CShaderLighting()
{
	
	Free();	
}

void CShaderLighting::UpdateProperties()
{
	EBEffect::UpdateProperties();
	AddProperty(new EBProperty("Wireframe", OBJECT_MEMBER(m_bWireframe), EBTYPE_BOOL_PROP));
	AddProperty(new EBProperty("Pause", OBJECT_MEMBER(m_bPause), EBTYPE_BOOL_PROP));
}

HRESULT CShaderLighting::GenerateSphere(D3DXVECTOR3& vCenter, FLOAT fRadius, WORD wNumRings, WORD wNumSections, FLOAT sx, FLOAT sy, FLOAT sz)
{
    FLOAT x, y, z, v, rsintheta; // Temporary variables
    WORD  i, j, n, m;            // counters
    D3DXVECTOR3 vPoint;
	HRESULT hr;

	SAFE_RELEASE(m_pSphereBuffer);

    //Generate space for the required triangles and vertices.
    WORD       wNumTriangles = (wNumRings + 1) * wNumSections * 2;
    DWORD      dwNumIndices   = wNumTriangles*3;
    DWORD      dwNumVertices  = (wNumRings + 1) * wNumSections + 2;

    Vertex* pvVertices     = new Vertex[dwNumVertices];
    WORD*      pwIndices      = new WORD[3*wNumTriangles];

    // Generate vertices at the top and bottom points.
    D3DXVECTOR3 vTopPoint  = vCenter + D3DXVECTOR3( 0.0f, +sy*fRadius, 0.0f);
    D3DXVECTOR3 vBotPoint  = vCenter + D3DXVECTOR3( 0.0f, -sy*fRadius, 0.0f);
    D3DXVECTOR3 vNormal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );

    pvVertices[0]               = Vertex( D3DXVECTOR3(vTopPoint.x, vTopPoint.y, vTopPoint.z),  D3DXVECTOR3(vNormal.x, vNormal.y, vNormal.z), D3DXVECTOR2(0.0f, 0.0f) );
    pvVertices[dwNumVertices-1] = Vertex( D3DXVECTOR3(vBotPoint.x, vTopPoint.y, vTopPoint.z), D3DXVECTOR3(-vNormal.x, -vNormal.y, -vNormal.z), D3DXVECTOR2(0.0f, 0.0f) );

    // Generate vertex points for rings
    FLOAT dtheta = (float)(D3DX_PI / (wNumRings + 2));     //Angle between each ring
    FLOAT dphi   = (float)(2*D3DX_PI / wNumSections); //Angle between each section
    FLOAT theta  = dtheta;
    n = 1; //vertex being generated, begins at 1 to skip top point

    for( i = 0; i < (wNumRings+1); i++ )
    {
        y = fRadius * (float)cos(theta); // y is the same for each ring
        v = theta / D3DX_PI;     // v is the same for each ring
        rsintheta = fRadius * (float)sin(theta);
        FLOAT phi = 0.0f;

        for( j = 0; j < wNumSections; j++ )
        {
            x = rsintheta * (float)sin(phi);
            z = rsintheta * (float)cos(phi);
        
            FLOAT u = (FLOAT)(1.0 - phi / (2*D3DX_PI) );
            
            vPoint        = vCenter + D3DXVECTOR3( sx*x, sy*y, sz*z );
            vNormal       = D3DXVECTOR3( x/fRadius, y/fRadius, z/fRadius );
			D3DXVec3Normalize(&vNormal, &vNormal);
			pvVertices[n] = Vertex( D3DXVECTOR3(vPoint.x, vPoint.y, vPoint.z), D3DXVECTOR3(vNormal.x, vNormal.y, vNormal.z), D3DXVECTOR2(u, v) );

            phi += dphi;
            ++n;
        }
        theta += dtheta;
    }

    // Generate triangles for top and bottom caps.
    for( i = 0; i < wNumSections; i++ )
    {
        pwIndices[3*i+0] = 0;
        pwIndices[3*i+1] = i + 1;
        pwIndices[3*i+2] = 1 + ((i + 1) % wNumSections);

        pwIndices[3*(wNumTriangles - wNumSections + i)+0] = (WORD)( dwNumVertices - 1 );
        pwIndices[3*(wNumTriangles - wNumSections + i)+1] = (WORD)( dwNumVertices - 2 - i );
        pwIndices[3*(wNumTriangles - wNumSections + i)+2] = (WORD)( dwNumVertices - 2 - 
                ((1 + i) % wNumSections) );
    }

    // Generate triangles for the rings
    m = 1;            // first vertex in current ring,begins at 1 to skip top point
    n = wNumSections; // triangle being generated, skip the top cap 
        
    for( i = 0; i < wNumRings; i++ )
    {
        for( j = 0; j < wNumSections; j++ )
        {
            pwIndices[3*n+0] = m + j;
            pwIndices[3*n+1] = m + wNumSections + j;
            pwIndices[3*n+2] = m + wNumSections + ((j + 1) % wNumSections);
            
            pwIndices[3*(n+1)+0] = pwIndices[3*n+0];
            pwIndices[3*(n+1)+1] = pwIndices[3*n+2];
            pwIndices[3*(n+1)+2] = m + ((j + 1) % wNumSections);
            
            n += 2;
        }
        m += wNumSections;
    }

	// Put the sphere in a VB.
	hr = m_pD3DDev->CreateVertexBuffer(dwNumIndices * (sizeof(D3DXVECTOR3) * 3), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &m_pSphereBuffer);
    if (FAILED(hr))
	{
		delete [] pvVertices;
		delete [] pwIndices;

        return hr;
	}

	SphereVertex* pSphereVertexBase;
	SphereVertex* pSphereVertex;
	DWORD dwVertices;

	hr = m_pSphereBuffer->Lock(0, dwNumIndices * (sizeof(D3DXVECTOR3) * 3), (BYTE **)&pSphereVertexBase, 0);
	if (FAILED(hr))
        return hr;

	pSphereVertex = pSphereVertexBase;
	for (dwVertices = 0; dwVertices < dwNumIndices; dwVertices++)
	{
		pSphereVertex->Position = pvVertices[pwIndices[dwVertices]].Position;
		pSphereVertex->Normal = pvVertices[pwIndices[dwVertices]].Normal;
		pSphereVertex++;
	}

	pSphereVertex = pSphereVertexBase;
	for (dwVertices = 0; dwVertices < dwNumIndices; dwVertices += 3)
	{
		D3DXVECTOR3 vecV0,vecV1;
		D3DXVECTOR3 vecFaceNormal;
		vecV0 = pvVertices[pwIndices[dwVertices]].Position - pvVertices[pwIndices[dwVertices + 1]].Position;
		vecV1 = pvVertices[pwIndices[dwVertices]].Position - pvVertices[pwIndices[dwVertices + 2]].Position;

		D3DXVec3Cross(&vecFaceNormal, &vecV0, &vecV1);
		D3DXVec3Normalize(&vecFaceNormal, &vecFaceNormal);
		
		// Copy the face normal into all 3 buffers
		pSphereVertex->FaceNormal = vecFaceNormal;
		pSphereVertex++;

		pSphereVertex->FaceNormal = vecFaceNormal;
		pSphereVertex++;
		
		pSphereVertex->FaceNormal = vecFaceNormal;
		pSphereVertex++;
	}

	m_dwSphereFaces = (dwNumIndices / 3);

	m_pSphereBuffer->Unlock();

	delete [] pvVertices;
	delete [] pwIndices;
    return S_OK;
}


HRESULT CShaderLighting::Initialize(IDirect3DDevice8* pDev)
{
	HRESULT hr;
	vector<DWORD> Declaration;

	m_pD3DDev = pDev;
	pDev->AddRef();

	m_pNVDevice = new NVLightingDevice(pDev, this);

	//initialize mouse UI
	RECT rect;
	rect.left = rect.top = 0;
	D3DVIEWPORT8 viewport;
	m_pD3DDev->GetViewport(&viewport);
	rect.bottom = viewport.Height;
	rect.right  = viewport.Width;
	m_pUI = new MouseUI((const RECT)rect);

	DWORD dwVBFlags = D3DUSAGE_WRITEONLY;

	switch(m_LightType)
	{
		case LIGHTTYPE_MANYPOINT:
			m_dwNumLights = 17;
			break;
		case LIGHTTYPE_POINT:
			m_dwNumLights = 3;
			break;
		case LIGHTTYPE_DIRECTIONAL:
			m_dwNumLights = 2;
			break;
		case LIGHTTYPE_TWOSIDE:
			m_pUI->OnLButtonDown( 40, 10 );
			m_pUI->OnMouseMove( 30, 0 );
			m_pUI->OnLButtonUp( 3, 30 );
			m_dwNumLights = 1;
			break;
	}

	m_LightColorDiffuse.resize(m_dwNumLights);
	m_LightColorSpecular.resize(m_dwNumLights);
	m_LightColorAmbient.resize(m_dwNumLights);
	
	// Setup the light colors
	srand(1);
	for (DWORD dwCurrentLight = 0; dwCurrentLight < m_dwNumLights; dwCurrentLight++)
	{
		switch (dwCurrentLight)
		{
			case 0:
				m_LightColorDiffuse[dwCurrentLight] = D3DXCOLOR(0.8f, 0.0f, 0.0f, 1.0f);
				m_LightColorSpecular[dwCurrentLight] = D3DXCOLOR(0.2f, 0.2f, 0.2f, 1.0f);
				m_LightColorAmbient[dwCurrentLight] = D3DXCOLOR(0.1f, 0.1f, 0.1f, 1.0f);
				break;
			case 1:
				m_LightColorDiffuse[dwCurrentLight] = D3DXCOLOR(0.0f, 0.8f, 0.0f, 1.0f);
				m_LightColorSpecular[dwCurrentLight] = D3DXCOLOR(0.2f, 0.2f, 0.2f, 1.0f);
				m_LightColorAmbient[dwCurrentLight] = D3DXCOLOR(0.1f, 0.1f, 0.1f, 1.0f);
				break;
			case 2:
				m_LightColorDiffuse[dwCurrentLight] = D3DXCOLOR(0.0f, 0.0f, 0.8f, 1.0f);
				m_LightColorSpecular[dwCurrentLight] = D3DXCOLOR(0.2f, 0.2f, 0.2f, 1.0f);
				m_LightColorAmbient[dwCurrentLight] = D3DXCOLOR(0.1f, 0.1f, 0.1f, 1.0f);
				break;
			default:
				float fLuminance = (float)(dwCurrentLight / (float)(m_dwNumLights + 1));
				D3DXCOLOR Luminance(fLuminance, fLuminance, fLuminance, 1.0f);
				D3DXCOLOR Color((float)rand() / (float)RAND_MAX, (float)rand() / (float)RAND_MAX, (float)rand() / (float)RAND_MAX, 1.0f);
				D3DXColorModulate(&m_LightColorDiffuse[dwCurrentLight], &Luminance, &Color);
				break;
		}
	}

	// We want a white light in the twosided case
	if (m_LightType == LIGHTTYPE_TWOSIDE)
	{
		m_LightColorDiffuse[0] = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
	}

	// Create a shape to light
	if (m_LightType == LIGHTTYPE_TWOSIDE)
	{
		hr = GenerateSphere(D3DXVECTOR3(0.0f, 0.0f, 0.0f),	// Center
					0.8f,				// Radius
					10,					// Rings
					20,					// Sections
					1.0f, 1.0f, 1.0f	// Scaling
					);	
		if (FAILED(hr))
		{
			m_strLastError = "Failed to generate sphere";
			return hr;
		}
	}
	else
	{
		m_pShapeMesh = new NVMesh();
		hr = m_pShapeMesh->Create(m_pNVDevice, GetFilePath("teapot.x"));
		if (FAILED(hr))
		{
			m_strLastError = "Failed to create teapot!";
			return hr;
		}

		m_pShapeMesh->SetFVF(m_pNVDevice, D3DFVF_NORMAL | D3DFVF_XYZ | D3DFVF_TEX1);
	}
	
	m_pLightMesh = new NVMesh();
	// Create a shape to display the position of the light
	switch(m_LightType)
	{
		case LIGHTTYPE_MANYPOINT:
		case LIGHTTYPE_POINT:
			hr = m_pLightMesh->Create(m_pNVDevice, GetFilePath("sphere.x"));
			if (FAILED(hr))
			{
				m_strLastError = "Could not load sphere.x";
				return hr;
			}
			break;
		case LIGHTTYPE_DIRECTIONAL:
		case LIGHTTYPE_TWOSIDE:
			hr = m_pLightMesh->Create(m_pNVDevice, GetFilePath("arrow.x"));
			if (FAILED(hr))
			{
				m_strLastError = "Could not load arrow.x";
				return hr;
			}
			break;
	}
	m_pLightMesh->SetFVF(m_pNVDevice, D3DFVF_NORMAL | D3DFVF_XYZ);

	Declaration.clear();
	Declaration.push_back(D3DVSD_STREAM(0));
	Declaration.push_back(D3DVSD_REG(0, D3DVSDT_FLOAT3));
	Declaration.push_back(D3DVSD_REG(1, D3DVSDT_FLOAT3));
	Declaration.push_back(D3DVSD_END());
	hr = LoadAndCreateShader(GetFilePath("fixedcolor.vso"), &Declaration[0], 0, SHADERTYPE_VERTEX, &m_dwFixedColorShader);
	if (FAILED(hr))
		return hr;


	Declaration.clear();
	Declaration.push_back(D3DVSD_STREAM(0));

	switch(m_LightType)
	{
		case LIGHTTYPE_MANYPOINT:
			Declaration.push_back(D3DVSD_REG(0, D3DVSDT_FLOAT3));
			Declaration.push_back(D3DVSD_REG(1, D3DVSDT_FLOAT3));
			Declaration.push_back(D3DVSD_REG(2, D3DVSDT_FLOAT2));
			Declaration.push_back(D3DVSD_END());
			hr = LoadAndCreateShader(GetFilePath("ManyPoint.vso"), &Declaration[0], 0, SHADERTYPE_VERTEX, &m_dwCurrentShader);
			if (FAILED(hr))
				return hr;
			
			break;
		case LIGHTTYPE_POINT:
			Declaration.push_back(D3DVSD_REG(0, D3DVSDT_FLOAT3));
			Declaration.push_back(D3DVSD_REG(1, D3DVSDT_FLOAT3));
			Declaration.push_back(D3DVSD_REG(2, D3DVSDT_FLOAT2));
			Declaration.push_back(D3DVSD_END());
			hr = LoadAndCreateShader(GetFilePath("PointLight.vso"), &Declaration[0], 0, SHADERTYPE_VERTEX, &m_dwCurrentShader);
			if (FAILED(hr))
				return hr;

			break;
		case LIGHTTYPE_DIRECTIONAL:
			Declaration.push_back(D3DVSD_REG(0, D3DVSDT_FLOAT3));
			Declaration.push_back(D3DVSD_REG(1, D3DVSDT_FLOAT3));
			Declaration.push_back(D3DVSD_REG(2, D3DVSDT_FLOAT2));
			Declaration.push_back(D3DVSD_END());
			hr = LoadAndCreateShader(GetFilePath("DirectionalLight.vso"), &Declaration[0], 0, SHADERTYPE_VERTEX, &m_dwCurrentShader);
			if (FAILED(hr))
				return hr;

			break;
		case LIGHTTYPE_TWOSIDE:
			Declaration.push_back(D3DVSD_REG(0, D3DVSDT_FLOAT3));
			Declaration.push_back(D3DVSD_REG(1, D3DVSDT_FLOAT3));
			Declaration.push_back(D3DVSD_REG(2, D3DVSDT_FLOAT3));
			Declaration.push_back(D3DVSD_END());
			hr = LoadAndCreateShader(GetFilePath("TwoSide.vso"), &Declaration[0], 0, SHADERTYPE_VERTEX, &m_dwCurrentShader);
			if (FAILED(hr))
				return hr;

			break;
	}

	if (m_pShapeMesh)
		m_pShapeMesh->SetVertexShader(m_dwCurrentShader);

	if (m_pLightMesh)
		m_pLightMesh->SetVertexShader(m_dwFixedColorShader);

	// Setup constants
	m_pD3DDev->SetVertexShaderConstant(CV_ZERO, D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f), 1);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -