Description

Runtime visualization with Irrlicht.

This module can be used to provide 3D realtime rendering in Chrono::Engine.

For additional information, see:

Namespaces

 chrono::irrlicht
 Namespace with classes for the Irrlicht module.
 

Classes

class  chrono::irrlicht::ChIrrApp
 Class to add some GUI to Irrlicht+ChronoEngine applications. More...
 
class  chrono::irrlicht::ChIrrAppInterface
 Class to add some GUI to Irrlicht + ChronoEngine applications. More...
 
class  chrono::irrlicht::ChIrrAssetConverter
 Class with static functions which allow creation of Irrlicht frequent 'scene nodes' like lights, camera, sky box etc. More...
 
class  chrono::irrlicht::RTSCamera
 Class to create an interactive videocamera in Irrlicht, that is similar to the Maya camera but hasn't the problems that the Maya camera has in Irrlicht 1.5. More...
 
class  chrono::irrlicht::CShaderPreprocessor
 CShaderPreprocessor. More...
 
class  chrono::irrlicht::DepthShaderCB
 DepthShaderCB. More...
 
class  chrono::irrlicht::ShadowShaderCB
 ShadowShaderCB. More...
 
class  chrono::irrlicht::ScreenQuadCB
 ScreenQuadCB. More...
 
class  chrono::irrlicht::CScreenQuad
 CScreenQuad. More...
 
class  chrono::irrlicht::EffectHandler
 Main effect handling class, use this to apply shadows and effects. More...
 
class  chrono::irrlicht::ChIrrNode
 Class for Irrlicht visualization. More...
 
class  chrono::irrlicht::ChIrrNodeAsset
 Class for adding Irrlicht visualization to a ChPhysicsItem. More...
 
class  chrono::irrlicht::ChIrrNodeProxyToAsset
 Class for proxy to ChAsset, it is a node with mesh in Irrlicht system and a shared pointer to the ChAsset to whom it corresponds. More...
 
class  chrono::irrlicht::ChIrrTools
 Class with static functions which help with the integration of Chrono and Irrlicht 3D rendering library. More...
 
class  chrono::irrlicht::ChIrrWizard
 Class with static functions which allow creation of Irrlicht frequent 'scene nodes' like lights, camera, sky box etc. More...
 

Enumerations

enum  E_SHADER_EXTENSION { ESE_GLSL, ESE_HLSL, ESE_COUNT }
 
enum  chrono::irrlicht::E_SHADOW_MODE {
  ESM_RECEIVE, ESM_CAST, ESM_BOTH, ESM_EXCLUDE,
  ESM_COUNT
}
 Shadow mode enums, sets whether a node recieves shadows, casts shadows, or both. More...
 
enum  chrono::irrlicht::E_FILTER_TYPE {
  EFT_NONE, EFT_4PCF, EFT_8PCF, EFT_12PCF,
  EFT_16PCF, EFT_COUNT
}
 Various filter types, up to 16 samples PCF.
 

Functions

irr::core::array< SDefineExp > chrono::irrlicht::grabDefineExpressions (irr::core::stringc &shaderProgram)
 
std::string chrono::irrlicht::getFileContent (const std::string pFile)
 
ChApiIrr irr::scene::IAnimatedMesh * chrono::irrlicht::createEllipticalMesh (irr::f32 radiusH, irr::f32 radiusV, irr::f32 Ylow, irr::f32 Yhigh, irr::f32 offset, irr::u32 polyCountX, irr::u32 polyCountY)
 Some functions to allow easy creation of meshes for Irrlicht visualization. More...
 
IMesh * chrono::irrlicht::createCubeMesh (const irr::core::vector3df &size)
 Create an Irrlicht mesh representing a box. More...
 
ChApiIrr irr::scene::IMesh * chrono::irrlicht::createCylinderMesh (irr::f32 radius, irr::f32 height, irr::u32 tesselation)
 Create an Irrlicht mesh representing a cylinder. More...
 
ChApiIrr irr::scene::IMesh * chrono::irrlicht::createCapsuleMesh (irr::f32 radius, irr::f32 hlen, irr::u32 numSegV, irr::u32 numSegR)
 Create an Irrlicht mesh representing a capsule. More...
 
ChApiIrr irr::scene::IMesh * chrono::irrlicht::createTruncatedConeMesh (irr::f32 radius_top, irr::f32 radius_low, irr::f32 height, irr::u32 tesselation)
 Create an Irrlicht mesh representing a truncated cone. More...
 
