Sign in to follow this  
spek

OpenGL Dual Paraboloid Mapping questions

Recommended Posts

Hi, Now that SH lighting is finally working, it's time for some optimizations. One of the things I had in mind, is to use Dual Paraboloid Maps instead of cubemaps. I want to use them for reflections in the world, and downscale them to tiny probes for realtime ambient lighting with spherical harmonics. DPM, The good - Only 2 passes instead of 6 DPM, The Bad - Less accurate, and/or high tesselation of world mesh required - Sampling a pixel with a given normal is more work (I think) Since the reflections and ambient lighting don't have to be 100% correct, the less accurate results don't have to be a huge problem. But... when I tried making my first DPM test program (with the help of Jason Zinks article on gamedev), I saw relative much code was required to obtain a pixel from the DPM, including a matrix multiplication:
	float3 E = normalize( cameraVec);		// normalize input per-vertex eye vector
	float3 R = reflect( E, normal );		// calculate the reflection vector
	
	R = mul( (float3x3)ParaboloidBasis, R );	// transform reflection vector to the maps basis
	
	// calculate the forward paraboloid map texture coordinates	
	float2 front;
	front.x = (R.x / (2*(1 + R.z))) + 0.5;
	front.y = 1-((R.y / (2*(1 + R.z))) + 0.5);
	
	// calculate the backward paraboloid map texture coordinates
	float2 back;
	back.x = (R.x / (2*(1 - R.z))) + 0.5;
	back.y = 1-((R.y / (2*(1 - R.z))) + 0.5);

	float3 forward  = tex2D( frontMap, front );	// sample the front paraboloid map
	float3 backward = tex2D( backMap , back );	// sample the back paraboloid map

	oColor.rgb = max(forward, backward);		// output the max of the two maps
