Environment mapping shader

Started by
5 comments, last by roos 19 years, 4 months ago
Hi, I am a bit new to DirectX, especially shaders... I'm trying to get a car to display with reflections, using sphere mapping from an example I found in the SDK. I think I got the sphere mapping part of it working (just copied and pasted the sdk code more or less...) but the problem is, now when I render the car, it looks like a shiny mirror. So, how do I combine the reflection on to the car texture instead of replacing it? I don't think SetTextureStageState() will work in this case, because the effect seems to be using a vertex shader... Here is the effect definition: const char g_szEffect[] = "texture texSphereMap;\n" "matrix matWorld;\n" "matrix matViewProject;\n" "vector vecPosition;\n" "technique Sphere\n" "{\n" "pass P0\n" "{\n" // Vertex state "VertexShader =\n" "decl\n" "{\n" // Decls no longer associated with vertex shaders in DX9 "}\n" "asm\n" "{\n" "vs.1.1\n" "def c64, 0.25f, 0.5f, 1.0f, -1.0f\n" "dcl_position v0\n" "dcl_normal v1\n" // r0: camera-space position // r1: camera-space normal // r2: camera-space vertex-eye vector // r3: camera-space reflection vector // r4: texture coordinates // Transform position and normal into camera-space "m4x4 r0, v0, c0\n" "m3x3 r1.xyz, v1, c0\n" "mov r1.w, c64.z\n" // Compute normalized view vector "add r2, c8, -r0\n" "dp3 r3, r2, r2\n" "rsq r3, r3.w\n" "mul r2, r2, r3\n" // Compute camera-space reflection vector "dp3 r3, r1, r2\n" "mul r1, r1, r3\n" "add r1, r1, r1\n" "add r3, r1, -r2\n" // Compute sphere-map texture coords "mad r4.w, -r3.z, c64.y, c64.y\n" "rsq r4, r4.w\n" "mul r4, r3, r4\n" "mad r4, r4, c64.x, c64.y\n" // Project position "m4x4 oPos, r0, c4\n" "mul oT0.xy, r4.xy, c64.zw\n" "mov oT0.zw, c64.z\n" "};\n" "VertexShaderConstant4[0] = <matWorld>;\n" "VertexShaderConstant4[4] = <matViewProject>;\n" "VertexShaderConstant1[8] = <vecPosition>;\n" // Pixel state "Texture[0] = <texSphereMap>;\n" "AddressU[0] = Wrap;\n" "AddressV[0] = Wrap;\n" "MinFilter[0] = Linear;\n" "MagFilter[0] = Linear;\n" "ColorOp[0] = SelectArg1;\n" "ColorArg1[0] = Texture;\n" "}\n" "}\n"; If anyone could give me some pointer I'd appreciate it a lot! Thanks, roos Edit: In case it helps, here's an image that shows what I mean... It looks kind of weird like there are some discontinuities, I'm not sure if this is a bug or just a regular artifact of sphere mapping:
Advertisement
What you need to do is basically as follows. This is mostly from memory, but I'm fairly confident it's correct.

First, declare your car texture:

"texture texCar;\n"


You will need to bind this with a SetTexture() call (as you do the spheremap) with your car texture, in your application.

In your vertex shader, you need to get yourself some texture coordinates for your car texture, you can output them to oT1. The simplest way to do this would be just to pass them through from texture coordinates which are on the mesh, something like:

// at the beginning of the vertex shader next to the other dcl_ statements"dcl_texcoord0 v2\n"// at the end of the vertex shader"mov oT1, v2\n"


Then you use your texture coordinates to look up your regular car texture.

This means changing the following:

// Pixel state"Texture[0] = <texSphereMap>;\n""AddressU[0] = Wrap;\n""AddressV[0] = Wrap;\n""MinFilter[0] = Linear;\n""MagFilter[0] = Linear;\n""ColorOp[0] = SelectArg1;\n""ColorArg1[0] = Texture;\n"


To something like
// Pixel state"Texture[0] = <texSphereMap>;\n""AddressU[0] = Wrap;\n""AddressV[0] = Wrap;\n""MinFilter[0] = Linear;\n""MagFilter[0] = Linear;\n"// car texture sampler states"Texture[1] = <texCar>;\n""AddressU[1] = Wrap;\n""AddressV[1] = Wrap;\n""MinFilter[1] = Linear;\n""MagFilter[1] = Linear;\n"// blend the two textures"ColorOp[0] = SelectArg1;\n""ColorArg1[0] = Texture;\n""ColorOp[1] = Modulate;\n""ColorArg1[1] = Current;\n""ColorArg2[1] = Texture;\n"


This should multiply the spheremap by the car's texture map, combining them. However, I'm not sure what kind of result you'd get with this, it's just the easiest way to get it working. For a better result you could linearly interpolate between the two textures. How do you do that? Well, here's a quick explanation:

Use the Lerp command, which has the following equation:

SRGBA = (Arg1) * Arg2 + (1 - Arg1) * Arg3

You want to interpolate between texSphereMap and texCar, based on some parameter value. Setting up the interpolation is quite easy.

// the last part of the texture stage state setup"ColorOp[0] = SelectArg1;\n""ColorArg1[0] = Texture;\n""ColorOp[1] = Lerp;\n""ColorArg1[1] = Current;\n""ColorArg2[1] = Texture;\n""ColorArg0[1] = TFactor;\n"


You can see we've added this "TFactor" item which acts as the parameter for the Lerp equation. You set this inside your effect too using the following:

"TextureFactor = 0x00000000;\n"


It takes DWORD values, the same as D3DCOLOR types infact. Tweak it all you like :)

Hope some of that helped.

-Mezz
Sweet! Thanks a million, you're a godsend :) I will try this out, it looks like it should work, or at least from here I can figure out the rest hopefully!
Cool, I got it working using the code you posted (thanks so much again!) It looks awesome, the only thing is I'm not sure if using "lerp" is accurate for modeling reflections, since real reflections are additive (I think). So, I tried simply changing "lerp" to "add", as in:

"ColorOp[1] = Add;\n"

This ignores TextureFactor though, it seems to be doing simply tex0 + tex1 instead of tex0 + (tex1 * TextureFactor) which is what I am aiming to do.

Anyone know if it's possible to control the amount of additive blending going on?

Thanks,
roos
Post up a picture;)
Yeah, you're right reflections are additive. I was getting ahead of myself with the lerp - typically that is what is used to account for fresnel as I recall. To control the amount of adding, well, you could set it up so you do something like this (pseudocode):

(spheremapTexture * someValue) + diffuseTexture

If you put someValue in the TextureFactor, and set up the pixel state appropriately that should give you control over how much is added on easily :)

Hope that helps.

EDIT

Sorry, I see you already decided this is what you want. Well, here is the way to go about it:

// texture stage 0, multiply spheremap by tfactor"ColorOp[0] = Modulate;\n""ColorArg1[0] = Texture;\n""ColorArg2[0] = TFactor;\n"// texture stage 1, add on previous stage output to this texture"ColorOp[1] = Add;\n""ColorArg1[1] = Current;\n""ColorArg2[1] = Texture;\n"


-Mezz
Ahh I see now.. It seems very easy when you explain it like that, thanks again for taking the time to spell things out to a noob like me!

Heh I'm going on vacation now for 2 days but when I get back in town I can post up a shot...

thanks,
roos

This topic is closed to new replies.

Advertisement