364 lines
13 KiB
C++
364 lines
13 KiB
C++
///////////////////////////////////////////////////////////////////////
|
|
// SpeedTreeRT DirectX Example
|
|
//
|
|
// (c) 2003 IDV, Inc.
|
|
//
|
|
// This example demonstrates how to render trees using SpeedTreeRT
|
|
// and DirectX. Techniques illustrated include ".spt" file parsing,
|
|
// static lighting, dynamic lighting, LOD implementation, cloning,
|
|
// instancing, and dynamic wind effects.
|
|
//
|
|
//
|
|
// *** INTERACTIVE DATA VISUALIZATION (IDV) PROPRIETARY INFORMATION ***
|
|
//
|
|
// This software is supplied under the terms of a license agreement or
|
|
// nondisclosure agreement with Interactive Data Visualization and may
|
|
// not be copied or disclosed except in accordance with the terms of
|
|
// that agreement.
|
|
//
|
|
// Copyright (c) 2001-2003 IDV, Inc.
|
|
// All Rights Reserved.
|
|
//
|
|
// IDV, Inc.
|
|
// 1233 Washington St. Suite 610
|
|
// Columbia, SC 29201
|
|
// Voice: (803) 799-1699
|
|
// Fax: (803) 931-0320
|
|
// Web: http://www.idvinc.com
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// Includes
|
|
|
|
#pragma once
|
|
#include <map>
|
|
#include <string>
|
|
#include "D3DUtil.h"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// Vertex shader constant locations
|
|
|
|
const unsigned int c_nShaderCompositeMatrix = 0; ///< 4 vectors
|
|
const unsigned int c_nShaderUnitGrassBillboard = 4; ///< 4 vectors
|
|
const unsigned int c_nShaderLodParams = 8; ///< 1 vector
|
|
const unsigned int c_nShaderCameraPos = 9; ///< 1 vector
|
|
const unsigned int c_nShaderWindDirection = 10; ///< 1 vector
|
|
const unsigned int c_nShaderTimeValues = 11; ///< 1 vector
|
|
//const unsigned int c_nShaderLightDirection = 21;
|
|
//const unsigned int c_nShaderLightAmbient = 22;
|
|
//const unsigned int c_nShaderLightDiffuse = 23;
|
|
const unsigned int c_nShaderLightInfos = 21; ///< 3 vectors
|
|
|
|
const float c_fShaderTimeScale = 1.0f; ///< (< 1.0) slower wind, (> 1.0) = faster wind
|
|
const float c_fShaderWindPeriod = 1.0f; ///< (< 1.0) longer rolling effects, (> 1.0) = shorter rolling effects
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
/// Grass Vertex Format
|
|
static DWORD D3DFVF_SPEEDGRASS_VERTEX =
|
|
D3DFVF_XYZ |
|
|
D3DFVF_NORMAL |
|
|
D3DFVF_DIFFUSE |
|
|
D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0) ///< always have first texture layer coords
|
|
| D3DFVF_TEX2 | D3DFVF_TEXCOORDSIZE2(1) ///< GPU Only - wind weight and index passed in second texture layer
|
|
| D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE2(2); ///< shadow texture coordinates
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
/// FVF Grass Vertex Structure
|
|
struct SFVFGrassVertex
|
|
{
|
|
D3DXVECTOR3 m_vPosition; ///< Always Used
|
|
D3DXVECTOR3 m_vNormal; ///< Dynamic Lighting Only
|
|
DWORD m_dwDiffuseColor; ///< Static Lighting Only
|
|
// texture layer 0
|
|
FLOAT m_fTexCoords[2]; ///< Always Used
|
|
// texture layer 1
|
|
FLOAT m_fVertexIndex;
|
|
FLOAT m_fBladeSize;
|
|
// texture layer 2
|
|
FLOAT m_fWindWeight;
|
|
FLOAT m_fNoiseFactor;
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// SpeedGrass Vertex Shader Source
|
|
//
|
|
// c[0-3] composite projection/world matrix
|
|
// c[4-7] unitized billboard
|
|
// c[8].x far LOD distance (distance at which grass shrinks)
|
|
// c[8].y shrink transition length
|
|
// c[9] camera position
|
|
// c[10] global wind direction
|
|
// c[11].x global time (in seconds)
|
|
// c[11].y global wind effect period
|
|
// c20 useful general constants (defined locally)
|
|
// c21 light direction
|
|
// c22 light ambient color
|
|
// c23 light diffuse color
|
|
// c24 grass ambient color scalar
|
|
// c30 used in generating sin/cos
|
|
// c31 used in generating sin/cos
|
|
// c32 used in generating sin/cos
|
|
//
|
|
// Texture Layer Contents:
|
|
// -----------------------
|
|
//
|
|
// Layer 0 (v7)
|
|
// S: s texture coordinate into grass texture
|
|
// T: t texture coordinate into grass texture
|
|
//
|
|
// Layer 1 (v8)
|
|
// S: vertex index (0 to 3)
|
|
// T: blade size (scalar value around 1.0)
|
|
//
|
|
// Layer 2 (v9)
|
|
// S: wind weight (allows each blade of grass to sway differently)
|
|
// T: noise factor (keeps rolling wind effect from looking too perfect)
|
|
|
|
static const char g_szGrassVertexProgram[] =
|
|
{
|
|
// identity shader version
|
|
"vs.1.1\n"
|
|
|
|
"dcl_position v0\n"
|
|
"dcl_normal v3\n"
|
|
"dcl_color v5\n"
|
|
"dcl_texcoord0 v7\n"
|
|
"dcl_texcoord1 v8\n"
|
|
"dcl_texcoord2 v9\n"
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Section: Local constants definitons
|
|
|
|
// general constants
|
|
"def c20, 1.0, 0.5, 0.0, 0.0\n"
|
|
|
|
// lighting constants
|
|
//"def c21, -0.69, 0.0, 0.717, 1.0\n" // light direction
|
|
//"def c22, 0.0, 0.0, 0.0, 1.0\n" // light ambient color
|
|
//"def c23, 2.0, 2.0, 2.0, 1.0\n" // light diffuse color
|
|
//"def c24, 0.33, 0.33, 0.33, 1.0\n" // grass ambient color scalar
|
|
"def c24, 1.0, 1.0, 1.0, 1.0\n" // grass ambient color scalar
|
|
|
|
// sin/cos constants
|
|
"def c30, 0.25, 0.5, 0.75, 1.0\n"
|
|
"def c31, -24.9808039603f, 60.1458091736f, -85.4537887573f, 64.9393539429f\n"
|
|
"def c32, -19.7392082214f, 1.0f, -1.0f, 0.159154\n"
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Section: Compute unique angle value for this vertex to
|
|
// pass into sin/cos section for rolling wind effect
|
|
// Input: v0 (raw vertex pos)
|
|
// v9.y (noise factor)
|
|
// Output: r1.x = unique angle
|
|
// Registers: r1
|
|
// Constants: c10, c11
|
|
|
|
"mov r1.y, v9.y\n" // mad cannot access two vertex registers at once
|
|
"mad r1.xyz, v0, c11.y, r1.y\n" // made unique point using original vertex (v0), noise of
|
|
// blade (r1.y) and global period (c11.y)
|
|
"dp3 r1, r1, c10\n" // take wind direction into account
|
|
"add r1.x, r1.x, c11.x\n" // add global time in order to animate the wind effect
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Section: Compute Sine and Cosine of same angle
|
|
// Input: r1.x = angle (in radians)
|
|
// Ouput: r0.x = cos(r1.x)
|
|
// r0.y = sin(r1.x)
|
|
// Registers: r0, r1, r2
|
|
// Constants: c30, c31, c32
|
|
//
|
|
// * Taken from NVIDIA paper "Where Is That Instruction? How
|
|
// to Implement "Missing" Vertex Shader Instructions," #20,
|
|
// written by Matthias Wloka (mwloka@nvidia.com)
|
|
|
|
"mul r1.x, c32.w, r1.x\n" // normalize input
|
|
"expp r1.y, r1.x\n" // and extract fraction
|
|
"slt r2, r1.yyyy, c30\n" // range check, one each to indicate:
|
|
"add r2.yzw, r2.xyzw, -r2.xxyz\n" // [0,.25),[.25,.5),[.5,.75),[.75,1.0)
|
|
"dp3 r1.z, r2.yzwx, c30.yywx\n" // calc shift for cos
|
|
"dp4 r1.w, r2, c30.xxzz\n" // calc shift for sin
|
|
"add r0.xz, r1.yyyy, -r1.zzww\n" // x for cos, z for sin
|
|
"mul r0.xz, r0.xxzz, r0.xxzz\n" // [ x^2, #, z^2, #]
|
|
"mul r0.yw, r0.xxzz, r0.xxzz\n" // [ x^2, x^4, z^2, z^4]
|
|
"mad r1, c31.xyxy, r0.yyww, c31.zwzw\n"
|
|
"mad r1, r1, r0.yyww, c32.xyxy\n"
|
|
"mad r1.xz, r1, r0.xxzz, r1.yyww\n"
|
|
"dp4 r0.x, r2, c32.yzzy\n" // sign for cos
|
|
"dp4 r0.y, r2, c32.yyzz\n" // sign for sin
|
|
"mul r0.xy, r0.xyww, r1.xzww\n"
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Section: Move vertex based on wind effects
|
|
// Input: v0 (raw vertex pos)
|
|
// r0.x = cosine
|
|
// r0.y = sine
|
|
// v9.x = wind weight
|
|
// Ouput: r6 = wind-blown vertex
|
|
// Registers:
|
|
// Constants: none
|
|
|
|
"mov r6, v0\n" // passthrough .z and .w values
|
|
"mad r6.xy, v9.x, r0, r6.xy\n" // (x,y) value of vertex follows sin/cos
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Section: Compute distance from camera position to current vertex
|
|
// Input: v0 (raw vertex pos)
|
|
// Ouput: r3.x = distance(camera, vertex)
|
|
// Registers: r3
|
|
// Constants: c9 (camera pos)
|
|
|
|
"sub r3, v0, c9\n" // find vector difference between camera and vertex
|
|
"dp3 r3.x, r3, r3\n" // square and sum the distance components
|
|
"rsq r3.x, r3.x\n" // find square root for true distance, not squared
|
|
"rcp r3.x, r3.x\n"
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Section: In order for the blades of grass to fade out, alpha values
|
|
// need to fade from 1.0 to 0.0 when a vertex is between
|
|
// c8.x (lod far distance) and c8.x + c8.y (lod far + shrink
|
|
// distance away). The specific equation is:
|
|
//
|
|
// alpha = 1.0 - (distance - far_lod) / shrink_distance
|
|
//
|
|
// The alpha value is then clipped to 0.0 to 1.0.
|
|
// Input: r3.x = distance(camera, vertex)
|
|
// Ouput: r4.x = alpha value
|
|
// Registers: r3
|
|
// Constants: c8.x, c8.y
|
|
|
|
"sub r4.y, r3.x, c8.x\n" // subtract far_lod from distance
|
|
"rcp r4.z, c8.y\n" // divide difference by shrink_dist
|
|
"mul r4.w, r4.y, r4.z\n"
|
|
"sub r4.x, c20.x, r4.w\n" // subtract value from 1.0
|
|
"max r4.x, r4.x, c20.z\n" // clamp to > 0.0
|
|
"min r4.x, r4.x, c20.x\n" // clamp to < 1.0
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Section: Takes the unit grass blade billboard and adds it to the
|
|
// incoming position. The vertex index (stored in v8.x)
|
|
// is used to know which of the four vertices is incoming.
|
|
// Input: v8.x (vertex index)
|
|
// r6 (wind blown vertex)
|
|
// Ouput: r4.x = alpha value
|
|
// Registers: r3
|
|
// Constants: c4, c5, c6, c7 (grass blade unit billboard)
|
|
|
|
"mov a0.x, v8.x\n" // vertex index stored in v8.x
|
|
"mad r1, c[a0.x+4], v8.y, r6\n" // scale the billboard c[a0.x+4] by
|
|
// by v8.y and add r6 (wind blown vertex)
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Section: Lighting computation (optional)
|
|
// Input:
|
|
// Ouput:
|
|
// Registers:
|
|
// Constants:
|
|
|
|
"mov r2, c22\n" // move lighting ambient into register
|
|
"mul r3, r2, v5\n" // multiply grass ambient by lighting ambient
|
|
"mov r2, c23\n" // move lighting diffuse into register
|
|
"mul r5, r2, v5\n" // multiply grass diffuse by lighting ambient
|
|
"dp3 r2.x, v3, c21\n" // dot light direction with vertex normal
|
|
"max r2.x, r2.x, c20.z\n" // clamp dot to >= 0.0
|
|
"mad oD0.xyz, r2.x, r5, r3\n"
|
|
|
|
//"mov oD0.xyz, v5\n" // ¸Ó¿© À̰Ç.. ¤Ñ.,¤Ñ by blackfish
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Section: Write final outputs
|
|
// Input: r1 (wind blown position)
|
|
// v5 (color)
|
|
// r4.x (alpha value)
|
|
// Ouput: oPos, oD0, oT0
|
|
// Registers: none
|
|
// Constants: c0, c1, c2, c3 (composite matrix)
|
|
|
|
"m4x4 oPos, r1, c[0]\n" // project to screen
|
|
"mov oD0.w, r4.x\n" // color alpha value
|
|
"mov oT0.xy, v7\n" // pass texcoords through
|
|
|
|
// end vertex shader
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
/// LoadGrassShader
|
|
static LPDIRECT3DVERTEXSHADER9 LoadGrassShader(LPDIRECT3DDEVICE9 pDx)
|
|
{
|
|
// assemble shader
|
|
LPDIRECT3DVERTEXSHADER9 dwShader;
|
|
LPD3DXBUFFER pCode, pError;
|
|
if (D3DXAssembleShader(g_szGrassVertexProgram, sizeof(g_szGrassVertexProgram) - 1, 0, NULL, 0, &pCode, &pError) == D3D_OK)
|
|
{
|
|
if (pDx->CreateVertexShader((DWORD*)pCode->GetBufferPointer( ), &dwShader) != D3D_OK)
|
|
{
|
|
char szError[1024];
|
|
sprintf(szError, "Failed to create grass vertex shader.");
|
|
MessageBox(NULL, szError, "Rappelz-Vertex Shader Error", MB_ICONSTOP);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char szError[1024];
|
|
sprintf(szError, "Failed to assemble grass vertex shader.\nThe error reported is [ %s ].\n", pError->GetBufferPointer( ));
|
|
MessageBox(NULL, szError, "Rappelz-Vertex Shader Error", MB_ICONSTOP);
|
|
}
|
|
|
|
if (pCode)
|
|
pCode->Release( );
|
|
|
|
return dwShader;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//// SetupVertexShaderConstants
|
|
//
|
|
//static void SetupVertexShaderConstants(LPDIRECT3DDEVICE9 pDx, D3DXMATRIX& cCompositeMatrix, float fTime)
|
|
//{
|
|
// // composite matrix
|
|
// D3DXMatrixTranspose(&cCompositeMatrix, &cCompositeMatrix);
|
|
// pDx->SetVertexShaderConstantF(c_nShaderCompositeMatrix, reinterpret_cast<float*>(&cCompositeMatrix), 4);
|
|
//
|
|
// // pass in unitized billboarded grass quad
|
|
// const float* pUnitBB = CSpeedGrassWrapper::GetUnitBillboard( );
|
|
// const float c_fGrassWidth = 2.0f;
|
|
// for (int i = 0; i < 4; ++i)
|
|
// {
|
|
// float afVector[4] = { c_fGrassWidth * pUnitBB[i * 3 + 0],
|
|
// c_fGrassWidth * pUnitBB[i * 3 + 1],
|
|
// pUnitBB[i * 3 + 2],
|
|
// 0.0f };
|
|
// pDx->SetVertexShaderConstantF(c_nShaderUnitGrassBillboard + i, afVector, 1);
|
|
// }
|
|
//
|
|
// // setup LOD information
|
|
// float afVector[4] = { 0.0f };
|
|
// CSpeedGrassWrapper::GetLodParams(afVector[0], afVector[1]);
|
|
// pDx->SetVertexShaderConstantF(c_nShaderLodParams, afVector, 1);
|
|
//
|
|
// // setup camera information
|
|
// const float* pCameraPos = CSpeedGrassWrapper::GetCameraPos( );
|
|
// pDx->SetVertexShaderConstantF(c_nShaderCameraPos, pCameraPos, 1);
|
|
//
|
|
// // set global wind direction
|
|
// pDx->SetVertexShaderConstantF(c_nShaderWindDirection, CSpeedGrassWrapper::GetWindDirection( ), 1);
|
|
//
|
|
// // set time values
|
|
// float afTimeValues[4] = { fTime * c_fShaderTimeScale, c_fShaderWindPeriod, 0.0f, 0.0f };
|
|
// pDx->SetVertexShaderConstantF(c_nShaderTimeValues, afTimeValues, 1);
|
|
//}
|