ChApiIrr irr::scene::IMesh * chrono::irrlicht::createConeMesh (irr::f32 radius_low, irr::f32 height, irr::u32 tesselation)
 Create an Irrlicht mesh representing a cone. More...
 
ChApiIrr void chrono::irrlicht::fillChTrimeshFromIrlichtMesh (geometry::ChTriangleMesh *chTrimesh, irr::scene::IMesh *pMesh)
 This function is based on a modified version of the irrlicht_bullet demo, see http://www.continuousphysics.com It is used to convert an Irrlicht mesh into a ChTriangleMesh, which is used for collision detection in Chrono. More...
 
ChApiIrr void chrono::irrlicht::fillIrlichtMeshFromChTrimesh (irr::scene::IMesh *pMesh, geometry::ChTriangleMesh *chTrimesh, irr::video::SColor clr=irr::video::SColor(255, 255, 255, 255))
 Given a ChTriangleMesh object, computes an Irrlicht mesh. More...
 
 chrono::irrlicht::CShaderPreprocessor::CShaderPreprocessor (irr::video::IVideoDriver *driverIn)
 
void chrono::irrlicht::CShaderPreprocessor::addShaderDefine (const irr::core::stringc name, const irr::core::stringc value="")
 
void chrono::irrlicht::CShaderPreprocessor::removeShaderDefine (const irr::core::stringc name)
 
irr::core::stringc chrono::irrlicht::CShaderPreprocessor::ppShader (irr::core::stringc shaderProgram)
 PreProcesses a shader using Irrlicht's built-in shader preprocessor.
 
irr::core::stringc chrono::irrlicht::CShaderPreprocessor::ppShaderFF (irr::core::stringc shaderProgram)
 PreProcesses a shader using Irrlicht's built-in shader preprocessor.
 
 chrono::irrlicht::EffectHandler::EffectHandler (irr::IrrlichtDevice *irrlichtDevice, const irr::core::dimension2du &screenRTTSize=irr::core::dimension2du(0, 0), const bool useVSMShadows=false, const bool useRoundSpotLights=false, const bool use32BitDepthBuffers=false)
 
 chrono::irrlicht::EffectHandler::~EffectHandler ()
 Destructor.
 
void chrono::irrlicht::EffectHandler::setScreenRenderTargetResolution (const irr::core::dimension2du &resolution)
 Sets a new screen render target resolution.
 
void chrono::irrlicht::EffectHandler::enableDepthPass (bool enableDepthPass)
 Enables/disables an additional pass before applying post processing effects (If there are any) which records screen depth info to the depth buffer for use with post processing effects that require screen depth info, such as SSAO or DOF. More...
 
void chrono::irrlicht::EffectHandler::addPostProcessingEffect (irr::s32 MaterialType, IPostProcessingRenderCallback *callback=0)
 A very easy to use post processing function. More...
 
void chrono::irrlicht::EffectHandler::addShadowToNode (irr::scene::ISceneNode *node, E_FILTER_TYPE filterType=EFT_NONE, E_SHADOW_MODE shadowMode=ESM_BOTH)
 Adds a shadow to the scene node. More...
 
void chrono::irrlicht::EffectHandler::addNodeToDepthPass (irr::scene::ISceneNode *node)
 This function is now unrelated to shadow mapping. More...
 
void chrono::irrlicht::EffectHandler::removeNodeFromDepthPass (irr::scene::ISceneNode *node)
 This function is now unrelated to shadow mapping. More...
 
void chrono::irrlicht::EffectHandler::update (irr::video::ITexture *outputTarget=0)
 Updates the effects handler. More...
 
irr::video::ITexture * chrono::irrlicht::EffectHandler::getShadowMapTexture (const irr::u32 resolution, const bool secondary=false)
 Retrieves the shadow map texture for the specified square shadow map resolution. More...
 
irr::video::ITexture * chrono::irrlicht::EffectHandler::generateRandomVectorTexture (const irr::core::dimension2du &dimensions, const irr::core::stringc &name="randVec")
 Generates a randomized texture composed of uniformly distributed 3 dimensional vectors.
 
void chrono::irrlicht::EffectHandler::setPostProcessingEffectConstant (const irr::s32 materialType, const irr::core::stringc &name, const irr::f32 *data, const irr::u32 count)
 Sets a shader parameter for a post-processing effect. More...
 