This is not a problem for 1 sample, but I'll have to take 512 samples in the shader for up to 10 pixels per frame. The upper part of the code only has to be done once, but how about the matrix multiply and the code below? I have multiple DPM probes on different locations. Can they all do with the same matrix? If not, I'll have pass 10 or maybe 20 different matrices to the shader somehow! (10 or 20 cubeMaps or DPM's are stored in 1 3D texture). Speaking of that matrix, I haven't managed to find the right matrix yet. I thought the modelView matrix should be used (the one used when generating the DPM), but that didn't work. BTW, I'm using Cg shaders & OpenGL. Another question. The ATI ambient demo showed how to speed up by rendering multiple cubeMaps at the same time with the help of geometry shaders. I assume I can do the same trick for DPM's? I haven't used geometry shaders so far... Greetings, Rick

Share this post


Link to post
Share on other sites
Hello, maybe I can help out here. The matrix needs to be the view matrix that is used in the generation of the paraboloid maps. This shouldn't include any object transformations - the matrix multiplication is changing the reflection vector from world space to view space.

With that in mind, the calculation of the reflection vector and the subsequent transformation could be moved to the vertex shader, but then you will be relying on the interpolation between vertices to produce a good reflection vector. This is not really a good solution because it is even more dependant on the tessellation of the scene!

Try using the effect in its current state and see what the performance is like. I'm not entirely clear about what you are doing with it, but you may be able to squeeze out some performance elsewhere to make it fast enough. If you have any more trouble post about it here - I'm sure we can work out any kinks!

Share this post


Link to post
Share on other sites
One thing that might not be obvious: You can just assume all of your lights are oriented in an axis-aligned fashion. (eg, they're all just facing down Z, or whatever). If you do that, you don't need the matrix multiply at all, you can replace it with a simple translation by the position of the light (or probe in this case). If you have a really good reason to orient the paraboloid splitting plane in some other way, then this doesn't work. But in most cases, the decision for how to orient the two halves is fairly arbitrary anyway. This is what we do for our dual paraboloid shadow maps.

Share this post


Link to post
Share on other sites
Hey, Jason Zink! I've seen your article alot last weeks. Strange indeed that there aren't much other articles/demo's about this stuff, besides old OpenGL demo's without shaders (or assembler shaders).

To clearify things, I'm using my reflection maps (either cubeMaps or DPM's) for reflections on the world geometry & objects. Just, by simply rendering the surrounding environment at a certain point. I was planning to experiment with a grid of 9 or 20 probes (depending on system speed) in front of the camera. The camera shoots 9 or 20 rays into the directions in front of the camera. Where the rays collide, a reflection probe will be placed. Another probe is placed inside the camera itself (for the reflection on nearby objects / player itself). The probes don't have any rotation. 2 maps are just rendered into +z and -z direction. (So maybe I can simplify this, like Osmanb said).

In the end, depending on the pixel screen position, it will blend its reflection between 2 or 3, maybe even 4 probes. For example, a pixel topleft will pick the probe that was generated with the ray shooting to the topleft corner of the view frustum. I don't know if it works, but the plan is to make this grid refresh every frame == realtime & dynamic reflections.

Because I need to render 9 or even 20 + 1 probes, Dual Paraboloid Maps can save some serieus work. Cubemap = 21 * 6 = 126 passes, while DPM = 21 * 2 = "only" 42 passes. The corner probes might not be refreshed every frame, but you can see the point of using DPM's here.


However, the first problems start here. In the final reflection shader, I need access to all 9 or 20 cubeMaps/DPM's. Therefore I place each face in 1 big 3D texture. That saves me switching and sorting on textures, plus I can blend between all maps. But if the matrix is different for each DPM, I also need access to 9 or 20 matrices. Easily accessing them is a problem, unless I can do something with an array. And is uploading 20 matrix parameters not a problem?

I wondered though, like Osmanb said, is that matrix transformation nescesary? My probes ALWAYS only point into +z and -z direction. Maybe I can replace the matrix operation with something more simple... I don't need any matrices for cubeMaps neither, the pixel world normal is enough.


The second part is SH lighting. The same probes used for the reflections are downscaled to tiny maps (8x8 for cubeMaps, 16x16 if they are DPM's). I'll have to downscale less maps, which is good. But the SH shaders have to sample ALOT of pixels from these maps. To illustrate, the shader that produces SH coefficients has to loop through all reflection map pixels. That means 8x8x6 = 386 texCUBE operations for a cubeMap, or 16x16x2=512 DPM pixel-fetch operations. In the last case I need to sample from 2 textures instead of 1, and test somehow if the pixel is not outside the sphere (only 70% from the DPM texture is actually used). I have 9/20+1 probes, that also means I need to update 9/20+1 SH coefficients as fast as possible with that shader.

I'm a little bit afraid that all the speed I win with saving 4 passes per probe, is not going to compensate the extra work required in the heavy SH shaders. I can simplify the original DPM pixel shader code... And if I only win a little performance, then I might choose for cubeMaps after all, since they don't require the world to be highly tesselatedUnless

[edit]
Forget about the SH part. I'll have to loop through ALL pixels, so I don't need any code to convert a specific normal to texture coordinates, neither I'll have to read 2 textures and choose between 1 of them. The only additional cost I'll get is to determine if the pixel is in- or outside the sphere. I can do that with the alpha channel of the dual paraboloid textures.

Nevertheless, I still wonder if there are faster ways to access the DPM's, and if I can skip the matrix operation or at least use the same matrices for all DPM's.

Thanks guys,
Rick

[Edited by - spek on July 3, 2008 7:05:06 AM]

Share this post


Link to post
Share on other sites
This all sounds pretty cool. We have a fairly solid DPM implementation for our shadows here, and we've talked about using it to do other things (if we ever get time). It's not directly applicable, but you might find something useful in:

http://osman.brian.googlepages.com/dpsm.pdf

You can definitely skip the matrix multiply, assuming that you're already in world space. And you might be able to avoid most of the tesselation stuff, depending on what exactly you're doing (and how your scene). Reflections are usually pretty distorted anyway, so when you're rendering the DPMs, it probably doesn't matter too much if they're somewhat distorted in the maps. When you're rendering the scene (which is equivalent to the lighting pass in the above paper), you can do the DP transformation in the pixel shader, rather than the vertex shader. That completely eliminates any further distortion, and I suspect the results will be good enough (in most cases).

Share this post


Link to post
Share on other sites
That was the type of answer I was hoping for. Yep, the reflections don't have to be superb, I render the maps on a low resolution anyway 128x128. I downscale it to 64x64, 32x32 and 16x16 (for the ambient lighting). the passes in between are blurred as well. Most of the stuff in my world only vagely reflects, therefore a low-res blurred map is fine.

Everything is in world-space indeed. When I render a probe, I basically do this:
1.- Apply field of View = 90 (is this nescesary?), screen ratio 1.0,
near = 0.01, far = x
2.- put camera on probe world position
3.- point towards +z, or -z
4.- Render the world with dual paraboloid transformation

I've checked both maps. They seem to be ok, well, almost. Some of the polygons that are not completely inside the hemisphere, seem to be missing...


Before I try all the cool stuff from my previous post, I first try to do reflections on a simply cube. So far, they are not correct yet. I can see the maps on it, but artifacts (lines) are on the cube as well, and the reflections are for the wrong directions. I guess this has to do with the matrix. When I use the modelview matrix, I get very wrong results. The cube just has 1 color (from 1 pixel in the DPM I suppose). If I don't do the matrix operation at all, I get these artifacts, and reflections on the wrong sides. It's also as if the camera was zoomed in alot (texture appears very big on the cube).

I'm using the code I posted earlier, but without the "mul( matrix, R )" part.

Greetings and thanks for helping,
Rick

Share this post


Link to post
Share on other sites
I think Osmanb is correct - you don't need to do a full matrix multiply if the vector is already in world space AND you enforce the rule that the paraboloids are oriented along the +/- z axes. However, you will need to ensure that the vector is generated from two world space points. (EDIT: I would really like to see your shader code before making this judgement - something isn't adding up here...)

From looking at the code that you posted, it seems like some of the vector creation is mixed and matched between the original generation and accessing shaders that I sent out with the article. Please be careful to create the vectors in the correct manner! This is a definite source of problems if they aren't created correctly. Perhaps it would help if you posted the shader code for generating the maps and then the shader code for accessing the maps - it could be a simple mistake making the whole technique seem ridiculous!!

The lighting technique that you are mentioning sounds quite complex, and would bring my GPU to its knees! Even so, that is usually how the next generation techniques get started - on hardware that doesn't do it justice... Given the fact that you are using low resolution information in the lighting 'probes', I think DPM is clearly the way to go. There isn't much advantage in using cube maps if quality isn't the top priority.

Also, I don't know if OpenGL has an equivalent or not, but I have been using D3D10 texture arrays to generate my DPM maps. It allows you to render to both targets at the same time from a single draw call (by setting the desired render target in the geometry shader for each instance created in the geometry shader). I have actually written full blown book chapter on different environment mapping techniques that describes how to do this. Hopefully it will be available soon to the community for just these types of situations!

Share this post


Link to post
Share on other sites
I'm not sure, but I think the shader code is from your HLSL example. I'm using Cg though, so I had to make a few changes. For example, switching the parameters for a "mul" operation ( mul( vector, modelView ) -> mul( modelView, vector )". Anyway, I'll post the full shaders at the end of this post. Ow, and could someone please tell me the tag again to put code in a highlighted box? I forgot it.

The ambient lighting is heavy stuff indeed, although it still runs reasonable on my GeForce 8800. The main problem is not to update too much probes per frame. If you only update 2 probes, no problemo. But the problem is that worlds ussually need an awful lot of probes, which results in big (uniform 3D) grids of probes. Fine for a small scene, but way too much for a bigger (outdoor) scene. It would take maybe 10 seconds before all probes are updated, and it takes alot of memory. A waste, since most of the probes aren't even used. Therefore I thought about shooting a fixed (small) number of probes out of the camera. Updating 8 probes can be done on 50 frames per second in my card. However, all other techniques are still disabled (SSAO, DoF, HDR, Bloom, reflections, complex scenes, ... ).

Thanks for reminding me the multiple target options. I can indeed render to two textures at the same time with OpenGL as well. I'm using an indicator ("zValue") and the Cg "skip" function to discard pixels on the wrong side. But if I understand it right, the entire surrounding scene (360 degrees) is rendered in front of the camera, and I skip ~50% of it. So if I want render both of them in 1 pass:

// fragment code
// Original
out.Color.a = 0; // Invisible pixel so far
skip( zValue ); // Return if zValue is 0(or 1, I'm not familiar yet with skip)
> proceed normally
out.Color.a = 1;

// NEW CODE
> do normal code
out.colorFront = out.colorBack = myResult;
if (zValue == 1)
{
out.colorFront.a = 0; // Hide pixel in front buffer
out.colorBack.a = 1; // Shiw pixel in back buffer
} else
{
out.colorFront.a = 1; // Show pixel in front buffer
out.colorBack.a = 0; // Hide pixel in back buffer
}

The vertex shader uses a "direction" parameter to indicate if the pixel is meant for the front or back buffer. What to do with that piece of code?


Ok, here comes the code. Currently I don't do any matrix operation in the fragment shader, so I commented it out. If I enable it, I still get wrong results though.
//------------------- DPM generation -------------------------------------

< Vertex Shader >
void main(
float4 iPos : POSITION, // World position
out float4 oPos : POSITION, // Result position
out float oZValue : TEXCOORD7,

uniform float4x4 MV = MV, // ModelView Matrix
uniform half3 cameraPos = V3_CAM_POS,
uniform half direction = F_CAM_DIRECTION // +1 or -1
)
{
// Bend vertex into the paraboloid
oPos = mul( MV, float4(iPos.xyz,1) );// transform vertex into the maps basis
oPos = oPos / oPos.w; // divide by w to normalize

oPos.z = oPos.z * direction; // set z-values to forward or backward

float L = length( oPos.xyz ); // determine the distance between (0,0,0) and the vertex
oPos = oPos / L; // divide the vertex position by the distance

oZValue = oPos.z; // remember which hemisphere the vertex is in
oPos.z = oPos.z + 1; // add the reflected vector to find the normal vector

oPos.x = oPos.x / oPos.z; // divide x coord by the new z-value
oPos.y = oPos.y / oPos.z; // divide y coord by the new z-value

const half MAX_VIEW_DIST = 500;
oPos.z = L / MAX_VIEW_DIST; // set a depth value for correct z-buffering
oPos.w = 1; // set w to 1 so there is no w divide

//---------------------------------------------------------------------
... Additional code for the lighting in the fragment shader
... shadowMap matrices, passing texcoords / normals, etc.

} // VP_Probe_Paraboloid


< Fragment Shader >
void main(
// VERTEX SHADER INPUT
...
float iZValue : TEXCOORD7,

out half4 oColor : COLOR0, // Result
)
{
oColor.a = 0;
clip( iZValue ); // Return if iZValue = 0?
// I'm not familiar with this Cg function

... Calculate lighting

// RESULT
oColor.rgb = (albedo * directDiffuse + emissive) * fog;
oColor.a = 1;

} // FP_Probe_Paraboloid

//------------------- DPM Usage ---------------------------------------------

< Vertex Shader >
void main(
float4 iPos : POSITION, // world position
float3 iNormal : NORMAL, // world normal

out float4 oPos : POSITION,
out float3 oNormal : TEXCOORD2,
out float3 oCamVec : TEXCOORD3,

uniform float4x4 MVP = MVP, // ModelViewProjection
uniform half3 cameraPos = V3_CAM_POS
)
{
oNormal.xyz = iNormal.xyz; // Pass world normal
oCamVec.xyz = iPos.xyz - cameraPos;
oPos = mul( MVP, iPos );
} // VP_DPM_Test

< Fragment Shader >
void main(
out half4 oColor : COLOR0,

float3 iNormal : TEXCOORD2,
float3 iCamVec : TEXCOORD3,

uniform sampler2D frontMap : TEXUNIT0,
uniform sampler2D backMap : TEXUNIT1,

uniform float3x3 ParaboloidBasis = TEX_MATRIX1 // modelView used when generating the probe.
// Stored in texture matrix
)
{
float3 E = normalize( iCamVec ); // normalize input per-vertex eye vector
float3 R = reflect( E, iNormal ); // calculate the reflection vector

//! R = mul( (float3x3)ParaboloidBasis, R ); // transform reflection vector to the maps basis

// calculate the forward paraboloid map texture coordinates
float2 front;
front.x = (R.x / (2*(1 + R.z))) + 0.5;
front.y = 1-((R.y / (2*(1 + R.z))) + 0.5);

// calculate the backward paraboloid map texture coordinates
float2 back;
back.x = (R.x / (2*(1 - R.z))) + 0.5;
back.y = 1-((R.y / (2*(1 - R.z))) + 0.5);

float3 forward = tex2D( frontMap, front ); // sample the front paraboloid map
float3 backward = tex2D( backMap , back ); // sample the back paraboloid map

oColor.rgb = max(forward, backward); // output the max of the two maps
oColor.a = 1;

} // FP_DPM_Test


Thanks, and good luck with your book!
Rick

Share this post


Link to post
Share on other sites
I think I see two different things in the shader code that could be changed. The first is not a source of error, but could be removed nonetheless. The divide by w after transforming to the paraboloid view space in the map generation vertex shader isn't needed. I had included it in the original article, but it isn't necesary since the matrix multiply doesn't include any projection (i.e. the w values will always be 1 without the divide anyways). So you can remove an unneeded divide from the vertex shader [grin].

The second point, and probably at least one source of error, is that the normal vector in the map accessing vertex shader is not transformed to world space. You are essentially using the object space normal vector of the geometry that is using the DPM instead of the world space vector. Here's the same operation from the original article shader code:

float3 N = normalize(mul(IN.normal, (float3x3)ModelWorld)); // find world space normal

This should at least be one step in the right direction. Try using the matrix multiply as it was originally, and then once it is working you can try to simplify and remove the instruction.

Also, I think the multiple render targets that you mention above is a little different than the texture arrays that I was talking about before (which use the geometry shader instead of the fragment shader). Even so, I think MRT should be useable as well but wouldn't really gain much performance. I would be very interested to hear if you try it out and have some success though!

Hopefully this helps get you up and running!

[Edited by - Jason Z on July 4, 2008 11:17:48 AM]

Share this post


Link to post
Share on other sites
Removing the division with position.w didn't hurt, removed that part. I don't understand the world-normal part though. All the vertex positions and normal are already in world space. Nothing is transformed, rotated or scaled (so far I'm only rendering a static world).

I tried multiplying the normal, but that didn't really work. But probably because I choose the wrong matrix. I'm not 100% sure, but "ModelView" matrix is not the same as "ModelWorld" matrix. This gives me the idea I'm using the wrong matrix for the "R = mul( dualParaboloidBasis, normal )" line as well. ModelWorld is not defined in OpenGL if I'm right, so I should make it myself. Unfortunately, I'm a disaster with matrices, so I need a helping hand on that.

But in the end I'm hoping to skip that part anyway. But yet again, I don't know how to correctly replace that part. Just commenting out the "R = mul..." line is not working. Here are some screenshots from what I have so far:
http://img364.imageshack.us/my.php?image=dpm1jh2.jpg
http://img354.imageshack.us/my.php?image=dpm2rq0.jpg

What you see on in the front/back maps is correct, although there a couple of problems. It's not exactly a nice circle. It seems that border polygons are falling away. You see the greenish polygons? These are polygons behind the ceiling/walls/floor. Normally they are culled away (therefore they have the wrong green color), but I disabled face culling. If I enable face culling, I only see the inverted world on the front map.

The cube with the reflections is not exactly correct either. That's because of skipping the matrix I suppose. If I enable the matrix operation, eventually with transforming the normal, the entire cube has only 1 color.
[edit]
I tried some simple code:

float3 E = normalize( iCamVec ); // normalize input per-vertex eye vector
float3 R = reflect( E, iNormal ); // calculate the reflection vector
if (R.z > 0)
{
float2 tx;
tx.x = 1-((R.x+1)*0.5); // maybe texture is swapped
tx.y = (R.y+1)*0.5;
oColor.rgb = tex2D( frontMap, tx );
} else
{
float2 tx;
tx.x = 1-((R.x+1)*0.5);
tx.y = (R.y+1)*0.5;
oColor.rgb = tex2D( backMap , tx );
}

This seems to work, without any matrices. I still see some wrong parts in the reflection though. That is because the circle is not filled entirely (see the 2 shots I posted). I don't know how to fix that. Maybe my scene is not tesselated enough? I estemate the big walls are subdivided in 1.5 x 1.5 metre parts.

Greetings,
Rick

[Edited by - spek on July 5, 2008 11:09:43 AM]

Share this post


Link to post
Share on other sites
Yes, you are correct. If the positions and normal vectors are already in world space (i.e. the only matrix in the modelview is the view matrix) then you don't need to multiply the normal.

After looking at the images that you posted and your comments about not filling in the circle - these symptoms are exactly what you will see if the scene isn't tessellated enough. Try rendering the paraboloid maps in wireframe and see what comes out. If there are any triangles that appear larger than ~10 pixels on any one side then it is either not tessellated finely enough or you are somehow rendering geometry that shouldn't be on that side of the paraboloid.

I think you are pretty close - just a few more small changes and you should be up and rendering...

EDIT: I am no expert in OpenGL, but I have used it a few times. The 'ModelView' matrix is indeed the combination of the world and view matrices from D3D. When setting the ModelView matrix, you set the identity first, then the view matrix on the matrix stack. Next you push on the model's world matrix, which gets pre-multiplied to the view matrix. The end result is a matrix that transforms the object space geometry to world space to view space all in one step.

Share this post


Link to post
Share on other sites
I'm happy to hear that I'm close. And the simplified reflection code works without costing too much energy. The only 2 problems are the missing polygons and the place where the 2 maps connect. The seam is not much noticable on curved objects, but a wall facing +x for example, will have a seam right in the middle (when facing straight forward). Maybe higher tesselation, higher render resolution (now I use 128x128) and/or blurring helps.

As for the tesselation, that will be the first thing to try. Hopefully it fixes the problem. However, no matter how much I increase the detail, very nearby polygons will always be relative big on the screen. I'm afraid there will always be some problems around the seams of the maps.


Another thing to consider is the tesselation itself. Maybe the bigger polycount itself isn't that much of a problem. I mean, a 10x10x4 meter chamber could be done with 6 quads. If I want 0.5 x 0.5 meter quads, I get 2880 polygons. Sounds much comparing to 12 polygons, but a few characters will have that polycount too. However, DPM is not the only thing that needs to be done. A lot of other passes need to be done as well. Maybe the lighting can profit from this as well (now I'm using cubemaps for pointlights), but ultimately, I have a low-res and high-res model. High-res for DPM passes, low-res for the rest.

My philosofy is that the map designer (if I ever get one crazy enough to share my hobby :) ) shouldn't be bothered with technical adjustments while mapping. Just sub-dividing the entire mesh into smaller bits is not a good option. Huge polygons stay huge, and already small polygons will get unnessarily much detail.

I could make a tool that makes a high-detail version of the original map. I don't know if its difficult to make such a thing. Another option might be tesselation in the vertex shader...? I never done it, but it's possible to increase the polycount realtime on the GPU right? Ifso, would that be a good thing to do, or would that cost way too much energy? In the end I'm using DPM to gain speed over cubeMaps, not to loose of course.

Osman's paper showed another way to do DPM with low-res models. It's not very clear to me how it works though. But maybe that's because I didn't have time to read it thoroughly so far.

[edit]
Another thing I'm thinking about right now. We save speed by only doing 2 passes instead of 6. But we also need bigger resolutions to get the same quality as a cubemap. In fact, I need even more pixels. For example, a cubeMap with 64x64 pixels has 24.576 pixels in total. I need at least a 128x128 DPM to match quality. 128x128x2 = 32.768 pixels. The actual quality is still less, since ~70% of the map is used -> 22.938 pixels. Of course I save speed with less pushing geometry to the hardware and less texture/shader switches. But the higher tesselation also has its costs. In fact, rendering a low-res scene (simple cube chamber with 12 polygons for example) 6 times (6x12 = 72) could still be (far) less polygons than render a high-tesselated scene twice.

So does DPM really a give a speed gain over cubeMaps, when trying to have the same quality as a cubeMap? I know, the best way to test this is by trying both. But maybe someone else also did some tests, and/or can explain where the real advantage is?

Thanks Jason & Osmanb,
Rick

[Edited by - spek on July 5, 2008 1:43:32 PM]

Share this post


Link to post
Share on other sites
I'm just glad to see people experimenting with DPM. We were sort of forced into using it due a combination of requirements, mostly the need to support several shadowing point lights simultaneously, and now we've grown to like it.

The technique from the paper I posted (doing the paraboloid projection in the pixel shader) just fixes the distortion during the receiver pass (which would be like your lighting pass). It doesn't help with the shadow-render pass (which would be equivalent to your pass that renders the reflecting environment into the DPMs).

However, we also did do some experiments with automatic hardware tessellation ... I'm not sure if that's actually available on most PCs or not. You still have the issues you've mentioned, where you only want to tessellate things that need it.

Another possibility, although we haven't tried this yet: There was a paper at the last I3D that talked about a way of removing the need for tessellation even during the initial pass.

http://portal.acm.org/citation.cfm?id=1342250.1342267&coll=GUIDE&dl=&type=series&idx=SERIES749%E2%88%82=series&WantType=Proceedings&title=I3D

I haven't read the whole thing, but I'm pretty sure the technique is basically two things:

1) For each triangle in the model, you can compute a larger polygon (which might even be two triangles) whose paraboloid projection is guaranteed to bound the correct paraboloid projection of the actual triangle. Basically, for large triangles, you artifically inflate them, so that when they get linearly rasterized into the DPMs, the resulting area covers the correct, curved, version of the original triangle. This might require geometry shaders (or an expensive pre-pass on the CPU).