irr::s32 chrono::irrlicht::EffectHandler::addPostProcessingEffectFromFile (const irr::core::stringc &filename, IPostProcessingRenderCallback *callback=0)
 Adds a post processing effect by reading a pixel shader from a file. More...
 
virtual void chrono::irrlicht::ScreenQuadCB::OnSetConstants (irr::video::IMaterialRendererServices *services, irr::s32 userData)
 

Variables

const char *const chrono::irrlicht::LIGHT_MODULATE_P [ESE_COUNT]
 
const char *const chrono::irrlicht::SHADOW_PASS_1P [ESE_COUNT]
 
const char *const chrono::irrlicht::SHADOW_PASS_1PT [ESE_COUNT]
 
const char *const chrono::irrlicht::SHADOW_PASS_1V [ESE_COUNT]
 
const char *const chrono::irrlicht::SHADOW_PASS_2P [ESE_COUNT]
 
const char *const chrono::irrlicht::SHADOW_PASS_2V [ESE_COUNT]
 
const char *const chrono::irrlicht::SIMPLE_P [ESE_COUNT]
 
const char *const chrono::irrlicht::WHITE_WASH_P [ESE_COUNT]
 
const char *const chrono::irrlicht::WHITE_WASH_P_ADD [ESE_COUNT]
 
const char *const chrono::irrlicht::SCREEN_QUAD_V [ESE_COUNT]
 
const char *const chrono::irrlicht::VSM_BLUR_P [ESE_COUNT]
 

Enumeration Type Documentation

◆ E_SHADOW_MODE

Shadow mode enums, sets whether a node recieves shadows, casts shadows, or both.

If the mode is ESM_CAST, it will not be affected by shadows or lighting.

Function Documentation

◆ addNodeToDepthPass()

void chrono::irrlicht::EffectHandler::addNodeToDepthPass ( irr::scene::ISceneNode *  node)
inline

This function is now unrelated to shadow mapping.