2) In your pixel shader, during that initial pass, you do the math to figure out if the pixel you're rendering is actually inside the paraboloid projection of the triangle. If not, you kill it with something like 'clip'. In addition, your pixel shader outputs the correct (paraboloid warped) depth value, rather than the (incorrect, linearly interpolated) one from the rasterization.

Those two things are both fairly expensive, so it's not clear if the technique is really feasible, especially in your case where you want to be rendering several DPMs. But on the other hand, they produce effectively PERFECT paraboloid views of your scene, with no tessellation requirement at all.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Announcements

  • Forum Statistics

    • Total Topics
      628342
    • Total Posts
      2982178
  • Similar Content

    • By test opty
      Hi all,
       
      I'm starting OpenGL using a tut on the Web. But at this point I would like to know the primitives needed for creating a window using OpenGL. So on Windows and using MS VS 2017, what is the simplest code required to render a window with the title of "First Rectangle", please?
       
       
    • By DejayHextrix
      Hi, New here. 
      I need some help. My fiance and I like to play this mobile game online that goes by real time. Her and I are always working but when we have free time we like to play this game. We don't always got time throughout the day to Queue Buildings, troops, Upgrades....etc.... 
      I was told to look into DLL Injection and OpenGL/DirectX Hooking. Is this true? Is this what I need to learn? 
      How do I read the Android files, or modify the files, or get the in-game tags/variables for the game I want? 
      Any assistance on this would be most appreciated. I been everywhere and seems no one knows or is to lazy to help me out. It would be nice to have assistance for once. I don't know what I need to learn. 
      So links of topics I need to learn within the comment section would be SOOOOO.....Helpful. Anything to just get me started. 
      Thanks, 
      Dejay Hextrix 
    • By mellinoe
      Hi all,
      First time poster here, although I've been reading posts here for quite a while. This place has been invaluable for learning graphics programming -- thanks for a great resource!
      Right now, I'm working on a graphics abstraction layer for .NET which supports D3D11, Vulkan, and OpenGL at the moment. I have implemented most of my planned features already, and things are working well. Some remaining features that I am planning are Compute Shaders, and some flavor of read-write shader resources. At the moment, my shaders can just get simple read-only access to a uniform (or constant) buffer, a texture, or a sampler. Unfortunately, I'm having a tough time grasping the distinctions between all of the different kinds of read-write resources that are available. In D3D alone, there seem to be 5 or 6 different kinds of resources with similar but different characteristics. On top of that, I get the impression that some of them are more or less "obsoleted" by the newer kinds, and don't have much of a place in modern code. There seem to be a few pivots:
      The data source/destination (buffer or texture) Read-write or read-only Structured or unstructured (?) Ordered vs unordered (?) These are just my observations based on a lot of MSDN and OpenGL doc reading. For my library, I'm not interested in exposing every possibility to the user -- just trying to find a good "middle-ground" that can be represented cleanly across API's which is good enough for common scenarios.
      Can anyone give a sort of "overview" of the different options, and perhaps compare/contrast the concepts between Direct3D, OpenGL, and Vulkan? I'd also be very interested in hearing how other folks have abstracted these concepts in their libraries.
    • By aejt
      I recently started getting into graphics programming (2nd try, first try was many years ago) and I'm working on a 3d rendering engine which I hope to be able to make a 3D game with sooner or later. I have plenty of C++ experience, but not a lot when it comes to graphics, and while it's definitely going much better this time, I'm having trouble figuring out how assets are usually handled by engines.
      I'm not having trouble with handling the GPU resources, but more so with how the resources should be defined and used in the system (materials, models, etc).
      This is my plan now, I've implemented most of it except for the XML parts and factories and those are the ones I'm not sure of at all:
      I have these classes:
      For GPU resources:
      Geometry: holds and manages everything needed to render a geometry: VAO, VBO, EBO. Texture: holds and manages a texture which is loaded into the GPU. Shader: holds and manages a shader which is loaded into the GPU. For assets relying on GPU resources:
      Material: holds a shader resource, multiple texture resources, as well as uniform settings. Mesh: holds a geometry and a material. Model: holds multiple meshes, possibly in a tree structure to more easily support skinning later on? For handling GPU resources:
      ResourceCache<T>: T can be any resource loaded into the GPU. It owns these resources and only hands out handles to them on request (currently string identifiers are used when requesting handles, but all resources are stored in a vector and each handle only contains resource's index in that vector) Resource<T>: The handles given out from ResourceCache. The handles are reference counted and to get the underlying resource you simply deference like with pointers (*handle).  
      And my plan is to define everything into these XML documents to abstract away files:
      Resources.xml for ref-counted GPU resources (geometry, shaders, textures) Resources are assigned names/ids and resource files, and possibly some attributes (what vertex attributes does this geometry have? what vertex attributes does this shader expect? what uniforms does this shader use? and so on) Are reference counted using ResourceCache<T> Assets.xml for assets using the GPU resources (materials, meshes, models) Assets are not reference counted, but they hold handles to ref-counted resources. References the resources defined in Resources.xml by names/ids. The XMLs are loaded into some structure in memory which is then used for loading the resources/assets using factory classes:
      Factory classes for resources:
      For example, a texture factory could contain the texture definitions from the XML containing data about textures in the game, as well as a cache containing all loaded textures. This means it has mappings from each name/id to a file and when asked to load a texture with a name/id, it can look up its path and use a "BinaryLoader" to either load the file and create the resource directly, or asynchronously load the file's data into a queue which then can be read from later to create the resources synchronously in the GL context. These factories only return handles.
      Factory classes for assets:
      Much like for resources, these classes contain the definitions for the assets they can load. For example, with the definition the MaterialFactory will know which shader, textures and possibly uniform a certain material has, and with the help of TextureFactory and ShaderFactory, it can retrieve handles to the resources it needs (Shader + Textures), setup itself from XML data (uniform values), and return a created instance of requested material. These factories return actual instances, not handles (but the instances contain handles).
       
       
      Is this a good or commonly used approach? Is this going to bite me in the ass later on? Are there other more preferable approaches? Is this outside of the scope of a 3d renderer and should be on the engine side? I'd love to receive and kind of advice or suggestions!
      Thanks!
    • By nedondev
      I 'm learning how to create game by using opengl with c/c++ coding, so here is my fist game. In video description also have game contain in Dropbox. May be I will make it better in future.
      Thanks.
  • Popular Now