It simply adds a node to the screen space depth map render, for use with post processing effects that require screen depth info. If you want the functionality of the old method (A node that only casts but does not receive shadows, use addShadowToNode with the ESM_CAST shadow mode.

◆ addPostProcessingEffect()

void chrono::irrlicht::EffectHandler::addPostProcessingEffect ( irr::s32  MaterialType,
IPostProcessingRenderCallback *  callback = 0 
)
inline

A very easy to use post processing function.

Simply add a material type to apply to the screen as a post processing effect and it will be applied. You can add as many material types as you desire, and they will be double buffered and executed in sequence.

For the material types, I recommend using "ScreenQuadCB" as the callback and referring to the texture names that are passed (When using OpenGL, in DirectX uniforms are not required to bind textures). Please note that this will only work in OpenGL on vanilla Irrlicht, DX requires the large RTT patch to be able to create sufficiently sized render targets for post processing. (Or you can just remove the engine check for Pow2).

The structure of the textures is as follows:

Texture1 - "ColorMapSampler" This is passed on from the previous post processing effect as they are executed in sequence. For example, if you do a horizontal blur on the first post processing material, then a vertical blur in the second material, you will use this sampler to access the post processed data of the horizontal blur when it is time to do the vertical blur. If accessed from the first post processing material, it will just contain the untainted screen map data.

Texture2 - "ScreenMapSampler" The second texture will always contain the untainted screen map data, from when the scene is first rendered. It will remain unchanged no matter how many post processing materials are applied. This kind of data is necessary, for example in bloom or DOF, you would require a copy of the blurred scene data and a copy of the normal untainted, unblurred screen data, and mix between them based on certain factors such as depth or luminance.

Texture3 - "DepthMapSampler" If a depth pass has been enabled using enableDepthPass, then this sampler will contain the screen space depth information. For better quality this is encoded to 16bits, and can be decoded like so: Texture.red + (Texture.green / 256.0f); That is by adding the red channel to the green channel which is first divided by 256. The data can still be used without decoding, in 8 bit precision, by just accessing the red component of the texture. Though this is not recommended as 8 bit precision is usually not sufficient for modern post processing effects.

Texture4 - "UserMapSampler" A custom texture that can be set by the user using setPostProcessingUserTexture(irr::video::ITexture* userTexture).

The last parameter is the render callback, you may pass 0 if you do not need one. Please see IPostProcessingRenderCallback for more info about this callback.

◆ addPostProcessingEffectFromFile()

irr::s32 chrono::irrlicht::EffectHandler::addPostProcessingEffectFromFile ( const irr::core::stringc &  filename,
IPostProcessingRenderCallback *  callback = 0 
)
inline

Adds a post processing effect by reading a pixel shader from a file.

The vertex shader is taken care of. The vertex shader will pass the correct screen quad texture coordinates via the TEXCOORD0 semantic in Direct3D or the gl_TexCoord[0] varying in OpenGL. See addPostProcessingEffect for more info. Returns the Irrlicht material type of the post processing effect.

◆ addShadowToNode()

void chrono::irrlicht::EffectHandler::addShadowToNode ( irr::scene::ISceneNode *  node,
E_FILTER_TYPE  filterType = EFT_NONE,
E_SHADOW_MODE  shadowMode = ESM_BOTH 
)
inline

Adds a shadow to the scene node.

The filter type specifies how many shadow map samples to take, a higher value can produce a smoother or softer result. The shadow mode can be either ESM_BOTH, ESM_CAST, or ESM_RECEIVE. ESM_BOTH casts and receives shadows, ESM_CAST only casts shadows, and is unaffected by shadows or lighting, and ESM_RECEIVE only receives but does not cast shadows.

◆ createCapsuleMesh()

ChApiIrr irr::scene::IMesh* chrono::irrlicht::createCapsuleMesh ( irr::f32  radius,
irr::f32  hlen,
irr::u32  numSegV,
irr::u32  numSegR 
)

Create an Irrlicht mesh representing a capsule.

Capsule axis is in Y direction, centered at origin. Capsule total length is radius + 2*hlen + radius. The hemispherical caps and cylindrical segment are all tesselated using numSegR radial segments. The hemispherical caps use numSegV vertical segments each.

◆ createConeMesh()

ChApiIrr irr::scene::IMesh* chrono::irrlicht::createConeMesh ( irr::f32  radius_low,
irr::f32  height,
irr::u32  tesselation 
)

Create an Irrlicht mesh representing a cone.

Truncated cone axis is in Y direction, centered in origin. Truncated cone tot length is 2*height, ranging from y=-height to y=+height.

◆ createCubeMesh()

ChApiIrr irr::scene::IMesh * chrono::irrlicht::createCubeMesh ( const irr::core::vector3df &  size)

Create an Irrlicht mesh representing a box.

Box is centered in origin, extending +/- size in each direction.

◆ createCylinderMesh()

ChApiIrr irr::scene::IMesh* chrono::irrlicht::createCylinderMesh ( irr::f32  radius,
irr::f32  height,
irr::u32  tesselation 
)

Create an Irrlicht mesh representing a cylinder.

Cylinder axis is in Y direction, centered in origin. Cylinder tot length is 2*height, ranging from y=-height to y=+height.

◆ createEllipticalMesh()

ChApiIrr irr::scene::IAnimatedMesh* chrono::irrlicht::createEllipticalMesh ( irr::f32  radiusH,
irr::f32  radiusV,
irr::f32  Ylow,
irr::f32  Yhigh,
irr::f32  offset,
irr::u32  polyCountX,
irr::u32  polyCountY 
)

Some functions to allow easy creation of meshes for Irrlicht visualization.

Create an Irrlicht mesh representing an ellipsoid. Ellispoid is centered in the origin.

◆ createTruncatedConeMesh()

ChApiIrr irr::scene::IMesh* chrono::irrlicht::createTruncatedConeMesh ( irr::f32  radius_top,
irr::f32  radius_low,
irr::f32  height,
irr::u32  tesselation 
)

Create an Irrlicht mesh representing a truncated cone.

Truncated cone axis is in Y direction, centered in origin. Truncated cone tot length is 2*height, ranging from y=-height to y=+height.

◆ enableDepthPass()

void chrono::irrlicht::EffectHandler::enableDepthPass ( bool  enableDepthPass)
inline

Enables/disables an additional pass before applying post processing effects (If there are any) which records screen depth info to the depth buffer for use with post processing effects that require screen depth info, such as SSAO or DOF.

For nodes to be rendered in this pass, they must first be added using addNodeToDepthPass(SceneNode).

◆ fillChTrimeshFromIrlichtMesh()

ChApiIrr void chrono::irrlicht::fillChTrimeshFromIrlichtMesh ( geometry::ChTriangleMesh chTrimesh,
irr::scene::IMesh *  pMesh 
)

This function is based on a modified version of the irrlicht_bullet demo, see http://www.continuousphysics.com It is used to convert an Irrlicht mesh into a ChTriangleMesh, which is used for collision detection in Chrono.

OBSOLETE

◆ fillIrlichtMeshFromChTrimesh()

ChApiIrr void chrono::irrlicht::fillIrlichtMeshFromChTrimesh ( irr::scene::IMesh *  pMesh,
geometry::ChTriangleMesh chTrimesh,
irr::video::SColor  clr = irr::video::SColor(255, 255, 255, 255) 
)

Given a ChTriangleMesh object, computes an Irrlicht mesh.

Note: the ChTriangleMesh is a 'triangle soup', so no connectivity is used. As a consequence, no Gourad/Phong shading is possible and all triangles will look flat.

OBSOLETE

◆ getShadowMapTexture()

irr::video::ITexture * chrono::irrlicht::EffectHandler::getShadowMapTexture ( const irr::u32  resolution,
const bool  secondary = false 
)
inline

Retrieves the shadow map texture for the specified square shadow map resolution.

Only one shadow map is kept for each resolution, so if multiple lights are using the same resolution, you will only see the last light drawn's output. The secondary param specifies whether to retrieve the secondary shadow map used in blurring.

◆ OnSetConstants()

void chrono::irrlicht::ScreenQuadCB::OnSetConstants ( irr::video::IMaterialRendererServices *  services,
irr::s32  userData 
)
inlinevirtual

Version for Irrlicht 1.7.3

◆ removeNodeFromDepthPass()

void chrono::irrlicht::EffectHandler::removeNodeFromDepthPass ( irr::scene::ISceneNode *  node)
inline

This function is now unrelated to shadow mapping.

It simply removes a node to the screen space depth map render, for use with post processing effects that require screen depth info.

◆ setPostProcessingEffectConstant()

void chrono::irrlicht::EffectHandler::setPostProcessingEffectConstant ( const irr::s32  materialType,
const irr::core::stringc &  name,
const irr::f32 *  data,
const irr::u32  count 
)
inline

Sets a shader parameter for a post-processing effect.

The first parameter is the material type, the second is the uniform paratmeter name, the third is a float pointer that points to the data and the last is the component count of the data. Please note that the float pointer must remain valid during render time. To disable the setting of a parameter you may simply pass a null float pointer.

◆ update()

void chrono::irrlicht::EffectHandler::update ( irr::video::ITexture *  outputTarget = 0)
inline

Updates the effects handler.

This must be done between IVideoDriver::beginScene and IVideoDriver::endScene. This function now replaces smgr->drawAll(). So place it where smgr->drawAll() would normally go. Please note that the clear color from IVideoDriver::beginScene is not preserved, so you must instead specify the clear color using EffectHandler::setClearColour(Color). A render target may be passed as the output target, else rendering will commence on the backbuffer.

Variable Documentation

◆ LIGHT_MODULATE_P

const char* const chrono::irrlicht::LIGHT_MODULATE_P[ESE_COUNT]
Initial value:
= {
"uniform sampler2D ColorMapSampler;\n"
"uniform sampler2D ScreenMapSampler;\n"
""
"void main() "
"{ "
" vec4 finalCol = texture2D(ColorMapSampler, gl_TexCoord[0].xy);\n"
" vec4 lightCol = texture2D(ScreenMapSampler, gl_TexCoord[0].xy);\n"
""
" gl_FragColor = finalCol * lightCol;\n"
"}",
"sampler2D ColorMapSampler : register(s0);\n"
"sampler2D ScreenMapSampler : register(s1);\n"
""
"float4 pixelMain(float2 TexCoords : TEXCOORD0) : COLOR0"
"{ "
" float4 finalCol = tex2D(ColorMapSampler, TexCoords);\n"
" float4 lightCol = tex2D(ScreenMapSampler, TexCoords);\n"
""
" return finalCol * lightCol;\n"
"}"}

◆ SHADOW_PASS_1P

const char* const chrono::irrlicht::SHADOW_PASS_1P[ESE_COUNT]
Initial value:
= {
"void main() "
"{"
" vec4 vInfo = gl_TexCoord[0];\n"
" float depth = vInfo.z / vInfo.x;\n"
" gl_FragColor = vec4(depth, depth * depth, 0.0, 0.0);\n"
"}",
"float4 pixelMain(float4 ClipPos: TEXCOORD0) : COLOR0"
"{"
" float depth = ClipPos.z / ClipPos.x;\n"
" return float4(depth, depth * depth, 0.0, 0.0);\n"
"}"}

◆ SHADOW_PASS_1PT

const char* const chrono::irrlicht::SHADOW_PASS_1PT[ESE_COUNT]
Initial value:
= {
"uniform sampler2D ColorMapSampler;\n"
""
"void main() "
"{"
" vec4 vInfo = gl_TexCoord[0];\n"
""
" float depth = vInfo.z / vInfo.x;\n"
""
" float alpha = texture2D(ColorMapSampler, gl_TexCoord[1].xy).a;\n"
""
" gl_FragColor = vec4(depth, depth * depth, 0.0, alpha);\n"
"}",
"sampler2D ColorMapSampler : register(s0);\n"
""
"float4 pixelMain(float4 Color: TEXCOORD0, float2 Texcoords: TEXCOORD1) : COLOR0"
"{"
" float depth = Color.z / Color.w;\n"
" "
" float alpha = tex2D(ColorMapSampler, Texcoords).a;\n"
" "
" return float4(depth, depth * depth, 0.0, alpha);\n"
"}"}

◆ SIMPLE_P

const char* const chrono::irrlicht::SIMPLE_P[ESE_COUNT]
Initial value:
= {
"uniform sampler2D ColorMapSampler;\n"
""
"void main() "
"{ "
" vec4 finalCol = texture2D(ColorMapSampler, gl_TexCoord[0].xy);\n"
" gl_FragColor = finalCol;\n"
"}",
"sampler2D ColorMapSampler : register(s0);\n"
""
"float4 pixelMain(float2 TexCoords : TEXCOORD0) : COLOR0"
"{ "
" float4 finalCol = tex2D(ColorMapSampler, TexCoords);\n"
" return finalCol;\n"
"}"}

◆ WHITE_WASH_P

const char* const chrono::irrlicht::WHITE_WASH_P[ESE_COUNT]
Initial value:
= {
"uniform sampler2D ColorMapSampler;\n"
""
"void main() "
"{"
" float alpha = texture2D(ColorMapSampler, gl_TexCoord[1].xy).a;\n"
""
" gl_FragColor = vec4(1.0, 1.0, 1.0, alpha);\n"
"}",
"sampler2D ColorMapSampler : register(s0);\n"
""
"float4 pixelMain(float4 Color: TEXCOORD0, float2 Texcoords: TEXCOORD1) : COLOR0"
"{"
" float alpha = tex2D(ColorMapSampler, Texcoords).a;\n"
""
" return float4(1.0, 1.0, 1.0, alpha);\n"
"}"}

◆ WHITE_WASH_P_ADD

const char* const chrono::irrlicht::WHITE_WASH_P_ADD[ESE_COUNT]
Initial value:
= {
"uniform sampler2D ColorMapSampler;\n"
"float luminance(vec3 color)"
"{"
" return clamp(color.r * 0.3 + color.g * 0.59 + color.b * 0.11, 0.0, 1.0);\n"
"}"
"void main() "
"{"
" vec4 diffuseTex = texture2D(ColorMapSampler, gl_TexCoord[1].xy);\n"
" //diffuseTex *= gl_TexCoord[2];\n"
""
" gl_FragColor = vec4(1.0, 1.0, 1.0, luminance(diffuseTex.rgb));\n"
"}",
"sampler2D ColorMapSampler : register(s0);\n"
""
"float luminance(float3 color)"
"{"
" return clamp(color.r * 0.3 + color.g * 0.59 + color.b * 0.11, 0.0, 1.0);\n"
"}"
""
"float4 pixelMain(float4 Color : TEXCOORD0, float2 Texcoords : TEXCOORD1, float4 VColor : TEXCOORD2) : COLOR0"
"{"
" float4 diffuseTex = tex2D(ColorMapSampler, Texcoords);\n"
" diffuseTex *= VColor;\n"
""
" return float4(1.0, 1.0, 1.0, luminance(diffuseTex.rgb));\n"
"}"}